From 0e78ffc9d61ffa0adca14be6e4214c8b08450b57 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 25 Oct 2013 11:42:37 -0300 Subject: [PATCH] qtdemux: When using a buffered mdat, store all received data for later use In push mode, when qtdemux can't use a seek to skip the mdat buffer it has to buffer it for later use. The issue is that after parsing the next moov/moof, there might be some trailing bytes from the next atom in the file. This data was being discarded along with the already parsed moov/moof and playback would fail to continue after the contents of this moov/moof are played. This is particularly bad on fragmented files that have the mdat before the corresponding moof. So you'd get: mdat|moof|mdat|moof ... When a moof was received, it usually came with some extra bytes that would belong to the next mdat (because upstream doesn't care about atoms alignment). So those bytes were being discarded and playback would fail. This patch makes qtdemux store those extra bytes to reuse them later after the mdat is emptied. https://bugzilla.gnome.org/show_bug.cgi?id=710623 --- gst/isomp4/qtdemux.c | 34 +++++++++++++++++++++++++++++++++- gst/isomp4/qtdemux.h | 9 +++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 3a7c29bc58..c6240cd9e5 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -532,6 +532,8 @@ gst_qtdemux_init (GstQTDemux * qtdemux) qtdemux->got_moov = FALSE; qtdemux->mdatoffset = GST_CLOCK_TIME_NONE; qtdemux->mdatbuffer = NULL; + qtdemux->restoredata_buffer = NULL; + qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE; qtdemux->fragment_start = -1; qtdemux->media_caps = NULL; qtdemux->exposed = FALSE; @@ -1804,9 +1806,13 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) qtdemux->first_mdat = -1; qtdemux->header_size = 0; qtdemux->mdatoffset = GST_CLOCK_TIME_NONE; + qtdemux->restoredata_offset = GST_CLOCK_TIME_NONE; if (qtdemux->mdatbuffer) gst_buffer_unref (qtdemux->mdatbuffer); + if (qtdemux->restoredata_buffer) + gst_buffer_unref (qtdemux->restoredata_buffer); qtdemux->mdatbuffer = NULL; + qtdemux->restoredata_buffer = NULL; qtdemux->mdatleft = 0; if (qtdemux->comp_brands) gst_buffer_unref (qtdemux->comp_brands); @@ -4770,13 +4776,29 @@ gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf) data = NULL; if (demux->mdatbuffer && demux->n_streams) { + gsize remaining_data_size = 0; + /* the mdat was before the header */ GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p", demux->n_streams, demux->mdatbuffer); /* restore our adapter/offset view of things with upstream; * put preceding buffered data ahead of current moov data. * This should also handle evil mdat, moov, mdat cases and alike */ - gst_adapter_clear (demux->adapter); + gst_adapter_flush (demux->adapter, demux->neededbytes); + + /* Store any remaining data after the mdat for later usage */ + remaining_data_size = gst_adapter_available (demux->adapter); + if (remaining_data_size > 0) { + g_assert (demux->restoredata_buffer == NULL); + demux->restoredata_buffer = + gst_adapter_take_buffer (demux->adapter, remaining_data_size); + demux->restoredata_offset = demux->offset + demux->neededbytes; + GST_DEBUG_OBJECT (demux, + "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %" + G_GUINT64_FORMAT, remaining_data_size, + demux->restoredata_offset); + } + gst_adapter_push (demux->adapter, demux->mdatbuffer); demux->mdatbuffer = NULL; demux->offset = demux->mdatoffset; @@ -4861,6 +4883,16 @@ gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf) /* need to resume atom parsing so we do not miss any other pieces */ demux->state = QTDEMUX_STATE_INITIAL; demux->neededbytes = 16; + + /* check if there was any stored post mdat data from previous buffers */ + if (demux->restoredata_buffer) { + g_assert (gst_adapter_available (demux->adapter) == 0); + + gst_adapter_push (demux->adapter, demux->restoredata_buffer); + demux->restoredata_buffer = NULL; + demux->offset = demux->restoredata_offset; + } + break; } } diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h index d27134c9b3..3fb43daea7 100644 --- a/gst/isomp4/qtdemux.h +++ b/gst/isomp4/qtdemux.h @@ -91,6 +91,15 @@ struct _GstQTDemux { GstAdapter *adapter; GstBuffer *mdatbuffer; guint64 mdatleft; + /* When restoring the mdat to the adatpter, this buffer + * stores any trailing data that was after the last atom parsed as it + * has to be restored later along with the correct offset. Used in + * fragmented scenario where mdat/moof are one after the other + * in any order. + * + * Check https://bugzilla.gnome.org/show_bug.cgi?id=710623 */ + GstBuffer *restoredata_buffer; + guint64 restoredata_offset; guint64 offset; /* offset of the mdat atom */