How to capture raw uncompressed picture of YUYV formatin c++ using v4l2

I have a webcam connected to beaglebone via usb. I am coding in c++ and my goal is to capture raw UNCOMPRESSED picture from the webcam. Firstly i checked what formats are supported via commandand v4l2-ctl --list-formats the result was:

1
2
3
4
5
6
7
8
9
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2



So from this I assume it has to be possible to get an uncompressed picture if i try to use YUYV format.

Knowing this I started writing a program in c++. I successfully written a program to capture a compressed picture, but when trying to capture using format YUYV it doesnt work and i really need some help to get this done.

Here is my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>


template <typename typeXX>
void clear_memmory(typeXX* x) {
    memset(x, 0, sizeof(*x));
    }
    
void xioctl(int cd, int request, void *arg){
    int response;
    do{
        //ensures we get the correct response.
        response = v4l2_ioctl(cd, request, arg);
        }
    while (response == -1 && ((errno == EINTR) || (errno == EAGAIN)));

    if (response == -1) {
        fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
        }
    }
    
    struct LMSBBB_buffer{
    void*  start;
    size_t length;
    };

int main(){
    
    const char* dev_name = "/dev/video0";
    int width=1920;
    int height=1080;
    
    int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
    
    struct v4l2_format format = {0};
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;//V4L2_PIX_FMT_YUYV //V4L2_PIX_FMT_RGB24
    format.fmt.pix.field = V4L2_FIELD_NONE; //V4L2_FIELD_NONE
    xioctl(fd, VIDIOC_S_FMT, &format);

        
    printf("Device initialized.\n");
    
    
    ///request buffers  
    struct v4l2_requestbuffers req = {0};
    req.count = 2;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    xioctl(fd, VIDIOC_REQBUFS, &req);

    printf("Buffers requested.\n");
    

    ///mapping buffers  
    struct v4l2_buffer buf;
    LMSBBB_buffer* buffers;
    unsigned int i;
    buffers = (LMSBBB_buffer*) calloc(req.count, sizeof(*buffers));
    for (i = 0; i < req.count; i++) {
    clear_memmory(&(buf));

    (buf).type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    (buf).memory      = V4L2_MEMORY_MMAP;
    (buf).index       = i;

    xioctl(fd, VIDIOC_QUERYBUF, &buf);

    buffers[i].length = (buf).length;
    printf("A buff has a len of: %i\n",buffers[i].length);
    buffers[i].start = v4l2_mmap(NULL, (buf).length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, (buf).m.offset);
    
    if (MAP_FAILED == buffers[i].start) {
        perror("Can not map the buffers.");
        exit(EXIT_FAILURE);
        }
    }
    printf("Buffers mapped.\n");    
    
    for (i = 0; i < req.count; i++) {
        clear_memmory(&(buf));
        (buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        (buf).memory = V4L2_MEMORY_MMAP;
        (buf).index = i;
        ioctl(fd,VIDIOC_QBUF, &(buf));
        }
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd,VIDIOC_STREAMON, &type);
    
    
    printf("buffers queued and streaming.\n");
    
    
    
    int pic_count=0;
    ///CAPTURE
    fd_set fds;
    struct timeval tv;
    int r;
    char out_name[256];
    FILE* fout;
        

        
    do {
        FD_ZERO(&fds);
        FD_SET(fd, &fds);

        // Timeout.
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        r = select(fd + 1, &fds, NULL, NULL, &tv);
        } while ((r == -1 && (errno = EINTR)));
    if (r == -1) {
        perror("select");
        exit(EXIT_FAILURE);
        }

    clear_memmory(&(buf));
    (buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    (buf).memory = V4L2_MEMORY_MMAP;
    xioctl(fd,VIDIOC_DQBUF, &(buf));
    
    printf("Buff index: %i\n",(buf).index);
    sprintf(out_name, "image%03d.ppm",pic_count);
    fout = fopen(out_name, "w");
    if (!fout) {
        perror("Cannot open image");
        exit(EXIT_FAILURE);
        }
    fprintf(fout, "P6\n%d %d 255\n",width, height);
    fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
    fclose(fout);
    pic_count++;
    
    clear_memmory(&(buf));
    (buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    (buf).memory = V4L2_MEMORY_MMAP;
    xioctl(fd,VIDIOC_DQBUF, &(buf));
    printf("Buff index: %i\n",(buf).index);
    sprintf(out_name, "image%03d.ppm",pic_count);
    fout = fopen(out_name, "w");
    if (!fout) {
        perror("Cannot open image");
        exit(EXIT_FAILURE);
        }
    fprintf(fout, "P6\n%d %d 255\n",width, height);
    fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
    fclose(fout);
    pic_count++;
    
    
    ///xioctl(fd,VIDIOC_QBUF, &(buf));
    
    
    return 0;
    }


in line 50, i can choose the format between V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_RGB24. for V4L2_PIX_FMT_RGB24 i get the picture, but when using V4L2_PIX_FMT_YUYV I get this error:
1
2
3
4
5
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable


the error lines goes for ever until i end the program manually.

Does anyone have an idea what to do? I spent over 2 weeks on this and i can't move anywhere from here. I would really appreciate any advice.
Always check return code for every function in your code to make troubleshooting easier, for example:

1
2
if (ioctl (fd, VIDIOC_S_FMT, &fmt) == -1)
	// Function failed 


1
2
3
4
int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);

if (fd == -1)
        // Function failed 



Ensure your camera is supported see header comment:
https://github.com/philips/libv4l/blob/master/include/libv4l2.h

Note the device name passed to v4l2_open must be of a video4linux2 device,
if it is anything else (including a video4linux1 device), v4l2_open will
fail.


I suggest you take a look at implementation of v4l2_fd_open in
https://github.com/philips/libv4l/blob/master/libv4l2/libv4l2.c

You can see code how to query device caps to learn more about your device before actually using it, ex. copy paste portions of the code into your main or check for return value and errno variable value.

Firstly i checked what formats are supported via commandand v4l2-ctl --list-formats

From what I understand (trough header docs), the library may support even if your device is not supported.

Following library may also be of help:
https://www.libraw.org/about
Last edited on
Everything works if in line 50 is:
V4L2_PIX_FMT_RGB24;

But if I put V4L2_PIX_FMT_YUYV in line 50, the program fails in line137 with repeating the error i showed above.

I am not checking any of the file descriptors beacuse i already checked that pieces gets done correct and i needed more clear view of other things.

yes, the camera of course supports YUYV.
Last edited on
OK, under assumption error handling is in place, I would step into v4l2_ioctl in your xioctl.

If you do so on which line does the v4l2_ioctl fail or where does it lead you?
You can use this approach to investigate further and step deeper into code.

EDIT:
Note that you get repeating error because you loop on error:

while (response == -1 && ((errno == EINTR) || (errno == EAGAIN)));

Which doesn't make much sense without a sleep function and some timeout value to exit program.
Last edited on
In case if I in line 50 set to V4L2_PIX_FMT_YUYV the program goes all until line 137, there xioctl is called and because icotl is there in loop of the xioctl then i keep getting:

1
2
3
4
5
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable


But if in line 50 i have V4L2_PIX_FMT_RGB24, everything works, and i get the image saved. Program ends sucesfully.
So what could be the problem for causing dequeing buf problem?

could it maybe be possible to save a picture without dequeing althogether?
Last edited on
I understand but we can only guess on why "resource is unavailable" without stepping into v4l2_ioctl, unless someone skilled with the library reads this thread..

Can you step into v4l2_ioctl? do you have sources installed or did you build the library yourself?
I don't know your environment setup so I can't give advice on stepping into external code.

Last edited on
What exactly means step into v4l2_ioctl?

btw, i changed resolution to 320x240, the error still appears exactly the same, but now only 20 of them and then program sucessfully completes. I even get the picture in yuyv format.

I checked what is happening in xioctl loop and appearently errno is getting EAGAIN: 11 . And after around 20 tries it somehow gets over it.

I assume it has to be possible to avoid this somehow? any ideas what i do next? I need this working in 1920x1080 and there the error just keeps poping up for ever.
What exactly means step into v4l2_ioctl?


v4l2_ioctl is an external function, meaning a function that is not your code, therefore the debugger (which ever you're using) will not "step into" trough code of that function (instead it will just "step over") unless you configure your debugger to let him know where are the sources (*.c files) of libv4l2 library.

To step into, you put a breakpoint on line 23:
response = v4l2_ioctl(cd, request, arg);

when breakpoint is hit, you step into v4l2_ioctl function, how do you step into depends on debugger you're using.
but unless the debugger knows the location of sources or unless source code is directly part of your project it will not step in.

I assume it has to be possible to avoid this somehow?

sure there must be a solution, my idea is to investigate the problem with that method, to step in and watch what's happening.
Registered users can post here. Sign in or register to post.