/* submit a packet to the oggpad, this function will run the
* typefind code for the pad if this is the first packet for this
- * stream
+ * stream
*/
static GstFlowReturn
gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
return ret;
}
-/* flush at most @npackets from the stream layer. All packets if
+/* flush at most @npackets from the stream layer. All packets if
* @npackets is 0;
*/
static GstFlowReturn
}
/* from the current offset, find the previous page, seeking backwards
- * until we find the page.
+ * until we find the page.
*/
static GstFlowReturn
gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
pad->added = FALSE;
}
- /* if we cannot seek back to the chain, we can destroy the chain
+ /* if we cannot seek back to the chain, we can destroy the chain
* completely */
if (!ogg->pullmode) {
gst_ogg_chain_free (chain);
static gboolean
do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
gint64 end, gint64 begintime, gint64 endtime, gint64 target,
- gint64 * offset)
+ gint64 * offset, gboolean only_serial_no, gint serialno)
{
gint64 best;
GstFlowReturn ret;
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 */
pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
if (pad == NULL || pad->map.is_skeleton)
gint64 total;
gint64 result = 0;
GstFlowReturn ret;
- gint i, pending, len;
- gboolean first_parsed_page = TRUE;
+ gint i, pending;
+ gint serialno = 0;
position = segment->last_stop;
target = position - total + begintime;
if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
- &best))
+ &best, FALSE, 0))
goto seek_error;
/* second step: find pages for all streams, we use the keyframe_granule to keep
* track of which ones we saw. If we have seen a page for each stream we can
* calculate the positions of each keyframe. */
GST_DEBUG_OBJECT (ogg, "find keyframes");
- len = pending = chain->streams->len;
+ pending = chain->streams->len;
/* figure out where the keyframes are */
keytarget = target;
continue;
}
- /* we only do this the first time we pass here */
- if (first_parsed_page) {
- /* Now that we have a time reference from the page, we can check
- * whether all streams still have pages from here on.
- *
- * This would be more elegant before the loop, but getting the page from
- * there without breaking anything would be more costly */
- granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
- granulepos);
- for (i = 0; i < len; i++) {
- GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
-
- if (stream == pad)
- /* we already know we have at least one page (the current one)
- * for this stream */
- continue;
-
- if (granule_time > stream->map.total_time)
- /* we won't encounter any more pages of this stream, so we don't
- * try finding a key frame for it */
- pending--;
- }
- first_parsed_page = FALSE;
- }
-
-
/* in reverse we want to go past the page with the lower timestamp */
if (segment->rate < 0.0) {
/* get time for this pad */
/* collect smallest value */
if (keyframe_time != -1) {
keyframe_time += begintime;
- if (keyframe_time < keytarget)
+ if (keyframe_time < keytarget) {
+ serialno = pad->map.serialno;
keytarget = keyframe_time;
+ }
}
next:
/* last step, seek to the location of the keyframe */
if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
- keytarget, &best))
+ keytarget, &best, TRUE, serialno))
goto seek_error;
} else {
/* seek back to previous position */
ogg->segment_running = TRUE;
ogg->seqnum = seqnum;
- /* restart our task since it might have been stopped when we did the
+ /* restart our task since it might have been stopped when we did the
* flush. */
gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
ogg->sinkpad);
granpos there, but it's fairly likely */
position =
ogg->push_byte_length - DURATION_CHUNK_OFFSET - EOS_AVOIDANCE_THRESHOLD;
- if (position < 0)
- position = 0;
+ if (position < 0) {
+ if (ogg->push_byte_length > EOS_AVOIDANCE_THRESHOLD)
+ position = ogg->push_byte_length - (EOS_AVOIDANCE_THRESHOLD / 2);
+ else
+ position = 0;
+ }
GST_DEBUG_OBJECT (ogg,
"Getting duration, seeking near the end, to %" G_GINT64_FORMAT, position);
}
/* read a chain from the ogg file. This code will
- * read all BOS pages and will create and return a GstOggChain
- * structure with the results.
- *
+ * read all BOS pages and will create and return a GstOggChain
+ * structure with the results.
+ *
* This function will also read N pages from each stream in the
* chain and submit them to the decoders. When the decoder has
* decoded the first buffer, we know the timestamp of the first