decklinkvideo{sink,src}: Make elements more similar to the audio elements by enabling...
authorSebastian Dröge <sebastian@centricular.com>
Wed, 28 Jan 2015 10:41:17 +0000 (11:41 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 28 Jan 2015 15:13:16 +0000 (16:13 +0100)
This will also make it easier later to support caps changes and support
selecting the mode based on the caps if that should ever be implemented.

sys/decklink/gstdecklinkvideosink.cpp
sys/decklink/gstdecklinkvideosrc.cpp

index fb70216d0508990bab33fd43b1da1b248cc54e0e..daa0208d972a70bee2dd2d42cbd08835e2f77661 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (gst_decklink_video_sink_debug);
 #define GST_CAT_DEFAULT gst_decklink_video_sink_debug
 
+class GStreamerVideoOutputCallback:public IDeckLinkVideoOutputCallback
+{
+public:
+  GStreamerVideoOutputCallback (GstDecklinkVideoSink * sink)
+  :IDeckLinkVideoOutputCallback (), m_refcount (1)
+  {
+    m_sink = GST_DECKLINK_VIDEO_SINK_CAST (gst_object_ref (sink));
+    g_mutex_init (&m_mutex);
+  }
+
+  virtual HRESULT QueryInterface (REFIID, LPVOID *)
+  {
+    return E_NOINTERFACE;
+  }
+
+  virtual ULONG AddRef (void)
+  {
+    ULONG ret;
+
+    g_mutex_lock (&m_mutex);
+    m_refcount++;
+    ret = m_refcount;
+    g_mutex_unlock (&m_mutex);
+
+    return ret;
+  }
+
+  virtual ULONG Release (void)
+  {
+    ULONG ret;
+
+    g_mutex_lock (&m_mutex);
+    m_refcount--;
+    ret = m_refcount;
+    g_mutex_unlock (&m_mutex);
+
+    if (ret == 0) {
+      delete this;
+    }
+
+    return ret;
+  }
+
+  virtual HRESULT ScheduledFrameCompleted (IDeckLinkVideoFrame * completedFrame,
+      BMDOutputFrameCompletionResult result)
+  {
+    switch (result) {
+      case bmdOutputFrameCompleted:
+        GST_LOG_OBJECT (m_sink, "Completed frame %p", completedFrame);
+        break;
+      case bmdOutputFrameDisplayedLate:
+        GST_INFO_OBJECT (m_sink, "Late Frame %p", completedFrame);
+        break;
+      case bmdOutputFrameDropped:
+        GST_INFO_OBJECT (m_sink, "Dropped Frame %p", completedFrame);
+        break;
+      case bmdOutputFrameFlushed:
+        GST_DEBUG_OBJECT (m_sink, "Flushed Frame %p", completedFrame);
+        break;
+      default:
+        GST_INFO_OBJECT (m_sink, "Unknown Frame %p: %d", completedFrame,
+            (gint) result);
+        break;
+    }
+
+    return S_OK;
+  }
+
+  virtual HRESULT ScheduledPlaybackHasStopped (void)
+  {
+    GST_LOG_OBJECT (m_sink, "Scheduled playback stopped");
+
+    return S_OK;
+  }
+
+  virtual ~ GStreamerVideoOutputCallback () {
+    gst_object_unref (m_sink);
+    g_mutex_clear (&m_mutex);
+  }
+
+private:
+  GstDecklinkVideoSink * m_sink;
+  GMutex m_mutex;
+  gint m_refcount;
+};
+
 enum
 {
   PROP_0,
@@ -48,6 +134,8 @@ static GstClock *gst_decklink_video_sink_provide_clock (GstElement * element);
 
 static GstCaps *gst_decklink_video_sink_get_caps (GstBaseSink * bsink,
     GstCaps * filter);
+static gboolean gst_decklink_video_sink_set_caps (GstBaseSink * bsink,
+    GstCaps * caps);
 static GstFlowReturn gst_decklink_video_sink_prepare (GstBaseSink * bsink,
     GstBuffer * buffer);
 static GstFlowReturn gst_decklink_video_sink_render (GstBaseSink * bsink,
@@ -80,6 +168,8 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
 
   basesink_class->get_caps =
       GST_DEBUG_FUNCPTR (gst_decklink_video_sink_get_caps);
+  basesink_class->set_caps =
+      GST_DEBUG_FUNCPTR (gst_decklink_video_sink_set_caps);
   basesink_class->prepare = GST_DEBUG_FUNCPTR (gst_decklink_video_sink_prepare);
   basesink_class->render = GST_DEBUG_FUNCPTR (gst_decklink_video_sink_render);
   // FIXME: These are misnamed in basesink!
@@ -170,6 +260,38 @@ gst_decklink_video_sink_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static gboolean
+gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
+  const GstDecklinkMode *mode;
+  HRESULT ret;
+
+  GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
+
+  if (!gst_video_info_from_caps (&self->info, caps))
+    return FALSE;
+
+  self->output->output->SetScheduledFrameCompletionCallback (new
+      GStreamerVideoOutputCallback (self));
+
+  mode = gst_decklink_get_mode (self->mode);
+  g_assert (mode != NULL);
+
+  ret = self->output->output->EnableVideoOutput (mode->mode,
+      bmdVideoOutputFlagDefault);
+  if (ret != S_OK) {
+    GST_WARNING_OBJECT (self, "Failed to enable video output");
+    return FALSE;
+  }
+
+  g_mutex_lock (&self->output->lock);
+  self->output->mode = mode;
+  g_mutex_unlock (&self->output->lock);
+
+  return TRUE;
+}
+
 static GstCaps *
 gst_decklink_video_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
 {
@@ -382,99 +504,11 @@ out:
   return flow_ret;
 }
 
-class GStreamerVideoOutputCallback:public IDeckLinkVideoOutputCallback
-{
-public:
-  GStreamerVideoOutputCallback (GstDecklinkVideoSink * sink)
-  :IDeckLinkVideoOutputCallback (), m_refcount (1)
-  {
-    m_sink = GST_DECKLINK_VIDEO_SINK_CAST (gst_object_ref (sink));
-    g_mutex_init (&m_mutex);
-  }
-
-  virtual HRESULT QueryInterface (REFIID, LPVOID *)
-  {
-    return E_NOINTERFACE;
-  }
-
-  virtual ULONG AddRef (void)
-  {
-    ULONG ret;
-
-    g_mutex_lock (&m_mutex);
-    m_refcount++;
-    ret = m_refcount;
-    g_mutex_unlock (&m_mutex);
-
-    return ret;
-  }
-
-  virtual ULONG Release (void)
-  {
-    ULONG ret;
-
-    g_mutex_lock (&m_mutex);
-    m_refcount--;
-    ret = m_refcount;
-    g_mutex_unlock (&m_mutex);
-
-    if (ret == 0) {
-      delete this;
-    }
-
-    return ret;
-  }
-
-  virtual HRESULT ScheduledFrameCompleted (IDeckLinkVideoFrame * completedFrame,
-      BMDOutputFrameCompletionResult result)
-  {
-    switch (result) {
-      case bmdOutputFrameCompleted:
-        GST_LOG_OBJECT (m_sink, "Completed frame %p", completedFrame);
-        break;
-      case bmdOutputFrameDisplayedLate:
-        GST_INFO_OBJECT (m_sink, "Late Frame %p", completedFrame);
-        break;
-      case bmdOutputFrameDropped:
-        GST_INFO_OBJECT (m_sink, "Dropped Frame %p", completedFrame);
-        break;
-      case bmdOutputFrameFlushed:
-        GST_DEBUG_OBJECT (m_sink, "Flushed Frame %p", completedFrame);
-        break;
-      default:
-        GST_INFO_OBJECT (m_sink, "Unknown Frame %p: %d", completedFrame,
-            (gint) result);
-        break;
-    }
-
-    return S_OK;
-  }
-
-  virtual HRESULT ScheduledPlaybackHasStopped (void)
-  {
-    GST_LOG_OBJECT (m_sink, "Scheduled playback stopped");
-
-    return S_OK;
-  }
-
-  virtual ~ GStreamerVideoOutputCallback () {
-    gst_object_unref (m_sink);
-    g_mutex_clear (&m_mutex);
-  }
-
-private:
-  GstDecklinkVideoSink * m_sink;
-  GMutex m_mutex;
-  gint m_refcount;
-};
-
 static gboolean
 gst_decklink_video_sink_open (GstBaseSink * bsink)
 {
   GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
   const GstDecklinkMode *mode;
-  GstCaps *caps;
-  HRESULT ret;
 
   GST_DEBUG_OBJECT (self, "Starting");
 
@@ -486,29 +520,13 @@ gst_decklink_video_sink_open (GstBaseSink * bsink)
     return FALSE;
   }
 
-  self->output->output->SetScheduledFrameCompletionCallback (new
-      GStreamerVideoOutputCallback (self));
-
   mode = gst_decklink_get_mode (self->mode);
   g_assert (mode != NULL);
 
-  ret = self->output->output->EnableVideoOutput (mode->mode,
-      bmdVideoOutputFlagDefault);
-  if (ret != S_OK) {
-    GST_WARNING_OBJECT (self, "Failed to enable video output");
-    gst_decklink_release_nth_output (self->device_number,
-        GST_ELEMENT_CAST (self), 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);
-  gst_video_info_from_caps (&self->info, caps);
-  gst_caps_unref (caps);
-
   return TRUE;
 }
 
index 704a2c394f226517d5762e763208eab55b38eca6..8d17419f71d7dbb0af741118a555a5ab3ffa1078 100644 (file)
@@ -85,6 +85,8 @@ 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);
 static GstCaps *gst_decklink_video_src_get_caps (GstBaseSrc * bsrc,
     GstCaps * filter);
 static gboolean gst_decklink_video_src_query (GstBaseSrc * bsrc,
@@ -120,6 +122,7 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
       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);
   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_stop =
@@ -245,6 +248,91 @@ gst_decklink_video_src_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static gboolean
+gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
+{
+  GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
+  GstCaps *current_caps;
+  const GstDecklinkMode *mode;
+  BMDVideoInputFlags flags;
+  HRESULT ret;
+
+  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_ERROR_OBJECT (self, "New caps are not equal to old caps");
+      gst_caps_unref (current_caps);
+      return FALSE;
+    } else {
+      gst_caps_unref (current_caps);
+      return TRUE;
+    }
+  }
+
+  if (!gst_video_info_from_caps (&self->info, caps))
+    return FALSE;
+
+  if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) {
+    ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection,
+        gst_decklink_get_connection (self->connection));
+    if (ret != S_OK) {
+      GST_ERROR_OBJECT (self, "Failed to set configuration (input source)");
+      return FALSE;
+    }
+
+    if (self->connection == GST_DECKLINK_CONNECTION_COMPOSITE) {
+      ret = self->input->config->SetInt (bmdDeckLinkConfigAnalogVideoInputFlags,
+          bmdAnalogVideoFlagCompositeSetup75);
+      if (ret != S_OK) {
+        GST_ERROR_OBJECT (self,
+            "Failed to set configuration (composite setup)");
+        return FALSE;
+      }
+    }
+  }
+
+  flags = bmdVideoInputFlagDefault;
+  if (self->mode == GST_DECKLINK_MODE_AUTO) {
+    bool autoDetection = false;
+
+    if (self->input->attributes) {
+      ret =
+          self->input->
+          attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
+          &autoDetection);
+      if (ret != S_OK) {
+        GST_ERROR_OBJECT (self, "Failed to get attribute (autodetection)");
+        return FALSE;
+      }
+      if (autoDetection)
+        flags |= bmdVideoInputEnableFormatDetection;
+    }
+    if (!autoDetection) {
+      GST_ERROR_OBJECT (self, "Failed to activate auto-detection");
+      return FALSE;
+    }
+  }
+
+  mode = gst_decklink_get_mode (self->mode);
+  g_assert (mode != NULL);
+
+  ret = self->input->input->EnableVideoInput (mode->mode,
+      bmdFormat8BitYUV, flags);
+  if (ret != S_OK) {
+    GST_WARNING_OBJECT (self, "Failed to enable video input");
+    return FALSE;
+  }
+
+  g_mutex_lock (&self->input->lock);
+  self->input->mode = mode;
+  g_mutex_unlock (&self->input->lock);
+
+  return TRUE;
+}
+
 static GstCaps *
 gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
 {
@@ -446,9 +534,6 @@ static gboolean
 gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
 {
   const GstDecklinkMode *mode;
-  BMDVideoInputFlags flags;
-  GstCaps *caps;
-  HRESULT ret;
 
   GST_DEBUG_OBJECT (self, "Starting");
 
@@ -460,69 +545,13 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
     return FALSE;
   }
 
-  if (self->input->config && self->connection != GST_DECKLINK_CONNECTION_AUTO) {
-    ret = self->input->config->SetInt (bmdDeckLinkConfigVideoInputConnection,
-        gst_decklink_get_connection (self->connection));
-    if (ret != S_OK) {
-      GST_ERROR_OBJECT (self, "Failed to set configuration (input source)");
-      return FALSE;
-    }
-
-    if (self->connection == GST_DECKLINK_CONNECTION_COMPOSITE) {
-      ret = self->input->config->SetInt (bmdDeckLinkConfigAnalogVideoInputFlags,
-          bmdAnalogVideoFlagCompositeSetup75);
-      if (ret != S_OK) {
-        GST_ERROR_OBJECT (self,
-            "Failed to set configuration (composite setup)");
-        return FALSE;
-      }
-    }
-  }
-
-  flags = bmdVideoInputFlagDefault;
-  if (self->mode == GST_DECKLINK_MODE_AUTO) {
-    bool autoDetection = false;
-
-    if (self->input->attributes) {
-      ret =
-          self->input->
-          attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
-          &autoDetection);
-      if (ret != S_OK) {
-        GST_ERROR_OBJECT (self, "Failed to get attribute (autodetection)");
-        return FALSE;
-      }
-      if (autoDetection)
-        flags |= bmdVideoInputEnableFormatDetection;
-    }
-    if (!autoDetection) {
-      GST_ERROR_OBJECT (self, "Failed to activate auto-detection");
-      return FALSE;
-    }
-  }
-
   mode = gst_decklink_get_mode (self->mode);
   g_assert (mode != NULL);
-
-  ret = self->input->input->EnableVideoInput (mode->mode,
-      bmdFormat8BitYUV, flags);
-  if (ret != S_OK) {
-    GST_WARNING_OBJECT (self, "Failed to enable video input");
-    gst_decklink_release_nth_input (self->device_number,
-        GST_ELEMENT_CAST (self), FALSE);
-    return FALSE;
-  }
-
   g_mutex_lock (&self->input->lock);
   self->input->mode = mode;
   self->input->got_video_frame = gst_decklink_video_src_got_frame;
   g_mutex_unlock (&self->input->lock);
 
-  self->caps_mode = gst_decklink_get_mode_enum_from_bmd (mode->mode);
-  caps = gst_decklink_mode_get_caps (self->caps_mode);
-  gst_video_info_from_caps (&self->info, caps);
-  gst_caps_unref (caps);
-
   return TRUE;
 }