mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
asfdemux: Add support for dvr-ms
https://bugzilla.gnome.org/show_bug.cgi?id=705026
This commit is contained in:
parent
8f6e8ef56b
commit
1803b3c185
5 changed files with 279 additions and 63 deletions
|
@ -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}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -134,26 +134,15 @@ 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;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* remove any incomplete payloads that will never be completed */
|
||||
while (stream->payloads->len > 0) {
|
||||
|
@ -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)) {
|
||||
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;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include <gst/gstutils.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
#include <gst/base/gsttypefindhelper.h>
|
||||
#include <gst/riff/riff-media.h>
|
||||
#include <gst/tag/tag.h>
|
||||
#include <gst/gst-i18n-plugin.h>
|
||||
|
@ -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;
|
||||
/* 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;
|
||||
/* 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,6 +2355,7 @@ gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
|
|||
return &demux->stream[i];
|
||||
}
|
||||
|
||||
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))
|
||||
|
@ -2465,6 +2629,25 @@ gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
|
|||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ 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__ */
|
||||
|
|
Loading…
Reference in a new issue