mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
decklink: Implement latency query in sources and remember selected mode
This commit is contained in:
parent
23d6eaaa10
commit
aac0027ed2
5 changed files with 100 additions and 2 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 ();
|
||||||
|
|
Loading…
Reference in a new issue