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.
This commit is contained in:
Tim-Philipp Müller 2007-04-30 15:36:00 +00:00
parent 850c0fbab8
commit b46ece6980
7 changed files with 124 additions and 17 deletions

View file

@ -1,3 +1,18 @@
2007-04-30 Tim-Philipp Müller <tim at centricular dot net>
* 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 <tim at centricular dot net>
* gst/asfdemux/asfheaders.h:

View file

@ -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}

View file

@ -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[];

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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