decklinkaudiosrc/decklinkvideosrc: Do nothing in BaseSrc::negotiate() and always...
authorSebastian Dröge <sebastian@centricular.com>
Tue, 6 Aug 2019 18:44:35 +0000 (21:44 +0300)
committerTim-Philipp Müller <tim@centricular.com>
Mon, 12 Aug 2019 12:15:32 +0000 (13:15 +0100)
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().

sys/decklink/gstdecklinkaudiosrc.cpp
sys/decklink/gstdecklinkvideosrc.cpp

index 6413ba5..2fef934 100644 (file)
@@ -123,10 +123,6 @@ static GstStateChangeReturn
 gst_decklink_audio_src_change_state (GstElement * element,
     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_stop (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 =
       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->negotiate = NULL;
   basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_audio_src_unlock);
   basesrc_class->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_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
 
+  gst_pad_use_fixed_caps (GST_BASE_SRC_PAD (self));
+
   g_mutex_init (&self->lock);
   g_cond_init (&self->cond);
 
@@ -332,47 +329,42 @@ gst_decklink_audio_src_finalize (GObject * object)
 }
 
 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;
-  GstCaps *current_caps;
   HRESULT ret;
   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) {
+    g_mutex_unlock (&self->input->lock);
+    return TRUE;
+  }
+  g_mutex_unlock (&self->input->lock);
 
-  if ((current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc)))) {
-    GstCaps *curcaps_cp;
-    GstStructure *cur_st, *caps_st;
+  /* Negotiate the format / sample depth with downstream */
+  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));
 
-    GST_DEBUG_OBJECT (self, "Pad already has caps %" GST_PTR_FORMAT, caps);
+  sample_depth = bmdAudioSampleType32bitInteger;
+  if (!gst_caps_is_empty (allowed_caps)) {
+    GstStructure *s;
 
-    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");
+    allowed_caps = gst_caps_simplify (allowed_caps);
 
-    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;
-    }
-  }
-
-  if (!gst_audio_info_from_caps (&self->info, caps))
-    return FALSE;
+    s = gst_caps_get_structure (allowed_caps, 0);
 
-  if (self->info.finfo->format == GST_AUDIO_FORMAT_S16LE) {
-    sample_depth = bmdAudioSampleType16bitInteger;
-  } else {
-    sample_depth = bmdAudioSampleType32bitInteger;
+    /* 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) {
     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,
-      sample_depth, self->info.channels);
+      sample_depth, self->channels_found);
   if (ret != S_OK) {
     GST_WARNING_OBJECT (self, "Failed to enable audio input: 0x%08lx",
         (unsigned long) ret);
     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);
   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);
   g_mutex_unlock (&self->input->lock);
 
-  return TRUE;
-}
-
-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);
+  caps = gst_audio_info_to_caps (&self->info);
+  if (!gst_base_src_set_caps (GST_BASE_SRC (self), 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
@@ -615,6 +580,10 @@ gst_decklink_audio_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
   static GstStaticCaps hardware_reference =
       GST_STATIC_CAPS ("timestamp/x-decklink-hardware");
 
+  if (!gst_decklink_audio_src_start (self)) {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
 retry:
   g_mutex_lock (&self->lock);
   while (gst_queue_array_is_empty (self->current_packets) && !self->flushing) {
index 2efeb59..f048ab3 100644 (file)
@@ -220,10 +220,6 @@ static GstStateChangeReturn
 gst_decklink_video_src_change_state (GstElement * element,
     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,
     GstQuery * query);
 static gboolean gst_decklink_video_src_unlock (GstBaseSrc * bsrc);
@@ -258,9 +254,8 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
   element_class->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->negotiate = NULL;
   basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock);
   basesrc_class->unlock_stop =
       GST_DEBUG_FUNCPTR (gst_decklink_video_src_unlock_stop);
@@ -397,6 +392,8 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
   gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
   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_cond_init (&self->cond);
 
@@ -557,36 +554,19 @@ gst_decklink_video_src_finalize (GObject * object)
 }
 
 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;
   BMDVideoInputFlags flags;
   HRESULT ret;
   BMDPixelFormat format;
 
-  GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
-
-  if ((current_caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (bsrc)))) {
-    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;
-    }
+  g_mutex_lock (&self->input->lock);
+  if (self->input->video_enabled) {
+    g_mutex_unlock (&self->input->lock);
+    return TRUE;
   }
-
-  if (!gst_video_info_from_caps (&self->info, caps))
-    return FALSE;
+  g_mutex_unlock (&self->input->lock);
 
   if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) {
     ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection,
@@ -655,32 +635,6 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
   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
 gst_decklink_video_src_update_time_mapping (GstDecklinkVideoSrc * self,
     GstClockTime capture_time, GstClockTime stream_time)
@@ -1036,6 +990,10 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
   static GstStaticCaps hardware_reference =
       GST_STATIC_CAPS ("timestamp/x-decklink-hardware");
 
+  if (!gst_decklink_video_src_start (self)) {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
   g_mutex_lock (&self->lock);
   while (gst_queue_array_is_empty (self->current_frames) && !self->flushing) {
     g_cond_wait (&self->cond, &self->lock);
@@ -1053,8 +1011,14 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
   g_assert (f.frame != NULL);
 
   g_mutex_lock (&self->lock);
+
+  if (!gst_pad_has_current_caps (GST_BASE_SRC_PAD (self))) {
+    caps_changed = TRUE;
+  }
+
   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,
           f.mode);
       caps_changed = TRUE;
@@ -1069,7 +1033,8 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
     }
   }
   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,
           f.format);
       caps_changed = TRUE;