0

I'm using v4l2loopback to create a virtual camera device. The VIDIOC_S_FMT operation is unable to set the format of the output device. The operation doesn't return an error, which is expected as it was explained in the documentation.

Drivers should not return an error code unless the type field is invalid, this is a mechanism to fathom device capabilities and to approach parameters acceptable for both the application and driver.

The documentation also mentions that under normal circumstances the hardware should be programmed, however some very simple and inflexible devices may continue to retain the original format. I think this is exactly what's happening.

On success, the driver may program the hardware, allocate resources and generally prepare for data exchange. ... Very simple, inflexible devices may even ignore all input and always return the default parameters.

// Step 1: open output video device here
#define VIDEO_OUT  "/dev/video6"
int output = open(VIDEO_OUT, O_RDWR);

Question 1: Considering that output has the following specs by default, it is possible to create output with the desired format so that VIDIOC_S_FMT operation can be avoided all together?

v4l2 --   desc   Planar YUV 4:2:0 
v4l2 --   flags V4L2_FMT_FLAG_UNCOMPRESSED 
v4l2 --   fourcc 0x32315559  YUV 4:2:0 (V4L2_PIX_FMT_YUV420)
// Step 2: acquire video format from device
struct v4l2_format old_format;
memset(&vid_format, 0, sizeof(vid_format));
vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (ioctl(output, VIDIOC_G_FMT, &vid_format) < 0) {
    std::cerr << "ERROR: unable to get video format!\n" <<
    strerror(errno); return -1;
}
// Print old_format here
v4l2 --   width  640
v4l2 --   height 480
v4l2 --   pitch  640
v4l2 --   size   460800
v4l2 --   format 0x32315559  YUV 4:2:0 (V4L2_PIX_FMT_YUV420)
v4l2 --   color  0x8
v4l2 --   field  0x1
// Step 3: configure desired video format on device
struct v4l2_format new_format;
memset(&new_format, 0, sizeof(new_format));
new_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
new_format.fmt.pix.width = w;
new_format.fmt.pix.height = h;
new_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
new_format.fmt.pix.sizeimage = framesize;
new_format.fmt.pix.field = V4L2_FIELD_NONE;
// Print new_format here
v4l2 --   width  640
v4l2 --   height 480
v4l2 --   pitch  1280
v4l2 --   size   614400
v4l2 --   format 0x56595559  YUV 4:2:2 (V4L2_PIX_FMT_YUYV)
v4l2 --   color  0x8
v4l2 --   field  0x1
// Step 4: attempt to set desired format
if (ioctl(output, VIDIOC_S_FMT, &new_format) < 0) {
    std::cerr << "ERROR: unable to set video format!\n" <<
    strerror(errno); return -1;
}
// Step 5: validate 
memset(&old_format, 0, sizeof(old_format));
old_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (ioctl(output, VIDIOC_G_FMT, &old_format) < 0) {
    std::cerr << "ERROR: unable to get video format!\n" <<
    strerror(errno); return -1;
}
// Print old_format here
v4l2 --   width  640
v4l2 --   height 480
v4l2 --   pitch  640
v4l2 --   size   460800
v4l2 --   format 0x32315559  YUV 4:2:0 (V4L2_PIX_FMT_YUV420)
v4l2 --   color  0x8
v4l2 --   field  0x1

This proves that the created output device falls into the "Very simple, inflexible device" category mentioned in the documentation.

Question 2: If VIDIOC_S_FMT operation is unavoidable, how can I create output such that it will allow the VIDIOC_S_FMT operation to change the default format?

Footer:

$ dmesg | grep v4l2loopback
[1388580.105991] v4l2loopback driver version 0.12.5 loaded
csg
  • 8,096
  • 3
  • 14
  • 38

0 Answers0