decklinksrc: Stop using the "hardware" timestamps and directly use the pipeline clock

The hardware timestamps have no relation to when frames were produced,
only when frames arrived somewhere in the hardware. Especially there is
no guarantee that audio and video will have the same hardware timestamps
although they belong together, and even more important: the rate with
which the hardware timestamps increase is completely unrelated to the
rate with which the frames are captured!

As such we can as well use the pipeline clock directly and stop doing
complicated calculations. Also as a side effect this allows now running
without any pipeline clock, by directly making use of the stream times
as reported by the driver.

https://bugzilla.gnome.org/show_bug.cgi?id=774850
This commit is contained in:
Sebastian Dröge 2016-11-22 19:30:27 +02:00
parent 423e4593aa
commit 881a08671e
6 changed files with 141 additions and 369 deletions

View file

@ -617,7 +617,6 @@ struct _GstDecklinkClock
{
GstSystemClock clock;
GstDecklinkInput *input;
GstDecklinkOutput *output;
};
@ -722,99 +721,108 @@ public:
GstElement *videosrc = NULL, *audiosrc = NULL;
void (*got_video_frame) (GstElement * videosrc,
IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode,
GstClockTime capture_time, GstClockTime capture_duration, guint hours,
guint minutes, guint seconds, guint frames, BMDTimecodeFlags bflags) =
NULL;
GstClockTime capture_time, GstClockTime stream_time,
GstClockTime stream_duration, guint hours, guint minutes, guint seconds,
guint frames, BMDTimecodeFlags bflags) = NULL;
void (*got_audio_packet) (GstElement * videosrc,
IDeckLinkAudioInputPacket * packet, GstClockTime capture_time,
gboolean discont) = NULL;
GstClockTime packet_time) = NULL;
GstDecklinkModeEnum mode;
BMDTimeValue capture_time = GST_CLOCK_TIME_NONE, capture_duration =
GST_CLOCK_TIME_NONE;
GstClockTime capture_time = GST_CLOCK_TIME_NONE;
GstClockTime base_time;
GstClock *clock = NULL;
HRESULT res;
IDeckLinkTimecode *dtc;
uint8_t hours, minutes, seconds, frames;
BMDTimecodeFlags bflags;
hours = minutes = seconds = frames = bflags = 0;
if (video_frame == NULL)
goto no_video_frame;
res =
video_frame->GetHardwareReferenceTimestamp (GST_SECOND, &capture_time,
&capture_duration);
if (res != S_OK) {
GST_ERROR ("Failed to get capture time: 0x%08x", res);
capture_time = GST_CLOCK_TIME_NONE;
capture_duration = GST_CLOCK_TIME_NONE;
}
if (m_input->videosrc) {
/* FIXME: Avoid circularity between gstdecklink.cpp and
* gstdecklinkvideosrc.cpp */
videosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->videosrc));
res =
video_frame->
GetTimecode (GST_DECKLINK_VIDEO_SRC (videosrc)->timecode_format,
&dtc);
if (res != S_OK) {
GST_DEBUG_OBJECT (videosrc, "Failed to get timecode: 0x%08x", res);
dtc = NULL;
} else {
res = dtc->GetComponents (&hours, &minutes, &seconds, &frames);
if (res != S_OK) {
GST_ERROR ("Could not get components for timecode %p: 0x%08x", dtc,
res);
hours = 0;
minutes = 0;
seconds = 0;
frames = 0;
bflags = 0;
} else {
GST_DEBUG_OBJECT (videosrc, "Got timecode %02d:%02d:%02d:%02d", hours,
minutes, seconds, frames);
bflags = dtc->GetFlags ();
}
}
}
g_mutex_lock (&m_input->lock);
if (capture_time > (BMDTimeValue) m_input->clock_start_time)
capture_time -= m_input->clock_start_time;
else
capture_time = 0;
if (capture_time > (BMDTimeValue) m_input->clock_offset)
capture_time -= m_input->clock_offset;
else
capture_time = 0;
if (m_input->videosrc) {
videosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->videosrc));
clock = gst_element_get_clock (videosrc);
base_time = gst_element_get_base_time (videosrc);
got_video_frame = m_input->got_video_frame;
}
mode = gst_decklink_get_mode_enum_from_bmd (m_input->mode->mode);
if (m_input->audiosrc) {
audiosrc = GST_ELEMENT_CAST (gst_object_ref (m_input->audiosrc));
if (!clock) {
clock = gst_element_get_clock (GST_ELEMENT_CAST (audiosrc));
base_time = gst_element_get_base_time (audiosrc);
}
got_audio_packet = m_input->got_audio_packet;
}
g_mutex_unlock (&m_input->lock);
if (got_video_frame && videosrc) {
got_video_frame (videosrc, video_frame, mode, capture_time,
capture_duration, (guint8) hours, (guint8) minutes, (guint8) seconds,
(guint8) frames, bflags);
if (clock) {
capture_time = gst_clock_get_time (clock);
if (capture_time > base_time)
capture_time -= base_time;
else
capture_time = 0;
}
if (got_video_frame && videosrc && video_frame) {
BMDTimeValue stream_time = GST_CLOCK_TIME_NONE;
BMDTimeValue stream_duration = GST_CLOCK_TIME_NONE;
IDeckLinkTimecode *dtc;
uint8_t hours, minutes, seconds, frames;
BMDTimecodeFlags bflags;
hours = minutes = seconds = frames = bflags = 0;
res =
video_frame->GetStreamTime (&stream_time, &stream_duration,
GST_SECOND);
if (res != S_OK) {
GST_ERROR ("Failed to get stream time: 0x%08x", res);
stream_time = GST_CLOCK_TIME_NONE;
stream_duration = GST_CLOCK_TIME_NONE;
}
if (m_input->videosrc) {
/* FIXME: Avoid circularity between gstdecklink.cpp and
* gstdecklinkvideosrc.cpp */
res =
video_frame->
GetTimecode (GST_DECKLINK_VIDEO_SRC (videosrc)->timecode_format,
&dtc);
if (res != S_OK) {
GST_DEBUG_OBJECT (videosrc, "Failed to get timecode: 0x%08x", res);
dtc = NULL;
} else {
res = dtc->GetComponents (&hours, &minutes, &seconds, &frames);
if (res != S_OK) {
GST_ERROR ("Could not get components for timecode %p: 0x%08x", dtc,
res);
hours = 0;
minutes = 0;
seconds = 0;
frames = 0;
bflags = 0;
} else {
GST_DEBUG_OBJECT (videosrc, "Got timecode %02d:%02d:%02d:%02d",
hours, minutes, seconds, frames);
bflags = dtc->GetFlags ();
}
}
}
got_video_frame (videosrc, video_frame, mode, capture_time,
stream_time, stream_duration, (guint8) hours, (guint8) minutes,
(guint8) seconds, (guint8) frames, bflags);
}
no_video_frame:
if (got_audio_packet && audiosrc && audio_packet) {
BMDTimeValue packet_time = GST_CLOCK_TIME_NONE;
res = audio_packet->GetPacketTime (&packet_time, GST_SECOND);
if (res != S_OK) {
GST_ERROR ("Failed to get stream time: 0x%08x", res);
packet_time = GST_CLOCK_TIME_NONE;
}
m_input->got_audio_packet (audiosrc, audio_packet, capture_time,
m_input->audio_discont);
m_input->audio_discont = FALSE;
packet_time);
} else {
m_input->audio_discont = TRUE;
if (!audio_packet)
GST_DEBUG ("Received no audio packet at %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
@ -822,6 +830,7 @@ public:
gst_object_replace ((GstObject **) & videosrc, NULL);
gst_object_replace ((GstObject **) & audiosrc, NULL);
gst_object_replace ((GstObject **) & clock, NULL);
return S_OK;
}
@ -919,9 +928,6 @@ init_devices (gpointer data)
ret);
} else {
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;
devices[i].input.
input->SetCallback (new GStreamerDecklinkInputCallback (&devices[i].
input));
@ -1073,7 +1079,6 @@ gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
g_mutex_lock (&input->lock);
if (is_audio && !input->audiosrc) {
input->audiosrc = GST_ELEMENT_CAST (gst_object_ref (src));
input->audio_discont = TRUE;
g_mutex_unlock (&input->lock);
return input;
} else if (!input->videosrc) {
@ -1148,88 +1153,46 @@ gst_decklink_clock_get_internal_time (GstClock * clock)
BMDTimeValue time;
HRESULT ret;
if (self->input != NULL) {
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;
}
result += self->input->clock_epoch;
g_mutex_unlock (&self->input->lock);
} else if (self->output != NULL) {
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;
}
result += self->output->clock_epoch;
g_mutex_unlock (&self->output->lock);
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 {
g_assert_not_reached ();
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;
}
result += self->output->clock_epoch;
g_mutex_unlock (&self->output->lock);
GST_LOG_OBJECT (clock,
"result %" GST_TIME_FORMAT " time %" GST_TIME_FORMAT " last time %"
GST_TIME_FORMAT " offset %" GST_TIME_FORMAT " start time %"

View file

@ -196,25 +196,21 @@ struct _GstDecklinkInput {
IDeckLinkInput *input;
IDeckLinkConfiguration *config;
IDeckLinkAttributes *attributes;
GstClock *clock;
GstClockTime clock_start_time, clock_offset, clock_last_time, clock_epoch;
gboolean started, clock_restart;
/* Everything below protected by mutex */
GMutex lock;
/* Set by the video source */
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode, GstClockTime capture_time, GstClockTime capture_duration, guint hours, guint minutes, guint seconds, guint frames, BMDTimecodeFlags bflags);
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode, GstClockTime capture_time, GstClockTime stream_time, GstClockTime stream_duration, guint hours, guint minutes, guint seconds, guint frames, BMDTimecodeFlags bflags);
/* Configured mode or NULL */
const GstDecklinkMode *mode;
BMDPixelFormat format;
/* Set by the audio source */
void (*got_audio_packet) (GstElement *videosrc, IDeckLinkAudioInputPacket * packet, GstClockTime capture_time, gboolean discont);
void (*got_audio_packet) (GstElement *videosrc, IDeckLinkAudioInputPacket * packet, GstClockTime capture_time, GstClockTime packet_time);
GstElement *audiosrc;
gboolean audio_enabled;
gboolean audio_discont;
GstElement *videosrc;
gboolean video_enabled;
void (*start_streams) (GstElement *videosrc);

View file

@ -57,7 +57,6 @@ typedef struct
{
IDeckLinkAudioInputPacket *packet;
GstClockTime capture_time;
gboolean discont;
} CapturePacket;
static void
@ -422,27 +421,13 @@ gst_decklink_audio_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
static void
gst_decklink_audio_src_got_packet (GstElement * element,
IDeckLinkAudioInputPacket * packet, GstClockTime capture_time,
gboolean discont)
GstClockTime packet_time)
{
GstDecklinkAudioSrc *self = GST_DECKLINK_AUDIO_SRC_CAST (element);
GstDecklinkVideoSrc *videosrc = NULL;
GST_LOG_OBJECT (self, "Got audio packet at %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
g_mutex_lock (&self->input->lock);
if (self->input->videosrc)
videosrc =
GST_DECKLINK_VIDEO_SRC_CAST (gst_object_ref (self->input->videosrc));
g_mutex_unlock (&self->input->lock);
if (videosrc) {
gst_decklink_video_src_convert_to_external_clock (videosrc, &capture_time,
NULL);
gst_object_unref (videosrc);
GST_LOG_OBJECT (self, "Actual timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
}
GST_LOG_OBJECT (self,
"Got audio packet at %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time), GST_TIME_ARGS (packet_time));
g_mutex_lock (&self->lock);
if (!self->flushing) {
@ -457,8 +442,8 @@ gst_decklink_audio_src_got_packet (GstElement * element,
p = (CapturePacket *) g_malloc0 (sizeof (CapturePacket));
p->packet = packet;
p->capture_time = capture_time;
p->discont = discont;
p->capture_time =
capture_time != GST_CLOCK_TIME_NONE ? capture_time : packet_time;
packet->AddRef ();
g_queue_push_tail (&self->current_packets, p);
g_cond_signal (&self->cond);
@ -523,7 +508,6 @@ retry:
ap->input->AddRef ();
timestamp = p->capture_time;
discont = p->discont;
// Jitter and discontinuity handling, based on audiobasesrc
start_time = timestamp;
@ -538,7 +522,7 @@ retry:
duration = end_time - start_time;
if (discont || self->next_offset == (guint64) - 1) {
if (self->next_offset == (guint64) - 1) {
discont = TRUE;
} else {
guint64 diff, max_sample_diff;

View file

@ -955,7 +955,8 @@ gst_decklink_video_sink_change_state (GstElement * element,
gst_decklink_video_sink_stop (self);
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:{
if (gst_decklink_video_sink_stop_scheduled_playback (self) == GST_STATE_CHANGE_FAILURE)
if (gst_decklink_video_sink_stop_scheduled_playback (self) ==
GST_STATE_CHANGE_FAILURE)
ret = GST_STATE_CHANGE_FAILURE;
break;
}

View file

@ -89,7 +89,6 @@ static void gst_decklink_video_src_finalize (GObject * object);
static GstStateChangeReturn
gst_decklink_video_src_change_state (GstElement * element,
GstStateChange transition);
static GstClock *gst_decklink_video_src_provide_clock (GstElement * element);
static gboolean gst_decklink_video_src_set_caps (GstBaseSrc * bsrc,
GstCaps * caps);
@ -128,8 +127,6 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_decklink_video_src_change_state);
element_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_decklink_video_src_provide_clock);
basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_decklink_video_src_get_caps);
basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_decklink_video_src_set_caps);
@ -434,97 +431,19 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
return caps;
}
void
gst_decklink_video_src_convert_to_external_clock (GstDecklinkVideoSrc * self,
GstClockTime * timestamp, GstClockTime * duration)
{
GstClock *clock;
g_assert (timestamp != NULL);
if (*timestamp == GST_CLOCK_TIME_NONE)
return;
clock = gst_element_get_clock (GST_ELEMENT_CAST (self));
if (clock && clock != self->input->clock) {
GstClockTime internal, external, rate_n, rate_d;
GstClockTimeDiff external_start_time_diff;
gst_clock_get_calibration (self->input->clock, &internal, &external,
&rate_n, &rate_d);
if (rate_n != rate_d && self->internal_base_time != GST_CLOCK_TIME_NONE) {
GstClockTime internal_timestamp = *timestamp;
// Convert to the running time corresponding to both clock times
internal -= self->internal_base_time;
external -= self->external_base_time;
// Get the difference in the internal time, note
// that the capture time is internal time.
// Then scale this difference and offset it to
// our external time. Now we have the running time
// according to our external clock.
//
// For the duration we just scale
*timestamp =
gst_clock_adjust_with_calibration (NULL, internal_timestamp, internal,
external, rate_n, rate_d);
GST_LOG_OBJECT (self,
"Converted %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT " (external: %"
GST_TIME_FORMAT " internal %" GST_TIME_FORMAT " rate: %lf)",
GST_TIME_ARGS (internal_timestamp), GST_TIME_ARGS (*timestamp),
GST_TIME_ARGS (external), GST_TIME_ARGS (internal),
((gdouble) rate_n) / ((gdouble) rate_d));
if (duration) {
GstClockTime internal_duration = *duration;
*duration = gst_util_uint64_scale (internal_duration, rate_d, rate_n);
GST_LOG_OBJECT (self,
"Converted duration %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
" (external: %" GST_TIME_FORMAT " internal %" GST_TIME_FORMAT
" rate: %lf)", GST_TIME_ARGS (internal_duration),
GST_TIME_ARGS (*duration), GST_TIME_ARGS (external),
GST_TIME_ARGS (internal), ((gdouble) rate_n) / ((gdouble) rate_d));
}
} else {
GST_LOG_OBJECT (self, "No clock conversion needed, relative rate is 1.0");
}
// Add the diff between the external time when we
// went to playing and the external time when the
// pipeline went to playing. Otherwise we will
// always start outputting from 0 instead of the
// current running time.
external_start_time_diff =
gst_element_get_base_time (GST_ELEMENT_CAST (self));
external_start_time_diff =
self->external_base_time - external_start_time_diff;
*timestamp += external_start_time_diff;
} else {
GST_LOG_OBJECT (self, "No clock conversion needed, same clocks");
}
}
static void
gst_decklink_video_src_got_frame (GstElement * element,
IDeckLinkVideoInputFrame * frame, GstDecklinkModeEnum mode,
GstClockTime capture_time, GstClockTime capture_duration, guint hours,
guint minutes, guint seconds, guint frames, BMDTimecodeFlags bflags)
GstClockTime capture_time, GstClockTime stream_time,
GstClockTime stream_duration, guint hours, guint minutes, guint seconds,
guint frames, BMDTimecodeFlags bflags)
{
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (element);
GST_LOG_OBJECT (self, "Got video frame at %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
gst_decklink_video_src_convert_to_external_clock (self, &capture_time,
&capture_duration);
GST_LOG_OBJECT (self, "Actual timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
GST_LOG_OBJECT (self,
"Got video frame at %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT " (%"
GST_TIME_FORMAT ")", GST_TIME_ARGS (capture_time),
GST_TIME_ARGS (stream_time), GST_TIME_ARGS (stream_duration));
g_mutex_lock (&self->lock);
if (!self->flushing) {
@ -542,8 +461,9 @@ gst_decklink_video_src_got_frame (GstElement * element,
f = (CaptureFrame *) g_malloc0 (sizeof (CaptureFrame));
f->frame = frame;
f->capture_time = capture_time;
f->capture_duration = capture_duration;
f->capture_time =
capture_time != GST_CLOCK_TIME_NONE ? capture_time : stream_time;
f->capture_duration = stream_duration;
f->mode = mode;
f->format = frame->GetPixelFormat ();
bmode = gst_decklink_get_mode (mode);
@ -659,7 +579,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
vf->input = self->input->input;
vf->input->AddRef ();
flags = f->frame->GetFlags();
flags = f->frame->GetFlags ();
if (flags & bmdFrameHasNoInputSource) {
if (!self->no_signal) {
self->no_signal = TRUE;
@ -771,10 +691,6 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
self->input->mode = mode;
self->input->got_video_frame = gst_decklink_video_src_got_frame;
self->input->start_streams = gst_decklink_video_src_start_streams;
self->input->clock_start_time = GST_CLOCK_TIME_NONE;
self->input->clock_epoch += self->input->clock_last_time;
self->input->clock_last_time = 0;
self->input->clock_offset = 0;
g_mutex_unlock (&self->input->lock);
return TRUE;
@ -832,42 +748,14 @@ gst_decklink_video_src_start_streams (GstElement * element)
|| self->input->audio_enabled)
&& (GST_STATE (self) == GST_STATE_PLAYING
|| GST_STATE_PENDING (self) == GST_STATE_PLAYING)) {
GstClock *clock;
clock = gst_element_get_clock (element);
if (!clock) {
GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL),
("Streams supposed to start but we have no clock"));
return;
}
GST_DEBUG_OBJECT (self, "Starting streams");
res = self->input->input->StartStreams ();
if (res != S_OK) {
GST_ELEMENT_ERROR (self, STREAM, FAILED,
(NULL), ("Failed to start streams: 0x%08x", res));
gst_object_unref (clock);
return;
}
self->input->started = TRUE;
self->input->clock_restart = TRUE;
// Need to unlock to get the clock time
g_mutex_unlock (&self->input->lock);
// Current times of internal and external clock when we go to
// playing. We need this to convert the pipeline running time
// to the running time of the hardware
//
// We can't use the normal base time for the external clock
// because we might go to PLAYING later than the pipeline
self->internal_base_time = gst_clock_get_internal_time (self->input->clock);
self->external_base_time = gst_clock_get_internal_time (clock);
gst_object_unref (clock);
g_mutex_lock (&self->input->lock);
} else {
GST_DEBUG_OBJECT (self, "Not starting streams yet");
}
@ -893,35 +781,8 @@ 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_epoch += self->input->clock_last_time;
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));
self->flushing = FALSE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{
GstClock *clock;
clock = gst_element_get_clock (GST_ELEMENT_CAST (self));
if (clock) {
if (clock != self->input->clock) {
gst_clock_set_master (self->input->clock, clock);
}
gst_object_unref (clock);
} else {
GST_ELEMENT_ERROR (self, STREAM, FAILED,
(NULL), ("Need a clock to go to PLAYING"));
ret = GST_STATE_CHANGE_FAILURE;
}
break;
}
default:
break;
}
@ -934,19 +795,7 @@ gst_decklink_video_src_change_state (GstElement * element,
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_element_post_message (element,
gst_message_new_clock_lost (GST_OBJECT_CAST (element),
self->input->clock));
gst_clock_set_master (self->input->clock, NULL);
// Reset calibration to make the clock reusable next time we use it
gst_clock_set_calibration (self->input->clock, 0, 0, 1, 1);
g_mutex_lock (&self->input->lock);
self->input->clock_start_time = GST_CLOCK_TIME_NONE;
self->input->clock_epoch += self->input->clock_last_time;
self->input->clock_last_time = 0;
self->input->clock_offset = 0;
self->no_signal = FALSE;
g_mutex_unlock (&self->input->lock);
gst_decklink_video_src_stop (self);
break;
@ -954,9 +803,6 @@ 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) {
@ -964,8 +810,6 @@ gst_decklink_video_src_change_state (GstElement * element,
(NULL), ("Failed to stop streams: 0x%08x", res));
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:{
@ -986,14 +830,3 @@ out:
return ret;
}
static GstClock *
gst_decklink_video_src_provide_clock (GstElement * element)
{
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (element);
if (!self->input)
return NULL;
return GST_CLOCK_CAST (gst_object_ref (self->input->clock));
}

View file

@ -69,9 +69,6 @@ struct _GstDecklinkVideoSrc
gboolean no_signal;
guint buffer_size;
GstClockTime internal_base_time;
GstClockTime external_base_time;
};
struct _GstDecklinkVideoSrcClass
@ -80,8 +77,6 @@ struct _GstDecklinkVideoSrcClass
};
GType gst_decklink_video_src_get_type (void);
void gst_decklink_video_src_convert_to_external_clock (GstDecklinkVideoSrc * self,
GstClockTime * timestamp, GstClockTime * duration);
G_END_DECLS