decklinkaudiosrc/decklinkvideosrc: Do nothing in BaseSrc::negotiate() and always set caps in ::create()

We don't support negotiation with downstream but simply set caps based
on the buffers we receive. This prevents renegotiation to other formats,
and negotiation to NTSC in mode=auto in the beginning until the first
buffer is received.

As side-effect of this, also remove various other caps handling code
that was working around the behaviour of the default
BaseSrc::negotiate().
This commit is contained in:
Sebastian Dröge 2019-08-06 21:44:35 +03:00 committed by Mathieu Duponchelle
parent 8257159909
commit ab8bd0aa44
2 changed files with 64 additions and 131 deletions

View file

@ -123,10 +123,6 @@ static GstStateChangeReturn
gst_decklink_audio_src_change_state (GstElement * element, gst_decklink_audio_src_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static gboolean gst_decklink_audio_src_set_caps (GstBaseSrc * bsrc,
GstCaps * caps);
static GstCaps *gst_decklink_audio_src_get_caps (GstBaseSrc * bsrc,
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, static gboolean gst_decklink_audio_src_query (GstBaseSrc * bsrc,
@ -158,9 +154,8 @@ gst_decklink_audio_src_class_init (GstDecklinkAudioSrcClass * klass)
element_class->change_state = element_class->change_state =
GST_DEBUG_FUNCPTR (gst_decklink_audio_src_change_state); GST_DEBUG_FUNCPTR (gst_decklink_audio_src_change_state);
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->query = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_query); basesrc_class->query = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_query);
basesrc_class->negotiate = NULL;
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);
@ -234,6 +229,8 @@ gst_decklink_audio_src_init (GstDecklinkAudioSrc * self)
gst_base_src_set_live (GST_BASE_SRC (self), TRUE); gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME); gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
gst_pad_use_fixed_caps (GST_BASE_SRC_PAD (self));
g_mutex_init (&self->lock); g_mutex_init (&self->lock);
g_cond_init (&self->cond); g_cond_init (&self->cond);
@ -332,47 +329,42 @@ gst_decklink_audio_src_finalize (GObject * object)
} }
static gboolean static gboolean
gst_decklink_audio_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) gst_decklink_audio_src_start (GstDecklinkAudioSrc * self)
{ {
GstDecklinkAudioSrc *self = GST_DECKLINK_AUDIO_SRC_CAST (bsrc);
BMDAudioSampleType sample_depth; BMDAudioSampleType sample_depth;
GstCaps *current_caps;
HRESULT ret; HRESULT ret;
BMDAudioConnection conn = (BMDAudioConnection) - 1; BMDAudioConnection conn = (BMDAudioConnection) - 1;
GstCaps *allowed_caps, *caps;
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps); g_mutex_lock (&self->input->lock);
if (self->input->audio_enabled) {
if ((current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc)))) { g_mutex_unlock (&self->input->lock);
GstCaps *curcaps_cp;
GstStructure *cur_st, *caps_st;
GST_DEBUG_OBJECT (self, "Pad already has caps %" GST_PTR_FORMAT, caps);
curcaps_cp = gst_caps_make_writable (current_caps);
cur_st = gst_caps_get_structure (curcaps_cp, 0);
caps_st = gst_caps_get_structure (caps, 0);
gst_structure_remove_field (cur_st, "channel-mask");
if (!gst_structure_can_intersect (caps_st, cur_st)) {
GST_ERROR_OBJECT (self, "New caps are not compatible with old caps");
gst_caps_unref (current_caps);
gst_caps_unref (curcaps_cp);
return FALSE;
} else {
gst_caps_unref (current_caps);
gst_caps_unref (curcaps_cp);
return TRUE; return TRUE;
} }
} g_mutex_unlock (&self->input->lock);
if (!gst_audio_info_from_caps (&self->info, caps)) /* Negotiate the format / sample depth with downstream */
return FALSE; allowed_caps = gst_pad_get_allowed_caps (GST_BASE_SRC_PAD (self));
if (!allowed_caps)
allowed_caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self));
if (self->info.finfo->format == GST_AUDIO_FORMAT_S16LE) {
sample_depth = bmdAudioSampleType16bitInteger;
} else {
sample_depth = bmdAudioSampleType32bitInteger; sample_depth = bmdAudioSampleType32bitInteger;
if (!gst_caps_is_empty (allowed_caps)) {
GstStructure *s;
allowed_caps = gst_caps_simplify (allowed_caps);
s = gst_caps_get_structure (allowed_caps, 0);
/* If it's not a string then both formats are supported */
if (gst_structure_has_field_typed (s, "format", G_TYPE_STRING)) {
const gchar *format = gst_structure_get_string (s, "format");
if (g_str_equal (format, "S16LE")) {
sample_depth = bmdAudioSampleType16bitInteger;
} }
}
}
gst_caps_unref (allowed_caps);
switch (self->connection) { switch (self->connection) {
case GST_DECKLINK_AUDIO_CONNECTION_AUTO:{ case GST_DECKLINK_AUDIO_CONNECTION_AUTO:{
@ -449,12 +441,16 @@ gst_decklink_audio_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
} }
ret = self->input->input->EnableAudioInput (bmdAudioSampleRate48kHz, ret = self->input->input->EnableAudioInput (bmdAudioSampleRate48kHz,
sample_depth, self->info.channels); sample_depth, self->channels_found);
if (ret != S_OK) { if (ret != S_OK) {
GST_WARNING_OBJECT (self, "Failed to enable audio input: 0x%08lx", GST_WARNING_OBJECT (self, "Failed to enable audio input: 0x%08lx",
(unsigned long) ret); (unsigned long) ret);
return FALSE; return FALSE;
} }
gst_audio_info_set_format (&self->info,
sample_depth ==
bmdAudioSampleType16bitInteger ? GST_AUDIO_FORMAT_S16LE :
GST_AUDIO_FORMAT_S32LE, 48000, self->channels_found, NULL);
g_mutex_lock (&self->input->lock); g_mutex_lock (&self->input->lock);
self->input->audio_enabled = TRUE; self->input->audio_enabled = TRUE;
@ -462,46 +458,15 @@ gst_decklink_audio_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
self->input->start_streams (self->input->videosrc); self->input->start_streams (self->input->videosrc);
g_mutex_unlock (&self->input->lock); g_mutex_unlock (&self->input->lock);
return TRUE; caps = gst_audio_info_to_caps (&self->info);
} if (!gst_base_src_set_caps (GST_BASE_SRC (self), caps)) {
static GstCaps *
gst_decklink_audio_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstDecklinkAudioSrc *self = GST_DECKLINK_AUDIO_SRC_CAST (bsrc);
GstCaps *caps;
// We don't support renegotiation
caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc));
if (!caps) {
GstCaps *channel_filter, *templ;
templ = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
if (self->channels_found > 0) {
channel_filter =
gst_caps_new_simple ("audio/x-raw", "channels", G_TYPE_INT,
self->channels_found, NULL);
} else if (self->channels > 0) {
channel_filter =
gst_caps_new_simple ("audio/x-raw", "channels", G_TYPE_INT,
self->channels, NULL);
} else {
channel_filter = gst_caps_new_empty_simple ("audio/x-raw");
}
caps = gst_caps_intersect (channel_filter, templ);
gst_caps_unref (channel_filter);
gst_caps_unref (templ);
}
if (filter) {
GstCaps *tmp =
gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (caps); gst_caps_unref (caps);
caps = tmp; GST_WARNING_OBJECT (self, "Failed to set caps");
return FALSE;
} }
gst_caps_unref (caps);
return caps; return TRUE;
} }
static void static void
@ -615,6 +580,10 @@ gst_decklink_audio_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
static GstStaticCaps hardware_reference = static GstStaticCaps hardware_reference =
GST_STATIC_CAPS ("timestamp/x-decklink-hardware"); GST_STATIC_CAPS ("timestamp/x-decklink-hardware");
if (!gst_decklink_audio_src_start (self)) {
return GST_FLOW_NOT_NEGOTIATED;
}
retry: retry:
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
while (gst_queue_array_is_empty (self->current_packets) && !self->flushing) { while (gst_queue_array_is_empty (self->current_packets) && !self->flushing) {

View file

@ -223,10 +223,6 @@ static GstStateChangeReturn
gst_decklink_video_src_change_state (GstElement * element, gst_decklink_video_src_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static gboolean gst_decklink_video_src_set_caps (GstBaseSrc * bsrc,
GstCaps * caps);
static GstCaps *gst_decklink_video_src_get_caps (GstBaseSrc * bsrc,
GstCaps * filter);
static gboolean gst_decklink_video_src_query (GstBaseSrc * bsrc, static gboolean gst_decklink_video_src_query (GstBaseSrc * bsrc,
GstQuery * query); GstQuery * query);
static gboolean gst_decklink_video_src_unlock (GstBaseSrc * bsrc); static gboolean gst_decklink_video_src_unlock (GstBaseSrc * bsrc);
@ -261,9 +257,8 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
element_class->change_state = element_class->change_state =
GST_DEBUG_FUNCPTR (gst_decklink_video_src_change_state); GST_DEBUG_FUNCPTR (gst_decklink_video_src_change_state);
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);
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_decklink_video_src_query); basesrc_class->query = GST_DEBUG_FUNCPTR (gst_decklink_video_src_query);
basesrc_class->negotiate = NULL;
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);
@ -408,6 +403,8 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
gst_base_src_set_live (GST_BASE_SRC (self), TRUE); gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME); gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
gst_pad_use_fixed_caps (GST_BASE_SRC_PAD (self));
g_mutex_init (&self->lock); g_mutex_init (&self->lock);
g_cond_init (&self->cond); g_cond_init (&self->cond);
@ -574,36 +571,19 @@ gst_decklink_video_src_finalize (GObject * object)
} }
static gboolean static gboolean
gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) gst_decklink_video_src_start (GstDecklinkVideoSrc * self)
{ {
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
GstCaps *current_caps;
const GstDecklinkMode *mode; const GstDecklinkMode *mode;
BMDVideoInputFlags flags; BMDVideoInputFlags flags;
HRESULT ret; HRESULT ret;
BMDPixelFormat format; BMDPixelFormat format;
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps); g_mutex_lock (&self->input->lock);
if (self->input->video_enabled) {
if ((current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc)))) { g_mutex_unlock (&self->input->lock);
GST_DEBUG_OBJECT (self, "Pad already has caps %" GST_PTR_FORMAT, caps);
if (!gst_caps_is_equal (caps, current_caps)) {
GST_DEBUG_OBJECT (self, "New caps, reconfiguring");
gst_caps_unref (current_caps);
if (self->mode == GST_DECKLINK_MODE_AUTO) {
return TRUE;
} else {
return FALSE;
}
} else {
gst_caps_unref (current_caps);
return TRUE; return TRUE;
} }
} g_mutex_unlock (&self->input->lock);
if (!gst_video_info_from_caps (&self->info, caps))
return FALSE;
if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) { if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) {
ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection, ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection,
@ -672,32 +652,6 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
return TRUE; return TRUE;
} }
static GstCaps *
gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
GstCaps *mode_caps, *caps;
BMDPixelFormat format;
GstDecklinkModeEnum mode;
g_mutex_lock (&self->lock);
mode = self->caps_mode;
format = self->caps_format;
g_mutex_unlock (&self->lock);
mode_caps = gst_decklink_mode_get_caps (mode, format, TRUE);
if (filter) {
caps =
gst_caps_intersect_full (filter, mode_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (mode_caps);
} else {
caps = mode_caps;
}
return caps;
}
static void static void
gst_decklink_video_src_update_time_mapping (GstDecklinkVideoSrc * self, gst_decklink_video_src_update_time_mapping (GstDecklinkVideoSrc * self,
GstClockTime capture_time, GstClockTime stream_time) GstClockTime capture_time, GstClockTime stream_time)
@ -1207,6 +1161,10 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
static GstStaticCaps hardware_reference = static GstStaticCaps hardware_reference =
GST_STATIC_CAPS ("timestamp/x-decklink-hardware"); GST_STATIC_CAPS ("timestamp/x-decklink-hardware");
if (!gst_decklink_video_src_start (self)) {
return GST_FLOW_NOT_NEGOTIATED;
}
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
retry: retry:
while (gst_queue_array_is_empty (self->current_frames) && !self->flushing) { while (gst_queue_array_is_empty (self->current_frames) && !self->flushing) {
@ -1252,8 +1210,13 @@ retry:
// If we're not flushing, we should have a valid frame from the queue // If we're not flushing, we should have a valid frame from the queue
g_assert (f.frame != NULL); g_assert (f.frame != NULL);
if (!gst_pad_has_current_caps (GST_BASE_SRC_PAD (self))) {
caps_changed = TRUE;
}
if (self->caps_mode != f.mode) { if (self->caps_mode != f.mode) {
if (self->mode == GST_DECKLINK_MODE_AUTO) { if (self->mode == GST_DECKLINK_MODE_AUTO
|| !gst_pad_has_current_caps (GST_BASE_SRC_PAD (self))) {
GST_DEBUG_OBJECT (self, "Mode changed from %d to %d", self->caps_mode, GST_DEBUG_OBJECT (self, "Mode changed from %d to %d", self->caps_mode,
f.mode); f.mode);
caps_changed = TRUE; caps_changed = TRUE;
@ -1268,7 +1231,8 @@ retry:
} }
} }
if (self->caps_format != f.format) { if (self->caps_format != f.format) {
if (self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO) { if (self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO
|| !gst_pad_has_current_caps (GST_BASE_SRC_PAD (self))) {
GST_DEBUG_OBJECT (self, "Format changed from %d to %d", self->caps_format, GST_DEBUG_OBJECT (self, "Format changed from %d to %d", self->caps_format,
f.format); f.format);
caps_changed = TRUE; caps_changed = TRUE;