mpegtsdemux: fix timestamps in newsegement event after seeking

This commit is contained in:
Janne Grunau 2011-03-23 18:50:25 +01:00 committed by Edward Hervey
parent cde65d6d6e
commit 9352cfc478

View file

@ -53,6 +53,11 @@
/* maximal PCR time */ /* maximal PCR time */
#define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298) #define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298)
/* seek to SEEK_TIMESTAMP_OFFSET before the desired offset and search then
* either accurately or for the next timestamp
*/
#define SEEK_TIMESTAMP_OFFSET (1000 * GST_MSECOND)
GST_DEBUG_CATEGORY_STATIC (ts_demux_debug); GST_DEBUG_CATEGORY_STATIC (ts_demux_debug);
#define GST_CAT_DEFAULT ts_demux_debug #define GST_CAT_DEFAULT ts_demux_debug
@ -652,8 +657,6 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
GstTSDemux *demux = (GstTSDemux *) base; GstTSDemux *demux = (GstTSDemux *) base;
GstFlowReturn res = GST_FLOW_ERROR; GstFlowReturn res = GST_FLOW_ERROR;
int max_loop_cnt, loop_cnt = 0; int max_loop_cnt, loop_cnt = 0;
double bias = 1.0;
gint64 desired_offset;
gint64 seekpos = 0; gint64 seekpos = 0;
gint64 time_diff; gint64 time_diff;
GstClockTime seektime; GstClockTime seektime;
@ -661,9 +664,9 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
max_loop_cnt = (segment->flags & GST_SEEK_FLAG_ACCURATE) ? 25 : 10; max_loop_cnt = (segment->flags & GST_SEEK_FLAG_ACCURATE) ? 25 : 10;
desired_offset = segment->last_stop; seektime =
MAX (0,
seektime = desired_offset + demux->first_pcr.gsttime; segment->last_stop - SEEK_TIMESTAMP_OFFSET) + demux->first_pcr.gsttime;
seekpcroffset.gsttime = seektime; seekpcroffset.gsttime = seektime;
GST_DEBUG ("seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (seektime)); GST_DEBUG ("seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (seektime));
@ -716,26 +719,28 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
GST_TIME_ARGS (demux->cur_pcr.gsttime), demux->cur_pcr.offset, time_diff); GST_TIME_ARGS (demux->cur_pcr.gsttime), demux->cur_pcr.offset, time_diff);
/* seek loop */ /* seek loop */
while (loop_cnt++ < max_loop_cnt && (time_diff < 0 while (loop_cnt++ < max_loop_cnt && (time_diff > SEEK_TIMESTAMP_OFFSET >> 1)
|| time_diff > 333 * GST_MSECOND)) { && (pcr_stop.gsttime - pcr_start.gsttime > SEEK_TIMESTAMP_OFFSET)) {
gint64 duration = pcr_stop.gsttime - pcr_start.gsttime; gint64 duration = pcr_stop.gsttime - pcr_start.gsttime;
gint64 size = pcr_stop.offset - pcr_start.offset; gint64 size = pcr_stop.offset - pcr_start.offset;
seekpos = if (loop_cnt & 1)
pcr_start.offset + size * bias * ((double) (seektime - seekpos = pcr_start.offset + (size >> 1);
pcr_start.gsttime) / duration); else
seekpos =
pcr_start.offset + size * ((double) (seektime -
pcr_start.gsttime) / duration);
/* look a litle bit behind */ /* look a litle bit behind */
seekpos = seekpos =
MAX (pcr_start.offset + 188, seekpos - 55 * MPEGTS_MAX_PACKETSIZE); MAX (pcr_start.offset + 188, seekpos - 55 * MPEGTS_MAX_PACKETSIZE);
GST_DEBUG ("looking for time: %" GST_TIME_FORMAT " .. %" GST_TIME_FORMAT GST_DEBUG ("looking for time: %" GST_TIME_FORMAT " .. %" GST_TIME_FORMAT
" .. %" GST_TIME_FORMAT " bias = %g", " .. %" GST_TIME_FORMAT,
GST_TIME_ARGS (pcr_start.gsttime), GST_TIME_ARGS (pcr_start.gsttime),
GST_TIME_ARGS (seektime), GST_TIME_ARGS (pcr_stop.gsttime), bias); GST_TIME_ARGS (seektime), GST_TIME_ARGS (pcr_stop.gsttime));
GST_DEBUG ("looking in bytes: %" G_GINT64_FORMAT " .. %" G_GINT64_FORMAT GST_DEBUG ("looking in bytes: %" G_GINT64_FORMAT " .. %" G_GINT64_FORMAT
" .. %" G_GINT64_FORMAT, pcr_start.offset, seekpos, pcr_stop.offset, " .. %" G_GINT64_FORMAT, pcr_start.offset, seekpos, pcr_stop.offset);
bias);
res = res =
find_pcr_packet (&demux->parent, seekpos, 4000 * MPEGTS_MAX_PACKETSIZE, find_pcr_packet (&demux->parent, seekpos, 4000 * MPEGTS_MAX_PACKETSIZE,
@ -755,10 +760,6 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
seekpcroffset.gsttime = calculate_gsttime (&pcr_start, seekpcroffset.pcr); seekpcroffset.gsttime = calculate_gsttime (&pcr_start, seekpcroffset.pcr);
bias =
1.0 + MAX (-.3, MIN (.3,
((double) seektime - seekpcroffset.gsttime) / duration));
/* validate */ /* validate */
if (G_UNLIKELY ((seekpcroffset.gsttime < pcr_start.gsttime) || if (G_UNLIKELY ((seekpcroffset.gsttime < pcr_start.gsttime) ||
(seekpcroffset.gsttime > pcr_stop.gsttime))) { (seekpcroffset.gsttime > pcr_stop.gsttime))) {
@ -774,13 +775,16 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
pcr_start = seekpcroffset; pcr_start = seekpcroffset;
} }
time_diff = seektime - pcr_start.gsttime; time_diff = seektime - pcr_start.gsttime;
GST_DEBUG ("looking: %" GST_TIME_FORMAT " found: %" GST_TIME_FORMAT GST_DEBUG ("seeking: %" GST_TIME_FORMAT " found: %" GST_TIME_FORMAT
" diff = %" G_GINT64_FORMAT, GST_TIME_ARGS (seektime), " diff = %" G_GINT64_FORMAT, GST_TIME_ARGS (seektime),
GST_TIME_ARGS (seekpcroffset.gsttime), time_diff); GST_TIME_ARGS (seekpcroffset.gsttime), time_diff);
} }
GST_DEBUG ("seeking finished after %d loops", loop_cnt); GST_DEBUG ("seeking finished after %d loops", loop_cnt);
/* use correct seek position for the auxiliary search */
seektime += SEEK_TIMESTAMP_OFFSET;
if (segment->flags & GST_SEEK_FLAG_ACCURATE if (segment->flags & GST_SEEK_FLAG_ACCURATE
|| segment->flags & GST_SEEK_FLAG_KEY_UNIT) { || segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
payload_parse_keyframe keyframe_seek = NULL; payload_parse_keyframe keyframe_seek = NULL;
@ -810,17 +814,23 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
pcr_stop.offset - pcr_start.offset, pid, segment->flags, keyframe_seek); pcr_stop.offset - pcr_start.offset, pid, segment->flags, keyframe_seek);
} }
segment->last_stop = seekpcroffset.gsttime;
segment->time = seekpcroffset.gsttime; /* update seektime to the actual timestamp of the found keyframe */
if (segment->flags & GST_SEEK_FLAG_KEY_UNIT)
seektime = seekpcroffset.gsttime;
seektime -= demux->first_pcr.gsttime;
segment->last_stop = seektime;
segment->time = seektime;
/* we stop at the end */ /* we stop at the end */
if (segment->stop == -1) if (segment->stop == -1)
segment->stop = segment->duration; segment->stop = demux->first_pcr.gsttime + segment->duration;
demux->need_newsegment = TRUE; demux->need_newsegment = TRUE;
demux->parent.seek_offset = seekpcroffset.offset; demux->parent.seek_offset = seekpcroffset.offset;
GST_DEBUG ("seeked to postion:%" GST_TIME_FORMAT, GST_DEBUG ("seeked to postion:%" GST_TIME_FORMAT, GST_TIME_ARGS (seektime));
GST_TIME_ARGS (seekpcroffset.gsttime));
res = GST_FLOW_OK; res = GST_FLOW_OK;
done: done:
@ -2223,15 +2233,25 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream)
} }
} }
GST_DEBUG ("segment: tinypts: %" GST_TIME_FORMAT " stop: %" GST_DEBUG ("old segment: tinypts: %" GST_TIME_FORMAT " stop: %"
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT, GST_TIME_FORMAT " time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (tinypts), GST_TIME_ARGS (tinypts),
GST_TIME_ARGS (demux->first_pcr.gsttime + demux->duration), GST_TIME_ARGS (demux->first_pcr.gsttime + demux->duration),
GST_TIME_ARGS (tinypts - demux->first_pcr.gsttime)); GST_TIME_ARGS (tinypts - demux->first_pcr.gsttime));
/* newsegmentevent = */
/* gst_event_new_new_segment (0, 1.0, GST_FORMAT_TIME, tinypts, */
/* demux->first_pcr.gsttime + demux->duration, */
/* tinypts - demux->first_pcr.gsttime); */
GST_DEBUG ("new segment: start: %" GST_TIME_FORMAT " stop: %"
GST_TIME_FORMAT " time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (demux->first_pcr.gsttime + demux->segment.start),
GST_TIME_ARGS (demux->first_pcr.gsttime + demux->segment.duration),
GST_TIME_ARGS (demux->segment.time));
newsegmentevent = newsegmentevent =
gst_event_new_new_segment (0, 1.0, GST_FORMAT_TIME, tinypts, gst_event_new_new_segment (0, 1.0, GST_FORMAT_TIME,
demux->first_pcr.gsttime + demux->duration, demux->first_pcr.gsttime + demux->segment.start,
tinypts - demux->first_pcr.gsttime); demux->first_pcr.gsttime + demux->segment.duration,
demux->segment.time);
push_event ((MpegTSBase *) demux, newsegmentevent); push_event ((MpegTSBase *) demux, newsegmentevent);