mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
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:
parent
69d47ef4a0
commit
44fa95d5cb
3 changed files with 37 additions and 15 deletions
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue