matroskademux: improve reverse playback

Slightly modify approach to also handle cases where cue entries do not reliably
lead to initial keyframes.

Fixes #619817.
This commit is contained in:
Mark Nauwelaerts 2010-05-28 16:37:32 +02:00
parent 69d47ef4a0
commit 44fa95d5cb
3 changed files with 37 additions and 15 deletions

View file

@ -433,8 +433,6 @@ gst_matroska_demux_reset (GstElement * element)
demux->seek_event = NULL; demux->seek_event = NULL;
} }
demux->from_offset = -1;
demux->to_offset = G_MAXINT64;
demux->seek_index = NULL; demux->seek_index = NULL;
demux->seek_entry = 0; demux->seek_entry = 0;
@ -1201,6 +1199,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT | GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
GST_MATROSKA_TRACK_LACING; GST_MATROSKA_TRACK_LACING;
context->last_flow = GST_FLOW_OK; context->last_flow = GST_FLOW_OK;
context->to_offset = G_MAXINT64;
demux->num_streams++; demux->num_streams++;
g_assert (demux->src->len == demux->num_streams); g_assert (demux->src->len == demux->num_streams);
@ -2281,6 +2280,8 @@ static gboolean
gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux, gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
GstMatroskaIndex * entry, gboolean reset) GstMatroskaIndex * entry, gboolean reset)
{ {
gint i;
GST_OBJECT_LOCK (demux); GST_OBJECT_LOCK (demux);
/* seek (relative to matroska segment) */ /* seek (relative to matroska segment) */
@ -2298,9 +2299,16 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
demux->seek_first = TRUE; demux->seek_first = TRUE;
demux->last_stop_end = GST_CLOCK_TIME_NONE; demux->last_stop_end = GST_CLOCK_TIME_NONE;
if (reset) { for (i = 0; i < demux->src->len; i++) {
demux->from_offset = -1; GstMatroskaTrackContext *stream = g_ptr_array_index (demux->src, i);
demux->to_offset = G_MAXINT64;
if (reset) {
stream->to_offset = G_MAXINT64;
} else {
if (stream->from_offset != -1)
stream->to_offset = stream->from_offset;
}
stream->from_offset = -1;
} }
GST_OBJECT_UNLOCK (demux); GST_OBJECT_UNLOCK (demux);
@ -2631,6 +2639,11 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
GST_DEBUG_OBJECT (demux, "stream %d not finished yet", stream->index); GST_DEBUG_OBJECT (demux, "stream %d not finished yet", stream->index);
done = FALSE; done = FALSE;
} }
} else {
/* nothing pushed for this stream;
* likely seek entry did not start at keyframe, so all was skipped.
* So we need an earlier entry */
done = FALSE;
} }
} }
@ -2641,8 +2654,7 @@ gst_matroska_demux_seek_to_previous_keyframe (GstMatroskaDemux * demux)
--demux->seek_entry); --demux->seek_entry);
if (!gst_matroska_demux_move_to_entry (demux, entry, FALSE)) if (!gst_matroska_demux_move_to_entry (demux, entry, FALSE))
goto exit; goto exit;
demux->to_offset = demux->from_offset;
demux->from_offset = -1;
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
} }
@ -4725,7 +4737,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gst_buffer_unref (sub); gst_buffer_unref (sub);
goto eos; goto eos;
} }
if (offset >= demux->to_offset) { if (offset >= stream->to_offset) {
GST_DEBUG_OBJECT (demux, "Stream %d after playback section", GST_DEBUG_OBJECT (demux, "Stream %d after playback section",
stream->index); stream->index);
gst_buffer_unref (sub); gst_buffer_unref (sub);
@ -4824,6 +4836,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
} }
if (stream->set_discont) { if (stream->set_discont) {
GST_DEBUG_OBJECT (demux, "marking DISCONT");
GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DISCONT);
stream->set_discont = FALSE; stream->set_discont = FALSE;
} }
@ -4831,8 +4844,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
/* reverse playback book-keeping */ /* reverse playback book-keeping */
if (!GST_CLOCK_TIME_IS_VALID (stream->from_time)) if (!GST_CLOCK_TIME_IS_VALID (stream->from_time))
stream->from_time = lace_time; stream->from_time = lace_time;
if (demux->from_offset == -1) if (stream->from_offset == -1)
demux->from_offset = offset; stream->from_offset = offset;
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"Pushing lace %d, data of size %d for stream %d, time=%" "Pushing lace %d, data of size %d for stream %d, time=%"
@ -4866,6 +4879,15 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
} }
ret = gst_pad_push (stream->pad, sub); ret = gst_pad_push (stream->pad, sub);
if (demux->segment.rate < 0) {
if (lace_time > demux->segment.stop && ret == GST_FLOW_UNEXPECTED) {
/* In reverse playback we can get a GST_FLOW_UNEXPECTED when
* we are at the end of the segment, so we just need to jump
* back to the previous section. */
GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
ret = GST_FLOW_OK;
}
}
/* combine flows */ /* combine flows */
ret = gst_matroska_demux_combine_flows (demux, stream, ret); ret = gst_matroska_demux_combine_flows (demux, stream, ret);
@ -5560,9 +5582,9 @@ gst_matroska_demux_loop (GstPad * pad)
next: next:
if (G_UNLIKELY (demux->offset == gst_matroska_demux_get_length (demux))) { if (G_UNLIKELY (demux->offset == gst_matroska_demux_get_length (demux))) {
GST_LOG_OBJECT (demux, "Reached end of stream, sending EOS"); GST_LOG_OBJECT (demux, "Reached end of stream");
ret = GST_FLOW_UNEXPECTED; ret = GST_FLOW_UNEXPECTED;
goto pause; goto eos;
} }
return; return;
@ -5573,7 +5595,7 @@ eos:
if (demux->segment.rate < 0.0) { if (demux->segment.rate < 0.0) {
ret = gst_matroska_demux_seek_to_previous_keyframe (demux); ret = gst_matroska_demux_seek_to_previous_keyframe (demux);
if (ret == GST_FLOW_OK) if (ret == GST_FLOW_OK)
goto next; return;
} }
/* fall-through */ /* fall-through */
} }

View file

@ -125,8 +125,6 @@ typedef struct _GstMatroskaDemux {
/* reverse playback */ /* reverse playback */
GArray *seek_index; GArray *seek_index;
gint seek_entry; gint seek_entry;
gint64 from_offset;
gint64 to_offset;
} GstMatroskaDemux; } GstMatroskaDemux;
typedef struct _GstMatroskaDemuxClass { typedef struct _GstMatroskaDemuxClass {

View file

@ -476,6 +476,8 @@ struct _GstMatroskaTrackContext {
GstFlowReturn last_flow; GstFlowReturn last_flow;
/* reverse playback */ /* reverse playback */
GstClockTime from_time; GstClockTime from_time;
gint64 from_offset;
gint64 to_offset;
GArray *index_table; GArray *index_table;