From 8596ec23cbf74a46b34ff3541718a1cdf311f370 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 4 Mar 2017 00:27:30 +1100 Subject: [PATCH] oggdemux: Fix reverse playback Fix various issues with reverse playback by clearing tracking vars when working in reverse, and where possible using the timestamp interpolation code to generate timestamps for outgoing buffers. Make sure to mark things as discontinuous only when looping backward to a new position and fix seeking to the next page when starting. --- ext/ogg/gstoggdemux.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index ff2cc61..51c5509 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -676,7 +676,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, packet->granulepos); GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT, pad->current_granule); - } else if (ogg->segment.rate > 0.0 && pad->current_granule != -1) { + } else if (pad->current_granule != -1) { pad->current_granule += duration; if (!delta_unit) { pad->keyframe_granule = pad->current_granule; @@ -684,19 +684,23 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, GST_DEBUG_OBJECT (ogg, "interpolating granule %" G_GUINT64_FORMAT, pad->current_granule); } - if (ogg->segment.rate < 0.0 && packet->granulepos == -1) { - /* negative rates, only set timestamp on the packets with a granulepos */ + + if (ogg->segment.rate < 0.0 && pad->current_granule == -1) { + /* negative rates, allow output of packets with no timestamp, let downstream reconstruct */ out_timestamp = -1; out_duration = -1; out_offset = -1; out_offset_end = -1; + pad->prev_granule = -1; } else { /* 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 - * because we base or seek on the packet after the page with the smaller + * because we base our seek on the packet after the page with the smaller * timestamp. */ - if (pad->current_granule == -1) + if (pad->current_granule == -1) { + pad->prev_granule = -1; goto no_timestamp; + } if (pad->map.is_ogm) { out_timestamp = gst_ogg_stream_granule_to_time (&pad->map, @@ -802,9 +806,8 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, /* Mark discont on the buffer */ if (pad->discont) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - if GST_BUFFER_TIMESTAMP_IS_VALID - (buf) - pad->discont = FALSE; + if (ogg->segment.rate < 0.0 || GST_BUFFER_TIMESTAMP_IS_VALID (buf)) + pad->discont = FALSE; } /* don't push the header packets when we are asked to skip them */ @@ -2100,6 +2103,7 @@ gst_ogg_chain_free (GstOggChain * chain) static void gst_ogg_pad_mark_discont (GstOggPad * pad) { + GST_LOG_OBJECT (pad, "Marking discont on pad"); pad->discont = TRUE; pad->map.last_size = 0; } @@ -3341,8 +3345,12 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment, granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map, granulepos); + /* Convert to stream time */ + granule_time -= pad->start_time; + granule_time += chain->begin_time; + GST_LOG_OBJECT (ogg, - "looking at page with ts %" GST_TIME_FORMAT ", target %" + "looking at page with time %" GST_TIME_FORMAT ", target %" GST_TIME_FORMAT, GST_TIME_ARGS (granule_time), GST_TIME_ARGS (target)); if (granule_time < target) @@ -4435,7 +4443,7 @@ gst_ogg_demux_update_chunk_size (GstOggDemux * ogg, ogg_page * page) } static GstFlowReturn -gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page) +gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page, gboolean discont) { GstOggPad *pad; gint64 granule; @@ -4517,6 +4525,10 @@ gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page) pad = gst_ogg_demux_find_pad (ogg, serialno); } if (pad) { + /* Reset granule interpolation if chaining in reverse (discont = TRUE) */ + if (discont) + pad->current_granule = -1; + result = gst_ogg_pad_submit_page (pad, page); } else { GST_PUSH_LOCK (ogg); @@ -4595,7 +4607,7 @@ gst_ogg_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) /* discontinuity in the pages */ GST_DEBUG_OBJECT (ogg, "discont in page found, continuing"); } else { - result = gst_ogg_demux_handle_page (ogg, &page); + result = gst_ogg_demux_handle_page (ogg, &page, FALSE); if (result < 0) { GST_DEBUG_OBJECT (ogg, "gst_ogg_demux_handle_page returned %d", result); } @@ -4718,7 +4730,9 @@ gst_ogg_demux_loop_reverse (GstOggDemux * ogg) ogg->newsegment = NULL; } - ret = gst_ogg_demux_handle_page (ogg, &page); + GST_LOG_OBJECT (ogg, "Handling page at offset %" G_GINT64_FORMAT, + ogg->offset); + ret = gst_ogg_demux_handle_page (ogg, &page, TRUE); done: return ret; -- 2.7.4