oggdemux: improve keyframe seeking

Improve keyframe seeking.
Fix reverse playback.
This commit is contained in:
Wim Taymans 2009-12-07 18:49:43 +01:00
parent c53cd385e3
commit 1ad0e4342e

View file

@ -518,11 +518,18 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
packet->granulepos); packet->granulepos);
GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT, GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT,
pad->current_granule); pad->current_granule);
} else if (pad->current_granule != -1) { } else if (ogg->segment.rate > 0.0 && pad->current_granule != -1) {
pad->current_granule += duration; pad->current_granule += duration;
GST_DEBUG_OBJECT (ogg, "interpollating granule %" G_GUINT64_FORMAT, GST_DEBUG_OBJECT (ogg, "interpollating granule %" G_GUINT64_FORMAT,
pad->current_granule); pad->current_granule);
} }
if (ogg->segment.rate < 0.0 && packet->granulepos == -1) {
/* negative rates, only set timestamp on the packets with a granulepos */
out_timestamp = -1;
out_duration = -1;
out_offset = -1;
out_offset_end = -1;
} else {
/* we only push buffers after we have a valid granule. This is done so that /* we only push buffers after we have a valid granule. This is done so that
* we nicely skip packets without a timestamp after a seek. This is ok * we nicely skip packets without a timestamp after a seek. This is ok
* because we base or seek on the packet after the page with the smaller * because we base or seek on the packet after the page with the smaller
@ -548,6 +555,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
out_offset = out_offset =
gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule); gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule);
} }
}
/* check for invalid buffer sizes */ /* check for invalid buffer sizes */
if (G_UNLIKELY (offset + trim >= packet->bytes)) if (G_UNLIKELY (offset + trim >= packet->bytes))
@ -1705,11 +1713,6 @@ do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
begin = ogg->offset; /* raw offset of next page */ begin = ogg->offset; /* raw offset of next page */
begintime = granuletime; begintime = granuletime;
/*
if (target - begintime > GST_SECOND)
break;
*/
bisect = begin; /* *not* begin + 1 */ bisect = begin; /* *not* begin + 1 */
} else { } else {
if (bisect <= begin + 1) { if (bisect <= begin + 1) {
@ -1757,7 +1760,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
GstOggChain *chain = NULL; GstOggChain *chain = NULL;
gint64 begin, end; gint64 begin, end;
gint64 begintime, endtime; gint64 begintime, endtime;
gint64 target; gint64 target, keytarget;
gint64 best; gint64 best;
gint64 total; gint64 total;
gint64 result = 0; gint64 result = 0;
@ -1795,10 +1798,14 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
GST_DEBUG_OBJECT (ogg, "find keyframes"); GST_DEBUG_OBJECT (ogg, "find keyframes");
len = pending = chain->streams->len; len = pending = chain->streams->len;
/* figure out where the keyframes are */
keytarget = target;
while (TRUE) { while (TRUE) {
ogg_page og; ogg_page og;
gint64 granulepos; gint64 granulepos;
GstOggPad *pad; GstOggPad *pad;
GstClockTime keyframe_time, granule_time;
ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result); ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT, GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
@ -1816,53 +1823,75 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
if (pad->map.is_skeleton) if (pad->map.is_skeleton)
goto next; goto next;
/* we've seen this pad */
if (pad->keyframe_granule != -1)
continue;
granulepos = ogg_page_granulepos (&og); granulepos = ogg_page_granulepos (&og);
if (granulepos == -1) { if (granulepos == -1) {
GST_LOG_OBJECT (ogg, "granulepos of next page is -1"); GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
continue; continue;
} }
/* store granule of this pad */ /* in reverse we want to go past the page with the lower timestamp */
if (segment->rate < 0.0) {
/* get time for this pad */
granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
granulepos);
GST_LOG_OBJECT (ogg,
"looking at page with ts %" GST_TIME_FORMAT ", target %"
GST_TIME_FORMAT, GST_TIME_ARGS (granule_time),
GST_TIME_ARGS (target));
if (granule_time < target)
continue;
}
/* we've seen this pad before */
if (pad->keyframe_granule != -1)
continue;
/* convert granule of this pad to the granule of the keyframe */
pad->keyframe_granule = gst_ogg_stream_granulepos_to_key_granule (&pad->map, pad->keyframe_granule = gst_ogg_stream_granulepos_to_key_granule (&pad->map,
granulepos); granulepos);
GST_LOG_OBJECT (ogg, "marking stream granule %" G_GINT64_FORMAT, GST_LOG_OBJECT (ogg, "marking stream granule %" G_GINT64_FORMAT,
pad->keyframe_granule); pad->keyframe_granule);
/* get time of the keyframe */
keyframe_time =
gst_ogg_stream_granule_to_time (&pad->map, pad->keyframe_granule);
GST_LOG_OBJECT (ogg, "stream %08x granule time %" GST_TIME_FORMAT,
pad->map.serialno, GST_TIME_ARGS (keyframe_time));
/* collect smallest value */
if (keyframe_time != -1 && keyframe_time < keytarget)
keytarget = keyframe_time;
next: next:
pending--; pending--;
if (pending == 0) if (pending == 0)
break; break;
} }
/* figure out where the keyframes are */ /* for negative rates we will get to the keyframe backwards */
for (i = 0; i < chain->streams->len; i++) { if (segment->rate < 0.0)
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); goto done;
GstClockTime granuletime;
granuletime =
gst_ogg_stream_granule_to_time (&pad->map, pad->keyframe_granule);
GST_LOG_OBJECT (ogg, "stream %08x granule time %" GST_TIME_FORMAT,
pad->map.serialno, GST_TIME_ARGS (granuletime));
if (granuletime != -1 && granuletime < target)
target = granuletime;
}
if (keytarget != target) {
GST_LOG_OBJECT (ogg, "final seek to target %" GST_TIME_FORMAT, GST_LOG_OBJECT (ogg, "final seek to target %" GST_TIME_FORMAT,
GST_TIME_ARGS (target)); GST_TIME_ARGS (keytarget));
/* last step, seek to the location of the keyframe */ /* last step, seek to the location of the keyframe */
if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target, if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
&best)) keytarget, &best))
goto seek_error; goto seek_error;
} else {
/* seek back to previous position */
GST_LOG_OBJECT (ogg, "keyframe on target");
gst_ogg_demux_seek (ogg, best);
}
done:
if (keyframe) { if (keyframe) {
segment->time = target; if (segment->rate > 0.0)
segment->last_stop = target - begintime; segment->time = keytarget;
segment->last_stop = keytarget - begintime;
} }
*rchain = chain; *rchain = chain;