From 8a5d2c561cdb38d49e9de9f933b48eef409412f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 28 Jan 2015 11:41:17 +0100 Subject: [PATCH] decklinkvideo{sink,src}: Make elements more similar to the audio elements by enabling the video input/output only when getting the actual caps 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 | 226 ++++++++++++++------------ sys/decklink/gstdecklinkvideosrc.cpp | 147 ++++++++++------- 2 files changed, 210 insertions(+), 163 deletions(-) diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index fb70216d05..daa0208d97 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -28,6 +28,92 @@ 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; } diff --git a/sys/decklink/gstdecklinkvideosrc.cpp b/sys/decklink/gstdecklinkvideosrc.cpp index 704a2c394f..8d17419f71 100644 --- a/sys/decklink/gstdecklinkvideosrc.cpp +++ b/sys/decklink/gstdecklinkvideosrc.cpp @@ -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; }