From 5b8e1925b566b57b516c76f12610d42e6ad2b791 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 6 Jan 2014 20:53:15 -0300 Subject: [PATCH] videodecoder: use new segment earlier for reverse playback For reverse playback, the segment event will only be pushed when the first buffer is actually pushed. But for decoding frames and storing those into the list to be pushed the output_segment.rate value is used to determine if it is forward or reverse playback. In case a previous segment event (or none) is in use it will mistakenly think it is doing forward playback and push the buffers immediatelly and try to clip buffers based on an old segment (or an uninitialized one, leading to an assertion) This patch fixes this by copying the segment earlier if on reverse playback https://bugzilla.gnome.org/show_bug.cgi?id=721666 --- gst-libs/gst/video/gstvideodecoder.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/gst-libs/gst/video/gstvideodecoder.c b/gst-libs/gst/video/gstvideodecoder.c index de39b8f360..3565fa878d 100644 --- a/gst-libs/gst/video/gstvideodecoder.c +++ b/gst-libs/gst/video/gstvideodecoder.c @@ -1938,6 +1938,39 @@ gst_video_decoder_flush_parse (GstVideoDecoder * dec, gboolean at_eos) /* move it to the front of the decode queue */ priv->decode = g_list_concat (walk, priv->decode); + /* this is reverse playback, check if we need to apply some segment + * to the output before decoding, as during decoding the segment.rate + * must be used to determine if a buffer should be pushed or added to + * the output list for reverse pushing. + * + * The new segment is not immediately pushed here because we must + * wait for negotiation to happen before it can be pushed to avoid + * pushing a segment before caps event. Negotiation only happens + * when finish_frame is called. + */ + for (walk = frame->events; walk;) { + GList *cur = walk; + GstEvent *event = walk->data; + + walk = g_list_next (walk); + if (GST_EVENT_TYPE (event) <= GST_EVENT_SEGMENT) { + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + GstSegment segment; + + GST_DEBUG_OBJECT (dec, "Segment at frame %p %" GST_TIME_FORMAT, + frame, GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer))); + gst_event_copy_segment (event, &segment); + if (segment.format == GST_FORMAT_TIME) { + dec->output_segment = segment; + } + } + dec->priv->pending_events = + g_list_append (dec->priv->pending_events, event); + frame->events = g_list_delete_link (frame->events, cur); + } + } + /* if we copied a keyframe, flush and decode the decode queue */ if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) { GST_DEBUG_OBJECT (dec, "found keyframe %p with PTS %" GST_TIME_FORMAT