From 1803b3c18530cb0100d140c2b8e49a8dfe41f941 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sun, 28 Jul 2013 16:43:28 +0200 Subject: [PATCH] asfdemux: Add support for dvr-ms https://bugzilla.gnome.org/show_bug.cgi?id=705026 --- gst/asfdemux/asfheaders.c | 13 +++ gst/asfdemux/asfheaders.h | 13 ++- gst/asfdemux/asfpacket.c | 80 ++++++------- gst/asfdemux/gstasfdemux.c | 227 ++++++++++++++++++++++++++++++++++--- gst/asfdemux/gstasfdemux.h | 9 +- 5 files changed, 279 insertions(+), 63 deletions(-) diff --git a/gst/asfdemux/asfheaders.c b/gst/asfdemux/asfheaders.c index ea5f9533bc..f1488be038 100644 --- a/gst/asfdemux/asfheaders.c +++ b/gst/asfdemux/asfheaders.c @@ -30,6 +30,8 @@ const ASFGuidHash asf_payload_ext_guids[] = { {ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO, "ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO", {0x1b1ee554, 0x4bc8f9ea, 0x6b371a82, 0xb8c4e474}}, + {ASF_PAYLOAD_EXTENSION_TIMING, "ASF_PAYLOAD_EXTENSION_TIMING", + {0XFD3CC02A, 0X4CFA06DB, 0X12721C80, 0XE44587D3}}, {ASF_PAYLOAD_EXTENSION_UNDEFINED, "ASF_PAYLOAD_EXTENSION_UNDEFINED", {0, 0, 0, 0} } @@ -58,11 +60,22 @@ const ASFGuidHash asf_stream_guids[] = { {ASF_STREAM_AUDIO, "ASF_STREAM_AUDIO", {0xF8699E40, 0x11CF5B4D, 0x8000FDA8, 0x2B445C5F} }, + {ASF_STREAM_EXT_EMBED_HEADER, "ASF_STREAM_EXT_EMBED_HEADER", + {0X3AFB65E2, 0X40F247EF, 0XA9702CAC, 0X43D3710D}}, {ASF_STREAM_UNDEFINED, "ASF_STREAM_UNDEFINED", {0, 0, 0, 0} } }; +const ASFGuidHash asf_ext_stream_guids[] = { + {ASF_EXT_STREAM_AUDIO, "ASF_EXT_STREAM_AUDIO", + {0X31178C9D, 0X452803E1, 0XF93D82B5, 0X03F522DB} + }, + {ASF_EXT_STREAM_UNDEFINED, "ASF_EXT_STREAM_UNDEFINED", + {0, 0, 0, 0} + } +}; + const ASFGuidHash asf_object_guids[] = { {ASF_OBJ_STREAM, "ASF_OBJ_STREAM", {0xB7DC0791, 0x11CFA9B7, 0xC000E68E, 0x6553200C} diff --git a/gst/asfdemux/asfheaders.h b/gst/asfdemux/asfheaders.h index 8a38b5a1e0..4b65b95e46 100644 --- a/gst/asfdemux/asfheaders.h +++ b/gst/asfdemux/asfheaders.h @@ -74,9 +74,15 @@ typedef enum { typedef enum { ASF_STREAM_UNDEFINED = 0, ASF_STREAM_VIDEO, - ASF_STREAM_AUDIO + ASF_STREAM_AUDIO, + ASF_STREAM_EXT_EMBED_HEADER } AsfStreamType; +typedef enum { + ASF_EXT_STREAM_UNDEFINED = 0, + ASF_EXT_STREAM_AUDIO +} AsfExtStreamType; + typedef enum { ASF_CORRECTION_UNDEFINED = 0, ASF_CORRECTION_ON, @@ -87,7 +93,8 @@ typedef enum { ASF_PAYLOAD_EXTENSION_UNDEFINED = 0, ASF_PAYLOAD_EXTENSION_DURATION, ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT, - ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO + ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO, + ASF_PAYLOAD_EXTENSION_TIMING } AsfPayloadExtensionID; extern const ASFGuidHash asf_payload_ext_guids[]; @@ -96,6 +103,8 @@ extern const ASFGuidHash asf_correction_guids[]; extern const ASFGuidHash asf_stream_guids[]; +extern const ASFGuidHash asf_ext_stream_guids[]; + extern const ASFGuidHash asf_object_guids[]; /* GUID utilities */ diff --git a/gst/asfdemux/asfpacket.c b/gst/asfdemux/asfpacket.c index 9dc4237c67..ecf1e056f4 100644 --- a/gst/asfdemux/asfpacket.c +++ b/gst/asfdemux/asfpacket.c @@ -134,27 +134,16 @@ gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload, GST_DEBUG_OBJECT (demux, "Got payload for stream %d ts:%" GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (payload->ts)); - /* Before preroll ts might be invalid and set to 0 */ - if (G_UNLIKELY (payload->ts == 0 && demux->preroll)) { - payload->ts = GST_CLOCK_TIME_NONE; + /* make timestamps start from 0; first_ts will be determined during activation (once we have enough data), + which will also update ts of all packets queued before we knew first_ts; */ + if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (demux->first_ts) + && GST_CLOCK_TIME_IS_VALID (payload->ts))) { + if (payload->ts > demux->first_ts) + payload->ts -= demux->first_ts; + else + payload->ts = 0; } - /* remember the first timestamp in the stream */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts) && - GST_CLOCK_TIME_IS_VALID (payload->ts))) { - GST_DEBUG_OBJECT (demux, "first ts: %" GST_TIME_FORMAT, - GST_TIME_ARGS (payload->ts)); - demux->first_ts = payload->ts; - } - - /* make timestamps start from 0 */ - if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (demux->first_ts) && - GST_CLOCK_TIME_IS_VALID (payload->ts) && - demux->first_ts < payload->ts)) - payload->ts -= demux->first_ts; - else - payload->ts = 0; - /* remove any incomplete payloads that will never be completed */ while (stream->payloads->len > 0) { AsfPayload *prev; @@ -201,19 +190,6 @@ gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload, GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT); } - /* remember the first queued timestamp for the segment */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) && - GST_CLOCK_TIME_IS_VALID (payload->ts))) { - GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT, - GST_TIME_ARGS (payload->ts)); - demux->segment_ts = payload->ts; - /* always note, but only determines segment when streaming */ - if (demux->streaming) - gst_segment_do_seek (&demux->segment, demux->in_segment.rate, - GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags, - GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL); - } - g_array_append_vals (stream->payloads, payload, 1); } @@ -223,29 +199,35 @@ asf_payload_parse_replicated_data_extensions (AsfStream * stream, { AsfPayloadExtension *ext; guint off; + guint16 ext_len; if (!stream->ext_props.valid || stream->ext_props.payload_extensions == NULL) return; off = 8; for (ext = stream->ext_props.payload_extensions; ext->len > 0; ++ext) { - if (G_UNLIKELY (off + ext->len > payload->rep_data_len)) { + ext_len = ext->len; + if (ext_len == 0xFFFF) { /* extension length is determined by first two bytes in replicated data */ + ext_len = GST_READ_UINT16_LE (payload->rep_data + off); + off += 2; + } + if (G_UNLIKELY (off + ext_len > payload->rep_data_len)) { GST_WARNING ("not enough replicated data for defined extensions"); return; } switch (ext->id) { case ASF_PAYLOAD_EXTENSION_DURATION: - if (G_LIKELY (ext->len == 2)) { + if (G_LIKELY (ext_len == 2)) { guint16 tdur = GST_READ_UINT16_LE (payload->rep_data + off); /* packet durations of 1ms are mostly invalid */ if (tdur != 1) payload->duration = tdur * GST_MSECOND; } else { - GST_WARNING ("unexpected DURATION extensions len %u", ext->len); + GST_WARNING ("unexpected DURATION extensions len %u", ext_len); } break; case ASF_PAYLOAD_EXTENSION_SYSTEM_CONTENT: - if (G_LIKELY (ext->len == 1)) { + if (G_LIKELY (ext_len == 1)) { guint8 data = payload->rep_data[off]; payload->interlaced = data & 0x1; @@ -254,24 +236,34 @@ asf_payload_parse_replicated_data_extensions (AsfStream * stream, GST_DEBUG ("SYSTEM_CONTENT: interlaced:%d, rff:%d, tff:%d", payload->interlaced, payload->rff, payload->tff); } else { - GST_WARNING ("unexpected SYSTEM_CONTE extensions len %u", ext->len); + GST_WARNING ("unexpected SYSTEM_CONTE extensions len %u", ext_len); } break; case ASF_PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO: - if (G_LIKELY (ext->len == 2)) { + if (G_LIKELY (ext_len == 2)) { payload->par_x = payload->rep_data[off]; payload->par_y = payload->rep_data[off + 1]; GST_DEBUG ("PAR %d / %d", payload->par_x, payload->par_y); } else { GST_WARNING ("unexpected SYSTEM_PIXEL_ASPECT_RATIO extensions len %u", - ext->len); + ext_len); } break; + case ASF_PAYLOAD_EXTENSION_TIMING: + { + /* dvr-ms timing - this will override packet timestamp */ + guint64 time = GST_READ_UINT64_LE (payload->rep_data + off + 8); + if (time != 0xFFFFFFFFFFFFFFFF) + payload->ts = time * 100; + else + payload->ts = GST_CLOCK_TIME_NONE; + } + break; default: - GST_WARNING ("UNKNOWN PAYLOAD EXTENSION !"); + GST_LOG ("UNKNOWN PAYLOAD EXTENSION!"); break; } - off += ext->len; + off += ext_len; } } @@ -351,8 +343,10 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, stream = gst_asf_demux_get_stream (demux, stream_num); if (G_UNLIKELY (stream == NULL)) { - GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping", - stream_num); + if (gst_asf_demux_is_unknown_stream (demux, stream_num)) { + GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping", + stream_num); + } if (*p_size < payload_len) { *p_data += *p_size; *p_size = 0; diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c index df0d86e294..b50d4a1e4e 100644 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -269,6 +270,9 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset) } else { demux->base_offset = 0; } + + g_slist_free (demux->other_streams); + demux->other_streams = NULL; } static void @@ -1237,9 +1241,9 @@ all_streams_prerolled (GstASFDemux * demux) * and (b) the timestamp of last piece of data queued is < demux->preroll * AND there is at least one other stream with data queued */ for (i = 0; i < demux->num_streams; ++i) { - AsfPayload *last_payload; + AsfPayload *last_payload = NULL; AsfStream *stream; - guint last_idx; + gint last_idx; stream = &demux->stream[i]; if (G_UNLIKELY (stream->payloads->len == 0)) { @@ -1248,19 +1252,24 @@ all_streams_prerolled (GstASFDemux * demux) continue; } - last_idx = stream->payloads->len - 1; - last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx); + /* find last payload with timestamp */ + for (last_idx = stream->payloads->len - 1; + last_idx >= 0 && (last_payload == NULL + || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) { + last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx); + } GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts), GST_TIME_ARGS (preroll_time)); - if (G_UNLIKELY (last_payload->ts <= preroll_time)) { + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts) + || last_payload->ts <= preroll_time)) { GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet"); return FALSE; } } - if (G_UNLIKELY (num_no_data == demux->num_streams)) + if (G_UNLIKELY (num_no_data > 0)) return FALSE; return TRUE; @@ -1305,6 +1314,132 @@ gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux, } #endif +static gboolean +gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force) +{ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) { + GstClockTime first_ts = GST_CLOCK_TIME_NONE; + int i; + + /* go trhough each stream, find smallest timestamp */ + for (i = 0; i < demux->num_streams; ++i) { + AsfStream *stream; + int j; + GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE; + stream = &demux->stream[i]; + + for (j = 0; j < stream->payloads->len; ++j) { + AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j); + if (GST_CLOCK_TIME_IS_VALID (payload->ts) && + (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) + || stream_min_ts > payload->ts)) + stream_min_ts = payload->ts; + } + + /* if we don't have timestamp for this stream, wait for more data */ + if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force) + return FALSE; + + if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) && + (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts)) + first_ts = stream_min_ts; + } + + if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */ + first_ts = 0; + + demux->first_ts = first_ts; + + /* update packets queued before we knew first timestamp */ + for (i = 0; i < demux->num_streams; ++i) { + AsfStream *stream; + int j; + stream = &demux->stream[i]; + + for (j = 0; j < stream->payloads->len; ++j) { + AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j); + if (GST_CLOCK_TIME_IS_VALID (payload->ts)) { + if (payload->ts > first_ts) + payload->ts -= first_ts; + else + payload->ts = 0; + } + } + } + + /* remember the first queued timestamp for the segment */ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts))) { + GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT, + GST_TIME_ARGS (first_ts)); + demux->segment_ts = first_ts; + /* always note, but only determines segment when streaming */ + if (demux->streaming) + gst_segment_do_seek (&demux->segment, demux->in_segment.rate, + GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags, + GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL); + } + } + + return TRUE; +} + +static gboolean +gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream) +{ + /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable + and often set wrong, inspecting the data is the only way that seem to be working */ + GstTypeFindProbability prob = GST_TYPE_FIND_NONE; + GstCaps *caps = NULL; + GstAdapter *adapter = gst_adapter_new (); + + for (int i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) { + const guint8 *data; + AsfPayload *payload; + int len; + + payload = &g_array_index (stream->payloads, AsfPayload, i); + gst_adapter_push (adapter, gst_buffer_ref (payload->buf)); + len = gst_adapter_available (adapter); + data = gst_adapter_map (adapter, len); + + again: + +#define MIN_LENGTH 128 + + /* look for the sync points */ + while (TRUE) { + if (len < MIN_LENGTH || /* give typefind something to work on */ + (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */ + (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */ + break; + ++data; + --len; + } + + gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux), + data, len, &prob)); + + if (prob < GST_TYPE_FIND_LIKELY) { + ++data; + --len; + if (len > MIN_LENGTH) + /* this wasn't it, look for another sync point */ + goto again; + } + + gst_adapter_unmap (adapter); + } + + gst_object_unref (adapter); + + if (caps) { + gst_caps_take (&stream->caps, caps); + return TRUE; + } else { + return FALSE; + } +} + static gboolean gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force) { @@ -1313,6 +1448,9 @@ gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force) if (demux->activated_streams) return TRUE; + if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force))) + return FALSE; + if (!all_streams_prerolled (demux) && !force) { GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet"); return FALSE; @@ -1322,6 +1460,14 @@ gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force) AsfStream *stream = &demux->stream[i]; if (stream->payloads->len > 0) { + + if (stream->inspect_payload && /* dvr-ms required payload inspection */ + !stream->active && /* do not inspect active streams (caps were already set) */ + !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */ + stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */ + /* try to gather some more data */ + return FALSE; + } /* we don't check mutual exclusion stuff here; either we have data for * a stream, then we active it, or we don't, then we'll ignore it */ GST_LOG_OBJECT (stream->pad, "is prerolled - activate!"); @@ -1352,6 +1498,7 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux) for (i = 0; i < demux->num_streams; ++i) { AsfStream *stream; + int j; stream = &demux->stream[i]; @@ -1360,11 +1507,15 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux) * don't need to be decoded after a seek, sending only data from the * keyframe directly before our segment start */ if (stream->payloads->len > 0) { - AsfPayload *payload; - guint last_idx; + AsfPayload *payload = NULL; + gint last_idx; - last_idx = stream->payloads->len - 1; - payload = &g_array_index (stream->payloads, AsfPayload, last_idx); + /* find last payload with timestamp */ + for (last_idx = stream->payloads->len - 1; + last_idx >= 0 && (payload == NULL + || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) { + payload = &g_array_index (stream->payloads, AsfPayload, last_idx); + } if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) && (payload->ts < demux->segment.start))) { if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) { @@ -1384,7 +1535,14 @@ gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux) /* Now see if there's a complete payload queued for this stream */ - payload = &g_array_index (stream->payloads, AsfPayload, 0); + payload = NULL; + /* find first complete payload with timestamp */ + for (j = 0; + j < stream->payloads->len && (payload == NULL + || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) { + payload = &g_array_index (stream->payloads, AsfPayload, j); + } + if (!gst_asf_payload_is_complete (payload)) continue; @@ -1526,7 +1684,10 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force) * typically useful for live src, but might (unavoidably) mess with * position reporting if a live src is playing not so live content * (e.g. rtspsrc taking some time to fall back to tcp) */ - GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap; + GST_BUFFER_PTS (payload->buf) = payload->ts; + if (GST_BUFFER_PTS_IS_VALID (payload->buf)) { + GST_BUFFER_PTS (payload->buf) += demux->in_gap; + } if (payload->duration == GST_CLOCK_TIME_NONE && stream->ext_props.avg_time_per_frame != 0) GST_BUFFER_DURATION (payload->buf) = @@ -2194,7 +2355,8 @@ gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id) return &demux->stream[i]; } - GST_WARNING ("Segment found for undefined stream: (%d)", id); + if (gst_asf_demux_is_unknown_stream (demux, id)) + GST_WARNING ("Segment found for undefined stream: (%d)", id); return NULL; } @@ -2441,6 +2603,8 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data, guint stream_specific_size; guint type_specific_size G_GNUC_UNUSED; guint unknown G_GNUC_UNUSED; + gboolean inspect_payload = FALSE; + AsfStream *stream; /* Get the rest of the header's header */ if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4)) @@ -2459,12 +2623,31 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data, flags = gst_asf_demux_get_uint16 (&data, &size); stream_id = flags & 0x7f; - is_encrypted = ! !((flags & 0x8000) << 15); + is_encrypted = !!((flags & 0x8000) << 15); unknown = gst_asf_demux_get_uint32 (&data, &size); GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT, stream_id, GST_TIME_ARGS (time_offset)); + /* dvr-ms has audio stream declared in stream specific data */ + if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) { + AsfExtStreamType ext_stream_type; + gst_asf_demux_get_guid (&guid, &data, &size); + ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid); + + if (ext_stream_type == ASF_EXT_STREAM_AUDIO) { + inspect_payload = TRUE; + + gst_asf_demux_get_guid (&guid, &data, &size); + gst_asf_demux_get_uint32 (&data, &size); + gst_asf_demux_get_uint32 (&data, &size); + gst_asf_demux_get_uint32 (&data, &size); + gst_asf_demux_get_guid (&guid, &data, &size); + gst_asf_demux_get_uint32 (&data, &size); + stream_type = ASF_STREAM_AUDIO; + } + } + switch (stream_type) { case ASF_STREAM_AUDIO:{ asf_stream_audio audio_object; @@ -2570,10 +2753,15 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data, default: GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u", stream_id); + demux->other_streams = + g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id)); break; } - return gst_asf_demux_get_stream (demux, stream_id); + stream = gst_asf_demux_get_stream (demux, stream_id); + if (stream) + stream->inspect_payload = inspect_payload; + return stream; not_enough_data: { @@ -3435,6 +3623,13 @@ not_enough_data: } } +gboolean +gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num) +{ + return g_slist_find (demux->other_streams, + GINT_TO_POINTER (stream_num)) == NULL; +} + static GstFlowReturn gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, guint64 size) @@ -3601,7 +3796,7 @@ done: GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx], NULL); } - } else { + } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) { GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream"); } diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h index 86cd5710da..deddb4df00 100644 --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -110,7 +110,8 @@ typedef struct /* extended stream properties (optional) */ AsfStreamExtProps ext_props; - + + gboolean inspect_payload; } AsfStream; typedef enum { @@ -167,7 +168,7 @@ struct _GstASFDemux { AsfStream old_stream[GST_ASF_DEMUX_NUM_STREAMS]; gboolean old_num_streams; - GstClockTime first_ts; /* first timestamp found */ + GstClockTime first_ts; /* smallest timestamp found */ guint32 packet_size; guint32 timestamp; /* in milliseconds */ @@ -203,6 +204,8 @@ struct _GstASFDemux { GstClockTime sidx_interval; /* interval between entries in ns */ guint sidx_num_entries; /* number of index entries */ AsfSimpleIndexEntry *sidx_entries; /* packet number for each entry */ + + GSList *other_streams; /* remember streams that are in header but have unknown type */ }; struct _GstASFDemuxClass { @@ -213,6 +216,8 @@ GType gst_asf_demux_get_type (void); AsfStream * gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id); +gboolean gst_asf_demux_is_unknown_stream(GstASFDemux *demux, guint stream_num); + G_END_DECLS #endif /* __ASF_DEMUX_H__ */