Skip to content

Commit

Permalink
v4l2loopback: Fixup bytesused field when writer sends a too large value
Browse files Browse the repository at this point in the history
Gstreamer's v4l2sink is known to submit buffers with bytesused set to
the length of the buffer instead of the size of the actual image-data
within the buffer which is typically smaller due to buffer sizes
being rounded op to a page-size:

https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2532

Despite this being a long standing issue and their being 2 merge-reqs:

https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3713
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4527

to try and fix this it looks like this is not going to get fixed
in gst's v4l2sink anytime soon and even if once it is fixed many users
will likely be using an older v4l2sink which still has this bug.

These buffers with a too large bytes used value are causing issues
with various apps which reject these buffers when reading from
the v4l2loopback device, such as e.g. ffmpeg and firefox.

Add a pix_format_has_valid_sizeimage flag which gets set from
vidioc_s_fmt_out() if dev->pix_format.sizeimage is known to have just
been set to a valid, fixed size (so this e.g. won't be set for MJPG).

And then fix this issue by making vidioc_qbuf() truncate
V4L2_BUF_TYPE_VIDEO_OUTPUT buffer's bytes_used value to
dev->pix_format.sizeimage when this flag is set.

Closes #190
Closes #448
Obsoletes #435
  • Loading branch information
jwrdegoede committed May 8, 2023
1 parent 2c9b670 commit 175adaf
Showing 1 changed file with 29 additions and 1 deletion.
30 changes: 29 additions & 1 deletion v4l2loopback.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ struct v4l2_loopback_device {
struct video_device *vdev;
/* pixel and stream format */
struct v4l2_pix_format pix_format;
bool pix_format_has_valid_sizeimage;
struct v4l2_captureparm capture_param;
unsigned long frame_jiffies;

Expand Down Expand Up @@ -543,6 +544,20 @@ static int v4l2l_fill_format(struct v4l2_format *fmt, int capture,
return 0;
}

/* Checks if v4l2l_fill_format() has set a valid, fixed sizeimage val. */
static bool v4l2l_pix_format_has_valid_sizeimage(struct v4l2_format *fmt)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
const struct v4l2_format_info *info;

info = v4l2_format_info(fmt->fmt.pix.pixelformat);
if (info && info->mem_planes == 1)
return true;
#endif

return false;
}

static int pix_format_eq(const struct v4l2_pix_format *ref,
const struct v4l2_pix_format *tgt, int strict)
{
Expand Down Expand Up @@ -1220,6 +1235,8 @@ static int vidioc_s_fmt_out(struct file *file, void *priv,
ret = inner_try_setfmt(file, fmt);
if (!ret) {
dev->pix_format = fmt->fmt.pix;
dev->pix_format_has_valid_sizeimage =
v4l2l_pix_format_has_valid_sizeimage(fmt);
dprintk("s_fmt_out(%d) %d...%d\n", ret, dev->ready_for_capture,
dev->pix_format.sizeimage);
dprintk("outFOURCC=%s\n",
Expand Down Expand Up @@ -1717,7 +1734,18 @@ static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
b->buffer.timestamp = buf->timestamp;
b->buffer.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
}
b->buffer.bytesused = buf->bytesused;
if (dev->pix_format_has_valid_sizeimage) {
if (buf->bytesused >= dev->pix_format.sizeimage) {
b->buffer.bytesused = dev->pix_format.sizeimage;
} else {
dev_warn_ratelimited(&dev->vdev->dev, "warning queued output buffer bytesused too small %d < %d\n",
buf->bytesused, dev->pix_format.sizeimage);
b->buffer.bytesused = buf->bytesused;
}
} else {
b->buffer.bytesused = buf->bytesused;
}

set_done(b);
buffer_written(dev, b);

Expand Down

0 comments on commit 175adaf

Please sign in to comment.