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; }