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