mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
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:
parent
850c0fbab8
commit
b46ece6980
7 changed files with 124 additions and 17 deletions
15
ChangeLog
15
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue