GNOME Bugzilla – Bug 732945
giosink: Won't work with mp4mux
Last modified: 2014-07-11 08:01:42 UTC
A sound-juicer user has reported that they cannot play the m4a files it creates (bug 732790). I think this is due to a problem with encodebin which sound-juicer uses for the encoding. Attachment 280079 [details] has a debug log from sound-juicer. The debug log contains a number of warnings from qtdemux that there are errors in the stream, I'm not sure what is creating the qtdmux element though as it seems to be logging from a different thread to the encoding elements. Attachment 280218 [details] shows the pipeline used to encode the broken file. I'm using gstreamer 1.2.4 Encoding with gst-launch-1.0 cdda://1 ! faac ! mp4mux ! filesink location=/tmp/works.m4a gives playable files. Trying to play the file created with sound-juicer with gst-launch --gst-debug=*:3 playbin uri=file:///tmp/broken.m4a gives Setting pipeline to PAUSED ... Pipeline is PREROLLING ... 0:00:00.906184341 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:3060:gst_qtdemux_loop_state_header:<qtdemux0> warning: Invalid atom size. 0:00:00.906372365 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:3060:gst_qtdemux_loop_state_header:<qtdemux0> warning: Header atom 'mdat' has empty length WARNING: from element /GstPlayBin:playbin0/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstQTDemux:qtdemux0: Invalid atom size. Additional debug info: qtdemux.c(3060): gst_qtdemux_loop_state_header (): /GstPlayBin:playbin0/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstQTDemux:qtdemux0: Header atom 'mdat' has empty length 0:00:00.907121823 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:573:gst_qtdemux_post_no_playable_stream_error:<qtdemux0> error: This file contains no playable streams. 0:00:00.907239922 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:573:gst_qtdemux_post_no_playable_stream_error:<qtdemux0> error: no known streams found ERROR: from element /GstPlayBin:playbin0/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstQTDemux:qtdemux0: This file contains no playable streams. Additional debug info: qtdemux.c(573): gst_qtdemux_post_no_playable_stream_error (): /GstPlayBin:playbin0/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstQTDemux:qtdemux0: no known streams found ERROR: pipeline doesn't want to preroll. Setting pipeline to NULL ... 0:00:00.910067438 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:573:gst_qtdemux_post_no_playable_stream_error:<qtdemux0> error: This file contains no playable streams. 0:00:00.910186418 31045 0x7f5b200ef8a0 WARN qtdemux qtdemux.c:573:gst_qtdemux_post_no_playable_stream_error:<qtdemux0> error: no known streams found Freeing pipeline ... VLC and mplayer also refuse to play the file The files created by sound-juicer and gst-launch are very similar, diffing their hexdumps gives diff works.hex broken.hex 3c3 < 00000020 00 00 00 08 66 72 65 65 00 17 56 d7 6d 64 61 74 |....free..V.mdat| --- > 00000020 00 00 00 01 6d 64 61 74 00 00 00 00 00 00 00 00 |....mdat........| 95601,95602c95601,95602 < 00175700 00 98 61 6d 6f 6f 76 00 00 00 6c 6d 76 68 64 00 |..amoov...lmvhd.| < 00175710 00 00 00 cf e1 77 b9 cf e1 77 b9 00 00 03 e8 00 |.....w...w......| --- > 00175700 00 99 5e 6d 6f 6f 76 00 00 00 6c 6d 76 68 64 00 |..^moov...lmvhd.| > 00175710 00 00 00 cf e1 d7 d0 cf e1 d7 d0 00 00 03 e8 00 |................| 95609c95609 < 00175780 6b 68 64 00 00 00 07 cf e1 77 b9 cf e1 77 b9 00 |khd......w...w..| --- > 00175780 6b 68 64 00 00 00 07 cf e1 d7 d0 cf e1 d7 d0 00 |khd.............| 95615,95616c95615,95616 < 001757e0 00 00 20 6d 64 68 64 00 00 00 00 cf e1 77 b9 cf |.. mdhd......w..| < 001757f0 e1 77 b9 00 00 ac 44 00 4a f0 00 00 00 00 00 00 |.w....D.J.......| --- > 001757e0 00 00 20 6d 64 68 64 00 00 00 00 cf e1 d7 d0 cf |.. mdhd.........| > 001757f0 e1 d7 d0 00 00 ac 44 00 4a f0 00 00 00 00 00 00 |......D.J.......| 95628,95629c95628,95629 < 001758b0 03 19 00 01 00 04 11 40 15 00 00 00 00 00 00 00 |.......@........| < 001758c0 00 01 ad 37 05 02 12 10 06 01 02 00 00 00 18 73 |...7...........s| --- > 001758b0 03 19 00 01 00 04 11 40 15 00 00 00 00 02 af b7 |.......@........| > 001758c0 00 01 b1 7d 05 02 12 10 06 01 02 00 00 00 18 73 |...}...........s| 98033c98033 < 0017ef00 17 55 d8 00 00 00 5d 75 64 74 61 00 00 00 55 6d |.U....]udta...Um| --- > 0017ef00 17 55 d8 00 00 01 5a 75 64 74 61 00 00 01 52 6d |.U....Zudta...Rm|
Use the -e parameter on gst-launch to properly shut down the pipeline. Without that the headers of the MP4 file will not be rewritten and are broken. In your own application you would implement the same by first sending on EOS event to the pipeline, then waiting for the EOS message from the pipeline... and only then shut down the pipeline (i.e. set it to READY or NULL state).
(In reply to comment #1) > Use the -e parameter on gst-launch to properly shut down the pipeline. Without > that the headers of the MP4 file will not be rewritten and are broken. I'm confused by this as the file created by gst-launch was not broken and played fine. > In your own application you would implement the same by first sending on EOS > event to the pipeline, then waiting for the EOS message from the pipeline... > and only then shut down the pipeline (i.e. set it to READY or NULL state). Thanks, I'll have a look, I thought we got an EOS message at the end of each track which we listen for to shut down the pipeline but I need to check exactly what's happening there.
(In reply to comment #2) > > In your own application you would implement the same by first sending on EOS > > event to the pipeline, then waiting for the EOS message from the pipeline... > > and only then shut down the pipeline (i.e. set it to READY or NULL state). > > Thanks, I'll have a look, I thought we got an EOS message at the end of each > track which we listen for to shut down the pipeline but I need to check exactly > what's happening there. At the moment sound-juicer does priv->pipeline = gst_pipeline_new ("pipeline"); bus = gst_element_get_bus (priv->pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message::eos", G_CALLBACK (eos_cb), extractor); /* create pipeline elelments, add them to the pipeline and link them */ state_ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); in eos_cb it does gst_element_set_state (priv->pipeline, GST_STATE_NULL); So it sets the pipeline to GST_STATE_PLAYING and waits for the eos message at the end of the track and then sets the pipeline state to GST_STATE_NULL. I'm not sure what should it be doing differently as it only sets the pipeline to GST_STATE_NULL when it gets an eos message so surely the pipeline should shut down properly and the MP4 file headers written?
Can you provide the encodebin profile. Notice this: 0:00:19.077658053 27666 0x7f8670004cf0 WARN qtmux gstqtmux.c:1649:gst_qt_mux_start_file:<muxer> downstream did not handle seeking query 0:00:19.077709467 27666 0x7f8670004cf0 WARN qtmux gstqtmux.c:1658:gst_qt_mux_start_file:<muxer> warning: Downstream is not seekable and headers can't be rewritten Also notice that sound-juicer uses giosink, not filesink. Can you test case (need to write it in C or Python) a muxing pipeline with giosink. Might be where the problem is. I'm not familiar with seeking a sink, but I think that's what mp4mux. For mp4 we put the header and index at the start, hence we need to seek back in the file at EOS, and prepend that data. It is likely that giosink is missing this feature. But I'm pretty much guessing at the moment.
(In reply to comment #4) > Can you provide the encodebin profile. [profile-m4a] name = m4a description = MPEG 4 Audio format = video/quicktime, variant=iso type = container [streamprofile-m4a-1] parent = m4a type = audio format = audio/mpeg, mpegversion=4, stream-format=raw presence = 1 > Notice this: > > 0:00:19.077658053 27666 0x7f8670004cf0 WARN qtmux > gstqtmux.c:1649:gst_qt_mux_start_file:<muxer> downstream did not handle seeking > query > 0:00:19.077709467 27666 0x7f8670004cf0 WARN qtmux > gstqtmux.c:1658:gst_qt_mux_start_file:<muxer> warning: Downstream is not > seekable and headers can't be rewritten > > Also notice that sound-juicer uses giosink, not filesink. Can you test case > (need to write it in C or Python) a muxing pipeline with giosink. Might be > where the problem is. I'm not familiar with seeking a sink, but I think that's > what mp4mux. For mp4 we put the header and index at the start, hence we need to > seek back in the file at EOS, and prepend that data. It is likely that giosink > is missing this feature. But I'm pretty much guessing at the moment. Thanks, I think you're right. I just changed the sound-juicer pipeline to use faac ! mp4mux instead of encodebin and I get the same error so it looks like giosink is the problem. For mp3 encoding xingmux manages to put the Xing header at the front of the file with giosink though.
Note, GstGioBaseSink do support seeking, so there might be another bug.
This was fixed already some time ago, it also caused problems for gnome-sound-recorder. The fix will be in 1.4. commit e8d176c20c6bbde070701bf029913a4fa930e51f Author: Sebastian Dröge <sebastian@centricular.com> Date: Fri Apr 25 17:32:59 2014 +0200 giobasesink: Implement handling of the SEEKING query
As there is no related bug.