decklink: Implement latency query in sources and remember selected mode

This commit is contained in:
Sebastian Dröge 2014-12-19 12:03:09 +01:00
parent 23d6eaaa10
commit aac0027ed2
5 changed files with 100 additions and 2 deletions

View file

@ -121,6 +121,10 @@ struct _GstDecklinkOutput {
/* Everything below protected by mutex */ /* Everything below protected by mutex */
GMutex lock; GMutex lock;
/* Set by the video source */
/* Configured mode or NULL */
const GstDecklinkMode *mode;
/* Set by the audio sink */ /* Set by the audio sink */
GstClock *audio_clock; GstClock *audio_clock;
@ -141,6 +145,8 @@ struct _GstDecklinkInput {
/* Set by the video source */ /* Set by the video source */
void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstClockTime capture_time); void (*got_video_frame) (GstElement *videosrc, IDeckLinkVideoInputFrame * frame, GstClockTime capture_time);
/* Configured mode or NULL */
const GstDecklinkMode *mode;
/* Set by the audio source */ /* Set by the audio source */
void (*got_audio_packet) (GstElement *videosrc, IDeckLinkAudioInputPacket * packet, GstClockTime capture_time); void (*got_audio_packet) (GstElement *videosrc, IDeckLinkAudioInputPacket * packet, GstClockTime capture_time);

View file

@ -498,8 +498,11 @@ gst_decklink_audio_sink_init (GstDecklinkAudioSink * self)
{ {
self->device_number = 0; self->device_number = 0;
// 25ms latency time seems to be needed at least, // 25.000ms latency time seems to be needed at least,
// everything below can cause drop-outs // everything below can cause drop-outs
// TODO: This is probably related to the video mode that
// is selected, but not directly it seems. Choosing the
// duration of a frame does not work.
GST_AUDIO_BASE_SINK_CAST (self)->latency_time = 25000; GST_AUDIO_BASE_SINK_CAST (self)->latency_time = 25000;
} }

View file

@ -60,6 +60,8 @@ static GstCaps *gst_decklink_audio_src_get_caps (GstBaseSrc * bsrc,
GstCaps * filter); GstCaps * filter);
static gboolean gst_decklink_audio_src_unlock (GstBaseSrc * bsrc); static gboolean gst_decklink_audio_src_unlock (GstBaseSrc * bsrc);
static gboolean gst_decklink_audio_src_unlock_stop (GstBaseSrc * bsrc); static gboolean gst_decklink_audio_src_unlock_stop (GstBaseSrc * bsrc);
static gboolean gst_decklink_audio_src_query (GstBaseSrc * bsrc,
GstQuery * query);
static GstFlowReturn gst_decklink_audio_src_create (GstPushSrc * psrc, static GstFlowReturn gst_decklink_audio_src_create (GstPushSrc * psrc,
GstBuffer ** buffer); GstBuffer ** buffer);
@ -89,6 +91,7 @@ gst_decklink_audio_src_class_init (GstDecklinkAudioSrcClass * klass)
basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_get_caps); basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_get_caps);
basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_set_caps); basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_set_caps);
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_query);
basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_unlock); basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_unlock);
basesrc_class->unlock_stop = basesrc_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_decklink_audio_src_unlock_stop); GST_DEBUG_FUNCPTR (gst_decklink_audio_src_unlock_stop);
@ -333,6 +336,44 @@ gst_decklink_audio_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
return flow_ret; return flow_ret;
} }
static gboolean
gst_decklink_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
{
GstDecklinkAudioSrc *self = GST_DECKLINK_AUDIO_SRC_CAST (bsrc);
gboolean ret = TRUE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:{
if (self->input) {
g_mutex_lock (&self->input->lock);
if (self->input->mode) {
GstClockTime min, max;
min =
gst_util_uint64_scale_ceil (GST_MSECOND, self->input->mode->fps_d,
self->input->mode->fps_n);
max = min;
gst_query_set_latency (query, TRUE, min, max);
ret = TRUE;
} else {
ret = FALSE;
}
g_mutex_unlock (&self->input->lock);
} else {
ret = FALSE;
}
break;
}
default:
ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
break;
}
return ret;
}
static gboolean static gboolean
gst_decklink_audio_src_unlock (GstBaseSrc * bsrc) gst_decklink_audio_src_unlock (GstBaseSrc * bsrc)
{ {

View file

@ -313,6 +313,10 @@ gst_decklink_video_sink_open (GstBaseSink * bsink)
return FALSE; return FALSE;
} }
g_mutex_lock (&self->output->lock);
self->output->mode = mode;
g_mutex_unlock (&self->output->lock);
caps = gst_decklink_mode_get_caps (self->mode); caps = gst_decklink_mode_get_caps (self->mode);
gst_video_info_from_caps (&self->info, caps); gst_video_info_from_caps (&self->info, caps);
gst_caps_unref (caps); gst_caps_unref (caps);
@ -328,6 +332,10 @@ gst_decklink_video_sink_close (GstBaseSink * bsink)
GST_DEBUG_OBJECT (self, "Stopping"); GST_DEBUG_OBJECT (self, "Stopping");
if (self->output) { if (self->output) {
g_mutex_lock (&self->output->lock);
self->output->mode = NULL;
g_mutex_unlock (&self->output->lock);
self->output->output->DisableVideoOutput (); self->output->output->DisableVideoOutput ();
gst_decklink_release_nth_output (self->device_number, gst_decklink_release_nth_output (self->device_number,
GST_ELEMENT_CAST (self), FALSE); GST_ELEMENT_CAST (self), FALSE);

View file

@ -48,6 +48,8 @@ static GstClock *gst_decklink_video_src_provide_clock (GstElement * element);
static GstCaps *gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, static GstCaps *gst_decklink_video_src_get_caps (GstBaseSrc * bsrc,
GstCaps * filter); GstCaps * filter);
static gboolean gst_decklink_video_src_query (GstBaseSrc * bsrc,
GstQuery * query);
static gboolean gst_decklink_video_src_unlock (GstBaseSrc * bsrc); static gboolean gst_decklink_video_src_unlock (GstBaseSrc * bsrc);
static gboolean gst_decklink_video_src_unlock_stop (GstBaseSrc * bsrc); static gboolean gst_decklink_video_src_unlock_stop (GstBaseSrc * bsrc);
@ -79,6 +81,7 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
GST_DEBUG_FUNCPTR (gst_decklink_video_src_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->get_caps = GST_DEBUG_FUNCPTR (gst_decklink_video_src_get_caps);
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_decklink_video_src_query);
basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock); basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock);
basesrc_class->unlock_stop = basesrc_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock_stop); GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock_stop);
@ -197,7 +200,8 @@ gst_decklink_video_src_got_frame (GstElement * element,
{ {
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (element); 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_LOG_OBJECT (self, "Got video frame at %" GST_TIME_FORMAT,
GST_TIME_ARGS (capture_time));
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
if (!self->flushing) { if (!self->flushing) {
@ -276,6 +280,40 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
return flow_ret; return flow_ret;
} }
static gboolean
gst_decklink_video_src_query (GstBaseSrc * bsrc, GstQuery * query)
{
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
gboolean ret = TRUE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:{
if (self->input) {
GstClockTime min, max;
const GstDecklinkMode *mode;
mode = gst_decklink_get_mode (self->mode);
min =
gst_util_uint64_scale_ceil (GST_MSECOND, mode->fps_d, mode->fps_n);
max = min;
gst_query_set_latency (query, TRUE, min, max);
ret = TRUE;
} else {
ret = FALSE;
}
break;
}
default:
ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
break;
}
return ret;
}
static gboolean static gboolean
gst_decklink_video_src_unlock (GstBaseSrc * bsrc) gst_decklink_video_src_unlock (GstBaseSrc * bsrc)
{ {
@ -331,6 +369,7 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
} }
g_mutex_lock (&self->input->lock); g_mutex_lock (&self->input->lock);
self->input->mode = mode;
self->input->got_video_frame = gst_decklink_video_src_got_frame; self->input->got_video_frame = gst_decklink_video_src_got_frame;
g_mutex_unlock (&self->input->lock); g_mutex_unlock (&self->input->lock);
@ -350,6 +389,7 @@ gst_decklink_video_src_close (GstDecklinkVideoSrc * self)
if (self->input) { if (self->input) {
g_mutex_lock (&self->input->lock); g_mutex_lock (&self->input->lock);
self->input->got_video_frame = NULL; self->input->got_video_frame = NULL;
self->input->mode = NULL;
g_mutex_unlock (&self->input->lock); g_mutex_unlock (&self->input->lock);
self->input->input->DisableVideoInput (); self->input->input->DisableVideoInput ();