From 33a93a66c82e2fb1c3a72b597643d44f2084b17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Nov 2016 16:12:42 +0200 Subject: [PATCH] decklinkvideosink: Also stop scheduled playback when gst_element_lost_state() is called Unfortunately this does not go through the normal state change machinery, so we don't get notified about this in change_state(). However we need to stop scheduled playback, so that once PLAYING is reached again we can start scheduled playback with the correct time. Without this, flushing seeks in PLAYING will not work correctly: decklinkvideosink will wait before showing the new frames for the amount of time the pipeline was in PLAYING before. --- sys/decklink/gstdecklinkvideosink.cpp | 118 ++++++++++++++++---------- 1 file changed, 74 insertions(+), 44 deletions(-) diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index 6fbcb34a70..c1c93c8c19 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -132,6 +132,9 @@ static void gst_decklink_video_sink_finalize (GObject * object); static GstStateChangeReturn gst_decklink_video_sink_change_state (GstElement * element, GstStateChange transition); +static void +gst_decklink_video_sink_state_changed (GstElement * element, + GstState old_state, GstState new_state, GstState pending_state); static GstClock *gst_decklink_video_sink_provide_clock (GstElement * element); static GstCaps *gst_decklink_video_sink_get_caps (GstBaseSink * bsink, @@ -179,6 +182,8 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass) element_class->change_state = GST_DEBUG_FUNCPTR (gst_decklink_video_sink_change_state); + element_class->state_changed = + GST_DEBUG_FUNCPTR (gst_decklink_video_sink_state_changed); element_class->provide_clock = GST_DEBUG_FUNCPTR (gst_decklink_video_sink_provide_clock); @@ -830,6 +835,60 @@ gst_decklink_video_sink_start_scheduled_playback (GstElement * element) } } +static GstStateChangeReturn +gst_decklink_video_sink_stop_scheduled_playback (GstDecklinkVideoSink * self) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstClockTime start_time; + HRESULT res; + GstClock *clock; + + if (!self->output->started) + return ret; + + clock = gst_element_get_clock (GST_ELEMENT_CAST (self)); + if (clock) { + // FIXME: start time is the same for the complete pipeline, + // but what we need here is the start time of this element! + start_time = gst_element_get_base_time (GST_ELEMENT (self)); + if (start_time != GST_CLOCK_TIME_NONE) + start_time = gst_clock_get_time (clock) - start_time; + + // FIXME: This will probably not work + if (start_time == GST_CLOCK_TIME_NONE) + start_time = 0; + + convert_to_internal_clock (self, &start_time, NULL); + + // The start time is now the running time when we stopped + // playback + + gst_object_unref (clock); + } else { + GST_WARNING_OBJECT (self, + "No clock, stopping scheduled playback immediately"); + start_time = 0; + } + + GST_DEBUG_OBJECT (self, + "Stopping scheduled playback at %" GST_TIME_FORMAT, + GST_TIME_ARGS (start_time)); + + g_mutex_lock (&self->output->lock); + self->output->started = FALSE; + g_mutex_unlock (&self->output->lock); + res = self->output->output->StopScheduledPlayback (start_time, 0, GST_SECOND); + if (res != S_OK) { + GST_ELEMENT_ERROR (self, STREAM, FAILED, + (NULL), ("Failed to stop scheduled playback: 0x%08x", res)); + ret = GST_STATE_CHANGE_FAILURE; + } + self->internal_base_time = GST_CLOCK_TIME_NONE; + self->external_base_time = GST_CLOCK_TIME_NONE; + + return ret; +} + static GstStateChangeReturn gst_decklink_video_sink_change_state (GstElement * element, GstStateChange transition) @@ -896,51 +955,8 @@ gst_decklink_video_sink_change_state (GstElement * element, gst_decklink_video_sink_stop (self); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED:{ - GstClockTime start_time; - HRESULT res; - GstClock *clock; - - clock = gst_element_get_clock (GST_ELEMENT_CAST (self)); - if (clock) { - // FIXME: start time is the same for the complete pipeline, - // but what we need here is the start time of this element! - start_time = gst_element_get_base_time (element); - if (start_time != GST_CLOCK_TIME_NONE) - start_time = gst_clock_get_time (clock) - start_time; - - // FIXME: This will probably not work - if (start_time == GST_CLOCK_TIME_NONE) - start_time = 0; - - convert_to_internal_clock (self, &start_time, NULL); - - // The start time is now the running time when we stopped - // playback - - gst_object_unref (clock); - } else { - GST_WARNING_OBJECT (self, - "No clock, stopping scheduled playback immediately"); - start_time = 0; - } - - GST_DEBUG_OBJECT (self, - "Stopping scheduled playback at %" GST_TIME_FORMAT, - GST_TIME_ARGS (start_time)); - - g_mutex_lock (&self->output->lock); - self->output->started = FALSE; - g_mutex_unlock (&self->output->lock); - res = - self->output->output->StopScheduledPlayback (start_time, 0, - GST_SECOND); - if (res != S_OK) { - GST_ELEMENT_ERROR (self, STREAM, FAILED, - (NULL), ("Failed to stop scheduled playback: 0x%08x", res)); + if (gst_decklink_video_sink_stop_scheduled_playback (self) == GST_STATE_CHANGE_FAILURE) ret = GST_STATE_CHANGE_FAILURE; - } - self->internal_base_time = GST_CLOCK_TIME_NONE; - self->external_base_time = GST_CLOCK_TIME_NONE; break; } case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{ @@ -957,6 +973,20 @@ gst_decklink_video_sink_change_state (GstElement * element, return ret; } +static void +gst_decklink_video_sink_state_changed (GstElement * element, + GstState old_state, GstState new_state, GstState pending_state) +{ + GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (element); + + // Aka gst_element_lost_state() + if (old_state == GST_STATE_PAUSED && + new_state == GST_STATE_PAUSED && pending_state == GST_STATE_PAUSED && + GST_STATE_TARGET (element) == GST_STATE_PLAYING) { + gst_decklink_video_sink_stop_scheduled_playback (self); + } +} + static GstClock * gst_decklink_video_sink_provide_clock (GstElement * element) {