diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2015-01-28 14:21:40 +0100 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2015-01-28 16:13:16 +0100 |
commit | 00176a1ddf53308936afc1615462c5f992c9d3e0 (patch) | |
tree | 342d1201da0f9267a1a30278b8be01b173b51c8c /sys/decklink | |
parent | b3a4772834ed16d48ee0bd79f686581b2d0172e5 (diff) | |
download | gstreamer-plugins-bad-00176a1ddf53308936afc1615462c5f992c9d3e0.tar.gz |
decklink: Make sure our clock never returns NONE, always advances and does not jump when going from PAUSED to PLAYING
It basically behaves the same as the audio clocks.
Diffstat (limited to 'sys/decklink')
-rw-r--r-- | sys/decklink/gstdecklink.cpp | 109 | ||||
-rw-r--r-- | sys/decklink/gstdecklink.h | 9 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkaudiosink.cpp | 12 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkaudiosrc.cpp | 5 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkvideosink.cpp | 27 | ||||
-rw-r--r-- | sys/decklink/gstdecklinkvideosrc.cpp | 23 |
6 files changed, 162 insertions, 23 deletions
diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp index 1c3f4493e..a06b812af 100644 --- a/sys/decklink/gstdecklink.cpp +++ b/sys/decklink/gstdecklink.cpp @@ -378,8 +378,8 @@ struct _GstDecklinkClock { GstSystemClock clock; - IDeckLinkInput *input; - IDeckLinkOutput *output; + GstDecklinkInput *input; + GstDecklinkOutput *output; }; struct _GstDecklinkClockClass @@ -589,7 +589,7 @@ init_devices (gpointer data) devices[i].input.device = decklink; devices[i].input.clock = gst_decklink_clock_new ("GstDecklinkInputClock"); GST_DECKLINK_CLOCK_CAST (devices[i].input.clock)->input = - devices[i].input.input; + &devices[i].input; devices[i].input. input->SetCallback (new GStreamerDecklinkInputCallback (&devices[i]. input)); @@ -604,7 +604,7 @@ init_devices (gpointer data) devices[i].output.clock = gst_decklink_clock_new ("GstDecklinkOutputClock"); GST_DECKLINK_CLOCK_CAST (devices[i].output.clock)->output = - devices[i].output.output; + &devices[i].output; } ret = decklink->QueryInterface (IID_IDeckLinkConfiguration, @@ -806,30 +806,97 @@ static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock) { GstDecklinkClock *self = GST_DECKLINK_CLOCK (clock); - GstClockTime result; + GstClockTime result, start_time, last_time; + GstClockTimeDiff offset; BMDTimeValue time; HRESULT ret; - GST_OBJECT_LOCK (clock); if (self->input != NULL) { - ret = - self->input->GetHardwareReferenceClock (GST_SECOND, &time, NULL, NULL); - if (ret == S_OK && time >= 0) - result = time; - else - result = GST_CLOCK_TIME_NONE; + g_mutex_lock (&self->input->lock); + start_time = self->input->clock_start_time; + offset = self->input->clock_offset; + last_time = self->input->clock_last_time; + time = -1; + if (!self->input->started) { + result = last_time; + ret = -1; + } else { + ret = + self->input->input->GetHardwareReferenceClock (GST_SECOND, &time, + NULL, NULL); + if (ret == S_OK && time >= 0) { + result = time; + if (start_time == GST_CLOCK_TIME_NONE) + start_time = self->input->clock_start_time = result; + + if (result > start_time) + result -= start_time; + else + result = 0; + + if (self->input->clock_restart) { + self->input->clock_offset = result - last_time; + offset = self->input->clock_offset; + self->input->clock_restart = FALSE; + } + result = MAX (last_time, result); + result -= offset; + result = MAX (last_time, result); + } else { + result = last_time; + } + + self->input->clock_last_time = result; + } + g_mutex_unlock (&self->input->lock); } else if (self->output != NULL) { - ret = - self->output->GetHardwareReferenceClock (GST_SECOND, &time, NULL, NULL); - if (ret == S_OK && time >= 0) - result = time; - else - result = GST_CLOCK_TIME_NONE; + g_mutex_lock (&self->output->lock); + start_time = self->output->clock_start_time; + offset = self->output->clock_offset; + last_time = self->output->clock_last_time; + time = -1; + if (!self->output->started) { + result = last_time; + ret = -1; + } else { + ret = + self->output->output->GetHardwareReferenceClock (GST_SECOND, &time, + NULL, NULL); + if (ret == S_OK && time >= 0) { + result = time; + + if (start_time == GST_CLOCK_TIME_NONE) + start_time = self->output->clock_start_time = result; + + if (result > start_time) + result -= start_time; + else + result = 0; + + if (self->output->clock_restart) { + self->output->clock_offset = result - last_time; + offset = self->output->clock_offset; + self->output->clock_restart = FALSE; + } + result = MAX (last_time, result); + result -= offset; + result = MAX (last_time, result); + } else { + result = last_time; + } + + self->output->clock_last_time = result; + } + g_mutex_unlock (&self->output->lock); } else { - result = GST_CLOCK_TIME_NONE; + g_assert_not_reached (); } - GST_OBJECT_UNLOCK (clock); - GST_LOG_OBJECT (clock, "result %" GST_TIME_FORMAT, GST_TIME_ARGS (result)); + GST_LOG_OBJECT (clock, + "result %" GST_TIME_FORMAT " time %" GST_TIME_FORMAT " last time %" + GST_TIME_FORMAT " offset %" GST_TIME_FORMAT " start time %" + GST_TIME_FORMAT " (ret: 0x%08x)", GST_TIME_ARGS (result), + GST_TIME_ARGS (time), GST_TIME_ARGS (last_time), GST_TIME_ARGS (offset), + GST_TIME_ARGS (start_time), ret); return result; } diff --git a/sys/decklink/gstdecklink.h b/sys/decklink/gstdecklink.h index 58508d8a4..c85f8b24e 100644 --- a/sys/decklink/gstdecklink.h +++ b/sys/decklink/gstdecklink.h @@ -134,6 +134,9 @@ struct _GstDecklinkOutput { IDeckLink *device; IDeckLinkOutput *output; GstClock *clock; + GstClockTime clock_start_time, clock_last_time; + GstClockTimeDiff clock_offset; + gboolean started, clock_restart; /* Everything below protected by mutex */ GMutex lock; @@ -147,7 +150,9 @@ struct _GstDecklinkOutput { /* <private> */ GstElement *audiosink; + gboolean audio_enabled; GstElement *videosink; + gboolean video_enabled; }; typedef struct _GstDecklinkInput GstDecklinkInput; @@ -157,6 +162,8 @@ struct _GstDecklinkInput { IDeckLinkConfiguration *config; IDeckLinkAttributes *attributes; GstClock *clock; + GstClockTime clock_start_time, clock_offset, clock_last_time; + gboolean started, clock_restart; /* Everything below protected by mutex */ GMutex lock; @@ -171,7 +178,9 @@ struct _GstDecklinkInput { /* <private> */ GstElement *audiosrc; + gboolean audio_enabled; GstElement *videosrc; + gboolean video_enabled; }; GstDecklinkOutput * gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio); diff --git a/sys/decklink/gstdecklinkaudiosink.cpp b/sys/decklink/gstdecklinkaudiosink.cpp index 2906470ce..61ff6bbca 100644 --- a/sys/decklink/gstdecklinkaudiosink.cpp +++ b/sys/decklink/gstdecklinkaudiosink.cpp @@ -361,6 +361,10 @@ gst_decklink_audio_sink_ringbuffer_acquire (GstAudioRingBuffer * rb, return FALSE; } + g_mutex_lock (&self->output->lock); + self->output->audio_enabled = TRUE; + g_mutex_unlock (&self->output->lock); + ret = self->output-> output->SetAudioCallback (new GStreamerAudioOutputCallback (self)); @@ -391,9 +395,13 @@ gst_decklink_audio_sink_ringbuffer_release (GstAudioRingBuffer * rb) GST_DEBUG_OBJECT (self->sink, "Release"); - if (self->output) - self->output->output->DisableAudioOutput (); + if (self->output) { + g_mutex_lock (&self->output->lock); + self->output->audio_enabled = FALSE; + g_mutex_unlock (&self->output->lock); + self->output->output->DisableAudioOutput (); + } // free the buffer g_free (rb->memory); rb->memory = NULL; diff --git a/sys/decklink/gstdecklinkaudiosrc.cpp b/sys/decklink/gstdecklinkaudiosrc.cpp index f46076e02..99b8a0fc3 100644 --- a/sys/decklink/gstdecklinkaudiosrc.cpp +++ b/sys/decklink/gstdecklinkaudiosrc.cpp @@ -379,6 +379,10 @@ gst_decklink_audio_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) return FALSE; } + g_mutex_lock (&self->input->lock); + self->input->audio_enabled = TRUE; + g_mutex_unlock (&self->input->lock); + return TRUE; } @@ -652,6 +656,7 @@ gst_decklink_audio_src_close (GstDecklinkAudioSrc * self) if (self->input) { g_mutex_lock (&self->input->lock); self->input->got_audio_packet = NULL; + self->input->audio_enabled = FALSE; g_mutex_unlock (&self->input->lock); self->input->input->DisableAudioInput (); diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index abaa5453e..741c655cb 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -287,6 +287,7 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) g_mutex_lock (&self->output->lock); self->output->mode = mode; + self->output->video_enabled = TRUE; g_mutex_unlock (&self->output->lock); return TRUE; @@ -527,6 +528,9 @@ gst_decklink_video_sink_open (GstBaseSink * bsink) g_mutex_lock (&self->output->lock); self->output->mode = mode; + self->output->clock_start_time = GST_CLOCK_TIME_NONE; + self->output->clock_last_time = 0; + self->output->clock_offset = 0; g_mutex_unlock (&self->output->lock); return TRUE; @@ -542,6 +546,7 @@ gst_decklink_video_sink_close (GstBaseSink * bsink) if (self->output) { g_mutex_lock (&self->output->lock); self->output->mode = NULL; + self->output->video_enabled = FALSE; g_mutex_unlock (&self->output->lock); self->output->output->DisableVideoOutput (); @@ -563,6 +568,11 @@ gst_decklink_video_sink_change_state (GstElement * element, switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: + g_mutex_lock (&self->output->lock); + self->output->clock_start_time = GST_CLOCK_TIME_NONE; + self->output->clock_last_time = 0; + self->output->clock_offset = 0; + g_mutex_unlock (&self->output->lock); gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->output->clock, TRUE)); @@ -597,6 +607,11 @@ gst_decklink_video_sink_change_state (GstElement * element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->output->clock)); gst_clock_set_master (self->output->clock, NULL); + g_mutex_lock (&self->output->lock); + self->output->clock_start_time = GST_CLOCK_TIME_NONE; + self->output->clock_last_time = 0; + self->output->clock_offset = 0; + g_mutex_unlock (&self->output->lock); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED:{ GstClockTime start_time; @@ -620,6 +635,10 @@ gst_decklink_video_sink_change_state (GstElement * element, 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); @@ -665,6 +684,10 @@ gst_decklink_video_sink_change_state (GstElement * element, if (active) { GST_DEBUG_OBJECT (self, "Stopping scheduled playback"); + g_mutex_lock (&self->output->lock); + self->output->started = FALSE; + g_mutex_unlock (&self->output->lock); + res = self->output->output->StopScheduledPlayback (0, 0, 0); if (res != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, @@ -686,6 +709,10 @@ gst_decklink_video_sink_change_state (GstElement * element, (NULL), ("Failed to start scheduled playback: 0x%08x", res)); ret = GST_STATE_CHANGE_FAILURE; } + g_mutex_lock (&self->output->lock); + self->output->started = TRUE; + self->output->clock_restart = TRUE; + g_mutex_unlock (&self->output->lock); break; } default: diff --git a/sys/decklink/gstdecklinkvideosrc.cpp b/sys/decklink/gstdecklinkvideosrc.cpp index 8d17419f7..095a7c65f 100644 --- a/sys/decklink/gstdecklinkvideosrc.cpp +++ b/sys/decklink/gstdecklinkvideosrc.cpp @@ -328,6 +328,7 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) g_mutex_lock (&self->input->lock); self->input->mode = mode; + self->input->video_enabled = TRUE; g_mutex_unlock (&self->input->lock); return TRUE; @@ -550,6 +551,9 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self) g_mutex_lock (&self->input->lock); self->input->mode = mode; self->input->got_video_frame = gst_decklink_video_src_got_frame; + self->input->clock_start_time = GST_CLOCK_TIME_NONE; + self->input->clock_last_time = 0; + self->input->clock_offset = 0; g_mutex_unlock (&self->input->lock); return TRUE; @@ -565,6 +569,7 @@ gst_decklink_video_src_close (GstDecklinkVideoSrc * self) g_mutex_lock (&self->input->lock); self->input->got_video_frame = NULL; self->input->mode = NULL; + self->input->video_enabled = FALSE; g_mutex_unlock (&self->input->lock); self->input->input->DisableVideoInput (); @@ -592,6 +597,11 @@ gst_decklink_video_src_change_state (GstElement * element, } break; case GST_STATE_CHANGE_READY_TO_PAUSED: + g_mutex_lock (&self->input->lock); + self->input->clock_start_time = GST_CLOCK_TIME_NONE; + self->input->clock_last_time = 0; + self->input->clock_offset = 0; + g_mutex_unlock (&self->input->lock); gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), self->input->clock, TRUE)); @@ -623,6 +633,11 @@ gst_decklink_video_src_change_state (GstElement * element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), self->input->clock)); gst_clock_set_master (self->input->clock, NULL); + g_mutex_lock (&self->input->lock); + self->input->clock_start_time = GST_CLOCK_TIME_NONE; + self->input->clock_last_time = 0; + self->input->clock_offset = 0; + g_mutex_unlock (&self->input->lock); g_queue_foreach (&self->current_frames, (GFunc) capture_frame_free, NULL); g_queue_clear (&self->current_frames); @@ -632,6 +647,10 @@ gst_decklink_video_src_change_state (GstElement * element, HRESULT res; GST_DEBUG_OBJECT (self, "Stopping streams"); + g_mutex_lock (&self->input->lock); + self->input->started = FALSE; + g_mutex_unlock (&self->input->lock); + res = self->input->input->StopStreams (); if (res != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, @@ -650,6 +669,10 @@ gst_decklink_video_src_change_state (GstElement * element, (NULL), ("Failed to start streams: 0x%08x", res)); ret = GST_STATE_CHANGE_FAILURE; } + g_mutex_lock (&self->input->lock); + self->input->started = TRUE; + self->input->clock_restart = TRUE; + g_mutex_unlock (&self->input->lock); break; } case GST_STATE_CHANGE_READY_TO_NULL: |