oggdemux: Make bisecting fully accurate

When bisecting after an earliest time has been found, we need
to only consider the stream for which the earliest time was found.

Before, the following scenario could be and was encountered:

a) Find the earliest time for stream X
b) bisect and find a page which granuletime is indeed < target, but
   contains another stream.
c) decide to seek at the wrong offset, sometimes inferior to
   the real one, in which case the error was undected or
d) the offset was superior, and thus the actual target keyframe was
   not processed, and packets were skipped waiting
   for a granulepos.

https://bugzilla.gnome.org/show_bug.cgi?id=700537
This commit is contained in:
Mathieu Duponchelle 2013-07-14 01:42:52 +02:00 committed by Sebastian Dröge
parent affd9f37aa
commit 905fe0f4ca

View file

@ -2695,7 +2695,7 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
static gboolean static gboolean
do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin, do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
gint64 end, gint64 begintime, gint64 endtime, gint64 target, gint64 end, gint64 begintime, gint64 endtime, gint64 target,
gint64 * offset) gint64 * offset, gboolean only_serial_no, gint serialno)
{ {
gint64 best; gint64 best;
GstFlowReturn ret; GstFlowReturn ret;
@ -2769,6 +2769,11 @@ do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
continue; continue;
} }
/* Avoid seeking to an incorrect granuletime by only considering
the stream for which we found the earliest time */
if (only_serial_no && ogg_page_serialno (&og) != serialno)
continue;
/* get the stream */ /* get the stream */
pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og)); pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
if (pad == NULL || pad->map.is_skeleton) if (pad == NULL || pad->map.is_skeleton)
@ -2887,6 +2892,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
gint64 result = 0; gint64 result = 0;
GstFlowReturn ret; GstFlowReturn ret;
gint i, pending; gint i, pending;
gint serialno = 0;
position = segment->position; position = segment->position;
@ -2985,8 +2991,10 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
/* collect smallest value */ /* collect smallest value */
if (keyframe_time != -1) { if (keyframe_time != -1) {
keyframe_time += begintime; keyframe_time += begintime;
if (keyframe_time < keytarget) if (keyframe_time < keytarget) {
serialno = pad->map.serialno;
keytarget = keyframe_time; keytarget = keyframe_time;
}
} }
next: next:
@ -3005,7 +3013,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
/* 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, if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
keytarget, &best)) keytarget, &best, TRUE, serialno))
goto seek_error; goto seek_error;
} else { } else {
/* seek back to previous position */ /* seek back to previous position */