-
Notifications
You must be signed in to change notification settings - Fork 13
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
Raspberry pi never fires a EPOLLPRI event #7
Comments
What is your kernel version? Maybe your kernel is missing this fix that has landed not so long ago: IIRC it fixes exactly the problem you are mentioning, which I have also met while testing with |
It is also possible that the RPI4 driver is not compliant with the stateful decoder specification. Is the source for it available? |
Does this issue exist on versions before 5.12? I'm using 5.10.25.
That is possible. Let me see. |
Seems RPI does support the stateful decode API. mpv-player/mpv#7492 (comment) And there is this |
I'm not sure if that's the right source code but it does seem to line up with the modules in use on my RPI4 board. $ lsmod | grep v4l2
bcm2835_v4l2 45056 0
v4l2_mem2mem 40960 1 bcm2835_codec
bcm2835_mmal_vchiq 32768 3 bcm2835_codec,bcm2835_v4l2,bcm2835_isp
videobuf2_vmalloc 20480 1 bcm2835_v4l2
videobuf2_v4l2 32768 4 bcm2835_codec,bcm2835_v4l2,v4l2_mem2mem,bcm2835_isp
videobuf2_common 61440 5 bcm2835_codec,videobuf2_v4l2,bcm2835_v4l2,v4l2_mem2mem,bcm2835_isp
videodev 303104 6 bcm2835_codec,videobuf2_v4l2,bcm2835_v4l2,videobuf2_common,v4l2_mem2mem,bcm2835_isp
mc 57344 6 videodev,bcm2835_codec,videobuf2_v4l2,videobuf2_common,v4l2_mem2mem,bcm2835_isp |
Mmm actually it seems like this patch I mentioned fixes a different kind of issue, which is https://github.com/Gnurou/v4l2r/blob/master/lib/src/device/poller.rs#L169 So maybe that's a different problem. But if in doubt maybe try to make sure your kernel includes these patches from mainline:
Which input codec are you trying to decode btw? It could also be useful if you could provide the output of |
Here are the strace logs: https://github.com/FallingSnow/v4l2-pi/tree/master/logs. The The code can be found in that repository as well.
Both of those are actually only in the I actually saw your workaround while trying to debug this issue. I have a C version of this program that works and found that the RPI doesn't trigger any v4l2_events in the C version either. Instead that version just listens to EPOLLOUT from the start.
H264 |
I don't know the V4L2 stateful decoder spec but if it requires you to fire a |
@6by9 Do you know if the RPI4 is supposed to submit a source change event when using the V4L2_mem2mem H264 decoder? |
Yes it creates source changed events should the resolution on the CAPTURE queue change. However currently we don't support enabling only the OUTPUT queue and expecting SOURCE_CHANGED events. The underlying code has an input and output port, corresponding to OUTPUT and CAPTURE queues. At present the ports are enabled with the queue STREAMON state. I had patches largely working to enable both ports based on the OUTPUT queue state, but seeing as neither FFmpeg nor GStreamer as the main users of the API enable only one stream at a time, the priority on polishing them up was low. edit: From discussion with others in the mainline Linux kernel community, I believe other platforms also have a similar restriction. |
Thanks for the logs! So one thing first, your program in Another thing that surprises me is that with both programs the driver returns the I wonder if the problem doesn't come from the way the H.264 stream is segmented. Most (all?) drivers should expect 1 full NAL unit per buffer, I need to check if your program does that... |
A stateful decoder should be able to generate that event per the specification: https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html#initialization Setting up the If the RPI4 driver cannot be updated to comply, maybe we need to add an extra flag to the queue so user-space knows it is expected to parse the stream and setup the |
The Pi has a bitstream parsing FIFO which IIRC is 2MB in size. It'll swallow OUTPUT buffers until that FIFO is full. V4L2 mandates that there is one NAL per buffer
Our decoder could set Certainly for encoders there is the expectation is that any header bytes are delivered in same buffer as the I/IDR frame that follows. To my mind this contradicts the spec, but does mean that simple implementations can work on a 1-in, 1-out basis. |
Chromium was the driver for starting on the patches, but I believe they have changed approach in the latest releases and hence the change of priority. The CAPTURE queue doesn't need to be configured correctly based on the bitstream headers, but it does need to have STREAMON called. |
Chromium definitely relies on the initial resolution change event, so I believe that will need to be fixed at some point.
Oh, so just calling |
I set it non blocking mode for the capture queue and, as @6by9 noted, the output buffer now proceeds even without any capture frames being dequeued until the RPI4 chip's buffer has be filled. Then it just hangs as neither the RPI4 want's more output buffers nor have any capture buffers been dequeued. At this point the output queue blocks and waits. So the output queue is working correctly.
The programs create "frames" by segmenting based on H264 access unit delimiters. So the driver should be receiving full NAL units. So the situation seems this...
I will try this. @Gnurou will this mess with the internal state of the @6by9 just so I'm clear, based on the statement below from the spec (linked by @Gnurou above)
RPI4 must trigger a |
Actually both queues are already 😕 Btw, if you're interested, this is the horrible piece of code that creates the "framed" data. |
Kernel module bcm2835-codec has a module parameter "debug". Increase that to 5 to get all the logging out of the module. The event is V4L2_EVENT_SOURCE_CHANGE with V4L2_EVENT_SRC_CH_RESOLUTION. If there are no changes then there should be no event. Or otherwise there is no way for a client that has parsed the headers and can set the CAPTURE queue to avoid going through dynamic allocation change process. https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html#initialization
So the client is entitled to set the coded resolution on the stream via the CAPTURE queue. Also the note
So the client isn't going to set that format after an initial V4L2_EVENT_SOURCE_CHANGE event, therefore this can only reflect the initialisation V4L2_EVENT_SOURCE_CHANGE event. |
I had only been using debug=1, I'll use 5 now.
I don't understand this part. Can't the client just choose to ignore the event? I understand there is a discrepancy between whether a v4l2 decoder has to trigger a Then I guess since RPI4 does not trigger the event if the capture queue is "off", then v4l2r needs to right @Gnurou? |
How would I event listen for the event using v4l2r? I see |
@6by9 I'm decoding a 1920x1080 video and the format change never appears in the logs. Now I'm wondering if I'm even passing the data to the decoder correctly. The dmesg: https://pastebin.com/PTXr1fQM Mediainfo of
|
You can use |
The decoder will stream the queue on itself after it receives a resolution change event, but the fact that it was already streaming should not be an issue. What is more worrying is that you will have to allocate buffers in order to to able to stream the queue in the first place, so you'll probably want to call the
The fact that RPI4 does not trigger the event if the capture queue is off is not compliant with the spec. It should trigger that event, and I don't see anything that prevents it from doing so. So preferably the issue would be fixed in the kernel driver itself. |
Do you have a C program that works with this driver? It would be interesting to see its |
Yeah, that should be fixed... C program's strace, You can ignore the
Ok, well in this case I'll stick with getting the low level functions working before moving to the stateful decoder. |
I've been doing some looking in the kernel log and in the C program, the driver out puts the following [ +0.009879] bcm2835-codec bcm2835-codec: bcm2835_codec_start_streaming: type: 10 count 0
[ +0.004389] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 9 ptr 00000000d59e583b vbuf->flags 0, seq 0, bytesused 4177920
[ +0.000009] bcm2835-codec bcm2835-codec: bcm2835_codec_start_streaming: type: 9 count 1
[ +0.000155] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000139] bcm2835-codec bcm2835-codec: device_run: Submitted src 0000000000000000, dst 00000000d59e583b
[ +2.388681] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 00000000c2db1bb7
[ +0.000054] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 10 ptr 00000000c2db1bb7 vbuf->flags 0, seq 0, bytesused 786432
[ +0.000018] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000258] bcm2835-codec bcm2835-codec: device_run: Submitted ip buffer len 786432, pts 0, flags 0004
[ +0.000057] bcm2835-codec bcm2835-codec: device_run: Submitted src 00000000c2db1bb7, dst 0000000000000000
[ +0.024081] bcm2835-codec bcm2835-codec: ip_buffer_cb: port 0000000047d75b3f buf 000000006eee54f1 length 0, flags 0
[ +0.000016] bcm2835-codec bcm2835-codec: ip_buffer_cb: no error. Return buffer 00000000c2db1bb7
[ +0.000017] bcm2835-codec bcm2835-codec: ip_buffer_cb: done 1 input buffers
[ +1.942382] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 00000000ba7b6a02
[ +0.000058] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 10 ptr 00000000ba7b6a02 vbuf->flags 0, seq 0, bytesused 786432
[ +0.000017] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000375] bcm2835-codec bcm2835-codec: device_run: Submitted ip buffer len 786432, pts 0, flags 0004
[ +0.000015] bcm2835-codec bcm2835-codec: device_run: Submitted src 00000000ba7b6a02, dst 0000000000000000
[ +0.006511] bcm2835-codec bcm2835-codec: ip_buffer_cb: port 0000000047d75b3f buf 00000000851dd6cb length 0, flags 0
[ +0.000008] bcm2835-codec bcm2835-codec: ip_buffer_cb: no error. Return buffer 00000000ba7b6a02
[ +0.000011] bcm2835-codec bcm2835-codec: ip_buffer_cb: done 2 input buffers
[ +0.034613] bcm2835-codec bcm2835-codec: op_buffer_cb: status:0, buf:0000000034ed926f, length:96, flags 0, pts -9223372036854775808
[ +0.000022] bcm2835-codec bcm2835-codec: handle_fmt_changed: Format changed: buff size min 4177920, rec 4177920, buff num min 1, rec 1
[ +0.000013] bcm2835-codec bcm2835-codec: handle_fmt_changed: Format changed to 1920x1088, crop 1920x1080, colourspace 00000000
[ +0.000008] bcm2835-codec bcm2835-codec: handle_fmt_changed: Format was 3840x1088, crop 1920x1080 However when doing the same with the rust program the For reference, running the rust program: [ +0.000229] bcm2835-codec bcm2835-codec: bcm2835_codec_start_streaming: type: 10 count 0
[ +0.002316] bcm2835-codec bcm2835-codec: bcm2835_codec_start_streaming: type: 9 count 0
[ +0.000263] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_init: ctx:000000004ad25ac9, vb 00000000dac9fbdf
[ +0.000007] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 9 ptr 00000000dac9fbdf
[ +0.000007] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 9 ptr 00000000dac9fbdf vbuf->flags 0, seq 0, bytesused 614400
[ +0.000007] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000100] bcm2835-codec bcm2835-codec: device_run: Submitted src 0000000000000000, dst 00000000dac9fbdf
[ +0.105459] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 0000000000ddbc9b
[ +0.000048] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 10 ptr 0000000000ddbc9b vbuf->flags 0, seq 0, bytesused 30
[ +0.000016] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000213] bcm2835-codec bcm2835-codec: device_run: Submitted ip buffer len 30, pts 0, flags 0004
[ +0.000012] bcm2835-codec bcm2835-codec: device_run: Submitted src 0000000000ddbc9b, dst 0000000000000000
[ +0.000466] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_init: ctx:000000004ad25ac9, vb 00000000aac09dc7
[ +0.000019] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 9 ptr 00000000aac09dc7
[ +0.000013] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 9 ptr 00000000aac09dc7 vbuf->flags 0, seq 0, bytesused 614400
[ +0.000013] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000198] bcm2835-codec bcm2835-codec: device_run: Submitted src 0000000000000000, dst 00000000aac09dc7
[ +0.001880] bcm2835-codec bcm2835-codec: ip_buffer_cb: port 0000000047d75b3f buf 000000005afc3164 length 0, flags 0
[ +0.000014] bcm2835-codec bcm2835-codec: ip_buffer_cb: no error. Return buffer 0000000000ddbc9b
[ +0.000012] bcm2835-codec bcm2835-codec: ip_buffer_cb: done 1 input buffers
[ +0.106086] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 000000000f165738
[ +0.000049] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 10 ptr 000000000f165738 vbuf->flags 0, seq 0, bytesused 4671
[ +0.000016] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000223] bcm2835-codec bcm2835-codec: device_run: Submitted ip buffer len 4671, pts 0, flags 0004
[ +0.000013] bcm2835-codec bcm2835-codec: device_run: Submitted src 000000000f165738, dst 0000000000000000
[ +0.000202] bcm2835-codec bcm2835-codec: ip_buffer_cb: port 0000000047d75b3f buf 000000008bdf9dd3 length 0, flags 0
[ +0.000010] bcm2835-codec bcm2835-codec: ip_buffer_cb: no error. Return buffer 000000000f165738
[ +0.000011] bcm2835-codec bcm2835-codec: ip_buffer_cb: done 2 input buffers
[ +0.107126] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 0000000000ddbc9b
[ +0.000024] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_queue: type: 10 ptr 0000000000ddbc9b vbuf->flags 0, seq 0, bytesused 1014
[ +0.000016] bcm2835-codec bcm2835-codec: device_run: off we go
[ +0.000033] bcm2835-codec bcm2835-codec: device_run: Submitted ip buffer len 1014, pts 0, flags 0004
[ +0.000089] bcm2835-codec bcm2835-codec: device_run: Submitted src 0000000000ddbc9b, dst 0000000000000000
[ +0.000099] bcm2835-codec bcm2835-codec: ip_buffer_cb: port 0000000047d75b3f buf 000000005afc3164 length 0, flags 0
[ +0.000010] bcm2835-codec bcm2835-codec: ip_buffer_cb: no error. Return buffer 0000000000ddbc9b
[ +0.000010] bcm2835-codec bcm2835-codec: ip_buffer_cb: done 3 input buffers
[ +0.107430] bcm2835-codec bcm2835-codec: bcm2835_codec_buf_prepare: type: 10 ptr 000000000f165738 |
I think I've got it work. Will update you soon. |
Oho, nice! Any hint on what the issue was? I'm not against the idea of adding per-device workarounds to the decoder if they can be properly separated into their own source file. |
Yeah, the issue was exactly what we thought it was. The raspberry pi doesn't signal a It seems a "temporary" (praying this gets fixed up stream someday) workaround would be necessary. We could do something like const DECODE_DEVICE_PATH: &'static str = "/dev/video10";
let decode_path = Path::new(DECODE_DEVICE_PATH);
let device = Device::open(decode_path, DeviceConfig::new())
.expect("Failed to open device");
let caps = &device.capability;
if caps.driver == "bcm2835-codec-decode" {
// Raspberry Pi Workaround: capture queue must be on to trigger V4L2_EVENT_SOURCE_CHANGE
// decoder.capture_queue.stream_on().expect("Failed to start capture_queue");
} |
I'll dig out my patches again. Is there a quick and easy test (for someone who has never used rust at all) that I can run? |
I just happen to have acquired a Raspberry Pi 4, for unrelated reasons (fantastic little device btw). Maybe I can take a look at how to fix the kernel driver.
I am not familiar with cross-compiling Rust yet, but @FallingSnow can probably share some instructions. Thanks to Cargo it should not take much more than 3 or 4 commands to get the Rust toolchain installed and build an ARM binary. If that's a hassle, I'll be happy to build a custom kernel and test. |
@6by9 If you can install rust I'll setup a minimal repo tomorrow (it's 3am here) where all you should need to do is run
You might need to remove this too if I remember correctly v4l2r/lib/examples/vicodec_test/ioctl_api.rs Lines 41 to 46 in 1fbc84f
@Gnurou You don't need to cross compile, you can compile right on the RPI (
Note: If you're using an arm7 (not aarch64) raspberry pi distro, the command is Lemme know if you have any trouble. |
@Gnurou It's a little ugly as the codec is remoted to the VPU (VideoCore's processor) over an RPC with the MMAL API. It's MMAL that has the issue of wanting the logical output (V4L2 CAPTURE) stream active to create the event. Working around that restriction is a bit of a pain, particularly if you don't know the MMAL API. I've pushed the patch I did have to https://github.com/6by9/linux/tree/rpi-5.10.y-codecs - compile testing it now. Ignore the couple of patches for adding interlace support - they should have no real effect. @FallingSnow I'll give it a 5 minute attempt, but otherwise happy to wait. |
@Gnurou I'm trying to setup a test repo for 6by9 but I'm running into a failed error here and I can't figure out why. Do you know what I'm doing wrong? @6by9 Maybe you can comment out that line and try running it on a RPi4 with |
I'm a little confused as to a useful test here.
Remove the checks for vicodec, replace the references to FWHT with H264, and run against /dev/video11, and it gets so far but panics on
Understandable as neither encoder nor decoder support userptr as they require contiguous buffers. Is there any benefit in taking that test further? |
Sorry, I only meant for
Either way I'll try to get you a test you can just run and shouldn't have to modify. |
Hmm, seems the issue I was running into (
So this leads us to:
So a bit of a cyclical dependency. |
https://github.com/FallingSnow/rpi-v4l2r-test runs for me with the normal snippet from Big Buck Bunny that we use as a test (https://github.com/6by9/userland/blob/hello_mmal/host_applications/linux/apps/hello_pi/hello_video/test.h264) and my patch, but it's also just blown up on me on the second run so something isn't quite right (looks like there's a competition initialisation missing). With your clip it fails to get going which is weird. The codec keeps on accepting the data but never producing any output. Does this framework frame the data correctly? V4L2 requires one NAL per buffer, but you're feeding in an elementary stream so something will need to parse it. |
Good to hear! We're part way there.
That's likely so. In Gnurou's code samples he usually handles shutdowns gracefully with What error are you getting when you try to run it a second time?
That's strange. Although I doubt the |
I've fixed the obvious issue with my tree, but need to have a further think as to whether we're doing things correctly here or not. I've got an error in a WARN_ON that I've added though (lines 1512 and 2652). There's also an issue with trips videobuf2 into complaining about buffers being left in the active state on stop_streaming that's been outstanding for a while. Never enough time to investigate everything. |
Hi, what's the status on this? It seems decoding is running perfectly well: However, the resulting decoded file doesn't display well: Am I missing anything? Did you get to decode an Annex B h264 bitstream with this library? |
It seems that while using V4L2 on the RPI4 no EPOLLPRI event is ever fired. The stateful decoder in v4l2r requires a EPOLLPRI to read a
v4l2_event
which will trigger a resolution change, in turn enabling the capture queue.Is there a way to use the stateful decoder even if no v4l2_event is triggered? Of course you would need to manually set the output format then.
The text was updated successfully, but these errors were encountered: