gst/asfdemux/: Refactor stream parse/activation a bit (stream activation heuristics are still the same though); some ...

Original commit message from CVS:
* gst/asfdemux/asfheaders.h:
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_free_stream),
(gst_asf_demux_reset), (gst_asf_demux_parse_data_object_start),
(gst_asf_demux_loop), (gst_asf_demux_setup_pad),
(gst_asf_demux_add_audio_stream), (gst_asf_demux_activate_stream),
(gst_asf_demux_parse_stream_object),
(gst_asf_demux_process_ext_stream_props),
(gst_asf_demux_process_queued_extended_stream_objects),
(gst_asf_demux_activate_ext_props_streams),
(gst_asf_demux_process_object):
* gst/asfdemux/gstasfdemux.h:
Refactor stream parse/activation a bit (stream activation heuristics
are still the same though); some more clean-ups.
This commit is contained in:
Tim-Philipp Müller 2007-04-30 11:41:22 +00:00
parent 9ca32166b2
commit 850c0fbab8
5 changed files with 244 additions and 190 deletions

View file

@ -1,3 +1,19 @@
2007-04-30 Tim-Philipp Müller <tim at centricular dot net>
* gst/asfdemux/asfheaders.h:
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_free_stream),
(gst_asf_demux_reset), (gst_asf_demux_parse_data_object_start),
(gst_asf_demux_loop), (gst_asf_demux_setup_pad),
(gst_asf_demux_add_audio_stream), (gst_asf_demux_activate_stream),
(gst_asf_demux_parse_stream_object),
(gst_asf_demux_process_ext_stream_props),
(gst_asf_demux_process_queued_extended_stream_objects),
(gst_asf_demux_activate_ext_props_streams),
(gst_asf_demux_process_object):
* gst/asfdemux/gstasfdemux.h:
Refactor stream parse/activation a bit (stream activation heuristics
are still the same though); some more clean-ups.
2007-04-28 Tim-Philipp Müller <tim at centricular dot net> 2007-04-28 Tim-Philipp Müller <tim at centricular dot net>
* win32/common/.cvsignore: * win32/common/.cvsignore:

2
common

@ -1 +1 @@
Subproject commit a19d235c89d99ca7849078d501129f521e30d98d Subproject commit 61edc2dc7b8eba179d85a6545e46e0d65239e94d

View file

@ -20,6 +20,8 @@
#ifndef __ASFHEADERS_H__ #ifndef __ASFHEADERS_H__
#define __ASFHEADERS_H__ #define __ASFHEADERS_H__
G_BEGIN_DECLS
typedef struct { typedef struct {
guint32 v1; guint32 v1;
guint32 v2; guint32 v2;
@ -68,17 +70,17 @@ typedef enum {
ASF_OBJ_MARKER ASF_OBJ_MARKER
} AsfObjectID; } AsfObjectID;
enum { typedef enum {
ASF_STREAM_UNDEFINED = 0, ASF_STREAM_UNDEFINED = 0,
ASF_STREAM_VIDEO, ASF_STREAM_VIDEO,
ASF_STREAM_AUDIO ASF_STREAM_AUDIO
}; } AsfStreamType;
enum { typedef enum {
ASF_CORRECTION_UNDEFINED = 0, ASF_CORRECTION_UNDEFINED = 0,
ASF_CORRECTION_ON, ASF_CORRECTION_ON,
ASF_CORRECTION_OFF ASF_CORRECTION_OFF
}; } AsfCorrectionType;
extern const ASFGuidHash asf_correction_guids[]; extern const ASFGuidHash asf_correction_guids[];
@ -93,43 +95,6 @@ guint32 gst_asf_identify_guid (const ASFGuidHash * guids,
const gchar *gst_asf_get_guid_nick (const ASFGuidHash * guids, const gchar *gst_asf_get_guid_nick (const ASFGuidHash * guids,
guint32 obj_id); guint32 obj_id);
struct _asf_obj_ext_stream_properties {
guint64 start_time;
guint64 end_time;
guint64 avg_time_per_frame;
guint32 data_bitrate;
guint32 buffer_size;
guint32 intial_buf_fullness;
guint32 data_bitrate2;
guint32 buffer_size2;
guint32 intial_buf_fullness2;
guint32 max_obj_size;
guint32 flags;
guint16 stream_num;
guint16 lang_idx;
/* missing: stream names */
/* missing: payload extension system stuff */
/* for delayed processing of these stream objects */
guint8 *stream_obj_data;
guint64 stream_obj_len;
};
typedef struct _asf_obj_ext_stream_properties asf_obj_ext_stream_properties;
struct _asf_obj_stream {
ASFGuid type;
ASFGuid correction;
guint64 time_offset;
guint32 type_specific_size;
guint32 stream_specific_size;
guint8 id;
guint8 encrypted;
guint32 unknown2;
};
typedef struct _asf_obj_stream asf_obj_stream;
struct _asf_stream_audio { struct _asf_stream_audio {
guint16 codec_tag; guint16 codec_tag;
guint16 channels; guint16 channels;
@ -198,4 +163,6 @@ struct _asf_segment_info {
typedef struct _asf_segment_info asf_segment_info; typedef struct _asf_segment_info asf_segment_info;
G_END_DECLS
#endif /* __ASFHEADERS_H__ */ #endif /* __ASFHEADERS_H__ */

View file

@ -97,6 +97,7 @@ static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
static void gst_asf_demux_loop (GstASFDemux * demux); static void gst_asf_demux_loop (GstASFDemux * demux);
static void static void
gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux); gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
static void gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux);
static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux); static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
static void gst_asf_demux_pull_indices (GstASFDemux * demux); static void gst_asf_demux_pull_indices (GstASFDemux * demux);
static GstFlowReturn gst_asf_demux_handle_data (GstASFDemux * demux, static GstFlowReturn gst_asf_demux_handle_data (GstASFDemux * demux,
@ -154,7 +155,10 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
stream->pending_tags = NULL; stream->pending_tags = NULL;
} }
if (stream->pad) { if (stream->pad) {
gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad); if (stream->active)
gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
else
gst_object_unref (stream->pad);
stream->pad = NULL; stream->pad = NULL;
} }
} }
@ -181,7 +185,8 @@ gst_asf_demux_reset (GstASFDemux * demux)
g_strfreev (demux->languages); g_strfreev (demux->languages);
demux->languages = NULL; demux->languages = NULL;
demux->num_languages = 0; demux->num_languages = 0;
g_slist_foreach (demux->ext_stream_props, (GFunc) g_free, NULL); g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
NULL);
g_slist_free (demux->ext_stream_props); g_slist_free (demux->ext_stream_props);
demux->ext_stream_props = NULL; demux->ext_stream_props = NULL;
while (demux->num_streams > 0) { while (demux->num_streams > 0) {
@ -844,6 +849,7 @@ gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
/* process pending stream objects and create pads for those */ /* process pending stream objects and create pads for those */
gst_asf_demux_process_queued_extended_stream_objects (demux); gst_asf_demux_process_queued_extended_stream_objects (demux);
gst_asf_demux_activate_ext_props_streams (demux);
gst_element_no_more_pads (GST_ELEMENT (demux)); gst_element_no_more_pads (GST_ELEMENT (demux));
GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, " GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
@ -1038,11 +1044,8 @@ gst_asf_demux_loop (GstASFDemux * demux)
/* FIXME: maybe we should just skip broken packets and error out only /* FIXME: maybe we should just skip broken packets and error out only
* after a few broken packets in a row? */ * after a few broken packets in a row? */
if (!gst_asf_demux_parse_packet (demux, buf)) { if (!gst_asf_demux_parse_packet (demux, buf))
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), goto parse_error;
("Error parsing ASF packet %u", (guint) demux->packet));
flow = GST_FLOW_ERROR;
}
gst_buffer_unref (buf); gst_buffer_unref (buf);
@ -1102,6 +1105,14 @@ read_failed:
gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ()); gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
goto pause; goto pause;
} }
parse_error:
{
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
("Error parsing ASF packet %u", (guint) demux->packet));
gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
goto pause;
}
} }
static inline gboolean static inline gboolean
@ -1271,28 +1282,6 @@ gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size); guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
} }
static gboolean
gst_asf_demux_get_obj_stream (asf_obj_stream * stream, guint8 ** p_data,
guint64 * p_size)
{
guint16 flags;
if (*p_size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
return FALSE;
gst_asf_demux_get_guid (&stream->type, p_data, p_size);
gst_asf_demux_get_guid (&stream->correction, p_data, p_size);
stream->time_offset = gst_asf_demux_get_uint64 (p_data, p_size) * 100;
stream->type_specific_size = gst_asf_demux_get_uint32 (p_data, p_size);
stream->stream_specific_size = gst_asf_demux_get_uint32 (p_data, p_size);
flags = gst_asf_demux_get_uint16 (p_data, p_size);
stream->id = flags & 0x7f;
stream->encrypted = (flags & 0x8000) << 15;
stream->unknown2 = gst_asf_demux_get_uint32 (p_data, p_size);
return TRUE;
}
static gboolean static gboolean
gst_asf_demux_get_obj_data_correction (asf_obj_data_correction * object, gst_asf_demux_get_obj_data_correction (asf_obj_data_correction * object,
guint8 ** p_data, guint64 * p_size) guint8 ** p_data, guint64 * p_size)
@ -1373,22 +1362,6 @@ gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
return NULL; return NULL;
} }
static asf_obj_ext_stream_properties *
gst_asf_demux_get_ext_stream_props_for_stream (GstASFDemux * demux, gint id)
{
GSList *l;
for (l = demux->ext_stream_props; l != NULL; l = l->next) {
asf_obj_ext_stream_properties *esp;
esp = (asf_obj_ext_stream_properties *) l->data;
if (esp->stream_num == id)
return esp;
}
return NULL;
}
static void static void
gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad, gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags) GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
@ -1422,22 +1395,18 @@ gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload)); stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
gst_pad_set_element_private (src_pad, stream);
GST_INFO ("Adding pad %s for stream %u with caps %" GST_PTR_FORMAT,
GST_PAD_NAME (src_pad), demux->num_streams, caps); GST_PAD_NAME (src_pad), demux->num_streams, caps);
++demux->num_streams; ++demux->num_streams;
gst_pad_set_active (src_pad, TRUE);
gst_element_add_pad (GST_ELEMENT (demux), src_pad); stream->active = FALSE;
} }
static void static void
gst_asf_demux_add_audio_stream (GstASFDemux * demux, gst_asf_demux_add_audio_stream (GstASFDemux * demux,
asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size) asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
{ {
asf_obj_ext_stream_properties *ext_props;
GstTagList *tags = NULL; GstTagList *tags = NULL;
GstBuffer *extradata = NULL; GstBuffer *extradata = NULL;
GstPad *src_pad; GstPad *src_pad;
@ -1482,20 +1451,12 @@ gst_asf_demux_add_audio_stream (GstASFDemux * demux,
g_free (codec_name); g_free (codec_name);
} }
/* add language info if we have it */
ext_props = gst_asf_demux_get_ext_stream_props_for_stream (demux, id);
if (ext_props && ext_props->lang_idx < demux->num_languages) {
if (tags == NULL)
tags = gst_tag_list_new ();
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE,
demux->languages[ext_props->lang_idx], NULL);
}
if (extradata) if (extradata)
gst_buffer_unref (extradata); gst_buffer_unref (extradata);
GST_INFO ("Adding audio stream %u codec %u (0x%04x), tags=%" GST_PTR_FORMAT, GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
demux->num_video_streams, audio->codec_tag, audio->codec_tag, tags); GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
audio->codec_tag, tags);
++demux->num_audio_streams; ++demux->num_audio_streams;
@ -1561,25 +1522,57 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags); gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
} }
static GstFlowReturn static void
gst_asf_demux_process_stream (GstASFDemux * demux, guint8 * data, guint64 size) gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
{ {
asf_obj_stream object; if (!stream->active) {
guint32 stream_id; GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
guint32 correction; GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
gst_pad_set_active (stream->pad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
stream->active = TRUE;
}
}
static AsfStream *
gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
guint64 size)
{
AsfCorrectionType correction_type;
AsfStreamType stream_type;
GstClockTime time_offset;
gboolean is_encrypted;
guint16 stream_id;
guint16 flags;
ASFGuid guid;
guint stream_specific_size;
guint type_specific_size;
guint unknown;
/* Get the rest of the header's header */ /* Get the rest of the header's header */
if (!gst_asf_demux_get_obj_stream (&object, &data, &size)) if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
goto not_enough_data; goto not_enough_data;
GST_DEBUG ("Found stream #%u", object.id); gst_asf_demux_get_guid (&guid, &data, &size);
stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
/* Identify the stream type */ gst_asf_demux_get_guid (&guid, &data, &size);
stream_id = gst_asf_demux_identify_guid (asf_stream_guids, &object.type); correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
correction =
gst_asf_demux_identify_guid (asf_correction_guids, &object.correction);
switch (stream_id) { time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
flags = gst_asf_demux_get_uint16 (&data, &size);
stream_id = flags & 0x7f;
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));
switch (stream_type) {
case ASF_STREAM_AUDIO:{ case ASF_STREAM_AUDIO:{
asf_stream_audio audio_object; asf_stream_audio audio_object;
@ -1589,10 +1582,10 @@ gst_asf_demux_process_stream (GstASFDemux * demux, guint8 * data, guint64 size)
GST_INFO ("Object is an audio stream with %u bytes of additional data", GST_INFO ("Object is an audio stream with %u bytes of additional data",
audio_object.size); audio_object.size);
gst_asf_demux_add_audio_stream (demux, &audio_object, object.id, gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
&data, &size); &data, &size);
switch (correction) { switch (correction_type) {
case ASF_CORRECTION_ON:{ case ASF_CORRECTION_ON:{
guint span, packet_size, chunk_size, data_size, silence_data; guint span, packet_size, chunk_size, data_size, silence_data;
@ -1642,22 +1635,16 @@ gst_asf_demux_process_stream (GstASFDemux * demux, guint8 * data, guint64 size)
#endif #endif
break; break;
} }
case ASF_CORRECTION_OFF: case ASF_CORRECTION_OFF:{
GST_INFO ("Error correction off"); GST_INFO ("Error correction off");
#if 0 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
/* gst_bytestream_flush (demux->bs, object.stream_specific_size); */
#else
/* FIXME: CHECKME */
if (!gst_asf_demux_skip_bytes (object.stream_specific_size,
&data, &size)) {
goto not_enough_data; goto not_enough_data;
}
#endif
break; break;
}
default: default:
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
("Audio stream using unknown error correction")); ("Audio stream using unknown error correction"));
return GST_FLOW_ERROR; return NULL;
} }
break; break;
@ -1681,25 +1668,25 @@ gst_asf_demux_process_stream (GstASFDemux * demux, guint8 * data, guint64 size)
goto not_enough_data; goto not_enough_data;
} }
gst_asf_demux_add_video_stream (demux, &video_format_object, object.id, gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
&data, &size); &data, &size);
break; break;
} }
default: default:
GST_WARNING_OBJECT (demux, "Unknown asf stream (id %08x)", GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
(guint) stream_id); stream_id);
break; break;
} }
return GST_FLOW_OK; return gst_asf_demux_get_stream (demux, stream_id);
not_enough_data: not_enough_data:
{ {
GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object"); GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
/* pretend it's ok, we'll error out later if we found no streams */ /* we'll error out later if we found no streams */
return GST_FLOW_OK; return NULL;
} }
} }
@ -2338,20 +2325,23 @@ static GstFlowReturn
gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
guint64 size) guint64 size)
{ {
AsfStreamExtProps esp;
AsfStream *stream = NULL;
AsfObject stream_obj; AsfObject stream_obj;
asf_obj_ext_stream_properties esp = { 0, };
guint16 stream_name_count; guint16 stream_name_count;
guint16 payload_ext_sys_count; guint16 payload_ext_sys_count;
guint64 len; guint64 len;
guint8 *stream_obj_data = NULL;
guint8 *data_start = data; guint8 *data_start = data;
guint obj_size = (guint) size; guint obj_size = (guint) size;
guint i; guint i, stream_num;
if (size < 8 + 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 2 + 2 + 8 + 2 + 2) /* 64 */ if (size < 64)
goto not_enough_data; goto not_enough_data;
esp.start_time = gst_asf_demux_get_uint64 (&data, &size); esp.valid = TRUE;
esp.end_time = gst_asf_demux_get_uint64 (&data, &size); esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size); esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size); esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size); esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
@ -2360,20 +2350,20 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size); esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size); esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
esp.flags = gst_asf_demux_get_uint32 (&data, &size); esp.flags = gst_asf_demux_get_uint32 (&data, &size);
esp.stream_num = gst_asf_demux_get_uint16 (&data, &size); stream_num = gst_asf_demux_get_uint16 (&data, &size);
esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size); esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size); esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size) * 100;
stream_name_count = gst_asf_demux_get_uint16 (&data, &size); stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
payload_ext_sys_count = gst_asf_demux_get_uint16 (&data, &size); payload_ext_sys_count = gst_asf_demux_get_uint16 (&data, &size);
GST_INFO ("start_time = %" GST_TIME_FORMAT, GST_INFO ("start_time = %" GST_TIME_FORMAT,
GST_TIME_ARGS (esp.start_time * GST_MSECOND)); GST_TIME_ARGS (esp.start_time));
GST_INFO ("end_time = %" GST_TIME_FORMAT, GST_INFO ("end_time = %" GST_TIME_FORMAT,
GST_TIME_ARGS (esp.end_time * GST_MSECOND)); GST_TIME_ARGS (esp.end_time));
GST_INFO ("flags = %08x", esp.flags); GST_INFO ("flags = %08x", esp.flags);
GST_INFO ("average time per frame = %" GST_TIME_FORMAT, GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
GST_TIME_ARGS (esp.avg_time_per_frame * 100)); GST_TIME_ARGS (esp.avg_time_per_frame));
GST_INFO ("stream number = %u", esp.stream_num); GST_INFO ("stream number = %u", stream_num);
GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx, GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
(esp.lang_idx < demux->num_languages) ? (esp.lang_idx < demux->num_languages) ?
GST_STR_NULL (demux->languages[esp.lang_idx]) : "??"); GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
@ -2408,9 +2398,13 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size); GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
/* there might be an optional STREAM_INFO object here now */ /* there might be an optional STREAM_INFO object here now; if not, we
if (size == 0) * should have parsed the corresponding stream info object already (since
* we are parsing the extended stream properties objects delayed) */
if (size == 0) {
stream = gst_asf_demux_get_stream (demux, stream_num);
goto done; goto done;
}
/* get size of the stream object */ /* get size of the stream object */
if (!asf_demux_peek_object (demux, data, size, &stream_obj)) if (!asf_demux_peek_object (demux, data, size, &stream_obj))
@ -2428,15 +2422,31 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
/* process this stream object later after all the other 'normal' ones /* process this stream object later after all the other 'normal' ones
* have been processed (since the others are more important/non-hidden) */ * have been processed (since the others are more important/non-hidden) */
len = stream_obj.size - ASF_OBJECT_HEADER_SIZE; len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
if (!gst_asf_demux_get_bytes (&esp.stream_obj_data, len, &data, &size)) if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
goto not_enough_data; goto not_enough_data;
esp.stream_obj_len = len; /* parse stream object */
stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
g_free (stream_obj_data);
done: done:
demux->ext_stream_props = g_slist_append (demux->ext_stream_props, if (stream) {
g_memdup (&esp, sizeof (esp))); stream->ext_props = esp;
/* add language info now if we have it */
if (stream->ext_props.lang_idx < demux->num_languages) {
if (stream->pending_tags == NULL)
stream->pending_tags = gst_tag_list_new ();
GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
demux->languages[stream->ext_props.lang_idx]);
gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
NULL);
}
} else {
GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
}
return GST_FLOW_OK; return GST_FLOW_OK;
@ -2493,37 +2503,66 @@ gst_asf_demux_pop_obj (GstASFDemux * demux)
static void static void
gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux) gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
{ {
GSList *l, *x; GSList *l;
guint i;
GST_DEBUG_OBJECT (demux, "parsing %d stream objects embedded in extended " /* Parse the queued extended stream property objects and add the info
"stream properties", g_slist_length (demux->ext_stream_props)); * to the existing streams or add the new embedded streams, but without
* activating them yet */
GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
g_slist_length (demux->ext_stream_props));
for (l = demux->ext_stream_props; l != NULL; l = l->next) { for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
asf_obj_ext_stream_properties *esp; GstBuffer *buf = GST_BUFFER (l->data);
gboolean is_hidden = FALSE;
guint8 *mes, i;
esp = (asf_obj_ext_stream_properties *) l->data; GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
gst_buffer_unref (buf);
}
g_slist_free (demux->ext_stream_props);
demux->ext_stream_props = NULL;
}
GST_DEBUG ("Parsing queued extended stream with ID %d", esp->stream_num); static void
gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
{
guint i, j;
for (i = 0; i < demux->num_streams; ++i) {
AsfStream *stream;
gboolean is_hidden;
GSList *x;
stream = &demux->stream[i];
GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
if (stream->active) {
GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
continue;
}
is_hidden = FALSE;
for (x = demux->mut_ex_streams; x != NULL; x = x->next) { for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
guint8 *mes;
/* check for each mutual exclusion whether it affects this stream */ /* check for each mutual exclusion whether it affects this stream */
for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) { for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
if (*mes == esp->stream_num) { if (*mes == stream->id) {
/* if yes, check if we've already added streams that are mutually /* if yes, check if we've already added streams that are mutually
* exclusive with the stream we're about to add */ * exclusive with the stream we're about to add */
for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) { for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
for (i = 0; i < demux->num_streams; ++i) { for (j = 0; j < demux->num_streams; ++j) {
/* if the broadcast flag is set, assume the hidden streams aren't /* if the broadcast flag is set, assume the hidden streams aren't
* actually streamed and hide them (or playbin won't work right), * actually streamed and hide them (or playbin won't work right),
* otherwise assume their data is available */ * otherwise assume their data is available */
if (demux->stream[i].id == *mes && demux->broadcast) { if (demux->stream[j].id == *mes && demux->broadcast) {
is_hidden = TRUE; is_hidden = TRUE;
GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is " GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
"mutually exclusive with already existing stream ID %d, " "mutually exclusive with already existing stream ID %d, "
"hiding stream", esp->stream_num, demux->stream[i].id); "hiding stream", stream->id, demux->stream[j].id);
break; goto next;
} }
} }
} }
@ -2532,23 +2571,11 @@ gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
} }
} }
if (!is_hidden && esp->stream_obj_data != NULL) { next:
guint64 len;
guint8 *data;
data = esp->stream_obj_data; /* FIXME: we should do stream activation based on preroll data */
len = esp->stream_obj_len; if (!is_hidden)
gst_asf_demux_activate_stream (demux, stream);
if (gst_asf_demux_process_stream (demux, data, len) != GST_FLOW_OK) {
GST_WARNING_OBJECT (demux,
"failed to parse stream object in extended "
"stream properties object for stream %u", esp->stream_num);
}
}
g_free (esp->stream_obj_data);
esp->stream_obj_data = NULL;
esp->stream_obj_data = 0;
} }
} }
@ -2576,9 +2603,16 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size); GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
switch (obj.id) { switch (obj.id) {
case ASF_OBJ_STREAM: case ASF_OBJ_STREAM:{
ret = gst_asf_demux_process_stream (demux, *p_data, obj_data_size); AsfStream *stream;
stream =
gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
if (stream)
gst_asf_demux_activate_stream (demux, stream);
ret = GST_FLOW_OK;
break; break;
}
case ASF_OBJ_FILE: case ASF_OBJ_FILE:
ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size); ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
break; break;
@ -2601,11 +2635,18 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
gst_asf_demux_process_ext_content_desc (demux, *p_data, gst_asf_demux_process_ext_content_desc (demux, *p_data,
obj_data_size); obj_data_size);
break; break;
case ASF_OBJ_EXTENDED_STREAM_PROPS: case ASF_OBJ_EXTENDED_STREAM_PROPS:{
ret = GstBuffer *buf;
gst_asf_demux_process_ext_stream_props (demux, *p_data,
obj_data_size); /* process these later, we might not have parsed the corresponding
* stream object yet */
GST_LOG ("%s: queued for later parsing", demux->objpath);
buf = gst_buffer_new_and_alloc (obj_data_size);
memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
ret = GST_FLOW_OK;
break; break;
}
case ASF_OBJ_LANGUAGE_LIST: case ASF_OBJ_LANGUAGE_LIST:
ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size); ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
break; break;

View file

@ -24,6 +24,8 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h> #include <gst/base/gstadapter.h>
#include "asfheaders.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_TYPE_ASF_DEMUX \ #define GST_TYPE_ASF_DEMUX \
@ -45,6 +47,31 @@ typedef struct _GstASFDemuxClass GstASFDemuxClass;
typedef struct typedef struct
{ {
gboolean valid; /* TRUE if structure is valid/filled */
GstClockTime start_time;
GstClockTime end_time;
GstClockTime avg_time_per_frame;
guint32 data_bitrate;
guint32 buffer_size;
guint32 intial_buf_fullness;
guint32 data_bitrate2;
guint32 buffer_size2;
guint32 intial_buf_fullness2;
guint32 max_obj_size;
guint32 flags;
guint16 lang_idx;
/* missing: stream names */
/* missing: payload extension system stuff */
} AsfStreamExtProps;
typedef struct
{
AsfStreamType type;
gboolean active; /* if the stream has been activated (pad added) */
GstPad *pad; GstPad *pad;
guint16 id; guint16 id;
guint32 frag_offset; guint32 frag_offset;
@ -70,6 +97,9 @@ typedef struct
GstFlowReturn last_flow; /* last flow return */ GstFlowReturn last_flow; /* last flow return */
GArray *payloads; /* pending payloads */ GArray *payloads; /* pending payloads */
/* extended stream properties (optional) */
AsfStreamExtProps ext_props;
} AsfStream; } AsfStream;
typedef enum { typedef enum {
@ -103,8 +133,8 @@ struct _GstASFDemux {
gchar **languages; gchar **languages;
guint num_languages; guint num_languages;
GSList *ext_stream_props; GSList *ext_stream_props; /* for delayed processing (buffers) */
GSList *mut_ex_streams; /* mutually exclusive streams */ GSList *mut_ex_streams; /* mutually exclusive streams */
guint32 num_audio_streams; guint32 num_audio_streams;
guint32 num_video_streams; guint32 num_video_streams;