I have a Raspberry Pi 3 with the latest Raspbian Stretch, and the Sony 8MB official camera.
I can save a good looking JPEG with the following commands:
v4l2-ctl --set-fmt-video=width=2592,height=1944,pixelformat=3
v4l2-ctl --stream-mmap=3 --stream-count=1 --stream-to=somefile.jpg
I can list all formats with this command:
root@raspberrypi:/home/pi# v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Index : 0
Type : Video Capture
Pixel Format: 'YU12'
Name : Planar YUV 4:2:0
Size: Stepwise 32x32 - 3280x2464 with step 2/2
...
Index : 3
Type : Video Capture
Pixel Format: 'JPEG' (compressed)
Name : JFIF JPEG
Size: Stepwise 32x32 - 3280x2464 with step 2/2
Now I want to translate the v4l2-ctl capture of a JPEG to C++ / Qt5 with libv4l2. My code is shown below and whenever I run it on the Pi, I get the following error:
root@raspberrypi:/home/pi# ./v4l2-test
Begin Capture
VIDIOC_STREAMON: Operation not permitted
C++ Code:
#include <QCoreApplication>
// C++ / V4L2 Includes
#include <linux/videodev2.h>
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
// Debugging
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Begin Capture";
int fd;
if((fd = open("/dev/video0", O_RDWR)) < 0){
perror("open");
exit(1);
}
struct v4l2_capability cap;
if(ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0){
perror("VIDIOC_QUERYCAP");
exit(1);
}
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
fprintf(stderr, "The device does not handle single-planar video capture.\n");
exit(1);
}
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
format.fmt.pix.width = 2592;
format.fmt.pix.height = 1944;
if(ioctl(fd, VIDIOC_S_FMT, &format) < 0){
perror("VIDIOC_S_FMT");
exit(1);
}
struct v4l2_requestbuffers bufrequest;
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 1;
if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0){
perror("VIDIOC_REQBUFS");
exit(1);
}
struct v4l2_buffer bufferinfo;
memset(&bufferinfo, 0, sizeof(bufferinfo));
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = 0;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0){
perror("VIDIOC_QUERYBUF");
exit(1);
}
void* buffer_start = mmap(
NULL,
bufferinfo.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
bufferinfo.m.offset
);
if(buffer_start == MAP_FAILED){
perror("mmap");
exit(1);
}
memset(buffer_start, 0, bufferinfo.length);
// Activate streaming
int type = bufferinfo.type;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0){
perror("VIDIOC_STREAMON");
exit(1);
}
/* Here is where you typically start two loops:
* - One which runs for as long as you want to
* capture frames (shoot the video).
* - One which iterates over your buffers everytime. */
bool capture_is_running = true;
while(capture_is_running){
for(int i = 0; i < bufrequest.count; i++){
// Put the buffer in the incoming queue.
if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0){
perror("VIDIOC_QBUF");
exit(1);
}
// The buffer's waiting in the outgoing queue.
if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0){
perror("VIDIOC_QBUF");
exit(1);
}
}
}
// Deactivate streaming
if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0){
perror("VIDIOC_STREAMOFF");
exit(1);
}
close(fd);
return EXIT_SUCCESS;
return a.exec();
}
What am I doing wrong? The camera works and I run as root, but for some reason I get "Permission Denied". I appreciate any help - thanks.
UPDATE - The exact error I see is shown below as well as the terminal output showing that "root" is in the "video" group
root@raspberrypi:/home/pi# groups root
root : root video
root@raspberrypi:/home/pi# ./v4l2-test
Begin Capture
VIDIOC_STREAMON: Operation not permitted
UPDATE: Running 'file' on the v4l2-ctl saved image shows the 2592x1944 sized frame:
root@raspberrypi:/tmp# file somefile.jpg
somefile.jpg: JPEG image data, Exif standard: [TIFF image data, big-endian, direntries=9, height=0, model=imx219, xresolution=130, yresolution=138, resolutionunit=2, datetime=1970:01:01 00:00:00, width=0], baseline, precision 8, 2592x1944, frames 3
UPDATE: Here is a paste of the complete STRACE output of all commands:
https://zerobin.net/?84fee190a4a904a0#ZZOwDe7ftBKjpqpP/lPfnTMPrUlILyJaCCCyunO6aug=
UPDATE: Linking step of application compilation
/home/me/Desktop/buildroot/output/host/bin/arm-buildroot-linux-gnueabihf-g++ --sysroot=/home/me/Desktop/buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot -o v4l2-test main.o -lrt -lpthread -ldl -latomic
UPDATE: I removed my S_FMT ioctl, but the issue still continues:
struct v4l2_format format;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
// 3280x2464
format.fmt.pix.width = 3280;
format.fmt.pix.height = 2464;
// if(ioctl(fd, VIDIOC_S_FMT, &format) < 0){
// perror("VIDIOC_S_FMT");
// exit(1);
// }
struct v4l2_requestbuffers bufrequest;
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 1;
UPDATE: I just checked dmesg again I'm seeing the following error - however Google has not turned up anything so far...
Jan 06 01:40:19 raspberrypi kernel: video0: VIDIOC_QUERYCAP
Jan 06 01:40:19 raspberrypi kernel: video0: VIDIOC_S_FMT
Jan 06 01:40:19 raspberrypi kernel: video0: VIDIOC_REQBUFS
Jan 06 01:40:19 raspberrypi kernel: video0: VIDIOC_QUERYBUF
Jan 06 01:40:20 raspberrypi kernel: bcm2835-v4l2: Failed to enable capture port - error -28. Disabling camera port again
Jan 06 01:40:20 raspberrypi kernel: video0: VIDIOC_STREAMON: error -1
UPDATE: Per suggestion - I tried increasing the buffer count to 3 - but it did not help:
struct v4l2_requestbuffers bufrequest;
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 3;
if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0){
perror("VIDIOC_REQBUFS");
exit(1);
}
fprintf(stderr,"Buffer Request is for 3 buffers...\n");
pi
is invideo
according to/etc/group
? Chances are it is as that's the Raspbian default and if it weren't you'd getopen: Permission denied
, but good to confirm. 2. In your post you wrote you're gettingOperation not permitted
(EPERM) but at the end you said "Permission Denied" (EACCES) in quotes. Could you clarify? 3.guvcview
andcheese
also work fine as non-root?v4l2-ctl --stream-mmap...
vs your program (starting fromopen("/dev/video0", O_RDWR)
down toVIDIOC_STREAMON
)? My USB camera works in both cases, but I notice that v4l2-ctl swaps the order of the first VIDIOC_QBUF with VIDIOC_STREAMON.perror()
and those happen after theEPERM
anyway. I also realized that ordering of VIODIC_QBUF/VIDIOC_STREAMON may be an artifact of strace order inaccuracy. Next:somefile.jpg
is viewable, but if you runfile somefile.jpg
is it the requested resolution 2592x1944? And 2592x1944 is for Camera Module V1 but yourv4l2-ctl --list-formats-ext
indicates this is Camera Module V2 (3280x2464), plus you said it's the Sony module. Strange if wrong resolution has different behavior on root vsvideo
, but might as well fix your code and rule it out?