GNOME Bugzilla – Bug 619778
oggdemux: fails on zero-length pages with Patent_Absurdity_HD_3540kbit.ogv
Last modified: 2011-04-09 21:13:28 UTC
gstreamer fails to demux the following file correctly: http://ia331209.us.archive.org/0/items/Patent_Absurdity/Patent_Absurdity_HD_3540kbit.ogv I discovered this when trying to execute the following pipeline: gst-launch-0.10 filesrc location= /tmp/Patent_Absurdity_HD_3540kbit.ogv ! oggdemux name=demux ! theoradec ! queue ! videoscale method=2 ! video/x-raw-yuv,width=720,height=480 ! queue ! mpeg2enc format=8 aspect=3 ! mpegpsmux name=mux ! filesink location=/tmp/patents_out.mpg . demux. ! vorbisdec ! audioconvert ! queue ! twolame bitrate=320 ! mux. This pipeline will hang after about a minute. I believe it stops because oggdemux is dropping zero-length pages (i.e. pages containing only zero-length packets), leading to audio and video drifting apart. I confirmed this suspicion by running gst-launch-0.10 filesrc location= /tmp/Patent_Absurdity_HD_3540kbit.ogv ! oggdemux name=demux ! theoradec ! queue ! videoscale method=2 ! video/x-raw-yuv,width=720,height=480 ! queue ! mpeg2enc format=9 bitrate=7000 ! mpegpsmux name=mux ! filesink location=/tmp/patents_out.m2v i.e. re-encoding just the video. The resulting m2v file is mostly complete, but long perfectly still scenes in the ogv are greatly shortened in the m2v. I suspect that this bug has not been observed previously because (1) real-time decode happens to work anyway because the dropped frames don't affect display, and (2) old versions of libogg were less likely to produce zero-length pages.
Which version of gstreamer and gst-plugins-base are you using? Playing this file via HTTP with latest releases and GIT works fine here.
0.10.29. To be clear, the file will appear to play fine. You need to run one of the above pipelines to see that there's a problem. This is consistent with oggdemux not forwarding some empty packets, because not forwarding them causes the preceding frame to continue being displayed, which is the same thing that happens if they _are_ forwarded. This behavior doesn't work correctly for re-encode, because those duplicate frames still need to reach the encoder in order to maintain a constant framerate stream of the correct length.
Your analysis about oggdemux/theoradec is incorrect: $ gst-launch filesrc location=green.ogg ! oggdemux ! fakesink -v ... /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 42 bytes, timestamp: none, duration: none, offset: 0, offset_end: -1, flags: 32) 0x83e6508" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 61 bytes, timestamp: none, duration: none, offset: 0, offset_end: -1, flags: 0) 0x83e6558" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 3196 bytes, timestamp: none, duration: none, offset: 0, offset_end: -1, flags: 0) 0x83e65a8" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (74880 bytes, timestamp: 0:00:00.000000000, duration: 0:00:00.041666666, offset: 41666666, offset_end: 1, flags: 0) 0x83e6240" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:00:00.041666666, duration: 0:00:00.041666667, offset: 83333333, offset_end: 2, flags: 0) 0x83e61f0" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:00:00.083333333, duration: 0:00:00.041666667, offset: 125000000, offset_end: 3, flags: 0) 0x83e61a0" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:00:00.125000000, duration: 0:00:00.041666666, offset: 166666666, offset_end: 4, flags: 0) 0x83e6150" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:00:00.166666666, duration: 0:00:00.041666667, offset: 208333333, offset_end: 5, flags: 0) 0x83e6100" $ gst-launch filesrc location=green.ogg ! oggdemux ! theoradec ! fakesink -v ... /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (279720 bytes, timestamp: 0:00:00.000000000, duration: 0:00:00.041666666, offset: -1, offset_end: -1, flags: 32) 0x8c265f0" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (279720 bytes, timestamp: 0:00:00.041666666, duration: 0:00:00.041666667, offset: -1, offset_end: -1, flags: 0) 0x8c26550" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (279720 bytes, timestamp: 0:00:00.083333333, duration: 0:00:00.041666667, offset: -1, offset_end: -1, flags: 0) 0x8c264b0" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (279720 bytes, timestamp: 0:00:00.125000000, duration: 0:00:00.041666666, offset: -1, offset_end: -1, flags: 0) 0x8c26410" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < (279720 bytes, timestamp: 0:00:00.166666666, duration: 0:00:00.041666667, offset: -1, offset_end: -1, flags: 0) 0x8c264b0"
ds: I agree. I did a test with a file constructed to have a few zero-length pages and all packets were decoded successfully. However, fakesink did provide some surprising output: /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:04:08.000000000, duration: 0:00:01.0000000 00, offset: 249000000000, offset_end: 249, flags: 0) 0x92c5468" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:04:09.000000000, duration: 0:00:01.0000000 00, offset: 250000000000, offset_end: 250, flags: 0) 0x92c5418" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:04:10.000000000, duration: 0:00:01.0000000 00, offset: 251000000000, offset_end: 1274, flags: 0) 0x92c5468" /GstPipeline:pipeline0/GstFakeSink:fakesink0: last-message = "chain ******* < ( 0 bytes, timestamp: 0:04:11.000000000, duration: 0:00:01.0000000 00, offset: 252000000000, offset_end: 1275, flags: 0) 0x92c54b8" Packet 250 is the last packet on the first page. 1274 is 250+1024, and 1024 is 2^granuleshift. (This has also matched when I tried with different granuleshifts.) I don't know if this is a problem, because I don't know what offset_end means. On Patent_Absurdity_HD_3540kbit.ogv, running theoradec into fakesink and counting packets shows the right number of packets coming out, so the problem must not be what I thought.
That's a known bug that only affects ogg remuxing.
Created attachment 177627 [details] [review] patch This patch fixes the case for the start of a normal file, as described in #638276. Mental note: I'm guessing there are still cases where granulepos is not reconstructed correctly, since the code is needlessly cumbersome.
Oh frack, that got merged with oggkoggk's patch from the other bug. You get the idea.
Maybe check for 0 for non sparse streams only ? I'm not sure if there's a good way to know whether a 0 granpos page is a header page or not since there might be another page before that with an unknown number of packets ending on it.
Can this be closed, or shall we keep it open for now? (re. comment #8) commit 3c4466b816eca8becc69ded9cf011eb45d6dfcdb Author: David Schleef <ds@schleef.org> Date: Wed Jan 5 15:54:15 2011 -0800 oggdemux: ignore header pages when looking for keyframe This was causing keyframe_granule to be set to 0 for all streams when seeking to the beginning of the stream, i.e., at the beginning of playback. Fixes #619778.
Ping?
This was supposed to be closed.