Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Our producer is always getting the same (shared mem) buffer and so does the example producer #607

Open
1 task done
Misterke opened this issue Dec 10, 2024 · 5 comments · May be fixed by #608
Open
1 task done
Assignees
Labels

Comments

@Misterke
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Detail

We are using v4l2loopback to pass uncompressed video frames between two applications, but were noticing tearing and other "corruption" as if the buffer that the consumer received was actually being overwritten by the producer before the consumer queued it again.

We noticed the producer was every time getting the same buffer from DQBUF and the consumer then also always got that same buffer.

Then we tried the test applications "producer" and "consumer" that are provided with v4l2loopback and also see similar behavior:


~/v4l2loopback/tests$ ./producer -c -1
get format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
tried format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
got format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
set format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
finalizing format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
final format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
requested 4 buffers, got 2
requested buffer 0/4: buffer#0 @ 0x7ffe93838e50 OUTPUT bytesused=614400, length=614400 flags=0x00000002 field=none timestamp=6676956.317695 memory=MMAP (offset=0)
buffer#0 @0x7ba3b3167000 of 614400 bytes
requested buffer 1/4: buffer#1 @ 0x7ffe93838e50 OUTPUT bytesused=614400, length=614400 flags=0x00000002 field=none timestamp=6676956.317695 memory=MMAP (offset=614400)
buffer#1 @0x7ba3b30d1000 of 614400 bytes
MMAP init qbuf 0/2 (length=614400): buffer#0 @ 0x7ffe93839020 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP init qbuf 1/2 (length=614400): buffer#1 @ 0x7ffe93839020 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP    buffer#1 @ 0x7ffe93839000 OUTPUT bytesused=614400, length=614400 flags=0x00000001 field=none timestamp=0.000000 memory=MMAP (offset=614400)

Notice that also this producer is always getting buffer#1 despite having received 2 buffers at initialization.

So, is this a huge bug in v4l2loopback or are we totally missing how passing buffers through v4l2loopback is supposed to work?



### v4l2loopback version

v0.13.2-13-ge750af9

### kernel version

