Commit d7e1dcce authored by Seungha Yang's avatar Seungha Yang

qtdemux: Handle initial header state using flags

Depending on specification, qtdemux can be initialized via
* moov atom - most common case
* upstaream caps - mss use case
* meta atom - HEIF specificaton (not implemented yet)
parent f554369e
...@@ -752,7 +752,8 @@ gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size, ...@@ -752,7 +752,8 @@ gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
/* Sanity check: catch bogus sizes (fuzzed/broken files) */ /* Sanity check: catch bogus sizes (fuzzed/broken files) */
if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) { if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) { if (qtdemux->state != QTDEMUX_STATE_MOVIE &&
qtdemux->header_state != QTDEMUX_HEADER_NONE) {
/* we're pulling header but already got most interesting bits, /* we're pulling header but already got most interesting bits,
* so never mind the rest (e.g. tags) (that much) */ * so never mind the rest (e.g. tags) (that much) */
GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT, GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
...@@ -2092,6 +2093,7 @@ gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps) ...@@ -2092,6 +2093,7 @@ gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
} }
} }
gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps); gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
demux->header_state |= QTDEMUX_HEADER_INIT;
} else { } else {
demux->mss_mode = FALSE; demux->mss_mode = FALSE;
} }
...@@ -2186,7 +2188,7 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard) ...@@ -2186,7 +2188,7 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
qtdemux->mss_mode = FALSE; qtdemux->mss_mode = FALSE;
gst_caps_replace (&qtdemux->media_caps, NULL); gst_caps_replace (&qtdemux->media_caps, NULL);
qtdemux->timescale = 0; qtdemux->timescale = 0;
qtdemux->got_moov = FALSE; qtdemux->header_state = QTDEMUX_HEADER_NONE;
qtdemux->cenc_aux_info_offset = 0; qtdemux->cenc_aux_info_offset = 0;
qtdemux->cenc_aux_info_sizes = NULL; qtdemux->cenc_aux_info_sizes = NULL;
qtdemux->cenc_aux_sample_count = 0; qtdemux->cenc_aux_sample_count = 0;
...@@ -4569,7 +4571,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) ...@@ -4569,7 +4571,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
} else { } else {
qtdemux->offset += length; /* skip moof and keep going */ qtdemux->offset += length; /* skip moof and keep going */
} }
if (qtdemux->got_moov) { if ((qtdemux->header_state & QTDEMUX_HEADER_MOOV) == QTDEMUX_HEADER_MOOV) {
GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers"); GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
ret = GST_FLOW_EOS; ret = GST_FLOW_EOS;
goto beach; goto beach;
...@@ -4592,7 +4594,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) ...@@ -4592,7 +4594,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
{ {
GstBuffer *moov = NULL; GstBuffer *moov = NULL;
if (qtdemux->got_moov) { if ((qtdemux->header_state & QTDEMUX_HEADER_MOOV) == QTDEMUX_HEADER_MOOV) {
GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already"); GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
qtdemux->offset = add_offset (qtdemux->offset, length); qtdemux->offset = add_offset (qtdemux->offset, length);
goto beach; goto beach;
...@@ -4654,7 +4656,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) ...@@ -4654,7 +4656,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
qtdemux->moov_node = NULL; qtdemux->moov_node = NULL;
gst_buffer_unmap (moov, &map); gst_buffer_unmap (moov, &map);
gst_buffer_unref (moov); gst_buffer_unref (moov);
qtdemux->got_moov = TRUE; qtdemux->header_state |= QTDEMUX_HEADER_MOOV;
break; break;
} }
...@@ -4722,7 +4724,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) ...@@ -4722,7 +4724,7 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
} }
beach: beach:
if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) { if (ret == GST_FLOW_EOS && qtdemux->header_state != QTDEMUX_HEADER_NONE) {
/* digested all data, show what we have */ /* digested all data, show what we have */
qtdemux_prepare_streams (qtdemux); qtdemux_prepare_streams (qtdemux);
QTDEMUX_EXPOSE_LOCK (qtdemux); QTDEMUX_EXPOSE_LOCK (qtdemux);
...@@ -7099,7 +7101,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) ...@@ -7099,7 +7101,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
if (fourcc == FOURCC_moov) { if (fourcc == FOURCC_moov) {
/* in usual fragmented setup we could try to scan for more /* in usual fragmented setup we could try to scan for more
* and end up at the the moov (after mdat) again */ * and end up at the the moov (after mdat) again */
if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 && if ((demux->header_state & QTDEMUX_HEADER_MOOV) == QTDEMUX_HEADER_MOOV
&& QTDEMUX_N_STREAMS (demux) > 0 &&
(!demux->fragmented (!demux->fragmented
|| demux->last_moov_offset == demux->offset)) { || demux->last_moov_offset == demux->offset)) {
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
...@@ -7107,7 +7110,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) ...@@ -7107,7 +7110,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
} else { } else {
GST_DEBUG_OBJECT (demux, "Parsing [moov]"); GST_DEBUG_OBJECT (demux, "Parsing [moov]");
if (demux->got_moov && demux->fragmented) { if ((demux->header_state & QTDEMUX_HEADER_MOOV) ==
QTDEMUX_HEADER_MOOV && demux->fragmented) {
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"Got a second moov, clean up data from old one"); "Got a second moov, clean up data from old one");
if (demux->moov_node_compressed) { if (demux->moov_node_compressed) {
...@@ -7135,7 +7139,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) ...@@ -7135,7 +7139,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
qtdemux_expose_streams (demux); qtdemux_expose_streams (demux);
QTDEMUX_EXPOSE_UNLOCK (demux); QTDEMUX_EXPOSE_UNLOCK (demux);
demux->got_moov = TRUE; demux->header_state |= QTDEMUX_HEADER_MOOV;
gst_qtdemux_check_send_pending_segment (demux); gst_qtdemux_check_send_pending_segment (demux);
...@@ -7149,7 +7153,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) ...@@ -7149,7 +7153,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
GST_DEBUG_OBJECT (demux, "Finished parsing the header"); GST_DEBUG_OBJECT (demux, "Finished parsing the header");
} }
} else if (fourcc == FOURCC_moof) { } else if (fourcc == FOURCC_moof) {
if ((demux->got_moov || demux->media_caps) && demux->fragmented) { if (demux->header_state != QTDEMUX_HEADER_NONE && demux->fragmented) {
guint64 dist = 0; guint64 dist = 0;
GstClockTime prev_pts; GstClockTime prev_pts;
guint64 prev_offset; guint64 prev_offset;
...@@ -7300,8 +7304,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force) ...@@ -7300,8 +7304,8 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
gst_adapter_flush (demux->adapter, demux->neededbytes); gst_adapter_flush (demux->adapter, demux->neededbytes);
/* only go back to the mdat if there are samples to play */ /* only go back to the mdat if there are samples to play */
if (demux->got_moov && demux->first_mdat != -1 if ((demux->header_state & QTDEMUX_HEADER_MOOV) == QTDEMUX_HEADER_MOOV
&& has_next_entry (demux)) { && demux->first_mdat != -1 && has_next_entry (demux)) {
gboolean res; gboolean res;
/* we need to seek back */ /* we need to seek back */
......
...@@ -57,6 +57,13 @@ enum QtDemuxState ...@@ -57,6 +57,13 @@ enum QtDemuxState
QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */ QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
}; };
enum QtDemuxHeaderState
{
QTDEMUX_HEADER_NONE, /* Initial state (haven't got moov or initial meta yet) */
QTDEMUX_HEADER_MOOV, /* Got moov and it's parsed */
QTDEMUX_HEADER_INIT /* Got init. data via caps or 'meta' atom */
};
struct _GstQTDemux { struct _GstQTDemux {
GstElement element; GstElement element;
...@@ -100,8 +107,9 @@ struct _GstQTDemux { ...@@ -100,8 +107,9 @@ struct _GstQTDemux {
/* FIXME : This is never freed. It is only assigned once. memleak ? */ /* FIXME : This is never freed. It is only assigned once. memleak ? */
GNode *moov_node_compressed; GNode *moov_node_compressed;
/* Set to TRUE when the [moov] header has been fully parsed */ /* Currrent initial header state. Depending on specification, qtdemux can
gboolean got_moov; * be initialized via moov, caps, or some other way */
enum QtDemuxHeaderState header_state;
/* Global timescale for the incoming stream. Use the QTTIME macros /* Global timescale for the incoming stream. Use the QTTIME macros
* to convert values to/from GstClockTime */ * to convert values to/from GstClockTime */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment