From b46ece69808d1ab3cc7c3a8a828825b782874e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 30 Apr 2007 15:36:00 +0000 Subject: [PATCH] gst/asfdemux/: Implement payload extension system/extended replicated data parsing, so we can extract payload duratio... Original commit message from CVS: * gst/asfdemux/asfheaders.c: * gst/asfdemux/asfheaders.h: * gst/asfdemux/asfpacket.c: (asf_payload_parse_replicated_data_extensions), (gst_asf_demux_parse_payload): * gst/asfdemux/asfpacket.h: * gst/asfdemux/gstasfdemux.c: (gst_asf_demux_free_stream), (gst_asf_demux_push_complete_payloads), (gst_asf_demux_process_ext_stream_props): * gst/asfdemux/gstasfdemux.h: Implement payload extension system/extended replicated data parsing, so we can extract payload durations if they're specified. --- ChangeLog | 15 ++++++++++ gst/asfdemux/asfheaders.c | 9 ++++++ gst/asfdemux/asfheaders.h | 7 +++++ gst/asfdemux/asfpacket.c | 56 ++++++++++++++++++++++++++++++++------ gst/asfdemux/asfpacket.h | 3 +- gst/asfdemux/gstasfdemux.c | 40 +++++++++++++++++++++++---- gst/asfdemux/gstasfdemux.h | 11 +++++++- 7 files changed, 124 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d335ad1d1..d47a909bc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2007-04-30 Tim-Philipp Müller + + * gst/asfdemux/asfheaders.c: + * gst/asfdemux/asfheaders.h: + * gst/asfdemux/asfpacket.c: + (asf_payload_parse_replicated_data_extensions), + (gst_asf_demux_parse_payload): + * gst/asfdemux/asfpacket.h: + * gst/asfdemux/gstasfdemux.c: (gst_asf_demux_free_stream), + (gst_asf_demux_push_complete_payloads), + (gst_asf_demux_process_ext_stream_props): + * gst/asfdemux/gstasfdemux.h: + Implement payload extension system/extended replicated data parsing, + so we can extract payload durations if they're specified. + 2007-04-30 Tim-Philipp Müller * gst/asfdemux/asfheaders.h: diff --git a/gst/asfdemux/asfheaders.c b/gst/asfdemux/asfheaders.c index 3752bc8c17..3815add522 100644 --- a/gst/asfdemux/asfheaders.c +++ b/gst/asfdemux/asfheaders.c @@ -21,6 +21,15 @@ #include "asfheaders.h" +const ASFGuidHash asf_payload_ext_guids[] = { + {ASF_PAYLOAD_EXTENSION_DURATION, "ASF_PAYLOAD_EXTENSION_DURATION", + {0xC6BD9450, 0x4907867F, 0x79C7A383, 0xAD33B721} + }, + {ASF_PAYLOAD_EXTENSION_UNDEFINED, "ASF_PAYLOAD_EXTENSION_UNDEFINED", + {0, 0, 0, 0} + } +}; + const ASFGuidHash asf_correction_guids[] = { {ASF_CORRECTION_ON, "ASF_CORRECTION_ON", {0xBFC3CD50, 0x11CF618F, 0xAA00B28B, 0x20E2B400} diff --git a/gst/asfdemux/asfheaders.h b/gst/asfdemux/asfheaders.h index 94b2d0242e..a52ff6a337 100644 --- a/gst/asfdemux/asfheaders.h +++ b/gst/asfdemux/asfheaders.h @@ -82,6 +82,13 @@ typedef enum { ASF_CORRECTION_OFF } AsfCorrectionType; +typedef enum { + ASF_PAYLOAD_EXTENSION_UNDEFINED = 0, + ASF_PAYLOAD_EXTENSION_DURATION +} AsfPayloadExtensionID; + +extern const ASFGuidHash asf_payload_ext_guids[]; + extern const ASFGuidHash asf_correction_guids[]; extern const ASFGuidHash asf_stream_guids[]; diff --git a/gst/asfdemux/asfpacket.c b/gst/asfdemux/asfpacket.c index 31ad650a2d..ad2fb02e6e 100644 --- a/gst/asfdemux/asfpacket.c +++ b/gst/asfdemux/asfpacket.c @@ -114,6 +114,9 @@ asf_payload_find_previous_fragment (AsfPayload * payload, AsfStream * stream) return ret; } +/* TODO: if we have another payload already queued for this stream and that + * payload doesn't have a duration, maybe we can calculate a duration for it + * (if the previous timestamp is smaller etc. etc.) */ static void gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload, AsfStream * stream) @@ -142,6 +145,38 @@ gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload, g_array_append_vals (stream->payloads, payload, 1); } +static void +asf_payload_parse_replicated_data_extensions (AsfStream * stream, + AsfPayload * payload) +{ + AsfPayloadExtension *ext; + guint off; + + 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 (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 (ext->len == 2) { + payload->duration = + GST_READ_UINT16_LE (payload->rep_data + off) * GST_MSECOND; + } else { + GST_WARNING ("unexpected DURATION extensions len %u", ext->len); + } + break; + default: + break; + } + off += ext->len; + } +} + static gboolean gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, gint lentype, const guint8 ** p_data, guint * p_size) @@ -163,6 +198,9 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, *p_data += 1; *p_size -= 1; + payload.ts = GST_CLOCK_TIME_NONE; + payload.duration = GST_CLOCK_TIME_NONE; + payload.mo_number = asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size); payload.mo_offset = @@ -218,19 +256,19 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, } if (!is_compressed) { - GstClockTime ts = GST_CLOCK_TIME_NONE; - GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len); if (payload.rep_data_len >= 8) { payload.mo_size = GST_READ_UINT32_LE (payload.rep_data); - ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND; - ts -= demux->preroll * GST_MSECOND; + payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND; + payload.ts -= demux->preroll * GST_MSECOND; + asf_payload_parse_replicated_data_extensions (stream, &payload); GST_LOG_OBJECT (demux, "media object size : %u", payload.mo_size); GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT, - GST_TIME_ARGS (ts)); - /* TODO: parse payload extensions, if there are any */ + GST_TIME_ARGS (payload.ts)); + GST_LOG_OBJECT (demux, "media object dur : %" GST_TIME_FORMAT, + GST_TIME_ARGS (payload.duration)); } else if (payload.rep_data_len != 0) { GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad"); } @@ -260,7 +298,6 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, } payload.buf = NULL; } else { - GST_BUFFER_TIMESTAMP (payload.buf) = ts; gst_asf_payload_queue_for_stream (demux, &payload, stream); } } @@ -298,8 +335,9 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, payload.buf = asf_packet_create_payload_buffer (packet, &payload_data, &payload_len, sub_payload_len); - GST_BUFFER_TIMESTAMP (payload.buf) = ts; - GST_BUFFER_DURATION (payload.buf) = ts_delta; + payload.ts = ts; + payload.duration = ts_delta; + gst_asf_payload_queue_for_stream (demux, &payload, stream); ts += ts_delta; diff --git a/gst/asfdemux/asfpacket.h b/gst/asfdemux/asfpacket.h index a42c60d2b4..1ca3e6604a 100644 --- a/gst/asfdemux/asfpacket.h +++ b/gst/asfdemux/asfpacket.h @@ -34,7 +34,8 @@ typedef struct { guint mo_size; /* size of media-object-to-be, or 0 */ guint rep_data_len; /* should never be more than 256, since */ guint8 rep_data[256]; /* the length should be stored in a byte */ - /* GstClockTime duration; */ /* TODO:get from payload extension system */ + GstClockTime ts; + GstClockTime duration; /* is not always available */ GstBuffer *buf; } AsfPayload; diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c index 919c867047..494d6a24d6 100644 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -161,6 +161,14 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream) gst_object_unref (stream->pad); stream->pad = NULL; } + if (stream->payloads) { + g_array_free (stream->payloads, TRUE); + stream->payloads = NULL; + } + if (stream->ext_props.valid) { + g_free (stream->ext_props.payload_extensions); + stream->ext_props.payload_extensions = NULL; + } } static void @@ -972,6 +980,9 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux) gst_buffer_set_caps (payload->buf, stream->caps); + GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts; + GST_BUFFER_DURATION (payload->buf) = payload->duration; + /* FIXME: we should really set durations on buffers if we can */ /* (this is a hack, obviously) if (strncmp (GST_PAD_NAME (stream->pad), "video", 5) == 0 && @@ -981,7 +992,9 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux) */ GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT - ", size=%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)), + ", dur=%" GST_TIME_FORMAT " size=%u", + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)), GST_BUFFER_SIZE (payload->buf)); stream->last_flow = gst_pad_push (stream->pad, payload->buf); @@ -2329,7 +2342,7 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, AsfStream *stream = NULL; AsfObject stream_obj; guint16 stream_name_count; - guint16 payload_ext_sys_count; + guint16 num_payload_ext; guint64 len; guint8 *stream_obj_data = NULL; guint8 *data_start = data; @@ -2354,7 +2367,7 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, esp.lang_idx = gst_asf_demux_get_uint16 (&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); - payload_ext_sys_count = gst_asf_demux_get_uint16 (&data, &size); + num_payload_ext = gst_asf_demux_get_uint16 (&data, &size); GST_INFO ("start_time = %" GST_TIME_FORMAT, GST_TIME_ARGS (esp.start_time)); @@ -2384,16 +2397,31 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, } /* read payload extension systems stuff */ - GST_LOG ("payload ext sys count = %u", payload_ext_sys_count); - for (i = 0; i < payload_ext_sys_count; ++i) { + GST_LOG ("payload extension systems count = %u", num_payload_ext); + + if (num_payload_ext > 0) + esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1); + else + esp.payload_extensions = NULL; + + for (i = 0; i < num_payload_ext; ++i) { + AsfPayloadExtension ext; + ASFGuid ext_guid; guint32 sys_info_len; - if (!gst_asf_demux_skip_bytes (16 + 2, &data, &size) || size < 4) + if (size < 16 + 2 + 4) goto not_enough_data; + + gst_asf_demux_get_guid (&ext_guid, &data, &size); + ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid); + ext.len = gst_asf_demux_get_uint16 (&data, &size); + sys_info_len = gst_asf_demux_get_uint32 (&data, &size); GST_LOG ("payload systems info len = %u", sys_info_len); if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size)) goto not_enough_data; + + esp.payload_extensions[i] = ext; } GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size); diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h index 8a92341de3..b7724fa300 100644 --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -45,6 +45,12 @@ GST_DEBUG_CATEGORY_EXTERN (asfdemux_dbg); typedef struct _GstASFDemux GstASFDemux; typedef struct _GstASFDemuxClass GstASFDemuxClass; +typedef struct { + AsfPayloadExtensionID id : 16; /* extension ID; the :16 makes sure the + * struct gets packed into 4 bytes */ + guint16 len; /* save this so we can skip unknown IDs */ +} AsfPayloadExtension; + typedef struct { gboolean valid; /* TRUE if structure is valid/filled */ @@ -62,8 +68,11 @@ typedef struct guint32 flags; guint16 lang_idx; + /* may be NULL if there are no extensions; otherwise, terminated by + * an AsfPayloadExtension record with len 0 */ + AsfPayloadExtension *payload_extensions; + /* missing: stream names */ - /* missing: payload extension system stuff */ } AsfStreamExtProps; typedef struct