mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +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>
|
2007-04-30 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* gst/asfdemux/asfheaders.h:
|
* gst/asfdemux/asfheaders.h:
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
|
|
||||||
#include "asfheaders.h"
|
#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[] = {
|
const ASFGuidHash asf_correction_guids[] = {
|
||||||
{ASF_CORRECTION_ON, "ASF_CORRECTION_ON",
|
{ASF_CORRECTION_ON, "ASF_CORRECTION_ON",
|
||||||
{0xBFC3CD50, 0x11CF618F, 0xAA00B28B, 0x20E2B400}
|
{0xBFC3CD50, 0x11CF618F, 0xAA00B28B, 0x20E2B400}
|
||||||
|
|
|
@ -82,6 +82,13 @@ typedef enum {
|
||||||
ASF_CORRECTION_OFF
|
ASF_CORRECTION_OFF
|
||||||
} AsfCorrectionType;
|
} 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_correction_guids[];
|
||||||
|
|
||||||
extern const ASFGuidHash asf_stream_guids[];
|
extern const ASFGuidHash asf_stream_guids[];
|
||||||
|
|
|
@ -114,6 +114,9 @@ asf_payload_find_previous_fragment (AsfPayload * payload, AsfStream * stream)
|
||||||
return ret;
|
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
|
static void
|
||||||
gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
|
gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
|
||||||
AsfStream * stream)
|
AsfStream * stream)
|
||||||
|
@ -142,6 +145,38 @@ gst_asf_payload_queue_for_stream (GstASFDemux * demux, AsfPayload * payload,
|
||||||
g_array_append_vals (stream->payloads, payload, 1);
|
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
|
static gboolean
|
||||||
gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet,
|
gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet,
|
||||||
gint lentype, const guint8 ** p_data, guint * p_size)
|
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_data += 1;
|
||||||
*p_size -= 1;
|
*p_size -= 1;
|
||||||
|
|
||||||
|
payload.ts = GST_CLOCK_TIME_NONE;
|
||||||
|
payload.duration = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
payload.mo_number =
|
payload.mo_number =
|
||||||
asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size);
|
asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size);
|
||||||
payload.mo_offset =
|
payload.mo_offset =
|
||||||
|
@ -218,19 +256,19 @@ gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_compressed) {
|
if (!is_compressed) {
|
||||||
GstClockTime ts = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len);
|
GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len);
|
||||||
|
|
||||||
if (payload.rep_data_len >= 8) {
|
if (payload.rep_data_len >= 8) {
|
||||||
payload.mo_size = GST_READ_UINT32_LE (payload.rep_data);
|
payload.mo_size = GST_READ_UINT32_LE (payload.rep_data);
|
||||||
ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND;
|
payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND;
|
||||||
ts -= demux->preroll * 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 size : %u", payload.mo_size);
|
||||||
GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT,
|
GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (ts));
|
GST_TIME_ARGS (payload.ts));
|
||||||
/* TODO: parse payload extensions, if there are any */
|
GST_LOG_OBJECT (demux, "media object dur : %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (payload.duration));
|
||||||
} else if (payload.rep_data_len != 0) {
|
} else if (payload.rep_data_len != 0) {
|
||||||
GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad");
|
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;
|
payload.buf = NULL;
|
||||||
} else {
|
} else {
|
||||||
GST_BUFFER_TIMESTAMP (payload.buf) = ts;
|
|
||||||
gst_asf_payload_queue_for_stream (demux, &payload, stream);
|
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.buf = asf_packet_create_payload_buffer (packet,
|
||||||
&payload_data, &payload_len, sub_payload_len);
|
&payload_data, &payload_len, sub_payload_len);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (payload.buf) = ts;
|
payload.ts = ts;
|
||||||
GST_BUFFER_DURATION (payload.buf) = ts_delta;
|
payload.duration = ts_delta;
|
||||||
|
|
||||||
gst_asf_payload_queue_for_stream (demux, &payload, stream);
|
gst_asf_payload_queue_for_stream (demux, &payload, stream);
|
||||||
|
|
||||||
ts += ts_delta;
|
ts += ts_delta;
|
||||||
|
|
|
@ -34,7 +34,8 @@ typedef struct {
|
||||||
guint mo_size; /* size of media-object-to-be, or 0 */
|
guint mo_size; /* size of media-object-to-be, or 0 */
|
||||||
guint rep_data_len; /* should never be more than 256, since */
|
guint rep_data_len; /* should never be more than 256, since */
|
||||||
guint8 rep_data[256]; /* the length should be stored in a byte */
|
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;
|
GstBuffer *buf;
|
||||||
} AsfPayload;
|
} AsfPayload;
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,14 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
|
||||||
gst_object_unref (stream->pad);
|
gst_object_unref (stream->pad);
|
||||||
stream->pad = NULL;
|
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
|
static void
|
||||||
|
@ -972,6 +980,9 @@ gst_asf_demux_push_complete_payloads (GstASFDemux * demux)
|
||||||
|
|
||||||
gst_buffer_set_caps (payload->buf, stream->caps);
|
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 */
|
/* FIXME: we should really set durations on buffers if we can */
|
||||||
/* (this is a hack, obviously)
|
/* (this is a hack, obviously)
|
||||||
if (strncmp (GST_PAD_NAME (stream->pad), "video", 5) == 0 &&
|
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
|
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));
|
GST_BUFFER_SIZE (payload->buf));
|
||||||
|
|
||||||
stream->last_flow = gst_pad_push (stream->pad, 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;
|
AsfStream *stream = NULL;
|
||||||
AsfObject stream_obj;
|
AsfObject stream_obj;
|
||||||
guint16 stream_name_count;
|
guint16 stream_name_count;
|
||||||
guint16 payload_ext_sys_count;
|
guint16 num_payload_ext;
|
||||||
guint64 len;
|
guint64 len;
|
||||||
guint8 *stream_obj_data = NULL;
|
guint8 *stream_obj_data = NULL;
|
||||||
guint8 *data_start = data;
|
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.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
|
||||||
esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size) * 100;
|
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);
|
num_payload_ext = 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_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 */
|
/* read payload extension systems stuff */
|
||||||
GST_LOG ("payload ext sys count = %u", payload_ext_sys_count);
|
GST_LOG ("payload extension systems count = %u", num_payload_ext);
|
||||||
for (i = 0; i < payload_ext_sys_count; ++i) {
|
|
||||||
|
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;
|
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;
|
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);
|
sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
|
||||||
GST_LOG ("payload systems info len = %u", sys_info_len);
|
GST_LOG ("payload systems info len = %u", sys_info_len);
|
||||||
if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
|
if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
|
||||||
goto not_enough_data;
|
goto not_enough_data;
|
||||||
|
|
||||||
|
esp.payload_extensions[i] = ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
|
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 _GstASFDemux GstASFDemux;
|
||||||
typedef struct _GstASFDemuxClass GstASFDemuxClass;
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
gboolean valid; /* TRUE if structure is valid/filled */
|
gboolean valid; /* TRUE if structure is valid/filled */
|
||||||
|
@ -62,8 +68,11 @@ typedef struct
|
||||||
guint32 flags;
|
guint32 flags;
|
||||||
guint16 lang_idx;
|
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: stream names */
|
||||||
/* missing: payload extension system stuff */
|
|
||||||
} AsfStreamExtProps;
|
} AsfStreamExtProps;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
Loading…
Reference in a new issue