flvdemux: detect large pts gaps and resync

Should work on multiple gaps, but tested on only one.

https://bugzilla.gnome.org/show_bug.cgi?id=631430
This commit is contained in:
Vincent Penquerc'h 2011-10-03 17:50:43 +01:00
parent 5a73374f2c
commit cf3f3f14da
2 changed files with 36 additions and 2 deletions

View file

@ -84,6 +84,9 @@ GST_BOILERPLATE (GstFlvDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
/* 1 byte of tag type + 3 bytes of tag data size */
#define FLV_TAG_TYPE_SIZE 4
/* two seconds - consider pts are resynced to another base if this different */
#define RESYNC_THRESHOLD 2000
static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
GstEvent * event);
static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
@ -759,6 +762,23 @@ gst_flv_demux_push_tags (GstFlvDemux * demux)
}
}
static void
gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, guint32 * last,
GstClockTime * offset)
{
if (ABS (pts - *last) >= RESYNC_THRESHOLD) {
/* Theoretically, we should use substract the duration of the last buffer,
but this demuxer sends no durations on buffers, not sure if it cannot
know, or just does not care to calculate. */
gint32 dpts = pts - *last;
*offset -= dpts * GST_MSECOND;
GST_WARNING_OBJECT (demux,
"Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
}
*last = pts;
}
static GstFlowReturn
gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
{
@ -945,8 +965,12 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
}
}
/* detect (and deem to be resyncs) large pts gaps */
gst_flv_demux_update_resync (demux, pts, &demux->last_audio_pts,
&demux->audio_time_offset);
/* Fill buffer with data */
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
@ -1313,8 +1337,12 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
}
}
/* detect (and deem to be resyncs) large pts gaps */
gst_flv_demux_update_resync (demux, pts, &demux->last_video_pts,
&demux->video_time_offset);
/* Fill buffer with data */
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
@ -1627,6 +1655,8 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
demux->index_max_time = 0;
demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
demux->last_audio_pts = demux->last_video_pts = 0;
demux->audio_time_offset = demux->video_time_offset = 0;
demux->no_more_pads = FALSE;

View file

@ -95,6 +95,8 @@ struct _GstFlvDemux
gboolean audio_linked;
GstBuffer * audio_codec_data;
GstClockTime audio_start;
guint32 last_audio_pts;
GstClockTime audio_time_offset;
/* Video infos */
guint32 w;
@ -109,6 +111,8 @@ struct _GstFlvDemux
gboolean got_par;
GstBuffer * video_codec_data;
GstClockTime video_start;
guint32 last_video_pts;
GstClockTime video_time_offset;
gdouble framerate;
gboolean random_access;