mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 23:06:49 +00:00
gst/realmedia/rmdemux.c: Do fragment collection in the demuxer so that we can now work with both ffmpeg and realvideo...
Original commit message from CVS: * gst/realmedia/rmdemux.c: (gst_rmdemux_reset), (gst_rmdemux_chain), (gst_rmdemux_parse_mdpr), (gst_rmdemux_fix_timestamp), (gst_rmdemux_parse_video_packet), (gst_rmdemux_parse_audio_packet), (gst_rmdemux_parse_packet): Do fragment collection in the demuxer so that we can now work with both ffmpeg and realvideodec to decoder real video content.
This commit is contained in:
parent
eeb7697ba2
commit
38dd0ad82b
2 changed files with 446 additions and 69 deletions
|
@ -1,3 +1,12 @@
|
|||
2007-08-07 Wim Taymans <wim.taymans@gmail.com>
|
||||
|
||||
* gst/realmedia/rmdemux.c: (gst_rmdemux_reset),
|
||||
(gst_rmdemux_chain), (gst_rmdemux_parse_mdpr),
|
||||
(gst_rmdemux_fix_timestamp), (gst_rmdemux_parse_video_packet),
|
||||
(gst_rmdemux_parse_audio_packet), (gst_rmdemux_parse_packet):
|
||||
Do fragment collection in the demuxer so that we can now work with
|
||||
both ffmpeg and realvideodec to decoder real video content.
|
||||
|
||||
2007-08-04 Stefan Kost <ensonic@users.sf.net>
|
||||
|
||||
* gst/realmedia/asmrules.c:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (C) <2005> Michael Smith <fluendo.com>
|
||||
* Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
|
||||
* Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -43,6 +44,8 @@
|
|||
#define HEADER_SIZE 10
|
||||
#define DATA_SIZE 8
|
||||
|
||||
#define MAX_FRAGS 256
|
||||
|
||||
typedef struct _GstRMDemuxIndex GstRMDemuxIndex;
|
||||
|
||||
struct _GstRMDemuxStream
|
||||
|
@ -80,6 +83,14 @@ struct _GstRMDemuxStream
|
|||
guint subpackets_needed; /* subpackets needed for descrambling */
|
||||
GPtrArray *subpackets; /* array containing subpacket GstBuffers */
|
||||
|
||||
gint frag_seqnum;
|
||||
gint frag_subseq;
|
||||
guint frag_length;
|
||||
guint frag_current;
|
||||
guint frag_count;
|
||||
guint frag_offset[MAX_FRAGS];
|
||||
GstAdapter *adapter;
|
||||
|
||||
GstTagList *pending_tags;
|
||||
};
|
||||
|
||||
|
@ -154,7 +165,7 @@ static void gst_rmdemux_parse_data (GstRMDemux * rmdemux, const guint8 * data,
|
|||
static void gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const guint8 * data,
|
||||
int length);
|
||||
static GstFlowReturn gst_rmdemux_parse_packet (GstRMDemux * rmdemux,
|
||||
const guint8 * data, guint16 version, guint16 length);
|
||||
GstBuffer * in, guint16 version);
|
||||
static void gst_rmdemux_parse_indx_data (GstRMDemux * rmdemux,
|
||||
const guint8 * data, int length);
|
||||
static void gst_rmdemux_stream_clear_cached_subpackets (GstRMDemux * rmdemux,
|
||||
|
@ -681,6 +692,7 @@ gst_rmdemux_reset (GstRMDemux * rmdemux)
|
|||
for (cur = rmdemux->streams; cur; cur = cur->next) {
|
||||
GstRMDemuxStream *stream = cur->data;
|
||||
|
||||
g_object_unref (stream->adapter);
|
||||
gst_rmdemux_stream_clear_cached_subpackets (rmdemux, stream);
|
||||
gst_element_remove_pad (GST_ELEMENT (rmdemux), stream->pad);
|
||||
if (stream->pending_tags)
|
||||
|
@ -951,16 +963,19 @@ gst_rmdemux_chain (GstPad * pad, GstBuffer * buffer)
|
|||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
const guint8 *data;
|
||||
guint16 version;
|
||||
guint avail;
|
||||
|
||||
GstRMDemux *rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
|
||||
|
||||
gst_adapter_push (rmdemux->adapter, buffer);
|
||||
|
||||
GST_LOG_OBJECT (rmdemux, "Chaining buffer of size %d",
|
||||
GST_BUFFER_SIZE (buffer));
|
||||
|
||||
gst_adapter_push (rmdemux->adapter, buffer);
|
||||
|
||||
while (TRUE) {
|
||||
GST_LOG_OBJECT (rmdemux, "looping in chain");
|
||||
avail = gst_adapter_available (rmdemux->adapter);
|
||||
|
||||
GST_LOG_OBJECT (rmdemux, "looping in chain, avail %u", avail);
|
||||
switch (rmdemux->state) {
|
||||
case RMDEMUX_STATE_HEADER:
|
||||
{
|
||||
|
@ -1155,20 +1170,30 @@ gst_rmdemux_chain (GstPad * pad, GstBuffer * buffer)
|
|||
data = gst_adapter_peek (rmdemux->adapter, 4);
|
||||
|
||||
length = RMDEMUX_GUINT16_GET (data + 2);
|
||||
GST_LOG_OBJECT (rmdemux, "Got length %d", length);
|
||||
|
||||
if (length < 4) {
|
||||
GST_LOG_OBJECT (rmdemux, "length too small, dropping");
|
||||
/* Invalid, just drop it */
|
||||
gst_adapter_flush (rmdemux->adapter, 4);
|
||||
} else {
|
||||
if (gst_adapter_available (rmdemux->adapter) < length)
|
||||
GstBuffer *buffer;
|
||||
|
||||
avail = gst_adapter_available (rmdemux->adapter);
|
||||
if (avail < length)
|
||||
goto unlock;
|
||||
data = gst_adapter_peek (rmdemux->adapter, length);
|
||||
|
||||
ret =
|
||||
gst_rmdemux_parse_packet (rmdemux, data + 4, version,
|
||||
length - 4);
|
||||
GST_LOG_OBJECT (rmdemux, "we have %u available and we needed %d",
|
||||
avail, length);
|
||||
|
||||
/* flush version and length */
|
||||
gst_adapter_flush (rmdemux->adapter, 4);
|
||||
length -= 4;
|
||||
|
||||
buffer = gst_adapter_take_buffer (rmdemux->adapter, length);
|
||||
|
||||
ret = gst_rmdemux_parse_packet (rmdemux, buffer, version);
|
||||
rmdemux->chunk_index++;
|
||||
|
||||
gst_adapter_flush (rmdemux->adapter, length);
|
||||
}
|
||||
|
||||
if (rmdemux->chunk_index == rmdemux->n_chunks || length == 0)
|
||||
|
@ -1509,14 +1534,13 @@ gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux, const guint8 * data, int length)
|
|||
int stream_type;
|
||||
int offset;
|
||||
|
||||
/* re_hexdump_bytes ((guint8 *) data, length, 0); */
|
||||
|
||||
stream = g_new0 (GstRMDemuxStream, 1);
|
||||
|
||||
stream->id = RMDEMUX_GUINT16_GET (data);
|
||||
stream->index = NULL;
|
||||
stream->seek_offset = 0;
|
||||
stream->last_flow = GST_FLOW_OK;
|
||||
stream->adapter = gst_adapter_new ();
|
||||
GST_LOG_OBJECT (rmdemux, "stream_number=%d", stream->id);
|
||||
|
||||
offset = 30;
|
||||
|
@ -1579,8 +1603,8 @@ gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux, const guint8 * data, int length)
|
|||
stream->rate = RMDEMUX_GUINT16_GET (data + offset + 16);
|
||||
stream->subformat = RMDEMUX_GUINT32_GET (data + offset + 26);
|
||||
stream->format = RMDEMUX_GUINT32_GET (data + offset + 30);
|
||||
stream->extra_data_size = length - (offset + 34);
|
||||
stream->extra_data = (guint8 *) data + offset + 34;
|
||||
stream->extra_data_size = length - (offset + 26);
|
||||
stream->extra_data = (guint8 *) data + offset + 26;
|
||||
/* Natural way to represent framerates here requires unsigned 32 bit
|
||||
* numerator, which we don't have. For the nasty case, approximate...
|
||||
*/
|
||||
|
@ -1949,48 +1973,383 @@ gst_rmdemux_handle_scrambled_packet (GstRMDemux * rmdemux,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static GstClockTime
|
||||
gst_rmdemux_fix_timestamp (GstRMDemux * rmdemux, GstClockTime timestamp)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
const guint8 *b;
|
||||
guint8 frame_type;
|
||||
guint16 seq;
|
||||
GstClockTime ts = timestamp;
|
||||
|
||||
GST_LOG_OBJECT (rmdemux, "timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
|
||||
|
||||
/* Fix timestamp. */
|
||||
b = gst_adapter_peek (dec->adapter, 4);
|
||||
switch (dec->version) {
|
||||
case GST_REAL_VIDEO_DEC_VERSION_2:
|
||||
{
|
||||
|
||||
/*
|
||||
* Bit 1- 2: frame type
|
||||
* Bit 3- 9: ?
|
||||
* Bit 10-22: sequence number
|
||||
* Bit 23-32: ?
|
||||
*/
|
||||
frame_type = (b[0] >> 6) & 0x03;
|
||||
seq = ((b[1] & 0x7f) << 6) + ((b[2] & 0xfc) >> 2);
|
||||
break;
|
||||
}
|
||||
case GST_REAL_VIDEO_DEC_VERSION_3:
|
||||
{
|
||||
/*
|
||||
* Bit 1- 2: ?
|
||||
* Bit 3: skip packet if 1
|
||||
* Bit 4- 5: frame type
|
||||
* Bit 6-12: ?
|
||||
* Bit 13-25: sequence number
|
||||
* Bit 26-32: ?
|
||||
*/
|
||||
frame_type = (b[0] >> 3) & 0x03;
|
||||
seq = ((b[1] & 0x0f) << 9) + (b[2] << 1) + ((b[3] & 0x80) >> 7);
|
||||
break;
|
||||
}
|
||||
case GST_REAL_VIDEO_DEC_VERSION_4:
|
||||
{
|
||||
/*
|
||||
* Bit 1: skip packet if 1
|
||||
* Bit 2- 3: frame type
|
||||
* Bit 4-13: ?
|
||||
* Bit 14-26: sequence number
|
||||
* Bit 27-32: ?
|
||||
*/
|
||||
frame_type = (b[0] >> 5) & 0x03;
|
||||
seq = ((b[1] & 0x07) << 10) + (b[2] << 2) + ((b[3] & 0xc0) >> 6);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown_version;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (dec, "frame_type:%d", frame_type);
|
||||
|
||||
switch (frame_type) {
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
/* I frame */
|
||||
timestamp = dec->next_ts;
|
||||
dec->last_ts = dec->next_ts;
|
||||
dec->next_ts = ts;
|
||||
dec->last_seq = dec->next_seq;
|
||||
dec->next_seq = seq;
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
/* P frame */
|
||||
timestamp = dec->last_ts = dec->next_ts;
|
||||
if (seq < dec->next_seq)
|
||||
dec->next_ts += (seq + 0x2000 - dec->next_seq) * GST_MSECOND;
|
||||
else
|
||||
dec->next_ts += (seq - dec->next_seq) * GST_MSECOND;
|
||||
dec->last_seq = dec->next_seq;
|
||||
dec->next_seq = seq;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
/* B frame */
|
||||
if (seq < dec->last_seq) {
|
||||
timestamp = (seq + 0x2000 - dec->last_seq) * GST_MSECOND + dec->last_ts;
|
||||
} else {
|
||||
timestamp = (seq - dec->last_seq) * GST_MSECOND + dec->last_ts;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown_frame_type;
|
||||
}
|
||||
/* Errors */
|
||||
unknown_version:
|
||||
{
|
||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE,
|
||||
("Unknown version: %i.", dec->version), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
unknown_frame_type:
|
||||
{
|
||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Unknown frame type."), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PARSE_NUMBER(data, size, number, label) \
|
||||
G_STMT_START { \
|
||||
if (size < 2) \
|
||||
goto label; \
|
||||
number = GST_READ_UINT16_BE (data); \
|
||||
if (!(number & 0xc000)) { \
|
||||
if (size < 4) \
|
||||
goto label; \
|
||||
number = GST_READ_UINT32_BE (data); \
|
||||
data += 4; \
|
||||
size -= 4; \
|
||||
} else { \
|
||||
number &= 0x3fff; \
|
||||
data += 2; \
|
||||
size -= 2; \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rmdemux_parse_packet (GstRMDemux * rmdemux, const guint8 * data,
|
||||
guint16 version, guint16 length)
|
||||
gst_rmdemux_parse_video_packet (GstRMDemux * rmdemux, GstRMDemuxStream * stream,
|
||||
GstBuffer * in, guint offset, guint16 version,
|
||||
GstClockTime timestamp, gboolean key)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
const guint8 *data, *base;
|
||||
guint size;
|
||||
|
||||
base = GST_BUFFER_DATA (in);
|
||||
data = base + offset;
|
||||
size = GST_BUFFER_SIZE (in) - offset;
|
||||
|
||||
while (size > 2) {
|
||||
guint8 pkg_header;
|
||||
guint pkg_offset;
|
||||
guint pkg_length;
|
||||
guint pkg_subseq = 0, pkg_seqnum = -1;
|
||||
guint fragment_size;
|
||||
GstBuffer *fragment;
|
||||
|
||||
pkg_header = *data++;
|
||||
size--;
|
||||
|
||||
/* packet header
|
||||
* bit 7: 1=last block in block chain
|
||||
* bit 6: 1=short header (only one block?)
|
||||
*/
|
||||
if ((pkg_header & 0xc0) == 0x40) {
|
||||
/* skip unknown byte */
|
||||
data++;
|
||||
size--;
|
||||
pkg_offset = 0;
|
||||
pkg_length = size;
|
||||
} else {
|
||||
if ((pkg_header & 0x40) == 0) {
|
||||
pkg_subseq = (*data++) & 0x7f;
|
||||
size--;
|
||||
} else {
|
||||
pkg_subseq = 0;
|
||||
}
|
||||
|
||||
/* length */
|
||||
PARSE_NUMBER (data, size, pkg_length, not_enough_data);
|
||||
|
||||
/* offset */
|
||||
PARSE_NUMBER (data, size, pkg_offset, not_enough_data);
|
||||
|
||||
/* seqnum */
|
||||
if (size < 1)
|
||||
goto not_enough_data;
|
||||
|
||||
pkg_seqnum = *data++;
|
||||
size--;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (rmdemux,
|
||||
"seq %d, subseq %d, offset %d, length %d, size %d, header %02x",
|
||||
pkg_seqnum, pkg_subseq, pkg_offset, pkg_length, size, pkg_header);
|
||||
|
||||
/* calc size of fragment */
|
||||
if ((pkg_header & 0xc0) == 0x80) {
|
||||
fragment_size = pkg_offset;
|
||||
} else {
|
||||
if ((pkg_header & 0xc0) == 0)
|
||||
fragment_size = size;
|
||||
else
|
||||
fragment_size = pkg_length;
|
||||
}
|
||||
GST_DEBUG_OBJECT (rmdemux, "fragment size %d", fragment_size);
|
||||
|
||||
/* get the fragment */
|
||||
fragment = gst_buffer_create_sub (in, data - base, fragment_size);
|
||||
|
||||
if (pkg_subseq == 1) {
|
||||
GST_DEBUG_OBJECT (rmdemux, "start new fragment");
|
||||
gst_adapter_clear (stream->adapter);
|
||||
stream->frag_current = 0;
|
||||
stream->frag_count = 0;
|
||||
stream->frag_length = pkg_length;
|
||||
} else if (pkg_subseq == 0) {
|
||||
GST_DEBUG_OBJECT (rmdemux, "non fragmented packet");
|
||||
stream->frag_current = 0;
|
||||
stream->frag_count = 0;
|
||||
stream->frag_length = fragment_size;
|
||||
}
|
||||
|
||||
/* put fragment in adapter */
|
||||
gst_adapter_push (stream->adapter, fragment);
|
||||
stream->frag_offset[stream->frag_count] = stream->frag_current;
|
||||
stream->frag_current += fragment_size;
|
||||
stream->frag_count++;
|
||||
|
||||
if (stream->frag_count > MAX_FRAGS)
|
||||
goto too_many_fragments;
|
||||
|
||||
GST_DEBUG_OBJECT (rmdemux, "stored fragment in adapter %d/%d",
|
||||
stream->frag_current, stream->frag_length);
|
||||
|
||||
/* flush fragment when complete */
|
||||
if (stream->frag_current >= stream->frag_length) {
|
||||
GstBuffer *out;
|
||||
guint8 *outdata;
|
||||
guint header_size;
|
||||
gint i;
|
||||
|
||||
/* calculate header size, which is:
|
||||
* 1 byte for the number of fragments - 1
|
||||
* for each fragment:
|
||||
* 4 bytes 0x00000001 little endian
|
||||
* 4 bytes fragment offset
|
||||
*
|
||||
* This is also the matroska header for realvideo, the decoder needs the
|
||||
* fragment offsets, both in ffmpeg and real .so, so we just give it that
|
||||
* in front of the data.
|
||||
*/
|
||||
header_size = 1 + (8 * (stream->frag_count));
|
||||
|
||||
GST_DEBUG_OBJECT (rmdemux,
|
||||
"fragmented completed. count %d, header_size %u", stream->frag_count,
|
||||
header_size);
|
||||
|
||||
out = gst_buffer_new_and_alloc (header_size + stream->frag_length);
|
||||
outdata = GST_BUFFER_DATA (out);
|
||||
|
||||
/* create header */
|
||||
*outdata++ = stream->frag_count - 1;
|
||||
for (i = 0; i < stream->frag_count; i++) {
|
||||
GST_WRITE_UINT32_LE (outdata, 0x00000001);
|
||||
outdata += 4;
|
||||
GST_WRITE_UINT32_LE (outdata, stream->frag_offset[i]);
|
||||
outdata += 4;
|
||||
}
|
||||
|
||||
/* copy packet data after the header now */
|
||||
gst_adapter_copy (stream->adapter, outdata, 0, stream->frag_length);
|
||||
gst_adapter_flush (stream->adapter, stream->frag_length);
|
||||
|
||||
gst_buffer_set_caps (out, GST_PAD_CAPS (stream->pad));
|
||||
GST_BUFFER_TIMESTAMP (out) = timestamp;
|
||||
|
||||
ret = gst_pad_push (stream->pad, out);
|
||||
}
|
||||
data += fragment_size;
|
||||
size -= fragment_size;
|
||||
}
|
||||
GST_DEBUG_OBJECT (rmdemux, "%d bytes left", size);
|
||||
|
||||
gst_buffer_unref (in);
|
||||
|
||||
ret = GST_FLOW_OK;
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
not_enough_data:
|
||||
{
|
||||
GST_ELEMENT_WARNING (rmdemux, STREAM, DECODE, ("Skipping bad packet."),
|
||||
(NULL));
|
||||
gst_buffer_unref (in);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
too_many_fragments:
|
||||
{
|
||||
GST_ELEMENT_ERROR (rmdemux, STREAM, DECODE,
|
||||
("Got more fragments (%u) than can be handled (%u)",
|
||||
stream->frag_count, MAX_FRAGS), (NULL));
|
||||
gst_buffer_unref (in);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rmdemux_parse_audio_packet (GstRMDemux * rmdemux, GstRMDemuxStream * stream,
|
||||
GstBuffer * in, guint offset, guint16 version,
|
||||
GstClockTime timestamp, gboolean key)
|
||||
{
|
||||
GstFlowReturn ret, cret;
|
||||
GstBuffer *buffer;
|
||||
const guint8 *data;
|
||||
guint size;
|
||||
|
||||
data = GST_BUFFER_DATA (in) + offset;
|
||||
size = GST_BUFFER_SIZE (in) - offset;
|
||||
|
||||
ret = gst_pad_alloc_buffer_and_set_caps (stream->pad,
|
||||
GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (stream->pad), &buffer);
|
||||
|
||||
cret = gst_rmdemux_combine_flows (rmdemux, stream, ret);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto alloc_failed;
|
||||
|
||||
memcpy (GST_BUFFER_DATA (buffer), (guint8 *) data, size);
|
||||
GST_BUFFER_TIMESTAMP (buffer) = timestamp - rmdemux->first_ts;
|
||||
|
||||
if (stream->needs_descrambling) {
|
||||
ret = gst_rmdemux_handle_scrambled_packet (rmdemux, stream, buffer, key);
|
||||
} else {
|
||||
GST_LOG_OBJECT (rmdemux, "Pushing buffer of size %d to pad %s",
|
||||
GST_BUFFER_SIZE (buffer), GST_PAD_NAME (stream->pad));
|
||||
|
||||
ret = gst_pad_push (stream->pad, buffer);
|
||||
}
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
alloc_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (rmdemux, "pad alloc returned %d", ret);
|
||||
return cret;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rmdemux_parse_packet (GstRMDemux * rmdemux, GstBuffer * in, guint16 version)
|
||||
{
|
||||
guint16 id;
|
||||
GstRMDemuxStream *stream;
|
||||
GstBuffer *buffer;
|
||||
guint16 packet_size;
|
||||
guint size;
|
||||
GstFlowReturn cret, ret;
|
||||
GstClockTime timestamp;
|
||||
gboolean key = FALSE;
|
||||
gboolean key;
|
||||
guint8 *data, *base;
|
||||
guint8 flags;
|
||||
|
||||
base = data = GST_BUFFER_DATA (in);
|
||||
size = GST_BUFFER_SIZE (in);
|
||||
|
||||
/* stream number */
|
||||
id = RMDEMUX_GUINT16_GET (data);
|
||||
|
||||
stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
|
||||
if (!stream || !stream->pad)
|
||||
goto unknown_stream;
|
||||
|
||||
/* timestamp in Msec */
|
||||
timestamp = RMDEMUX_GUINT32_GET (data + 2) * GST_MSECOND;
|
||||
|
||||
gst_segment_set_last_stop (&rmdemux->segment, GST_FORMAT_TIME, timestamp);
|
||||
|
||||
GST_LOG_OBJECT (rmdemux, "Parsing a packet for stream=%d, timestamp=%"
|
||||
GST_TIME_FORMAT ", version=%d", id, GST_TIME_ARGS (timestamp), version);
|
||||
|
||||
/* skip stream_id and timestamp */
|
||||
data += 2 + 4;
|
||||
packet_size = length - (2 + 4);
|
||||
|
||||
/* skip other stuff */
|
||||
if (version == 0) {
|
||||
/* uint8 packet_group */
|
||||
/* uint8 flags */
|
||||
key = ((GST_READ_UINT8 (data + 1) & 0x02) != 0);
|
||||
data += 2;
|
||||
packet_size -= 2;
|
||||
} else {
|
||||
/* uint16 asm_rule */
|
||||
/* uint8 asm_flags */
|
||||
data += 3;
|
||||
packet_size -= 3;
|
||||
}
|
||||
|
||||
stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
|
||||
if (!stream || !stream->pad)
|
||||
goto unknown_stream;
|
||||
GST_TIME_FORMAT ", size %u, version=%d", id, GST_TIME_ARGS (timestamp),
|
||||
size, version);
|
||||
|
||||
if (rmdemux->first_ts == GST_CLOCK_TIME_NONE) {
|
||||
GST_DEBUG_OBJECT (rmdemux, "First timestamp: %" GST_TIME_FORMAT,
|
||||
|
@ -1998,6 +2357,27 @@ gst_rmdemux_parse_packet (GstRMDemux * rmdemux, const guint8 * data,
|
|||
rmdemux->first_ts = timestamp;
|
||||
}
|
||||
|
||||
/* skip stream_id and timestamp */
|
||||
data += (2 + 4);
|
||||
size -= (2 + 4);
|
||||
|
||||
/* skip other stuff */
|
||||
if (version == 0) {
|
||||
/* uint8 packet_group */
|
||||
/* uint8 flags */
|
||||
flags = GST_READ_UINT8 (data + 1);
|
||||
data += 2;
|
||||
size -= 2;
|
||||
} else {
|
||||
/* uint16 asm_rule */
|
||||
/* uint8 asm_flags */
|
||||
flags = GST_READ_UINT8 (data + 2);
|
||||
data += 3;
|
||||
size -= 3;
|
||||
}
|
||||
key = (flags & 0x02) != 0;
|
||||
GST_DEBUG_OBJECT (rmdemux, "flags %d, Keyframe %d", flags, key);
|
||||
|
||||
if (rmdemux->need_newsegment) {
|
||||
GstEvent *event;
|
||||
|
||||
|
@ -2019,32 +2399,25 @@ gst_rmdemux_parse_packet (GstRMDemux * rmdemux, const guint8 * data,
|
|||
stream->pending_tags = NULL;
|
||||
}
|
||||
|
||||
if ((rmdemux->offset + packet_size) <= stream->seek_offset) {
|
||||
if ((rmdemux->offset + size) <= stream->seek_offset) {
|
||||
GST_DEBUG_OBJECT (rmdemux,
|
||||
"Stream %d is skipping: seek_offset=%d, offset=%d, packet_size=%u",
|
||||
stream->id, stream->seek_offset, rmdemux->offset, packet_size);
|
||||
"Stream %d is skipping: seek_offset=%d, offset=%d, size=%u",
|
||||
stream->id, stream->seek_offset, rmdemux->offset, size);
|
||||
cret = GST_FLOW_OK;
|
||||
goto beach;
|
||||
}
|
||||
|
||||
ret = gst_pad_alloc_buffer_and_set_caps (stream->pad,
|
||||
GST_BUFFER_OFFSET_NONE, packet_size, GST_PAD_CAPS (stream->pad), &buffer);
|
||||
|
||||
cret = gst_rmdemux_combine_flows (rmdemux, stream, ret);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto alloc_failed;
|
||||
|
||||
memcpy (GST_BUFFER_DATA (buffer), (guint8 *) data, packet_size);
|
||||
GST_BUFFER_TIMESTAMP (buffer) = timestamp - rmdemux->first_ts;
|
||||
|
||||
if (stream->needs_descrambling) {
|
||||
ret = gst_rmdemux_handle_scrambled_packet (rmdemux, stream, buffer, key);
|
||||
} else {
|
||||
GST_LOG_OBJECT (rmdemux, "Pushing buffer of size %d to pad %s",
|
||||
GST_BUFFER_SIZE (buffer), GST_PAD_NAME (stream->pad));
|
||||
|
||||
ret = gst_pad_push (stream->pad, buffer);
|
||||
}
|
||||
/* do special headers */
|
||||
if (stream->subtype == GST_RMDEMUX_STREAM_VIDEO) {
|
||||
ret =
|
||||
gst_rmdemux_parse_video_packet (rmdemux, stream, in, data - base,
|
||||
version, timestamp, key);
|
||||
} else if (stream->subtype == GST_RMDEMUX_STREAM_AUDIO) {
|
||||
ret =
|
||||
gst_rmdemux_parse_audio_packet (rmdemux, stream, in, data - base,
|
||||
version, timestamp, key);
|
||||
} else
|
||||
ret = GST_FLOW_OK;
|
||||
|
||||
cret = gst_rmdemux_combine_flows (rmdemux, stream, ret);
|
||||
|
||||
|
@ -2058,11 +2431,6 @@ unknown_stream:
|
|||
"data packet", id);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
alloc_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (rmdemux, "pad alloc returned %d", ret);
|
||||
return cret;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
Loading…
Reference in a new issue