psdemux: Rewrite PSM parsing using GstByteReader

Avoid possible buffer overflows and ignore invalid PSM packets better
by using GstByteReader.

https://bugzilla.gnome.org/show_bug.cgi?id=777957
This commit is contained in:
Jan Schmidt 2017-02-01 14:25:32 +11:00
parent dd4f14fd68
commit 948b87bf15
2 changed files with 115 additions and 205 deletions

View file

@ -11,7 +11,7 @@ libgstmpegpsdemux_la_CFLAGS = \
libgstmpegpsdemux_la_LIBADD = \ libgstmpegpsdemux_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) \
-lgstpbutils-$(GST_API_VERSION) \ -lgstpbutils-$(GST_API_VERSION) \
$(GST_BASE_LIBS) $(GST_LIBS) $(GST_BASE_LIBS) -lgstbase-$(GST_API_VERSION) $(GST_LIBS)
libgstmpegpsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstmpegpsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmpegpsdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) libgstmpegpsdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

View file

@ -50,6 +50,7 @@
#include <gst/tag/tag.h> #include <gst/tag/tag.h>
#include <gst/pbutils/pbutils.h> #include <gst/pbutils/pbutils.h>
#include <gst/base/gstbytereader.h>
#include "gstmpegdefs.h" #include "gstmpegdefs.h"
#include "gstmpegdemux.h" #include "gstmpegdemux.h"
@ -2062,42 +2063,48 @@ need_more_data:
static GstFlowReturn static GstFlowReturn
gst_ps_demux_parse_psm (GstPsDemux * demux) gst_ps_demux_parse_psm (GstPsDemux * demux)
{ {
guint16 length = 0, info_length = 0, es_map_length = 0; guint16 psm_length, info_length = 0, es_map_length = 0;
guint8 psm_version = 0; guint8 psm_version = 0;
const guint8 *data, *es_map_base; GstByteReader br;
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
gboolean applicable; gboolean applicable;
#endif #endif
/* Need at least 6 bytes for start code + length */
if (gst_adapter_available (demux->adapter) < 6) if (gst_adapter_available (demux->adapter) < 6)
goto need_more_data; goto need_more_data;
/* start code + length */ {
data = gst_adapter_map (demux->adapter, 6); const guint8 *data;
/* skip start code */ /* start code + length */
data += 4; data = gst_adapter_map (demux->adapter, 6);
/* skip start code */
data += 4;
psm_length = GST_READ_UINT16_BE (data);
GST_DEBUG_OBJECT (demux, "PSM length %u", psm_length);
length = GST_READ_UINT16_BE (data); if (G_UNLIKELY (psm_length > 0x3FA))
GST_DEBUG_OBJECT (demux, "length %u", length); goto psm_len_error;
psm_length += 6; /* Add start code + size to length */
if (G_UNLIKELY (length > 0x3FA)) gst_adapter_unmap (demux->adapter);
goto psm_len_error;
length += 6; if (gst_adapter_available (demux->adapter) < psm_length)
goto need_more_data;
gst_adapter_unmap (demux->adapter); data = gst_adapter_map (demux->adapter, psm_length);
if (gst_adapter_available (demux->adapter) < length) gst_byte_reader_init (&br, data, psm_length);
goto need_more_data; }
data = gst_adapter_map (demux->adapter, length);
/* skip start code and length */ /* skip start code and length */
data += 6; if (!gst_byte_reader_skip (&br, 6))
goto fail_invalid;
/* Read PSM applicable bit together with version */ /* Read PSM applicable bit together with version */
psm_version = GST_READ_UINT8 (data); if (!gst_byte_reader_get_uint8 (&br, &psm_version))
goto fail_invalid;
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
applicable = (psm_version & 0x80) >> 7; applicable = (psm_version & 0x80) >> 7;
#endif #endif
@ -2105,62 +2112,70 @@ gst_ps_demux_parse_psm (GstPsDemux * demux)
GST_DEBUG_OBJECT (demux, "PSM version %u (applicable now %u)", psm_version, GST_DEBUG_OBJECT (demux, "PSM version %u (applicable now %u)", psm_version,
applicable); applicable);
/* Jump over version and marker bit */ /* Jump over the next byte (marker bit) */
data += 2; if (!gst_byte_reader_skip (&br, 1))
goto fail_invalid;
/* Read PS info length */ /* Read PS info length */
info_length = GST_READ_UINT16_BE (data); if (!gst_byte_reader_get_uint16_be (&br, &info_length))
/* Cap it to PSM length - needed bytes for ES map length and CRC */ goto fail_invalid;
info_length = MIN (length - 16, info_length);
GST_DEBUG_OBJECT (demux, "PS info length %u bytes", info_length); GST_DEBUG_OBJECT (demux, "PS info length %u bytes", info_length);
/* Skip the PS info, we don't use it */
/* Jump over that section */ if (!gst_byte_reader_skip (&br, info_length))
data += (2 + info_length); goto fail_invalid;
/* Read ES map length */ /* Read ES map length */
es_map_length = GST_READ_UINT16_BE (data); if (!gst_byte_reader_get_uint16_be (&br, &es_map_length))
/* Cap it to PSM remaining length - CRC */ goto fail_invalid;
es_map_length = MIN (length - (16 + info_length), es_map_length);
GST_DEBUG_OBJECT (demux, "ES map length %u bytes", es_map_length); GST_DEBUG_OBJECT (demux, "ES map length %u bytes", es_map_length);
/* Jump over the size */
data += 2;
/* Now read the ES map */ /* Now read the ES map */
es_map_base = data; {
while (es_map_base + 4 <= data + es_map_length) { GstByteReader es_map_br;
guint8 stream_type = 0, stream_id = 0; if (!gst_byte_reader_get_sub_reader (&br, &es_map_br, es_map_length))
guint16 stream_info_length = 0; goto fail_invalid;
stream_type = GST_READ_UINT8 (es_map_base); while (gst_byte_reader_get_remaining (&es_map_br) >= 4) {
es_map_base++; guint8 stream_type = 0, stream_id = 0;
stream_id = GST_READ_UINT8 (es_map_base); guint16 stream_info_length = 0;
es_map_base++;
stream_info_length = GST_READ_UINT16_BE (es_map_base);
es_map_base += 2;
/* Cap stream_info_length */
stream_info_length = MIN (data + es_map_length - es_map_base,
stream_info_length);
GST_DEBUG_OBJECT (demux, "Stream type %02X with id %02X and %u bytes info", if (!gst_byte_reader_get_uint8 (&es_map_br, &stream_type) ||
stream_type, stream_id, stream_info_length); !gst_byte_reader_get_uint8 (&es_map_br, &stream_id) ||
if (G_LIKELY (stream_id != 0xbd)) !gst_byte_reader_get_uint16_be (&es_map_br, &stream_info_length))
demux->psm[stream_id] = stream_type; break;
else {
/* Ignore stream type for private_stream_1 and discover it looking at GST_DEBUG_OBJECT (demux,
* the stream data. "Stream type %02X with id %02X and %u bytes info", stream_type,
* Fixes demuxing some clips with lpcm that was wrongly declared as stream_id, stream_info_length);
* mpeg audio */
GST_DEBUG_OBJECT (demux, "stream type for private_stream_1 ignored"); if (G_LIKELY (stream_id != 0xbd))
demux->psm[stream_id] = stream_type;
else {
/* Ignore stream type for private_stream_1 and discover it looking at
* the stream data.
* Fixes demuxing some clips with lpcm that was wrongly declared as
* mpeg audio */
GST_DEBUG_OBJECT (demux, "stream type for private_stream_1 ignored");
}
/* FIXME: We could use the descriptors instead of skipping them */
if (!gst_byte_reader_skip (&es_map_br, stream_info_length))
break;
} }
es_map_base += stream_info_length;
} }
/* We ignore the 4-byte CRC at the end */
gst_adapter_unmap (demux->adapter); gst_adapter_unmap (demux->adapter);
gst_adapter_flush (demux->adapter, length); gst_adapter_flush (demux->adapter, psm_length);
ADAPTER_OFFSET_FLUSH (length); ADAPTER_OFFSET_FLUSH (psm_length);
return GST_FLOW_OK; return GST_FLOW_OK;
fail_invalid:
GST_DEBUG_OBJECT (demux, "Failed to parse PSM. Skipping");
gst_adapter_unmap (demux->adapter);
gst_adapter_flush (demux->adapter, psm_length);
ADAPTER_OFFSET_FLUSH (psm_length);
return GST_FLOW_LOST_SYNC;
psm_len_error: psm_len_error:
{ {
GST_DEBUG_OBJECT (demux, "error in PSM length"); GST_DEBUG_OBJECT (demux, "error in PSM length");
@ -2191,13 +2206,10 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
GstMapInfo map; GstMapInfo map;
gsize datalen; gsize datalen;
guint offset = 0; guint offset = 0;
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map (buffer, &map, GST_MAP_READ);
datalen = map.size; datalen = map.size;
start_code = filter->start_code; start_code = filter->start_code;
id = filter->id; id = filter->id;
if (first) { if (first) {
/* find the stream type */ /* find the stream type */
stream_type = demux->psm[id]; stream_type = demux->psm[id];
@ -2208,7 +2220,6 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
* (see ftp://ftp.mplayerhq.hu/MPlayer/samples/MPEG-VOB/vdr-AC3) */ * (see ftp://ftp.mplayerhq.hu/MPlayer/samples/MPEG-VOB/vdr-AC3) */
if (datalen >= 4) { if (datalen >= 4) {
guint hdr = GST_READ_UINT32_BE (map.data); guint hdr = GST_READ_UINT32_BE (map.data);
if (G_UNLIKELY ((hdr & 0xffff0000) == AC3_SYNC_WORD)) { if (G_UNLIKELY ((hdr & 0xffff0000) == AC3_SYNC_WORD)) {
id = 0x80; id = 0x80;
stream_type = demux->psm[id] = ST_GST_AUDIO_RAWA52; stream_type = demux->psm[id] = ST_GST_AUDIO_RAWA52;
@ -2220,10 +2231,8 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
/* new id is in the first byte */ /* new id is in the first byte */
id = map.data[offset++]; id = map.data[offset++];
datalen--; datalen--;
/* and remap */ /* and remap */
stream_type = demux->psm[id]; stream_type = demux->psm[id];
/* Now, if it's a subpicture stream - no more, otherwise /* Now, if it's a subpicture stream - no more, otherwise
* take the first byte too, since it's the frame count in audio * take the first byte too, since it's the frame count in audio
* streams and our backwards compat convention is to strip it off */ * streams and our backwards compat convention is to strip it off */
@ -2231,7 +2240,6 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
/* Number of audio frames in this packet */ /* Number of audio frames in this packet */
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
guint8 nframes; guint8 nframes;
nframes = map.data[offset]; nframes = map.data[offset];
GST_LOG_OBJECT (demux, "private type 0x%02x, %d frames", id, GST_LOG_OBJECT (demux, "private type 0x%02x, %d frames", id,
nframes); nframes);
@ -2239,8 +2247,8 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
offset++; offset++;
datalen--; datalen--;
} else { } else {
GST_LOG_OBJECT (demux, "private type 0x%02x, stream type %d", id, GST_LOG_OBJECT (demux, "private type 0x%02x, stream type %d",
stream_type); id, stream_type);
} }
} }
} }
@ -2253,7 +2261,6 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
" (%" G_GUINT64_FORMAT ")", id, filter->pts, demux->next_pts); " (%" G_GUINT64_FORMAT ")", id, filter->pts, demux->next_pts);
} else } else
demux->next_pts = G_MAXUINT64; demux->next_pts = G_MAXUINT64;
if (filter->dts != -1) { if (filter->dts != -1) {
demux->next_dts = filter->dts + demux->scr_adjust; demux->next_dts = filter->dts + demux->scr_adjust;
GST_LOG_OBJECT (demux, "stream 0x%02x DTS = orig %" G_GUINT64_FORMAT GST_LOG_OBJECT (demux, "stream 0x%02x DTS = orig %" G_GUINT64_FORMAT
@ -2290,7 +2297,6 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
if (demux->current_stream->notlinked == FALSE) { if (demux->current_stream->notlinked == FALSE) {
out_buf = out_buf =
gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, datalen); gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, datalen);
ret = gst_ps_demux_send_data (demux, demux->current_stream, out_buf); ret = gst_ps_demux_send_data (demux, demux->current_stream, out_buf);
if (ret == GST_FLOW_NOT_LINKED) { if (ret == GST_FLOW_NOT_LINKED) {
demux->current_stream->notlinked = TRUE; demux->current_stream->notlinked = TRUE;
@ -2300,9 +2306,7 @@ gst_ps_demux_data_cb (GstPESFilter * filter, gboolean first,
done: done:
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return ret; return ret;
/* ERRORS */ /* ERRORS */
unknown_stream_type: unknown_stream_type:
{ {
@ -2320,17 +2324,13 @@ gst_ps_demux_resync (GstPsDemux * demux, gboolean save)
guint32 code; guint32 code;
gint offset; gint offset;
gboolean found; gboolean found;
avail = gst_adapter_available (demux->adapter); avail = gst_adapter_available (demux->adapter);
if (G_UNLIKELY (avail < 4)) if (G_UNLIKELY (avail < 4))
goto need_data; goto need_data;
/* Common case, read 4 bytes an check it */ /* Common case, read 4 bytes an check it */
data = gst_adapter_map (demux->adapter, 4); data = gst_adapter_map (demux->adapter, 4);
/* read currect code */ /* read currect code */
code = GST_READ_UINT32_BE (data); code = GST_READ_UINT32_BE (data);
/* The common case is that the sync code is at 0 bytes offset */ /* The common case is that the sync code is at 0 bytes offset */
if (G_LIKELY ((code & 0xffffff00) == 0x100L)) { if (G_LIKELY ((code & 0xffffff00) == 0x100L)) {
GST_LOG_OBJECT (demux, "Found resync code %08x after 0 bytes", code); GST_LOG_OBJECT (demux, "Found resync code %08x after 0 bytes", code);
@ -2344,16 +2344,12 @@ gst_ps_demux_resync (GstPsDemux * demux, gboolean save)
offset = 4; offset = 4;
if (offset >= avail) if (offset >= avail)
goto need_data; /* Not enough data to find sync */ goto need_data; /* Not enough data to find sync */
data = gst_adapter_map (demux->adapter, avail); data = gst_adapter_map (demux->adapter, avail);
do { do {
code = (code << 8) | data[offset++]; code = (code << 8) | data[offset++];
found = (code & 0xffffff00) == 0x100L; found = (code & 0xffffff00) == 0x100L;
} while (offset < avail && !found); } while (offset < avail && !found);
gst_adapter_unmap (demux->adapter); gst_adapter_unmap (demux->adapter);
if (!save || demux->sink_segment.rate >= 0.0) { if (!save || demux->sink_segment.rate >= 0.0) {
GST_LOG_OBJECT (demux, "flushing %d bytes", offset - 4); GST_LOG_OBJECT (demux, "flushing %d bytes", offset - 4);
/* forward playback, we can discard and flush the skipped bytes */ /* forward playback, we can discard and flush the skipped bytes */
@ -2384,7 +2380,6 @@ gst_ps_demux_resync (GstPsDemux * demux, gboolean save)
} }
return found; return found;
need_data: need_data:
{ {
GST_LOG_OBJECT (demux, "we need more data for resync %d", avail); GST_LOG_OBJECT (demux, "we need more data for resync %d", avail);
@ -2409,42 +2404,32 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
guint64 pts, dts; guint64 pts, dts;
guint32 code; guint32 code;
guint16 len; guint16 len;
/* read the 4 bytes for the sync code */ /* read the 4 bytes for the sync code */
code = GST_READ_UINT32_BE (data); code = GST_READ_UINT32_BE (data);
if (G_LIKELY (code != ID_PS_PACK_START_CODE)) if (G_LIKELY (code != ID_PS_PACK_START_CODE))
goto beach; goto beach;
/* skip start code */ /* skip start code */
data += 4; data += 4;
scr1 = GST_READ_UINT32_BE (data); scr1 = GST_READ_UINT32_BE (data);
scr2 = GST_READ_UINT32_BE (data + 4); scr2 = GST_READ_UINT32_BE (data + 4);
/* start parsing the stream */ /* start parsing the stream */
if ((*data & 0xc0) == 0x40) { if ((*data & 0xc0) == 0x40) {
/* MPEG-2 PACK header */ /* MPEG-2 PACK header */
guint32 scr_ext; guint32 scr_ext;
guint32 next32; guint32 next32;
guint8 stuffing_bytes; guint8 stuffing_bytes;
/* :2=01 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 */ /* :2=01 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 */
/* check markers */ /* check markers */
if ((scr1 & 0xc4000400) != 0x44000400) if ((scr1 & 0xc4000400) != 0x44000400)
goto beach; goto beach;
scr = ((guint64) scr1 & 0x38000000) << 3; scr = ((guint64) scr1 & 0x38000000) << 3;
scr |= ((guint64) scr1 & 0x03fff800) << 4; scr |= ((guint64) scr1 & 0x03fff800) << 4;
scr |= ((guint64) scr1 & 0x000003ff) << 5; scr |= ((guint64) scr1 & 0x000003ff) << 5;
scr |= ((guint64) scr2 & 0xf8000000) >> 27; scr |= ((guint64) scr2 & 0xf8000000) >> 27;
/* marker:1==1 ! scr_ext:9 ! marker:1==1 */ /* marker:1==1 ! scr_ext:9 ! marker:1==1 */
if ((scr2 & 0x04010000) != 0x04010000) if ((scr2 & 0x04010000) != 0x04010000)
goto beach; goto beach;
scr_ext = (scr2 & 0x03fe0000) >> 17; scr_ext = (scr2 & 0x03fe0000) >> 17;
if (scr_ext) { if (scr_ext) {
scr = (scr * 300 + scr_ext % 300) / 300; scr = (scr * 300 + scr_ext % 300) / 300;
} }
@ -2455,7 +2440,6 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
next32 = GST_READ_UINT32_BE (data); next32 = GST_READ_UINT32_BE (data);
if ((next32 & 0x00000300) != 0x00000300) if ((next32 & 0x00000300) != 0x00000300)
goto beach; goto beach;
stuffing_bytes = (next32 & 0x07); stuffing_bytes = (next32 & 0x07);
data += 4; data += 4;
while (stuffing_bytes--) { while (stuffing_bytes--) {
@ -2467,10 +2451,8 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
/* check markers */ /* check markers */
if ((scr1 & 0xf1000100) != 0x21000100) if ((scr1 & 0xf1000100) != 0x21000100)
goto beach; goto beach;
if ((scr2 & 0x01800001) != 0x01800001) if ((scr2 & 0x01800001) != 0x01800001)
goto beach; goto beach;
/* :4=0010 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 ! marker:1==1 */ /* :4=0010 ! scr:3 ! marker:1==1 ! scr:15 ! marker:1==1 ! scr:15 ! marker:1==1 */
scr = ((guint64) scr1 & 0x0e000000) << 5; scr = ((guint64) scr1 & 0x0e000000) << 5;
scr |= ((guint64) scr1 & 0x00fffe00) << 6; scr |= ((guint64) scr1 & 0x00fffe00) << 6;
@ -2488,7 +2470,6 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
/* Possible optional System header here */ /* Possible optional System header here */
code = GST_READ_UINT32_BE (data); code = GST_READ_UINT32_BE (data);
len = GST_READ_UINT16_BE (data + 4); len = GST_READ_UINT16_BE (data + 4);
if (code == ID_PS_SYSTEM_HEADER_START_CODE) { if (code == ID_PS_SYSTEM_HEADER_START_CODE) {
/* Found a system header, skip it */ /* Found a system header, skip it */
/* Check for sufficient data - system header, plus enough /* Check for sufficient data - system header, plus enough
@ -2496,7 +2477,6 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
if (data + 6 + len + 6 > end) if (data + 6 + len + 6 > end)
return FALSE; return FALSE;
data += len + 6; data += len + 6;
/* read the 4 bytes for the PES sync code */ /* read the 4 bytes for the PES sync code */
code = GST_READ_UINT32_BE (data); code = GST_READ_UINT32_BE (data);
len = GST_READ_UINT16_BE (data + 4); len = GST_READ_UINT16_BE (data + 4);
@ -2505,10 +2485,8 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
/* Check we have enough data left for reading the PES packet */ /* Check we have enough data left for reading the PES packet */
if (data + 6 + len > end) if (data + 6 + len > end)
return FALSE; return FALSE;
if (!gst_ps_demux_is_pes_sync (code)) if (!gst_ps_demux_is_pes_sync (code))
goto beach; goto beach;
switch (code) { switch (code) {
case ID_PS_PROGRAM_STREAM_MAP: case ID_PS_PROGRAM_STREAM_MAP:
case ID_PRIVATE_STREAM_2: case ID_PRIVATE_STREAM_2:
@ -2525,9 +2503,7 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
/* skip sync code and size */ /* skip sync code and size */
data += 6; data += 6;
pts = dts = -1; pts = dts = -1;
/* stuffing bits, first two bits are '10' for mpeg2 pes so this code is /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
* not triggered. */ * not triggered. */
while (TRUE) { while (TRUE) {
@ -2539,7 +2515,6 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
/* STD buffer size, never for mpeg2 */ /* STD buffer size, never for mpeg2 */
if ((*data & 0xc0) == 0x40) if ((*data & 0xc0) == 0x40)
data += 2; data += 2;
/* PTS but no DTS, never for mpeg2 */ /* PTS but no DTS, never for mpeg2 */
if ((*data & 0xf0) == 0x20) { if ((*data & 0xf0) == 0x20) {
READ_TS (data, pts, beach); READ_TS (data, pts, beach);
@ -2551,7 +2526,6 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
} else if ((*data & 0xc0) == 0x80) { } else if ((*data & 0xc0) == 0x80) {
/* mpeg2 case */ /* mpeg2 case */
guchar flags; guchar flags;
/* 2: '10' /* 2: '10'
* 2: PES_scrambling_control * 2: PES_scrambling_control
* 1: PES_priority * 1: PES_priority
@ -2560,10 +2534,8 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
* 1: original_or_copy * 1: original_or_copy
*/ */
flags = *data++; flags = *data++;
if ((flags & 0xc0) != 0x80) if ((flags & 0xc0) != 0x80)
goto beach; goto beach;
/* 2: PTS_DTS_flags /* 2: PTS_DTS_flags
* 1: ESCR_flag * 1: ESCR_flag
* 1: ES_rate_flag * 1: ES_rate_flag
@ -2573,14 +2545,11 @@ gst_ps_demux_scan_ts (GstPsDemux * demux, const guint8 * data,
* 1: PES_extension_flag * 1: PES_extension_flag
*/ */
flags = *data++; flags = *data++;
/* 8: PES_header_data_length */ /* 8: PES_header_data_length */
data++; data++;
/* only DTS: this is invalid */ /* only DTS: this is invalid */
if ((flags & 0xc0) == 0x40) if ((flags & 0xc0) == 0x40)
goto beach; goto beach;
/* check for PTS */ /* check for PTS */
if ((flags & 0x80)) { if ((flags & 0x80)) {
READ_TS (data, pts, beach); READ_TS (data, pts, beach);
@ -2617,26 +2586,21 @@ gst_ps_demux_scan_forward_ts (GstPsDemux * demux, guint64 * pos,
guint cursor, to_read = BLOCK_SZ; guint cursor, to_read = BLOCK_SZ;
guint end_scan; guint end_scan;
GstMapInfo map; GstMapInfo map;
do { do {
/* Check we can get at least scan_sz bytes */ /* Check we can get at least scan_sz bytes */
if (offset + scan_sz > demux->sink_segment.stop) if (offset + scan_sz > demux->sink_segment.stop)
return FALSE; return FALSE;
/* Don't go further than 'limit' bytes */ /* Don't go further than 'limit' bytes */
if (limit && offset > *pos + limit) if (limit && offset > *pos + limit)
return FALSE; return FALSE;
if (offset + to_read > demux->sink_segment.stop) if (offset + to_read > demux->sink_segment.stop)
to_read = demux->sink_segment.stop - offset; to_read = demux->sink_segment.stop - offset;
/* read some data */ /* read some data */
buffer = NULL; buffer = NULL;
ret = gst_pad_pull_range (demux->sinkpad, offset, to_read, &buffer); ret = gst_pad_pull_range (demux->sinkpad, offset, to_read, &buffer);
if (G_UNLIKELY (ret != GST_FLOW_OK)) if (G_UNLIKELY (ret != GST_FLOW_OK))
return FALSE; return FALSE;
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map (buffer, &map, GST_MAP_READ);
/* may get a short buffer at the end of the file */ /* may get a short buffer at the end of the file */
if (G_UNLIKELY (map.size <= scan_sz)) { if (G_UNLIKELY (map.size <= scan_sz)) {
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
@ -2645,7 +2609,6 @@ gst_ps_demux_scan_forward_ts (GstPsDemux * demux, guint64 * pos,
} }
end_scan = map.size - scan_sz; end_scan = map.size - scan_sz;
/* scan the block */ /* scan the block */
for (cursor = 0; !found && cursor <= end_scan; cursor++) { for (cursor = 0; !found && cursor <= end_scan; cursor++) {
found = gst_ps_demux_scan_ts (demux, map.data + cursor, mode, &ts, found = gst_ps_demux_scan_ts (demux, map.data + cursor, mode, &ts,
@ -2655,7 +2618,6 @@ gst_ps_demux_scan_forward_ts (GstPsDemux * demux, guint64 * pos,
/* done with the buffer, unref it */ /* done with the buffer, unref it */
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
if (found) { if (found) {
*rts = ts; *rts = ts;
*pos = offset + cursor - 1; *pos = offset + cursor - 1;
@ -2663,7 +2625,6 @@ gst_ps_demux_scan_forward_ts (GstPsDemux * demux, guint64 * pos,
offset += cursor; offset += cursor;
} }
} while (!found && offset < demux->sink_segment.stop); } while (!found && offset < demux->sink_segment.stop);
return found; return found;
} }
@ -2681,16 +2642,13 @@ gst_ps_demux_scan_backward_ts (GstPsDemux * demux, guint64 * pos,
guint start_scan; guint start_scan;
guint8 *data; guint8 *data;
GstMapInfo map; GstMapInfo map;
do { do {
/* Check we have at least scan_sz bytes available */ /* Check we have at least scan_sz bytes available */
if (offset < scan_sz - 1) if (offset < scan_sz - 1)
return FALSE; return FALSE;
/* Don't go backward past the start or 'limit' bytes */ /* Don't go backward past the start or 'limit' bytes */
if (limit && offset + limit < *pos) if (limit && offset + limit < *pos)
return FALSE; return FALSE;
if (offset > BLOCK_SZ) if (offset > BLOCK_SZ)
offset -= BLOCK_SZ; offset -= BLOCK_SZ;
else { else {
@ -2702,9 +2660,7 @@ gst_ps_demux_scan_backward_ts (GstPsDemux * demux, guint64 * pos,
ret = gst_pad_pull_range (demux->sinkpad, offset, to_read, &buffer); ret = gst_pad_pull_range (demux->sinkpad, offset, to_read, &buffer);
if (G_UNLIKELY (ret != GST_FLOW_OK)) if (G_UNLIKELY (ret != GST_FLOW_OK))
return FALSE; return FALSE;
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map (buffer, &map, GST_MAP_READ);
/* may get a short buffer at the end of the file */ /* may get a short buffer at the end of the file */
if (G_UNLIKELY (map.size <= scan_sz)) { if (G_UNLIKELY (map.size <= scan_sz)) {
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
@ -2714,7 +2670,6 @@ gst_ps_demux_scan_backward_ts (GstPsDemux * demux, guint64 * pos,
start_scan = map.size - scan_sz; start_scan = map.size - scan_sz;
data = map.data + start_scan; data = map.data + start_scan;
/* scan the block */ /* scan the block */
for (cursor = (start_scan + 1); !found && cursor > 0; cursor--) { for (cursor = (start_scan + 1); !found && cursor > 0; cursor--) {
found = gst_ps_demux_scan_ts (demux, data--, mode, &ts, found = gst_ps_demux_scan_ts (demux, data--, mode, &ts,
@ -2724,14 +2679,12 @@ gst_ps_demux_scan_backward_ts (GstPsDemux * demux, guint64 * pos,
/* done with the buffer, unref it */ /* done with the buffer, unref it */
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
if (found) { if (found) {
*rts = ts; *rts = ts;
*pos = offset + cursor; *pos = offset + cursor;
} }
} while (!found && offset > 0); } while (!found && offset > 0);
return found; return found;
} }
@ -2745,54 +2698,47 @@ gst_ps_sink_get_duration (GstPsDemux * demux)
guint64 offset; guint64 offset;
guint i; guint i;
guint64 scr = 0; guint64 scr = 0;
/* init the sink segment */ /* init the sink segment */
gst_segment_init (&demux->sink_segment, format); gst_segment_init (&demux->sink_segment, format);
/* get peer to figure out length */ /* get peer to figure out length */
if ((peer = gst_pad_get_peer (demux->sinkpad)) == NULL) if ((peer = gst_pad_get_peer (demux->sinkpad)) == NULL)
goto beach; goto beach;
res = gst_pad_query_duration (peer, format, &length); res = gst_pad_query_duration (peer, format, &length);
gst_object_unref (peer); gst_object_unref (peer);
if (!res || length <= 0) if (!res || length <= 0)
goto beach; goto beach;
GST_DEBUG_OBJECT (demux, "file length %" G_GINT64_FORMAT, length); GST_DEBUG_OBJECT (demux, "file length %" G_GINT64_FORMAT, length);
/* update the sink segment */ /* update the sink segment */
demux->sink_segment.stop = length; demux->sink_segment.stop = length;
gst_segment_set_duration (&demux->sink_segment, format, length); gst_segment_set_duration (&demux->sink_segment, format, length);
gst_segment_set_position (&demux->sink_segment, format, 0); gst_segment_set_position (&demux->sink_segment, format, 0);
/* Scan for notorious SCR and PTS to calculate the duration */ /* Scan for notorious SCR and PTS to calculate the duration */
/* scan for first SCR in the stream */ /* scan for first SCR in the stream */
offset = demux->sink_segment.start; offset = demux->sink_segment.start;
gst_ps_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &demux->first_scr, gst_ps_demux_scan_forward_ts (demux, &offset, SCAN_SCR,
DURATION_SCAN_LIMIT); &demux->first_scr, DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux,
" in packet starting at %" G_GUINT64_FORMAT, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
demux->first_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)), " in packet starting at %" G_GUINT64_FORMAT, demux->first_scr,
offset); GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)), offset);
demux->first_scr_offset = offset; demux->first_scr_offset = offset;
/* scan for last SCR in the stream */ /* scan for last SCR in the stream */
offset = demux->sink_segment.stop; offset = demux->sink_segment.stop;
gst_ps_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &demux->last_scr, gst_ps_demux_scan_backward_ts (demux, &offset, SCAN_SCR,
DURATION_SCAN_LIMIT); &demux->last_scr, DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux,
" in packet starting at %" G_GUINT64_FORMAT, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
demux->last_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)), " in packet starting at %" G_GUINT64_FORMAT, demux->last_scr,
offset); GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)), offset);
demux->last_scr_offset = offset; demux->last_scr_offset = offset;
/* scan for first PTS in the stream */ /* scan for first PTS in the stream */
offset = demux->sink_segment.start; offset = demux->sink_segment.start;
gst_ps_demux_scan_forward_ts (demux, &offset, SCAN_PTS, &demux->first_pts, gst_ps_demux_scan_forward_ts (demux, &offset, SCAN_PTS,
DURATION_SCAN_LIMIT); &demux->first_pts, DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux,
" in packet starting at %" G_GUINT64_FORMAT, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
demux->first_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)), " in packet starting at %" G_GUINT64_FORMAT, demux->first_pts,
offset); GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)), offset);
if (demux->first_pts != G_MAXUINT64) { if (demux->first_pts != G_MAXUINT64) {
/* scan for last PTS in the stream */ /* scan for last PTS in the stream */
offset = demux->sink_segment.stop; offset = demux->sink_segment.stop;
@ -2817,8 +2763,8 @@ gst_ps_sink_get_duration (GstPsDemux * demux)
/* Start demuxing from the right place */ /* Start demuxing from the right place */
demux->sink_segment.position = offset; demux->sink_segment.position = offset;
GST_DEBUG_OBJECT (demux, "Replaced First SCR: %" G_GINT64_FORMAT GST_DEBUG_OBJECT (demux, "Replaced First SCR: %" G_GINT64_FORMAT
" %" GST_TIME_FORMAT " in packet starting at %" G_GUINT64_FORMAT, " %" GST_TIME_FORMAT " in packet starting at %"
demux->first_scr, G_GUINT64_FORMAT, demux->first_scr,
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)), offset); GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)), offset);
break; break;
} }
@ -2828,7 +2774,6 @@ gst_ps_sink_get_duration (GstPsDemux * demux)
demux->base_time = MPEGTIME_TO_GSTTIME (demux->first_scr); demux->base_time = MPEGTIME_TO_GSTTIME (demux->first_scr);
demux->scr_rate_n = demux->last_scr_offset - demux->first_scr_offset; demux->scr_rate_n = demux->last_scr_offset - demux->first_scr_offset;
demux->scr_rate_d = demux->last_scr - demux->first_scr; demux->scr_rate_d = demux->last_scr - demux->first_scr;
if (G_LIKELY (demux->first_pts != G_MAXUINT64 && if (G_LIKELY (demux->first_pts != G_MAXUINT64 &&
demux->last_pts != G_MAXUINT64)) { demux->last_pts != G_MAXUINT64)) {
/* update the src segment */ /* update the src segment */
@ -2845,9 +2790,7 @@ gst_ps_sink_get_duration (GstPsDemux * demux)
&demux->sink_segment); &demux->sink_segment);
GST_INFO_OBJECT (demux, "src segment configured %" GST_SEGMENT_FORMAT, GST_INFO_OBJECT (demux, "src segment configured %" GST_SEGMENT_FORMAT,
&demux->src_segment); &demux->src_segment);
res = TRUE; res = TRUE;
beach: beach:
return res; return res;
} }
@ -2858,7 +2801,6 @@ gst_ps_demux_pull_block (GstPad * pad, GstPsDemux * demux,
{ {
GstFlowReturn ret; GstFlowReturn ret;
GstBuffer *buffer = NULL; GstBuffer *buffer = NULL;
ret = gst_pad_pull_range (pad, offset, size, &buffer); ret = gst_pad_pull_range (pad, offset, size, &buffer);
if (G_UNLIKELY (ret != GST_FLOW_OK)) { if (G_UNLIKELY (ret != GST_FLOW_OK)) {
GST_DEBUG_OBJECT (demux, "pull range at %" G_GUINT64_FORMAT GST_DEBUG_OBJECT (demux, "pull range at %" G_GUINT64_FORMAT
@ -2867,13 +2809,11 @@ gst_ps_demux_pull_block (GstPad * pad, GstPsDemux * demux,
} else } else
GST_LOG_OBJECT (demux, "pull range at %" G_GUINT64_FORMAT GST_LOG_OBJECT (demux, "pull range at %" G_GUINT64_FORMAT
" size %u done", offset, size); " size %u done", offset, size);
if (demux->sink_segment.rate < 0) { if (demux->sink_segment.rate < 0) {
GST_LOG_OBJECT (demux, "setting discont flag on backward rate"); GST_LOG_OBJECT (demux, "setting discont flag on backward rate");
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
} }
ret = gst_ps_demux_chain (pad, GST_OBJECT (demux), buffer); ret = gst_ps_demux_chain (pad, GST_OBJECT (demux), buffer);
beach: beach:
return ret; return ret;
} }
@ -2884,9 +2824,7 @@ gst_ps_demux_loop (GstPad * pad)
GstPsDemux *demux; GstPsDemux *demux;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
guint64 offset = 0; guint64 offset = 0;
demux = GST_PS_DEMUX (gst_pad_get_parent (pad)); demux = GST_PS_DEMUX (gst_pad_get_parent (pad));
if (G_UNLIKELY (demux->flushing)) { if (G_UNLIKELY (demux->flushing)) {
ret = GST_FLOW_FLUSHING; ret = GST_FLOW_FLUSHING;
goto pause; goto pause;
@ -2894,7 +2832,6 @@ gst_ps_demux_loop (GstPad * pad)
if (G_UNLIKELY (demux->sink_segment.format == GST_FORMAT_UNDEFINED)) if (G_UNLIKELY (demux->sink_segment.format == GST_FORMAT_UNDEFINED))
gst_ps_sink_get_duration (demux); gst_ps_sink_get_duration (demux);
offset = demux->sink_segment.position; offset = demux->sink_segment.position;
if (demux->sink_segment.rate >= 0) { if (demux->sink_segment.rate >= 0) {
guint size = BLOCK_SZ; guint size = BLOCK_SZ;
@ -2903,24 +2840,22 @@ gst_ps_demux_loop (GstPad * pad)
} }
/* pull in data */ /* pull in data */
ret = gst_ps_demux_pull_block (pad, demux, offset, size); ret = gst_ps_demux_pull_block (pad, demux, offset, size);
/* pause if something went wrong */ /* pause if something went wrong */
if (G_UNLIKELY (ret != GST_FLOW_OK)) if (G_UNLIKELY (ret != GST_FLOW_OK))
goto pause; goto pause;
/* update our position */ /* update our position */
offset += size; offset += size;
gst_segment_set_position (&demux->sink_segment, GST_FORMAT_BYTES, offset); gst_segment_set_position (&demux->sink_segment, GST_FORMAT_BYTES, offset);
/* check EOS condition */ /* check EOS condition */
if ((demux->src_segment.flags & GST_SEEK_FLAG_SEGMENT) && if ((demux->src_segment.flags & GST_SEEK_FLAG_SEGMENT) &&
((demux->sink_segment.position >= demux->sink_segment.stop) || ((demux->sink_segment.position >= demux->sink_segment.stop) ||
(demux->src_segment.stop != (guint64) - 1 && (demux->src_segment.stop != (guint64) - 1 &&
demux->src_segment.position >= demux->src_segment.stop))) { demux->src_segment.position >= demux->src_segment.stop))) {
GST_DEBUG_OBJECT (demux, "forward mode using segment reached end of " GST_DEBUG_OBJECT (demux,
"segment pos %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT "forward mode using segment reached end of " "segment pos %"
" pos in bytes %" G_GUINT64_FORMAT " stop in bytes %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT " pos in bytes %"
G_GUINT64_FORMAT, GST_TIME_ARGS (demux->src_segment.position), G_GUINT64_FORMAT " stop in bytes %" G_GUINT64_FORMAT,
GST_TIME_ARGS (demux->src_segment.position),
GST_TIME_ARGS (demux->src_segment.stop), GST_TIME_ARGS (demux->src_segment.stop),
demux->sink_segment.position, demux->sink_segment.stop); demux->sink_segment.position, demux->sink_segment.stop);
ret = GST_FLOW_EOS; ret = GST_FLOW_EOS;
@ -2928,25 +2863,22 @@ gst_ps_demux_loop (GstPad * pad)
} }
} else { /* Reverse playback */ } else { /* Reverse playback */
guint64 size = MIN (offset, BLOCK_SZ); guint64 size = MIN (offset, BLOCK_SZ);
/* pull in data */ /* pull in data */
ret = gst_ps_demux_pull_block (pad, demux, offset - size, size); ret = gst_ps_demux_pull_block (pad, demux, offset - size, size);
/* pause if something went wrong */ /* pause if something went wrong */
if (G_UNLIKELY (ret != GST_FLOW_OK)) if (G_UNLIKELY (ret != GST_FLOW_OK))
goto pause; goto pause;
/* update our position */ /* update our position */
offset -= size; offset -= size;
gst_segment_set_position (&demux->sink_segment, GST_FORMAT_BYTES, offset); gst_segment_set_position (&demux->sink_segment, GST_FORMAT_BYTES, offset);
/* check EOS condition */ /* check EOS condition */
if (demux->sink_segment.position <= demux->sink_segment.start || if (demux->sink_segment.position <= demux->sink_segment.start ||
demux->src_segment.position <= demux->src_segment.start) { demux->src_segment.position <= demux->src_segment.start) {
GST_DEBUG_OBJECT (demux, "reverse mode using segment reached end of " GST_DEBUG_OBJECT (demux,
"segment pos %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT "reverse mode using segment reached end of " "segment pos %"
" pos in bytes %" G_GUINT64_FORMAT " stop in bytes %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT " pos in bytes %"
G_GUINT64_FORMAT, GST_TIME_ARGS (demux->src_segment.position), G_GUINT64_FORMAT " stop in bytes %" G_GUINT64_FORMAT,
GST_TIME_ARGS (demux->src_segment.position),
GST_TIME_ARGS (demux->src_segment.start), GST_TIME_ARGS (demux->src_segment.start),
demux->sink_segment.position, demux->sink_segment.start); demux->sink_segment.position, demux->sink_segment.start);
ret = GST_FLOW_EOS; ret = GST_FLOW_EOS;
@ -2955,27 +2887,21 @@ gst_ps_demux_loop (GstPad * pad)
} }
gst_object_unref (demux); gst_object_unref (demux);
return; return;
pause: pause:
{ {
const gchar *reason = gst_flow_get_name (ret); const gchar *reason = gst_flow_get_name (ret);
GST_LOG_OBJECT (demux, "pausing task, reason %s", reason); GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
gst_pad_pause_task (pad); gst_pad_pause_task (pad);
if (ret == GST_FLOW_EOS) { if (ret == GST_FLOW_EOS) {
/* perform EOS logic */ /* perform EOS logic */
gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
if (demux->src_segment.flags & GST_SEEK_FLAG_SEGMENT) { if (demux->src_segment.flags & GST_SEEK_FLAG_SEGMENT) {
gint64 stop; gint64 stop;
/* for segment playback we need to post when (in stream time) /* for segment playback we need to post when (in stream time)
* we stopped, this is either stop (when set) or the duration. */ * we stopped, this is either stop (when set) or the duration. */
if ((stop = demux->src_segment.stop) == -1) if ((stop = demux->src_segment.stop) == -1)
stop = demux->src_segment.duration; stop = demux->src_segment.duration;
if (demux->sink_segment.rate >= 0) { if (demux->sink_segment.rate >= 0) {
GST_LOG_OBJECT (demux, "Sending segment done, at end of segment"); GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
gst_element_post_message (GST_ELEMENT_CAST (demux), gst_element_post_message (GST_ELEMENT_CAST (demux),
@ -2984,8 +2910,8 @@ pause:
gst_ps_demux_send_event (demux, gst_ps_demux_send_event (demux,
gst_event_new_segment_done (GST_FORMAT_TIME, stop)); gst_event_new_segment_done (GST_FORMAT_TIME, stop));
} else { /* Reverse playback */ } else { /* Reverse playback */
GST_LOG_OBJECT (demux, "Sending segment done, at beginning of " GST_LOG_OBJECT (demux,
"segment"); "Sending segment done, at beginning of " "segment");
gst_element_post_message (GST_ELEMENT_CAST (demux), gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_segment_done (GST_OBJECT_CAST (demux), gst_message_new_segment_done (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, demux->src_segment.start)); GST_FORMAT_TIME, demux->src_segment.start));
@ -3020,7 +2946,6 @@ gst_ps_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GstQuery *query = gst_query_new_scheduling (); GstQuery *query = gst_query_new_scheduling ();
if (gst_pad_peer_query (sinkpad, query)) { if (gst_pad_peer_query (sinkpad, query)) {
if (gst_query_has_scheduling_mode_with_flags (query, if (gst_query_has_scheduling_mode_with_flags (query,
GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) { GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
@ -3033,7 +2958,6 @@ gst_ps_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
} }
gst_query_unref (query); gst_query_unref (query);
return res; return res;
} }
@ -3043,9 +2967,7 @@ gst_ps_demux_sink_activate_push (GstPad * sinkpad, GstObject * parent,
gboolean active) gboolean active)
{ {
GstPsDemux *demux = GST_PS_DEMUX (parent); GstPsDemux *demux = GST_PS_DEMUX (parent);
demux->random_access = FALSE; demux->random_access = FALSE;
return TRUE; return TRUE;
} }
@ -3057,12 +2979,11 @@ gst_ps_demux_sink_activate_pull (GstPad * sinkpad, GstObject * parent,
gboolean active) gboolean active)
{ {
GstPsDemux *demux = GST_PS_DEMUX (parent); GstPsDemux *demux = GST_PS_DEMUX (parent);
if (active) { if (active) {
GST_DEBUG ("pull mode activated"); GST_DEBUG ("pull mode activated");
demux->random_access = TRUE; demux->random_access = TRUE;
return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ps_demux_loop, return gst_pad_start_task (sinkpad,
sinkpad, NULL); (GstTaskFunction) gst_ps_demux_loop, sinkpad, NULL);
} else { } else {
demux->random_access = FALSE; demux->random_access = FALSE;
return gst_pad_stop_task (sinkpad); return gst_pad_stop_task (sinkpad);
@ -3090,12 +3011,9 @@ static GstFlowReturn
gst_ps_demux_combine_flows (GstPsDemux * demux, GstFlowReturn ret) gst_ps_demux_combine_flows (GstPsDemux * demux, GstFlowReturn ret)
{ {
GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret)); GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret); ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
if (G_UNLIKELY (demux->need_no_more_pads && ret == GST_FLOW_NOT_LINKED)) if (G_UNLIKELY (demux->need_no_more_pads && ret == GST_FLOW_NOT_LINKED))
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret)); GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
return ret; return ret;
} }
@ -3107,32 +3025,28 @@ gst_ps_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
guint32 avail; guint32 avail;
gboolean save, discont; gboolean save, discont;
discont = GST_BUFFER_IS_DISCONT (buffer); discont = GST_BUFFER_IS_DISCONT (buffer);
if (discont) { if (discont) {
GST_LOG_OBJECT (demux, "Received buffer with discont flag and" GST_LOG_OBJECT (demux,
" offset %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buffer)); "Received buffer with discont flag and" " offset %"
G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buffer));
gst_pes_filter_drain (&demux->filter); gst_pes_filter_drain (&demux->filter);
gst_ps_demux_mark_discont (demux, TRUE, FALSE); gst_ps_demux_mark_discont (demux, TRUE, FALSE);
/* mark discont on all streams */ /* mark discont on all streams */
if (demux->sink_segment.rate >= 0.0) { if (demux->sink_segment.rate >= 0.0) {
demux->current_scr = G_MAXUINT64; demux->current_scr = G_MAXUINT64;
demux->bytes_since_scr = 0; demux->bytes_since_scr = 0;
} }
} else { } else {
GST_LOG_OBJECT (demux, "Received buffer with offset %" G_GUINT64_FORMAT, GST_LOG_OBJECT (demux,
"Received buffer with offset %" G_GUINT64_FORMAT,
GST_BUFFER_OFFSET (buffer)); GST_BUFFER_OFFSET (buffer));
} }
/* We keep the offset to interpolate SCR */ /* We keep the offset to interpolate SCR */
demux->adapter_offset = GST_BUFFER_OFFSET (buffer); demux->adapter_offset = GST_BUFFER_OFFSET (buffer);
gst_adapter_push (demux->adapter, buffer); gst_adapter_push (demux->adapter, buffer);
demux->bytes_since_scr += gst_buffer_get_size (buffer); demux->bytes_since_scr += gst_buffer_get_size (buffer);
avail = gst_adapter_available (demux->rev_adapter); avail = gst_adapter_available (demux->rev_adapter);
if (avail > 0) { if (avail > 0) {
GST_LOG_OBJECT (demux, "appending %u saved bytes", avail); GST_LOG_OBJECT (demux, "appending %u saved bytes", avail);
@ -3145,7 +3059,6 @@ gst_ps_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
avail = gst_adapter_available (demux->adapter); avail = gst_adapter_available (demux->adapter);
GST_LOG_OBJECT (demux, "avail now: %d, state %d", avail, demux->filter.state); GST_LOG_OBJECT (demux, "avail now: %d, state %d", avail, demux->filter.state);
switch (demux->filter.state) { switch (demux->filter.state) {
case STATE_DATA_SKIP: case STATE_DATA_SKIP:
case STATE_DATA_PUSH: case STATE_DATA_PUSH:
@ -3215,7 +3128,6 @@ gst_ps_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
* saved up to the next ps sync. */ * saved up to the next ps sync. */
if (ps_sync) if (ps_sync)
save = FALSE; save = FALSE;
switch (ret) { switch (ret) {
case GST_FLOW_NEED_MORE_DATA: case GST_FLOW_NEED_MORE_DATA:
GST_DEBUG_OBJECT (demux, "need more data"); GST_DEBUG_OBJECT (demux, "need more data");
@ -3249,7 +3161,6 @@ gst_ps_demux_change_state (GstElement * element, GstStateChange transition)
{ {
GstPsDemux *demux = GST_PS_DEMUX (element); GstPsDemux *demux = GST_PS_DEMUX (element);
GstStateChangeReturn result; GstStateChangeReturn result;
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
gst_pes_filter_init (&demux->filter, demux->adapter, gst_pes_filter_init (&demux->filter, demux->adapter,
@ -3266,7 +3177,6 @@ gst_ps_demux_change_state (GstElement * element, GstStateChange transition)
} }
result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_ps_demux_reset (demux); gst_ps_demux_reset (demux);