```text
Linux rd-int-nuc-1 6.8.0-45-generic #45-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 30 12:02:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
(but also seen on ARM architecture)

OS Version

Ubuntu 24.04.1 LTS

Which CPU are you using?

amd64/x86_64 ("64bit Intel"), arm64 ("64bit ARM"; e.g. Apple Silicon,...)

@stephematician
Copy link
Contributor

Can you provide a link to your source code? I think QBUF needs to be called on all buffers when streaming begins.

@Misterke
Copy link
Author

Misterke commented Dec 12, 2024

@stephematician , the source code is simply that of the producer and consumer in the tests folder of v4l2loopback itself. If you run that producer, it already mentions that it is always getting the same buffer on every dqbuf (irrespective of whether a consumer is running or not).

@stephematician
Copy link
Contributor

stephematician commented Dec 13, 2024

Looks like this was introduced in 97dc86b? NFI if this was intended. v4l2loopback maintains an 'outbuffer list'; It looks like that when dequeue occurs it returns the tail of that list, then moves the tail to ... the tail. It absolutely looks like a bug to me; and isn't linked to any 'issue' that I can find.

		b = list_entry(dev->outbufs_list.prev, struct v4l2l_buffer,
			       list_head);
		list_move_tail(&b->list_head, &dev->outbufs_list);

The use of dev->outbufs_list.next would make more sense, as this would take the first item in the list and add it to the end; see /include/linux/list.h from the kernel for a macro for getting the first item:

/**
 * list_first_entry - get the first element from a list
 * @ptr:	the list head to take the element from.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 *
 * Note, that list is expected to be not empty.
 */
#define list_first_entry(ptr, type, member) \
	list_entry((ptr)->next, type, member)

That macro has existed since 2.6.22; it might be good practise to use it here rather than relying on things internal to list_head.

@stephematician
Copy link
Contributor

This is what I get from producer if I revert the commit - looks good to me?

user@home:~v4l2loopback/tests$ sudo modprobe v4l2loopback max_buffers=4 video_nr=10
user@home:~v4l2loopback/tests$ ./producer -c 6 -d /dev/video10
get format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
tried format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
got format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
set format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
finalizing format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
final format: OUTPUT:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
requested 4 buffers, got 4
requested buffer 0/4: buffer#0 @ 0x7fff413ce0e0 OUTPUT bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40138.746690 memory=MMAP (offset=0)
buffer#0 @0x7d8386c40000 of 614400 bytes
requested buffer 1/4: buffer#1 @ 0x7fff413ce0e0 OUTPUT bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40138.746691 memory=MMAP (offset=614400)
buffer#1 @0x7d838696a000 of 614400 bytes
requested buffer 2/4: buffer#2 @ 0x7fff413ce0e0 OUTPUT bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40138.746692 memory=MMAP (offset=1228800)
buffer#2 @0x7d83868d4000 of 614400 bytes
requested buffer 3/4: buffer#3 @ 0x7fff413ce0e0 OUTPUT bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40138.746693 memory=MMAP (offset=1843200)
buffer#3 @0x7d838683e000 of 614400 bytes
MMAP init qbuf 0/4 (length=614400): buffer#0 @ 0x7fff413ce2b0 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP init qbuf 1/4 (length=614400): buffer#1 @ 0x7fff413ce2b0 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP init qbuf 2/4 (length=614400): buffer#2 @ 0x7fff413ce2b0 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP init qbuf 3/4 (length=614400): buffer#3 @ 0x7fff413ce2b0 OUTPUT bytesused=614400, length=614400 flags=0x00000000 field=any timestamp=0.000000 memory=MMAP (offset=0)
MMAP	buffer#0 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=0)
MMAP	buffer#1 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=614400)
MMAP	buffer#2 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=1228800)
MMAP	buffer#3 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=1843200)
MMAP	buffer#0 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=0)
MMAP	buffer#1 @ 0x7fff413ce290 OUTPUT bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=0.000000 memory=MMAP (offset=614400)

If I invoke consumer in a separate terminal while the producer is running (invoked with more frames so it runs long enough for me to switch to a new terminal):

user@home:~v4l2loopback/tests$ ./consumer -d /dev/video10
got format: CAPTURE:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
set format: CAPTURE:640x480:YUYV bytes/line=1280 sizeimage=614400 field=none
requested 4 buffers, got 4
requested buffer 0/4: buffer#0 @ 0x7ffe9330f8d0 CAPTURE bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40304.269190 memory=MMAP (offset=0)
requested buffer 1/4: buffer#1 @ 0x7ffe9330f8d0 CAPTURE bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40304.269190 memory=MMAP (offset=614400)
requested buffer 2/4: buffer#2 @ 0x7ffe9330f8d0 CAPTURE bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40304.269191 memory=MMAP (offset=1228800)
requested buffer 3/4: buffer#3 @ 0x7ffe9330f8d0 CAPTURE bytesused=614400, length=614400 flags=0x00002002 field=none timestamp=40304.269192 memory=MMAP (offset=1843200)
MMAP	buffer#3 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.269192 memory=MMAP (offset=1843200)
MMAP	buffer#0 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.289982 memory=MMAP (offset=0)
MMAP	buffer#1 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.326207 memory=MMAP (offset=614400)
MMAP	buffer#2 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.362905 memory=MMAP (offset=1228800)
MMAP	buffer#3 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.400182 memory=MMAP (offset=1843200)
MMAP	buffer#0 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.436792 memory=MMAP (offset=0)
MMAP	buffer#1 @ 0x7ffe9330fde0 CAPTURE bytesused=614400, length=614400 flags=0x00002001 field=none timestamp=40304.473265 memory=MMAP (offset=614400)

stephematician added a commit to stephematician/v4l2loopback that referenced this issue Dec 13, 2024
Revert to FIFO management of dev->outbuf_list
@stephematician stephematician linked a pull request Dec 13, 2024 that will close this issue
stephematician added a commit to stephematician/v4l2loopback that referenced this issue Dec 13, 2024
Revert to FIFO management of dev->outbuf_list
@stephematician
Copy link
Contributor

Fairly sure this is a duplicate of #191 and #456.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants