summaryrefslogtreecommitdiff
path: root/sys/decklink
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2015-01-28 14:21:40 +0100
committerSebastian Dröge <sebastian@centricular.com>2015-01-28 16:13:16 +0100
commit00176a1ddf53308936afc1615462c5f992c9d3e0 (patch)
tree342d1201da0f9267a1a30278b8be01b173b51c8c /sys/decklink
parentb3a4772834ed16d48ee0bd79f686581b2d0172e5 (diff)
downloadgstreamer-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.cpp109
-rw-r--r--sys/decklink/gstdecklink.h9
-rw-r--r--sys/decklink/gstdecklinkaudiosink.cpp12
-rw-r--r--sys/decklink/gstdecklinkaudiosrc.cpp5
-rw-r--r--sys/decklink/gstdecklinkvideosink.cpp27
-rw-r--r--sys/decklink/gstdecklinkvideosrc.cpp23
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: