Opened 16 months ago
Closed 16 months ago
#11451 closed defect (fixed)
Ogg/Theora: Duplicate frames dropped when copying Theora streams
| Reported by: | Bernat | Owned by: | |
|---|---|---|---|
| Priority: | normal | Component: | avformat |
| Version: | git-master | Keywords: | |
| Cc: | Bernat | Blocked By: | |
| Blocking: | Reproduced by developer: | no | |
| Analyzed by developer: | no |
Description (last modified by )
Hi. I'm working on Theora decoding support for Godot. Almost everything is working fine except for some kind of video streams.
Theora encodes duplicate frames (frames identical to the previous one) as empty packets. Those empty packets seem to be discarded by FFmpeg when doing an operation that involves copying a Theora stream. It doesn't happen when encoding.
Example:
ffmpeg -i input.ogv -c:v copy -a:n copy output.ogv
Although I'm not familiar with the code, I've searched the code for the cause and I think I found a possible regression in this commit: https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/18f24527eb4b520585e55f922cdbc234aa9f0f18
The following line in the Ogg encoder is dropping empty packets: https://git.ffmpeg.org/gitweb/ffmpeg.git/blob/HEAD:/libavformat/oggenc.c#l693
Additionally, doing copies of copies of copies, increases gradually the size of the file and eventually throws this error:
[ogg @ 0x55c70ba998c0] Broken file, non-keyframe not correctly marked.
I use this command to create a test file for this issue:
ffmpeg -f lavfi -i color=white:320x240:d=1.5 -f lavfi -i color=red:320x240:d=0.1 -f lavfi -i color=cyan:320x240:d=1.5 -f lavfi -i color=green:320x240:d=0.1 -f lavfi -i color=yellow:320x240:d=3 -filter_complex "[0:v] [1:v] [2:v] [3:v] [4:v] concat=n=5:v=1 [v]" -map "[v]" -framerate 50 -codec:v libtheora -qscale:v 5 -g:v 30 test.ogv
This command works correctly with FFmpeg 5.1.6 but with the latest master it suffers from the exact same issue this ticket describes.
I hope this can be easily fixed. Thanks in advance. Cheers.
Change History (12)
comment:1 by , 16 months ago
| Component: | undetermined → avformat |
|---|---|
| Description: | modified (diff) |
| Version: | unspecified → git-master |
comment:2 by , 16 months ago
| Description: | modified (diff) |
|---|
comment:3 by , 16 months ago
| Summary: | Duplicate frames dropped when copying Theora streams → Ogg/Theora: Duplicate frames dropped when copying Theora streams |
|---|
comment:4 by , 16 months ago
| Description: | modified (diff) |
|---|
comment:5 by , 16 months ago
comment:6 by , 16 months ago
No, it's still dropping duplicate frames.
It seems only packets with size > 0 reach that line. Maybe it's already filtered out when this stage is reached?
comment:7 by , 16 months ago
Wait, there's something I overlooked.
I did my encoding tests using FFmpeg 5.1.6 and it worked well, it only failed when copying the video stream. I tried the latest master to see if it failed the same when copying streams but didn't try encoding.
Now, I've tried encoding with the latest master and encoding fails in the same way that it fails when copying streams. But when I apply this patch encoding works well, it only fails when copying streams.
So this patch works, it fixes a regression in master that wasn't in 5.1.6. It just doesn't fix the issue when copying streams.
comment:8 by , 16 months ago
Let me put this in a table to ease reading.
V: duplicate frames are correctly encoded.
X: duplicate frames are dropped.
| FFmpeg version | encoding | copying |
|---|---|---|
| 5.1.6 | V | X |
| 6.1.2 | X | X |
| master | X | X |
| master with your patch | V | X |
comment:9 by , 16 months ago
I'd like to help more but this code base is too dense and unfamiliar to me. I've traced the code and the empty packets seem to be dropped (when copying the stream) in this function: https://git.ffmpeg.org/gitweb/ffmpeg.git/blob/HEAD:/libavformat/demux.c#l1162
comment:10 by , 16 months ago
comment:11 by , 16 months ago
Tested applying both latest patches from the mailing list to master and this issue seems completely fixed.
Great job! Thank you!
comment:12 by , 16 months ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |



Does this fix the issue?
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 224519a4da..57bf5b3509 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -241,7 +241,8 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, len = FFMIN(size, segments*255); page->segments[page->segments_count++] = len - (segments-1)*255; - memcpy(page->data+page->size, p, len); + if (len) + memcpy(page->data+page->size, p, len); p += len; size -= len; i += segments; @@ -690,7 +691,7 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt) int i; if (pkt) - return pkt->size ? ogg_write_packet_internal(s, pkt) : 0; + return pkt->size || !pkt->side_data_elems ? ogg_write_packet_internal(s, pkt) : 0; for (i = 0; i < s->nb_streams; i++) { OGGStreamContext *oggstream = s->streams[i]->priv_data;