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,
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,
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!
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)
{
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");
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;
}
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,
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 =
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)
{
gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
{
const GstDecklinkMode *mode;
- BMDVideoInputFlags flags;
- GstCaps *caps;
- HRESULT ret;
GST_DEBUG_OBJECT (self, "Starting");
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;
}