mpegdemux: catch smaller PTS dicontinuities

In a test stream, I get one buffer with a PTS of about 15 seconds
in the future compared to the previous one, and next buffers with
timestamps continuing where the original ones left off.

This caused the sink to wait 15 seconds to display the frame while
more frames queued up, and then dump all the subsequent frames as
they "arrived too late".

Maybe that threshold should be made configurable, but for now,
make it more smaller to catch more of these.

https://bugzilla.gnome.org/show_bug.cgi?id=655804

Non AV streams keep using the larger threshold (10 minutes), as
subtitles may arrive only every so often.
This commit is contained in:
Vincent Penquerc'h 2011-08-30 14:50:52 +01:00
parent 7521b597f4
commit 7960280afb
2 changed files with 35 additions and 8 deletions

View file

@ -88,6 +88,10 @@ enum
/* latency in mseconds */
#define TS_LATENCY 700
/* threshold at which we deem PTS difference to be a discontinuity */
#define DISCONT_THRESHOLD_AV (GST_SECOND * 2) /* 2 seconds */
#define DISCONT_THRESHOLD_OTHER (GST_SECOND * 60 * 10) /* 10 minutes */
enum
{
PROP_0,
@ -539,6 +543,20 @@ gst_mpegts_stream_is_video (GstMpegTSStream * stream)
return FALSE;
}
static FORCE_INLINE gboolean
gst_mpegts_stream_is_audio (GstMpegTSStream * stream)
{
switch (stream->stream_type) {
case ST_AUDIO_MPEG1:
case ST_AUDIO_MPEG2:
case ST_AUDIO_AAC_ADTS:
case ST_AUDIO_AAC_LOAS:
return TRUE;
}
return FALSE;
}
static gboolean
gst_mpegts_demux_is_reserved_PID (GstMpegTSDemux * demux, guint16 PID)
{
@ -1040,16 +1058,21 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
demux = stream->demux;
srcpad = stream->pad;
GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x", stream->PID);
GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x (flags %x)", stream->PID,
stream->flags);
if (first && filter->pts != -1) {
gint64 discont_threshold =
((stream->flags & (MPEGTS_STREAM_FLAG_IS_AUDIO |
MPEGTS_STREAM_FLAG_IS_VIDEO))) ? DISCONT_THRESHOLD_AV :
DISCONT_THRESHOLD_OTHER;
pts = filter->pts;
time = MPEGTIME_TO_GSTTIME (pts) + stream->base_time;
if ((stream->last_time > 0 && stream->last_time < time &&
time - stream->last_time > GST_SECOND * 60 * 10)
time - stream->last_time > discont_threshold)
|| (stream->last_time > time
&& stream->last_time - time > GST_SECOND * 60 * 10)) {
&& stream->last_time - time > discont_threshold)) {
/* check first to see if we're in middle of detecting a discont in PCR.
* if we are we're not sure what timestamp the buffer should have, best
* to drop. */
@ -1065,8 +1088,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
stream->last_time - time > MPEGTIME_TO_GSTTIME (G_MAXUINT32)) {
/* wrap around occurred */
if (stream->base_time + MPEGTIME_TO_GSTTIME ((guint64) (1) << 33) +
MPEGTIME_TO_GSTTIME (pts) >
stream->last_time + GST_SECOND * 60 * 10) {
MPEGTIME_TO_GSTTIME (pts) > stream->last_time + discont_threshold) {
GST_DEBUG_OBJECT (demux,
"looks like we have a corrupt packet because its pts is a lot lower than"
" the previous pts but not a wraparound");
@ -1100,7 +1122,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
stream->base_time > 0) {
/* had a previous wrap around */
if (time - MPEGTIME_TO_GSTTIME ((guint64) (1) << 33) +
GST_SECOND * 60 * 10 < stream->last_time) {
discont_threshold < stream->last_time) {
GST_DEBUG_OBJECT (demux,
"looks like we have a corrupt packet because its pts is a lot higher than"
" the previous pts but not because of a wraparound or pcr discont");
@ -1202,7 +1224,8 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
gst_mpegts_demux_send_tags_for_stream (demux, stream);
}
GST_DEBUG_OBJECT (srcpad, "pushing buffer");
GST_DEBUG_OBJECT (srcpad, "pushing buffer ts %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad));
if (stream->discont) {
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
@ -1479,6 +1502,9 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream,
/* Recognise video streams based on stream_type */
if (gst_mpegts_stream_is_video (ES_stream))
ES_stream->flags |= MPEGTS_STREAM_FLAG_IS_VIDEO;
/* likewise for audio */
if (gst_mpegts_stream_is_audio (ES_stream))
ES_stream->flags |= MPEGTS_STREAM_FLAG_IS_AUDIO;
/* set adaptor */
GST_LOG ("Initializing PES filter for PID %u", ES_stream->PID);

View file

@ -121,7 +121,8 @@ struct _GstMpegTSPAT {
typedef enum _MpegTsStreamFlags {
MPEGTS_STREAM_FLAG_STREAM_TYPE_UNKNOWN = 0x01,
MPEGTS_STREAM_FLAG_PMT_VALID = 0x02,
MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04
MPEGTS_STREAM_FLAG_IS_VIDEO = 0x04,
MPEGTS_STREAM_FLAG_IS_AUDIO = 0x08
} MpegTsStreamFlags;
/* Information associated to a single MPEG stream. */