GNOME Bugzilla – Bug 563828
[decodebin2] Complains about loops in the graph when demuxer output requires another demuxer
Last modified: 2009-10-07 15:47:51 UTC
Hi, decodebin2 complains about loops in the graph when playing MXF files which contain DV. Other files work fine so it's probably caused by the demuxer after the demuxer (mxfdemux ! dvdemux). Output below, full debug log attached ;) Setting pipeline to PAUSED ... /GstPipeline:pipeline0/GstDecodeBin2:d/GstTypeFindElement:typefind.GstPad:src: caps = application/mxf Pipeline is PREROLLING ... /GstPipeline:pipeline0/GstDecodeBin2:d/GstMXFDemux:mxfdemux0.GstPad:sink: caps = application/mxf /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink0: caps = video/x-dv, systemstream=(boolean)true /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src0: caps = video/x-dv, systemstream=(boolean)true /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src0: caps = video/x-dv, systemstream=(boolean)true /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink2: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink2: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 # no audio /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0: max-size-buffers = 5 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0: max-size-time = 2000000000 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0: max-size-bytes = 2097152 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src1: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:src: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:sink: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src1: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src1.GstProxyPad:proxypad3: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstAlsaSink:alsasink0.GstPad:sink: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstAlsaSink:alsasink0.GstPad:sink: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstAlsaSink:alsasink0.GstPad:sink: caps = audio/x-raw-int, rate=(int)48000, channels=(int)1, signed=(boolean)true, endianness=(int)1234, depth=(int)16, width=(int)16 /GstPipeline:pipeline0/GstDecodeBin2:d/GstDVDemux:dvdemux0.GstPad:video: caps = video/x-dv, systemstream=(boolean)false, width=(int)720, height=(int)576, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink3: caps = video/x-dv, systemstream=(boolean)false, width=(int)720, height=(int)576, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src3: caps = video/x-dv, systemstream=(boolean)false, width=(int)720, height=(int)576, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d/ffdec_dvvideo:ffdec_dvvideo0.GstPad:sink: caps = video/x-dv, systemstream=(boolean)false, width=(int)720, height=(int)576, framerate=(fraction)25/1, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d/ffdec_dvvideo:ffdec_dvvideo0.GstPad:src: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstFFMpegCsp:ffmpegcsp0.GstPad:src: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstFFMpegCsp:ffmpegcsp0.GstPad:sink: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src0: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src0.GstProxyPad:proxypad6: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio # no audio /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0.GstPad:sink: caps = video/x-raw-yuv, width=(int)720, height=(int)576, framerate=(fraction)25/1, format=(fourcc)I420, pixel-aspect-ratio=(fraction)59/54 Pipeline is PREROLLED ... Setting pipeline to PLAYING ... (gst-launch-0.10:11118): GStreamer-WARNING **: loop detected in the graph of bin d!! New clock: GstAudioSinkClock # no audio # no audio Got EOS from element "pipeline0". Execution ended after 2163142172 ns. Setting pipeline to PAUSED ... (gst-launch-0.10:11118): GStreamer-WARNING **: loop detected in the graph of bin d!! Setting pipeline to READY ... /GstPipeline:pipeline0/GstAlsaSink:alsasink0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:src: caps = NULL /GstPipeline:pipeline0/GstAudioConvert:audioconvert0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstFFMpegCsp:ffmpegcsp0.GstPad:src: caps = NULL /GstPipeline:pipeline0/GstFFMpegCsp:ffmpegcsp0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src2: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src1: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d.GstDecodePad:src0: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/ffdec_dvvideo:ffdec_dvvideo0.GstPad:src: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/ffdec_dvvideo:ffdec_dvvideo0.GstPad:sink: caps = NULL (gst-launch-0.10:11118): GStreamer-WARNING **: loop detected in the graph of bin d!! /GstPipeline:pipeline0/GstDecodeBin2:d/GstDVDemux:dvdemux0.GstPad:video: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstDVDemux:dvdemux0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink3: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src3: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink2: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src2: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink1: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src1: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:sink0: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMultiQueue:multiqueue0.GstPad:src0: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMXFDemux:mxfdemux0.GstMXFDemuxPad:track_4: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMXFDemux:mxfdemux0.GstMXFDemuxPad:track_3: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMXFDemux:mxfdemux0.GstMXFDemuxPad:track_2: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstMXFDemux:mxfdemux0.GstPad:sink: caps = NULL /GstPipeline:pipeline0/GstDecodeBin2:d/GstTypeFindElement:typefind.GstPad:src: caps = NULL Setting pipeline to NULL ... FREEING pipeline ...
Ah, an example file would be http://gstreamer.freedesktop.org/media/incoming/mxf/opencubetech.com/op1a-pal-dv25-dms1.mxf
...and I can't attach the debug log because it's too large (even when bz2 compressed). Fortunately this can be easily reproduced ;)
Not only does it complain about loops in the graph, it also stops playback very soon while playbin(1) plays it correctly.
The problem is, that both, mxfdemux and dvdemux, go through the same multiqueue which then of course creates a loop in the pipeline. According to Edward decodebin2 should be changed to put everything that needs further demuxing/parsing before the multiqueue and only connect the final demuxer/parser to the multiqueue.
Having had another look at the code, this should be possible to implement in connect_pad (gstdecodebin2.c:1080). The idea would be to add a first step check to see if the pad caps can be connected to a parser/muxer and not pass the pad to gst_decode_group_control_demuxer_pad() until we get something different from a parser or muxer.
How would you detect that "we get something different from a parser or demuxer"? Checking the caps for equality won't work because an intermediate parser might add some caps fields... just checking the caps's structure name doesn't work (just think about video/x-dv,systemstream=true and video/x-dv,systemstream=false).
I never said the check should be done on the caps, but on the compatible factory(ies) you get passed as arguments. That might require adding a is_demuxer_parser_element_factory() function that checks whether the factory is a demuxer or parser. And that check would be similar to is_demuxer_element(). You don't check the caps, but the klass and padtemplate types.
Ah, makes sense and shouldn't be too hard to implement :)
Hm, there's still a problem. We can't just check on the factories as the factories only contain the static pad templates and we probably don't want to instanciate all elements. The other solution would be to move the "is_demuxer_element (src)" check and gst_decode_group_control_demuxer_pad() call between 2.4 and 2.5. The check should be extended to "is_demuxer_element (src) && !is_demuxer_element (element)" and then it works just fine for my testcase. mxfd10.c Now there's only the problem, what to do if linking or set_state() on the element fails later. We might need to destroy a decode group (as it was created just for the current element that didn't work) and we have to remove the created requestpad on the multiqueue. And of course reset pad/src to the old values. Currently I don't see an easy way to accomplish that :)
Edward, any idea how to do this as clean as possible? :)
ping
Created attachment 132111 [details] [review] decodebin2-demuxer-demuxer.diff Potential patch, unfortunately it doesn't work correctly for some reason and all threads are hanging...
will be reviewing the patch in the plane.
Edward, did you take a look at the patch already?
... alas no :(
Fixed now: commit cf9c6a2271ad35e422c8fba6af842e3ea309d82d Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> Date: Sat Sep 26 12:17:49 2009 +0200 decodebin2: Rewrite autoplugging and how groups of pads are exposed This now keeps track of everything that is going on, creates a tree of chains and groups to allow "demuxer after demuxer" scenarios and allows chained Oggs with multiple streams (needs oggdemux or playbin2 fi Also document everything in detail and give a general overview of what decodebin2 is doing at the top of the sources. Fixes bug #596183, #563828 and #591677.