diff --git a/sys/decklink/capture.cpp b/sys/decklink/capture.cpp deleted file mode 100644 index 1795af2a92..0000000000 --- a/sys/decklink/capture.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -LICENSE-START- -** Copyright (c) 2009 Blackmagic Design -** -** Permission is hereby granted, free of charge, to any person or organization -** obtaining a copy of the software and accompanying documentation covered by -** this license (the "Software") to use, reproduce, display, distribute, -** execute, and transmit the Software, and to prepare derivative works of the -** Software, and to permit third-parties to whom the Software is furnished to -** do so, all subject to the following: -** -** The copyright notices in the Software and this entire statement, including -** the above license grant, this restriction and the following disclaimer, -** must be included in all copies of the Software, in whole or in part, and -** all derivative works of the Software, unless such copies or derivative -** works are solely in the form of machine-executable object code generated by -** a source language processor. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -** DEALINGS IN THE SOFTWARE. -** -LICENSE-END- -*/ - -#include -#include -#include -#include -#include - -#include "gstdecklinksrc.h" - -#include "capture.h" - -#define GST_CAT_DEFAULT gst_decklink_src_debug_category - -static BMDTimecodeFormat g_timecodeFormat = (BMDTimecodeFormat) 0; - -DeckLinkCaptureDelegate::DeckLinkCaptureDelegate ():priv (NULL), m_refCount (0) -{ - g_mutex_init (&m_mutex); -} - -DeckLinkCaptureDelegate::~DeckLinkCaptureDelegate () -{ - g_mutex_clear (&m_mutex); -} - -ULONG DeckLinkCaptureDelegate::AddRef (void) -{ - g_mutex_lock (&m_mutex); - m_refCount++; - g_mutex_unlock (&m_mutex); - - return (ULONG) m_refCount; -} - -ULONG DeckLinkCaptureDelegate::Release (void) -{ - g_mutex_lock (&m_mutex); - m_refCount--; - g_mutex_unlock (&m_mutex); - - if (m_refCount == 0) { - delete - this; - return 0; - } - - return (ULONG) m_refCount; -} - -HRESULT - DeckLinkCaptureDelegate::VideoInputFrameArrived (IDeckLinkVideoInputFrame * - videoFrame, IDeckLinkAudioInputPacket * audioFrame) -{ - GstDecklinkSrc *decklinksrc; - GstClock *clock; - GstClockTime base_time, clock_time, capture_time; - const char *timecodeString = NULL; - - g_return_val_if_fail (priv != NULL, S_OK); - g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK); - - decklinksrc = GST_DECKLINK_SRC (priv); - - if (videoFrame == NULL) { - GST_WARNING_OBJECT (decklinksrc, "video frame is NULL"); - return S_OK; - } - - if (audioFrame == NULL) { - GST_WARNING_OBJECT (decklinksrc, "audio frame is NULL"); - return S_OK; - } - - if (videoFrame->GetFlags () & bmdFrameHasNoInputSource) { - GST_DEBUG_OBJECT (decklinksrc, "Frame received - No input signal detected"); - return S_OK; - } - - /* FIXME: g_timecodeFormat is inited to 0 and never changed? dead code? */ - if (g_timecodeFormat != 0) { - IDeckLinkTimecode *timecode; - if (videoFrame->GetTimecode (g_timecodeFormat, &timecode) == S_OK) { - timecode->GetString (&timecodeString); - CONVERT_COM_STRING (timecodeString); - } - } - - GST_OBJECT_LOCK (decklinksrc); - if ((clock = GST_ELEMENT_CLOCK (decklinksrc))) { - base_time = GST_ELEMENT (decklinksrc)->base_time; - gst_object_ref (clock); - } else { - base_time = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (decklinksrc); - if (clock) { - clock_time = gst_clock_get_time (clock); - gst_object_unref (clock); - } else { - clock_time = GST_CLOCK_TIME_NONE; - } - - if (base_time != GST_CLOCK_TIME_NONE) { - capture_time = clock_time - base_time; - } else { - capture_time = GST_CLOCK_TIME_NONE; - } - - GST_DEBUG_OBJECT (decklinksrc, - "Frame received [%s] - %s - %" GST_TIME_FORMAT "Size: %li bytes", - timecodeString != NULL ? timecodeString : "No timecode", "Valid Frame", - GST_TIME_ARGS (capture_time), - videoFrame->GetRowBytes () * videoFrame->GetHeight ()); - - if (timecodeString) - FREE_COM_STRING (timecodeString); - - g_mutex_lock (&decklinksrc->mutex); - if (decklinksrc->video_frame != NULL) { - decklinksrc->dropped_frames++; - decklinksrc->video_frame->Release (); - if (decklinksrc->audio_frame) { - decklinksrc->audio_frame->Release (); - } - } - videoFrame->AddRef (); - decklinksrc->video_frame = videoFrame; - if (audioFrame) { - audioFrame->AddRef (); - decklinksrc->audio_frame = audioFrame; - } - decklinksrc->capture_time = capture_time; - - /* increment regardless whether frame was dropped or not */ - decklinksrc->frame_num++; - - g_cond_signal (&decklinksrc->cond); - g_mutex_unlock (&decklinksrc->mutex); - - return S_OK; -} - -HRESULT - DeckLinkCaptureDelegate::VideoInputFormatChanged - (BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode * mode, - BMDDetectedVideoInputFormatFlags) { - GstDecklinkSrc * - decklinksrc; - - g_return_val_if_fail (priv != NULL, S_OK); - g_return_val_if_fail (GST_IS_DECKLINK_SRC (priv), S_OK); - - decklinksrc = GST_DECKLINK_SRC (priv); - - GST_ERROR_OBJECT (decklinksrc, "unimplemented: video input format changed"); - - return S_OK; -} diff --git a/sys/decklink/capture.h b/sys/decklink/capture.h deleted file mode 100644 index e6c5846486..0000000000 --- a/sys/decklink/capture.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __CAPTURE_H__ -#define __CAPTURE_H__ - -#include "gstdecklink.h" - -class DeckLinkCaptureDelegate : public IDeckLinkInputCallback -{ - public: - DeckLinkCaptureDelegate(); - virtual ~DeckLinkCaptureDelegate(); - - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } - virtual ULONG STDMETHODCALLTYPE AddRef(void); - virtual ULONG STDMETHODCALLTYPE Release(void); - virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags); - virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); - - void *priv; - - private: - ULONG m_refCount; - GMutex m_mutex; -}; - -#endif diff --git a/sys/decklink/gstdecklinksink.cpp b/sys/decklink/gstdecklinksink.cpp deleted file mode 100644 index 257277d6fa..0000000000 --- a/sys/decklink/gstdecklinksink.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/* GStreamer - * Copyright (C) 2011 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, - * Boston, MA 02110-1335, USA. - */ -/** - * SECTION:element-gstdecklinksink - * - * The decklinksink element is a sink element for BlackMagic DeckLink - * cards. - * - * - * Example launch line - * |[ - * gst-launch-1.0 -v videotestsrc ! decklinksink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include "gstdecklink.h" -#include "gstdecklinksink.h" -#include - -/* FIXME: - * - handle ALLOCATION query - * - provide buffer pool with suitable strides/alignment for video - * - handle video meta - */ - -GST_DEBUG_CATEGORY_STATIC (gst_decklink_sink_debug_category); -#define GST_CAT_DEFAULT gst_decklink_sink_debug_category - -static void gst_decklink_sink_set_property (GObject * object, - guint property_id, const GValue * value, GParamSpec * pspec); -static void gst_decklink_sink_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); -static void gst_decklink_sink_finalize (GObject * object); - -static GstStateChangeReturn -gst_decklink_sink_change_state (GstElement * element, - GstStateChange transition); - -static GstFlowReturn gst_decklink_sink_videosink_chain (GstPad * pad, - GstObject * parent, GstBuffer * buffer); -static gboolean gst_decklink_sink_videosink_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_decklink_sink_videosink_query (GstPad * pad, - GstObject * parent, GstQuery * query); - -static GstFlowReturn gst_decklink_sink_audiosink_chain (GstPad * pad, - GstObject * parent, GstBuffer * buffer); -static gboolean gst_decklink_sink_audiosink_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_decklink_sink_audiosink_query (GstPad * pad, - GstObject * parent, GstQuery * query); - -#ifdef _MSC_VER -/* COM initialization/uninitialization thread */ -static void gst_decklink_sink_com_thread (GstDecklinkSink * sink); -#endif /* _MSC_VER */ - -enum -{ - PROP_0, - PROP_MODE, - PROP_DEVICE_NUMBER -}; - -/* pad templates */ - -/* the video sink pad template is created on the fly */ - -static GstStaticPadTemplate gst_decklink_sink_audiosink_template = -GST_STATIC_PAD_TEMPLATE ("audiosink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw, format=S16LE, channels=2, rate=48000, " - "layout=interleaved") - ); - -#define parent_class gst_decklink_sink_parent_class -G_DEFINE_TYPE (GstDecklinkSink, gst_decklink_sink, GST_TYPE_ELEMENT); - -static void -gst_decklink_sink_class_init (GstDecklinkSinkClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gobject_class->set_property = gst_decklink_sink_set_property; - gobject_class->get_property = gst_decklink_sink_get_property; - gobject_class->finalize = gst_decklink_sink_finalize; - - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_decklink_sink_change_state); - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Playback Mode", - "Video Mode to use for playback", - GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - g_object_class_install_property (gobject_class, PROP_DEVICE_NUMBER, - g_param_spec_int ("device-number", "Device number", - "Output device instance to use", 0, G_MAXINT, 0, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - gst_element_class_add_pad_template (element_class, - gst_pad_template_new ("videosink", GST_PAD_SINK, GST_PAD_ALWAYS, - gst_decklink_mode_get_template_caps ())); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_decklink_sink_audiosink_template)); - - gst_element_class_set_static_metadata (element_class, "Decklink Sink", - "Video/Sink", "Decklink Sink", "David Schleef "); - - GST_DEBUG_CATEGORY_INIT (gst_decklink_sink_debug_category, "decklinksink", 0, - "debug category for decklinksink element"); -} - -static void -gst_decklink_sink_init (GstDecklinkSink * decklinksink) -{ - GstDecklinkSinkClass *decklinksink_class; - - decklinksink_class = GST_DECKLINK_SINK_GET_CLASS (decklinksink); - - decklinksink->videosinkpad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_CLASS (decklinksink_class), "videosink"), "videosink"); - gst_pad_set_chain_function (decklinksink->videosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_videosink_chain)); - gst_pad_set_event_function (decklinksink->videosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_videosink_event)); - gst_pad_set_query_function (decklinksink->videosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_videosink_query)); - gst_element_add_pad (GST_ELEMENT (decklinksink), decklinksink->videosinkpad); - - decklinksink->audiosinkpad = - gst_pad_new_from_static_template (&gst_decklink_sink_audiosink_template, - "audiosink"); - gst_pad_set_chain_function (decklinksink->audiosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_audiosink_chain)); - gst_pad_set_event_function (decklinksink->audiosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_audiosink_event)); - gst_pad_set_query_function (decklinksink->audiosinkpad, - GST_DEBUG_FUNCPTR (gst_decklink_sink_audiosink_query)); - gst_element_add_pad (GST_ELEMENT (decklinksink), decklinksink->audiosinkpad); - - GST_OBJECT_FLAG_SET (decklinksink, GST_ELEMENT_FLAG_SINK); - - g_cond_init (&decklinksink->cond); - g_mutex_init (&decklinksink->mutex); - g_mutex_init (&decklinksink->audio_mutex); - g_cond_init (&decklinksink->audio_cond); - - decklinksink->mode = GST_DECKLINK_MODE_NTSC; - decklinksink->device_number = 0; - -#ifdef _MSC_VER - g_mutex_init (&decklinksink->com_init_lock); - g_mutex_init (&decklinksink->com_deinit_lock); - g_cond_init (&decklinksink->com_initialized); - g_cond_init (&decklinksink->com_uninitialize); - g_cond_init (&decklinksink->com_uninitialized); - - g_mutex_lock (&decklinksink->com_init_lock); - - /* create the COM initialization thread */ - g_thread_create ((GThreadFunc) gst_decklink_sink_com_thread, - decklinksink, FALSE, NULL); - - /* wait until the COM thread signals that COM has been initialized */ - g_cond_wait (&decklinksink->com_initialized, &decklinksink->com_init_lock); - g_mutex_unlock (&decklinksink->com_init_lock); -#endif /* _MSC_VER */ -} - -void -gst_decklink_sink_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstDecklinkSink *decklinksink; - - g_return_if_fail (GST_IS_DECKLINK_SINK (object)); - decklinksink = GST_DECKLINK_SINK (object); - - switch (property_id) { - case PROP_MODE: - decklinksink->mode = (GstDecklinkModeEnum) g_value_get_enum (value); - break; - case PROP_DEVICE_NUMBER: - decklinksink->device_number = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -void -gst_decklink_sink_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstDecklinkSink *decklinksink; - - g_return_if_fail (GST_IS_DECKLINK_SINK (object)); - decklinksink = GST_DECKLINK_SINK (object); - - switch (property_id) { - case PROP_MODE: - g_value_set_enum (value, decklinksink->mode); - break; - case PROP_DEVICE_NUMBER: - g_value_set_int (value, decklinksink->device_number); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -#ifdef _MSC_VER -static void -gst_decklink_sink_com_thread (GstDecklinkSink * sink) -{ - HRESULT res; - - g_mutex_lock (sink->com_init_lock); - - /* Initialize COM with a MTA for this process. This thread will - * be the first one to enter the apartement and the last one to leave - * it, unitializing COM properly */ - - res = CoInitializeEx (0, COINIT_MULTITHREADED); - if (res == S_FALSE) - GST_WARNING_OBJECT (sink, - "COM has been already initialized in the same process"); - else if (res == RPC_E_CHANGED_MODE) - GST_WARNING_OBJECT (sink, "The concurrency model of COM has changed."); - else - GST_INFO_OBJECT (sink, "COM intialized succesfully"); - - sink->comInitialized = TRUE; - - /* Signal other threads waiting on this condition that COM was initialized */ - g_cond_signal (sink->com_initialized); - - g_mutex_unlock (sink->com_init_lock); - - /* Wait until the unitialize condition is met to leave the COM apartement */ - g_mutex_lock (sink->com_deinit_lock); - g_cond_wait (sink->com_uninitialize, sink->com_deinit_lock); - - CoUninitialize (); - GST_INFO_OBJECT (sink, "COM unintialized succesfully"); - sink->comInitialized = FALSE; - g_cond_signal (sink->com_uninitialized); - g_mutex_unlock (sink->com_deinit_lock); -} -#endif /* _MSC_VER */ - -void -gst_decklink_sink_finalize (GObject * object) -{ - GstDecklinkSink *decklinksink; - - decklinksink = GST_DECKLINK_SINK (object); - - g_cond_clear (&decklinksink->cond); - g_mutex_clear (&decklinksink->mutex); - g_cond_clear (&decklinksink->audio_cond); - g_mutex_clear (&decklinksink->audio_mutex); - -#ifdef _MSC_VER - /* signal the COM thread that it should uninitialize COM */ - if (decklinksink->comInitialized) { - g_mutex_lock (&decklinksink->com_deinit_lock); - g_cond_signal (&decklinksink->com_uninitialize); - g_cond_wait (&decklinksink->com_uninitialized, - &decklinksink->com_deinit_lock); - g_mutex_unlock (&decklinksink->com_deinit_lock); - } - - g_mutex_clear (&decklinksink->com_init_lock); - g_mutex_clear (&decklinksink->com_deinit_lock); - g_cond_clear (&decklinksink->com_initialized); - g_cond_clear (&decklinksink->com_uninitialize); - g_cond_clear (&decklinksink->com_uninitialized); -#endif /* _MSC_VER */ - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -/* FIXME: post error messages for the misc. failures */ -static gboolean -gst_decklink_sink_start (GstDecklinkSink * decklinksink) -{ - HRESULT ret; - const GstDecklinkMode *mode; - BMDAudioSampleType sample_depth; - - decklinksink->decklink = - gst_decklink_get_nth_device (decklinksink->device_number); - if (!decklinksink->decklink) { - GST_WARNING ("failed to get device %d", decklinksink->device_number); - return FALSE; - } - - decklinksink->output = - gst_decklink_get_nth_output (decklinksink->device_number); - if (!decklinksink->output) { - GST_WARNING ("no output for device %d", decklinksink->device_number); - return FALSE; - } - - decklinksink->callback = new Output; - decklinksink->callback->decklinksink = decklinksink; - - decklinksink->output->SetAudioCallback (decklinksink->callback); - - mode = gst_decklink_get_mode (decklinksink->mode); - - ret = decklinksink->output->EnableVideoOutput (mode->mode, - bmdVideoOutputFlagDefault); - if (ret != S_OK) { - GST_WARNING ("failed to enable video output"); - return FALSE; - } - //decklinksink->video_enabled = TRUE; - - decklinksink->output-> - SetScheduledFrameCompletionCallback (decklinksink->callback); - - sample_depth = bmdAudioSampleType16bitInteger; - ret = decklinksink->output->EnableAudioOutput (bmdAudioSampleRate48kHz, - sample_depth, 2, bmdAudioOutputStreamContinuous); - if (ret != S_OK) { - GST_WARNING ("failed to enable audio output"); - return FALSE; - } - decklinksink->audio_adapter = gst_adapter_new (); - - decklinksink->num_frames = 0; - - return TRUE; -} - -static gboolean -gst_decklink_sink_force_stop (GstDecklinkSink * decklinksink) -{ - g_mutex_lock (&decklinksink->mutex); - decklinksink->stop = TRUE; - g_cond_signal (&decklinksink->cond); - g_mutex_unlock (&decklinksink->mutex); - - g_mutex_lock (&decklinksink->audio_mutex); - g_cond_signal (&decklinksink->audio_cond); - g_mutex_unlock (&decklinksink->audio_mutex); - - return TRUE; -} - -static gboolean -gst_decklink_sink_stop (GstDecklinkSink * decklinksink) -{ - decklinksink->output->StopScheduledPlayback (0, NULL, 0); - decklinksink->output->DisableAudioOutput (); - decklinksink->output->DisableVideoOutput (); - - decklinksink->output->SetAudioCallback (NULL); - decklinksink->output->SetScheduledFrameCompletionCallback (NULL); - delete decklinksink->callback; - decklinksink->callback = NULL; - - return TRUE; -} - -static GstStateChangeReturn -gst_decklink_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstDecklinkSink *decklinksink; - GstStateChangeReturn ret; - - decklinksink = GST_DECKLINK_SINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_decklink_sink_start (decklinksink)) { - ret = GST_STATE_CHANGE_FAILURE; - goto out; - } - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_segment_init (&decklinksink->audio_segment, GST_FORMAT_TIME); - gst_segment_init (&decklinksink->video_segment, GST_FORMAT_TIME); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - gst_decklink_sink_force_stop (decklinksink); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_decklink_sink_stop (decklinksink); - break; - default: - break; - } - -out: - return ret; -} - -static GstFlowReturn -gst_decklink_sink_videosink_chain (GstPad * pad, GstObject * parent, - GstBuffer * buffer) -{ - GstDecklinkSink *decklinksink; - IDeckLinkMutableVideoFrame *frame; - void *data; - GstFlowReturn flow_ret; - const GstDecklinkMode *mode; - HRESULT ret; - GstClockTime timestamp, duration; - GstClockTime running_time; - GstClockTime running_time_duration; - GstClock *clock; - GstClockID clock_id; - GstClockTime base_time; - - decklinksink = GST_DECKLINK_SINK (parent); - -#if 0 - if (!decklinksink->video_enabled) { - HRESULT ret; - ret = decklinksink->output->EnableVideoOutput (decklinksink->display_mode, - bmdVideoOutputFlagDefault); - if (ret != S_OK) { - GST_WARNING ("failed to enable video output"); - //return FALSE; - } - decklinksink->video_enabled = TRUE; - } -#endif - - mode = gst_decklink_get_mode (decklinksink->mode); - - ret = decklinksink->output->CreateVideoFrame (mode->width, - mode->height, mode->width * 2, decklinksink->pixel_format, - bmdFrameFlagDefault, &frame); - if (ret != S_OK) { - GST_ELEMENT_ERROR (decklinksink, STREAM, FAILED, - (NULL), ("Failed to create video frame: 0x%08x", ret)); - return GST_FLOW_ERROR; - } - - frame->GetBytes (&data); - gst_buffer_extract (buffer, 0, data, gst_buffer_get_size (buffer)); - timestamp = GST_BUFFER_TIMESTAMP (buffer); - duration = GST_BUFFER_DURATION (buffer); - if (duration == GST_CLOCK_TIME_NONE) { - duration = gst_util_uint64_scale_int (GST_SECOND, mode->fps_d, mode->fps_n); - } - running_time = - gst_segment_to_running_time (&decklinksink->video_segment, - GST_FORMAT_TIME, timestamp); - running_time_duration = - gst_segment_to_running_time (&decklinksink->video_segment, - GST_FORMAT_TIME, timestamp + duration) - running_time; - gst_buffer_unref (buffer); - -#if 0 - g_mutex_lock (&decklinksink->mutex); - /* FIXME: This is not correct as it assumes that the decklink clock - * has the exact same value as the pipeline clock at any time. Not - * only the same rate! - */ - while (decklinksink->queued_frames > 2 && !decklinksink->stop) { - g_cond_wait (&decklinksink->cond, &decklinksink->mutex); - } -#else - /* XXX: Wait until the pipeline clock reaches our running time to - * throttle filling the decklinksink internal queue */ - clock = gst_element_get_clock (GST_ELEMENT (decklinksink)); - base_time = gst_element_get_base_time (GST_ELEMENT (decklinksink)); - if (clock) { - if (base_time != GST_CLOCK_TIME_NONE) { - GstClockTime clock_time = gst_clock_get_time (clock); - - if (base_time + running_time + running_time_duration < - gst_clock_get_time (clock)) { - GST_WARNING_OBJECT (decklinksink, - "Dropping too late frame: %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, - GST_TIME_ARGS (running_time + running_time_duration), - GST_TIME_ARGS (clock_time - base_time)); - gst_object_unref (clock); - flow_ret = GST_FLOW_OK; - goto out; - } - clock_id = gst_clock_new_single_shot_id (clock, base_time + running_time); - - GST_LOG_OBJECT (decklinksink, - "waiting for clock: %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT, - GST_TIME_ARGS (clock_time), GST_TIME_ARGS (base_time + running_time)); - gst_clock_id_wait (clock_id, NULL); - GST_LOG_OBJECT (decklinksink, "finished waiting for clock"); - gst_clock_id_unref (clock_id); - } - - gst_object_unref (clock); - } -#endif - if (!decklinksink->stop) { - decklinksink->queued_frames++; - } -#if 0 - g_mutex_unlock (&decklinksink->mutex); -#endif - - if (!decklinksink->stop) { - GST_LOG_OBJECT (decklinksink, "Scheduling frame for %" GST_TIME_FORMAT, - GST_TIME_ARGS (running_time)); - - ret = decklinksink->output->ScheduleVideoFrame (frame, - running_time, running_time_duration, GST_SECOND); - if (ret != S_OK) { - GST_ELEMENT_ERROR (decklinksink, STREAM, FAILED, - (NULL), ("Failed to schedule frame: 0x%08x", ret)); - flow_ret = GST_FLOW_ERROR; - goto out; - } - - decklinksink->num_frames++; - - if (!decklinksink->sched_started) { - GST_DEBUG_OBJECT (decklinksink, - "Starting scheduled playback at %" GST_TIME_FORMAT, - GST_TIME_ARGS (running_time)); - ret = - decklinksink->output->StartScheduledPlayback (running_time, - GST_SECOND, 1.0); - if (ret != S_OK) { - GST_ELEMENT_ERROR (decklinksink, STREAM, FAILED, - (NULL), ("Failed to start scheduled playback: 0x%08x", ret)); - flow_ret = GST_FLOW_ERROR; - goto out; - } - decklinksink->sched_started = TRUE; - } - - flow_ret = GST_FLOW_OK; - } else { - flow_ret = GST_FLOW_FLUSHING; - } - -out: - frame->Release (); - - return flow_ret; -} - -static gboolean -gst_decklink_sink_videosink_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - gboolean res; - GstDecklinkSink *decklinksink; - - decklinksink = GST_DECKLINK_SINK (parent); - - GST_DEBUG_OBJECT (pad, "event: %" GST_PTR_FORMAT, event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS:{ - decklinksink->pixel_format = bmdFormat8BitYUV; - res = TRUE; - /* FIXME: this makes no sense, template caps don't contain v210 */ -#if 0 - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - ret = gst_video_format_parse_caps (caps, &format, &width, &height); - if (ret) { - if (format == GST_VIDEO_FORMAT_v210) { - decklinksink->pixel_format = bmdFormat10BitYUV; - } else { - decklinksink->pixel_format = bmdFormat8BitYUV; - } - } -#endif - break; - } - case GST_EVENT_EOS: - /* FIXME: EOS aggregation with audio pad looks wrong */ - decklinksink->video_eos = TRUE; - decklinksink->video_seqnum = gst_event_get_seqnum (event); - { - GstMessage *message; - - message = gst_message_new_eos (GST_OBJECT_CAST (decklinksink)); - gst_message_set_seqnum (message, decklinksink->video_seqnum); - gst_element_post_message (GST_ELEMENT_CAST (decklinksink), message); - } - res = gst_pad_event_default (pad, parent, event); - break; - case GST_EVENT_SEGMENT: - gst_event_copy_segment (event, &decklinksink->video_segment); - res = gst_pad_event_default (pad, parent, event); - break; - case GST_EVENT_FLUSH_STOP: - gst_segment_init (&decklinksink->video_segment, GST_FORMAT_TIME); - res = gst_pad_event_default (pad, parent, event); - break; - default: - res = gst_pad_event_default (pad, parent, event); - break; - } - - return res; -} - -static gboolean -gst_decklink_sink_videosink_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - gboolean res; - GstDecklinkSink *decklinksink; - - decklinksink = GST_DECKLINK_SINK (parent); - - GST_DEBUG_OBJECT (decklinksink, "query"); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CAPS:{ - GstCaps *mode_caps, *filter, *caps; - - /* FIXME: do we change mode if incoming caps change? If yes, we - * should probably return the template caps instead */ - mode_caps = gst_decklink_mode_get_caps (decklinksink->mode); - gst_query_parse_caps (query, &filter); - if (filter) { - caps = - gst_caps_intersect_full (filter, mode_caps, - GST_CAPS_INTERSECT_FIRST); - gst_caps_unref (mode_caps); - } else { - caps = mode_caps; - } - gst_query_set_caps_result (query, caps); - gst_caps_unref (caps); - res = TRUE; - break; - } - default: - res = gst_pad_query_default (pad, parent, query); - break; - } - - return res; -} - -static GstFlowReturn -gst_decklink_sink_audiosink_chain (GstPad * pad, GstObject * parent, - GstBuffer * buffer) -{ - GstDecklinkSink *decklinksink; - GstFlowReturn ret; - - decklinksink = GST_DECKLINK_SINK (parent); - - if (decklinksink->stop) - return GST_FLOW_FLUSHING; - - g_mutex_lock (&decklinksink->audio_mutex); - /* FIXME: This is not correct as it assumes that the decklink clock - * has the exact same value as the pipeline clock at any time. Not - * only the same rate! - */ - while (!decklinksink->stop && - gst_adapter_available (decklinksink->audio_adapter) > 1600 * 4 * 2) { - g_cond_wait (&decklinksink->audio_cond, &decklinksink->audio_mutex); - } - gst_adapter_push (decklinksink->audio_adapter, buffer); - g_mutex_unlock (&decklinksink->audio_mutex); - - ret = GST_FLOW_OK; - return ret; -} - -static gboolean -gst_decklink_sink_audiosink_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - gboolean res; - GstDecklinkSink *decklinksink; - - decklinksink = GST_DECKLINK_SINK (parent); - - GST_DEBUG_OBJECT (pad, "event: %" GST_PTR_FORMAT, event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - /* FIXME: EOS aggregation with video pad looks wrong */ - decklinksink->audio_eos = TRUE; - decklinksink->audio_seqnum = gst_event_get_seqnum (event); - res = gst_pad_event_default (pad, parent, event); - break; - case GST_EVENT_SEGMENT: - gst_event_copy_segment (event, &decklinksink->audio_segment); - res = gst_pad_event_default (pad, parent, event); - break; - case GST_EVENT_FLUSH_STOP: - gst_segment_init (&decklinksink->audio_segment, GST_FORMAT_TIME); - res = gst_pad_event_default (pad, parent, event); - break; - default: - res = gst_pad_event_default (pad, parent, event); - break; - } - - return res; -} - -static gboolean -gst_decklink_sink_audiosink_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - gboolean res; - - GST_DEBUG_OBJECT (pad, "query: %" GST_PTR_FORMAT, query); - - switch (GST_QUERY_TYPE (query)) { - default: - res = gst_pad_query_default (pad, parent, query); - break; - } - - return res; -} - -HRESULT - Output::ScheduledFrameCompleted (IDeckLinkVideoFrame * completedFrame, - BMDOutputFrameCompletionResult result) -{ - GST_DEBUG ("ScheduledFrameCompleted"); - - g_mutex_lock (&decklinksink->mutex); - g_cond_signal (&decklinksink->cond); - decklinksink->queued_frames--; - g_mutex_unlock (&decklinksink->mutex); - - return S_OK; -} - -HRESULT -Output::ScheduledPlaybackHasStopped () -{ - GST_DEBUG ("ScheduledPlaybackHasStopped"); - return S_OK; -} - -HRESULT -Output::RenderAudioSamples (bool preroll) -{ - uint32_t samplesWritten; - HRESULT ret; - - // guint64 samplesToWrite; - - if (decklinksink->stop) { - GST_DEBUG ("decklinksink->stop set TRUE!"); - decklinksink->output->BeginAudioPreroll (); - // running = true; - } else { - gconstpointer data; - int n; - - g_mutex_lock (&decklinksink->audio_mutex); - - n = gst_adapter_available (decklinksink->audio_adapter); - if (n > 0) { - data = gst_adapter_map (decklinksink->audio_adapter, n); - - /* FIXME: This is not correct. We assume here that the decklink - * clock runs at the same rate as the pipeline clock and that - * the input stream has no discontinuities at all - */ - ret = decklinksink->output->ScheduleAudioSamples ((void *) data, n / 4, - 0, 0, &samplesWritten); - - gst_adapter_unmap (decklinksink->audio_adapter); - gst_adapter_flush (decklinksink->audio_adapter, samplesWritten * 4); - if (ret != S_OK) { - GST_ELEMENT_ERROR (decklinksink, STREAM, FAILED, - (NULL), ("Failed to schedule audio samples: 0x%08x", ret)); - } else { - GST_DEBUG ("wrote %d samples, %d available", samplesWritten, n / 4); - } - - g_cond_signal (&decklinksink->audio_cond); - } else { - if (decklinksink->audio_eos) { - GstMessage *message; - - message = gst_message_new_eos (GST_OBJECT_CAST (decklinksink)); - gst_message_set_seqnum (message, decklinksink->audio_seqnum); - gst_element_post_message (GST_ELEMENT_CAST (decklinksink), message); - } - } - g_mutex_unlock (&decklinksink->audio_mutex); - - } - - GST_DEBUG ("RenderAudioSamples"); - - return S_OK; -} - -Output::~Output () -{ -} diff --git a/sys/decklink/gstdecklinksink.h b/sys/decklink/gstdecklinksink.h deleted file mode 100644 index 5aec1a66e7..0000000000 --- a/sys/decklink/gstdecklinksink.h +++ /dev/null @@ -1,108 +0,0 @@ -/* GStreamer - * Copyright (C) 2011 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _GST_DECKLINK_SINK_H_ -#define _GST_DECKLINK_SINK_H_ - -#include -#include -#include "gstdecklink.h" - -G_BEGIN_DECLS - -#define GST_TYPE_DECKLINK_SINK (gst_decklink_sink_get_type()) -#define GST_DECKLINK_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECKLINK_SINK,GstDecklinkSink)) -#define GST_DECKLINK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECKLINK_SINK,GstDecklinkSinkClass)) -#define GST_DECKLINK_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DECKLINK_SINK, GstDecklinkSinkClass)) -#define GST_IS_DECKLINK_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECKLINK_SINK)) -#define GST_IS_DECKLINK_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECKLINK_SINK)) - -typedef struct _GstDecklinkSink GstDecklinkSink; -typedef struct _GstDecklinkSinkClass GstDecklinkSinkClass; - -class Output : public IDeckLinkVideoOutputCallback, -public IDeckLinkAudioOutputCallback -{ - public: - GstDecklinkSink *decklinksink; - - virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID iid, LPVOID *ppv) {return E_NOINTERFACE;} - virtual ULONG STDMETHODCALLTYPE AddRef () {return 1;} - virtual ULONG STDMETHODCALLTYPE Release () {return 1;} - virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result); - virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped (); - virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples (bool preroll); - - virtual ~Output(); -}; - -struct _GstDecklinkSink -{ - GstElement base_decklinksink; - GstAdapter *audio_adapter; - - GstPad *videosinkpad; - GstPad *audiosinkpad; - - GMutex mutex; - GCond cond; - GMutex audio_mutex; - GCond audio_cond; - int queued_frames; - gboolean stop; - gboolean video_eos; - gboolean audio_eos; - int video_seqnum; - int audio_seqnum; - GstSegment audio_segment, video_segment; - - IDeckLink *decklink; - IDeckLinkOutput *output; - Output *callback; - BMDDisplayMode display_mode; - BMDPixelFormat pixel_format; - gboolean video_enabled; - gboolean sched_started; - - int num_frames; - - /* properties */ - GstDecklinkModeEnum mode; - int device_number; - -#ifdef _MSC_VER - gboolean comInitialized; - GMutex com_init_lock; - GMutex com_deinit_lock; - GCond com_initialized; - GCond com_uninitialize; - GCond com_uninitialized; -#endif /* _MSC_VER */ -}; - -struct _GstDecklinkSinkClass -{ - GstElementClass base_decklinksink_class; -}; - -GType gst_decklink_sink_get_type (void); - -G_END_DECLS - -#endif diff --git a/sys/decklink/gstdecklinksrc.cpp b/sys/decklink/gstdecklinksrc.cpp deleted file mode 100644 index b2e7d82175..0000000000 --- a/sys/decklink/gstdecklinksrc.cpp +++ /dev/null @@ -1,972 +0,0 @@ -/* GStreamer - * Copyright (C) 2011 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, - * Boston, MA 02110-1335, USA. - */ -/** - * SECTION:element-gstdecklinksrc - * - * The decklinksrc element is a source element for Blackmagic - * Decklink cards. - * - * - * Example launch line - * |[ - * gst-launch-1.0 -v decklinksrc ! videoconvert ! xvimagesink - * ]| - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstdecklink.h" -#include "gstdecklinksrc.h" -#include "capture.h" -#include - - -GST_DEBUG_CATEGORY (gst_decklink_src_debug_category); -#define GST_CAT_DEFAULT gst_decklink_src_debug_category - -typedef struct _VideoFrame VideoFrame; -struct _VideoFrame -{ - IDeckLinkVideoInputFrame *frame; - IDeckLinkInput *input; -}; - -static void gst_decklink_src_set_property (GObject * object, - guint property_id, const GValue * value, GParamSpec * pspec); -static void gst_decklink_src_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); -static void gst_decklink_src_finalize (GObject * object); - -static GstStateChangeReturn -gst_decklink_src_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_decklink_src_send_event (GstElement * element, - GstEvent * event); - -static gboolean gst_decklink_src_audio_src_query (GstPad * pad, - GstObject * parent, GstQuery * query); -static gboolean gst_decklink_src_video_src_query (GstPad * pad, - GstObject * parent, GstQuery * query); - -static void gst_decklink_src_task (void *priv); - -#ifdef _MSC_VER -/* COM initialization/uninitialization thread */ -static void gst_decklink_src_com_thread (GstDecklinkSrc * src); -#endif /* _MSC_VER */ - -enum -{ - PROP_0, - PROP_MODE, - PROP_CONNECTION, - PROP_AUDIO_INPUT, - PROP_DEVICE_NUMBER -}; - -static GstStaticPadTemplate gst_decklink_src_audio_src_template = -GST_STATIC_PAD_TEMPLATE ("audiosrc", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw, format=S16LE, channels=2, rate=48000, " - "layout=interleaved") - ); - -/* the video source pad template is created on the fly */ - -#define parent_class gst_decklink_src_parent_class -G_DEFINE_TYPE (GstDecklinkSrc, gst_decklink_src, GST_TYPE_ELEMENT); - -static void -gst_decklink_src_class_init (GstDecklinkSrcClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gobject_class->set_property = gst_decklink_src_set_property; - gobject_class->get_property = gst_decklink_src_get_property; - gobject_class->finalize = gst_decklink_src_finalize; - - element_class->send_event = GST_DEBUG_FUNCPTR (gst_decklink_src_send_event); - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_decklink_src_change_state); - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", "Video mode to use for capture", - GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - g_object_class_install_property (gobject_class, PROP_CONNECTION, - g_param_spec_enum ("connection", "Connection", - "Video input connection to use", - GST_TYPE_DECKLINK_CONNECTION, GST_DECKLINK_CONNECTION_SDI, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - g_object_class_install_property (gobject_class, PROP_AUDIO_INPUT, - g_param_spec_enum ("audio-input", "Audio Input", - "Audio input connection", - GST_TYPE_DECKLINK_AUDIO_CONNECTION, - GST_DECKLINK_AUDIO_CONNECTION_AUTO, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - g_object_class_install_property (gobject_class, PROP_DEVICE_NUMBER, - g_param_spec_int ("device-number", "Device number", - "Capture device instance to use", 0, G_MAXINT, 0, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_CONSTRUCT))); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_decklink_src_audio_src_template)); - - gst_element_class_add_pad_template (element_class, - gst_pad_template_new ("videosrc", GST_PAD_SRC, GST_PAD_ALWAYS, - gst_decklink_mode_get_template_caps ())); - - gst_element_class_set_static_metadata (element_class, "Decklink source", - "Source/Video", "DeckLink Source", "David Schleef "); -} - -static void -gst_decklink_src_init (GstDecklinkSrc * decklinksrc) -{ - GstDecklinkSrcClass *decklinksrc_class; - - decklinksrc_class = GST_DECKLINK_SRC_GET_CLASS (decklinksrc); - - g_rec_mutex_init (&decklinksrc->task_mutex); - decklinksrc->task = gst_task_new (gst_decklink_src_task, decklinksrc, NULL); - gst_task_set_lock (decklinksrc->task, &decklinksrc->task_mutex); - - decklinksrc->audiosrcpad = - gst_pad_new_from_static_template (&gst_decklink_src_audio_src_template, - "audiosrc"); - gst_pad_set_query_function (decklinksrc->audiosrcpad, - GST_DEBUG_FUNCPTR (gst_decklink_src_audio_src_query)); - gst_element_add_pad (GST_ELEMENT (decklinksrc), decklinksrc->audiosrcpad); - - - - decklinksrc->videosrcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_CLASS (decklinksrc_class), "videosrc"), "videosrc"); - gst_pad_set_query_function (decklinksrc->videosrcpad, - GST_DEBUG_FUNCPTR (gst_decklink_src_video_src_query)); - gst_element_add_pad (GST_ELEMENT (decklinksrc), decklinksrc->videosrcpad); - - GST_OBJECT_FLAG_SET (decklinksrc, GST_ELEMENT_FLAG_SOURCE); - - g_cond_init (&decklinksrc->cond); - g_mutex_init (&decklinksrc->mutex); - - /* FIXME: turn this into a property? */ - decklinksrc->copy_data = TRUE; - decklinksrc->mode = GST_DECKLINK_MODE_NTSC; - decklinksrc->connection = GST_DECKLINK_CONNECTION_SDI; - decklinksrc->audio_connection = GST_DECKLINK_AUDIO_CONNECTION_AUTO; - decklinksrc->device_number = 0; - - decklinksrc->stop = FALSE; - decklinksrc->dropped_frames = 0; - decklinksrc->dropped_frames_old = 0; - decklinksrc->frame_num = -1; /* -1 so will be 0 after incrementing */ - -#ifdef _MSC_VER - g_mutex_init (&decklinksrc->com_init_lock); - g_mutex_init (&decklinksrc->com_deinit_lock); - g_cond_init (&decklinksrc->com_initialized); - g_cond_init (&decklinksrc->com_uninitialize); - g_cond_init (&decklinksrc->com_uninitialized); - - g_mutex_lock (&decklinksrc->com_init_lock); - - /* create the COM initialization thread */ - g_thread_create ((GThreadFunc) gst_decklink_src_com_thread, - decklinksrc, FALSE, NULL); - - /* wait until the COM thread signals that COM has been initialized */ - g_cond_wait (&decklinksrc->com_initialized, &decklinksrc->com_init_lock); - g_mutex_unlock (&decklinksrc->com_init_lock); -#endif /* _MSC_VER */ - - GST_DEBUG_CATEGORY_INIT (gst_decklink_src_debug_category, "decklinksrc", 0, - "debug category for decklinksrc element"); -} - -void -gst_decklink_src_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstDecklinkSrc *decklinksrc; - - decklinksrc = GST_DECKLINK_SRC (object); - - switch (property_id) { - case PROP_MODE: - decklinksrc->mode = (GstDecklinkModeEnum) g_value_get_enum (value); - break; - case PROP_CONNECTION: - decklinksrc->connection = - (GstDecklinkConnectionEnum) g_value_get_enum (value); - break; - case PROP_AUDIO_INPUT: - decklinksrc->audio_connection = - (GstDecklinkAudioConnectionEnum) g_value_get_enum (value); - break; - case PROP_DEVICE_NUMBER: - decklinksrc->device_number = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -void -gst_decklink_src_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstDecklinkSrc *decklinksrc; - - decklinksrc = GST_DECKLINK_SRC (object); - - switch (property_id) { - case PROP_MODE: - g_value_set_enum (value, decklinksrc->mode); - break; - case PROP_CONNECTION: - g_value_set_enum (value, decklinksrc->connection); - break; - case PROP_AUDIO_INPUT: - g_value_set_enum (value, decklinksrc->audio_connection); - break; - case PROP_DEVICE_NUMBER: - g_value_set_int (value, decklinksrc->device_number); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -#ifdef _MSC_VER -static void -gst_decklink_src_com_thread (GstDecklinkSrc * src) -{ - HRESULT res; - - g_mutex_lock (src->com_init_lock); - - /* Initialize COM with a MTA for this process. This thread will - * be the first one to enter the apartement and the last one to leave - * it, unitializing COM properly */ - - res = CoInitializeEx (0, COINIT_MULTITHREADED); - if (res == S_FALSE) - GST_WARNING_OBJECT (src, - "COM has been already initialized in the same process"); - else if (res == RPC_E_CHANGED_MODE) - GST_WARNING_OBJECT (src, "The concurrency model of COM has changed."); - else - GST_INFO_OBJECT (src, "COM intialized succesfully"); - - src->comInitialized = TRUE; - - /* Signal other threads waiting on this condition that COM was initialized */ - g_cond_signal (src->com_initialized); - - g_mutex_unlock (src->com_init_lock); - - /* Wait until the unitialize condition is met to leave the COM apartement */ - g_mutex_lock (src->com_deinit_lock); - g_cond_wait (src->com_uninitialize, src->com_deinit_lock); - - CoUninitialize (); - GST_INFO_OBJECT (src, "COM unintialized succesfully"); - src->comInitialized = FALSE; - g_cond_signal (src->com_uninitialized); - g_mutex_unlock (src->com_deinit_lock); -} -#endif /* _MSC_VER */ - -void -gst_decklink_src_finalize (GObject * object) -{ - GstDecklinkSrc *decklinksrc; - - g_return_if_fail (GST_IS_DECKLINK_SRC (object)); - decklinksrc = GST_DECKLINK_SRC (object); - - /* clean up object here */ - - g_cond_clear (&decklinksrc->cond); - g_mutex_clear (&decklinksrc->mutex); - gst_task_set_lock (decklinksrc->task, NULL); - g_object_unref (decklinksrc->task); - -#ifdef _MSC_VER - /* signal the COM thread that it should uninitialize COM */ - if (decklinksrc->comInitialized) { - g_mutex_lock (&decklinksrc->com_deinit_lock); - g_cond_signal (&decklinksrc->com_uninitialize); - g_cond_wait (&decklinksrc->com_uninitialized, - &decklinksrc->com_deinit_lock); - g_mutex_unlock (&decklinksrc->com_deinit_lock); - } - - g_mutex_clear (&decklinksrc->com_init_lock); - g_mutex_clear (&decklinksrc->com_deinit_lock); - g_cond_clear (&decklinksrc->com_initialized); - g_cond_clear (&decklinksrc->com_uninitialize); - g_cond_clear (&decklinksrc->com_uninitialized); -#endif /* _MSC_VER */ - - g_rec_mutex_clear (&decklinksrc->task_mutex); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -/* events sent to this element directly, mainly from the application */ -static gboolean -gst_decklink_src_send_event (GstElement * element, GstEvent * event) -{ - GstDecklinkSrc *src; - gboolean result = FALSE; - - src = GST_DECKLINK_SRC (element); - - GST_DEBUG_OBJECT (src, "handling event %p %" GST_PTR_FORMAT, event, event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - g_atomic_int_set (&src->pending_eos, TRUE); - GST_INFO_OBJECT (src, "EOS pending"); - g_cond_signal (&src->cond); - result = TRUE; - break; - break; - case GST_EVENT_TAG: - case GST_EVENT_CUSTOM_DOWNSTREAM: - case GST_EVENT_CUSTOM_BOTH: - /* Insert TAG, CUSTOM_DOWNSTREAM, CUSTOM_BOTH in the dataflow */ - GST_OBJECT_LOCK (src); - src->pending_events = g_list_append (src->pending_events, event); - g_atomic_int_set (&src->have_events, TRUE); - GST_OBJECT_UNLOCK (src); - event = NULL; - result = TRUE; - break; - case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: - case GST_EVENT_CUSTOM_BOTH_OOB: - /* insert a random custom event into the pipeline */ - GST_DEBUG_OBJECT (src, "pushing custom OOB event downstream"); - result = gst_pad_push_event (src->videosrcpad, gst_event_ref (event)); - result |= gst_pad_push_event (src->audiosrcpad, event); - /* we gave away the ref to the event in the push */ - event = NULL; - break; - case GST_EVENT_CUSTOM_UPSTREAM: - /* drop */ - case GST_EVENT_SEGMENT: - /* sending random SEGMENT downstream can break sync - drop */ - default: - GST_LOG_OBJECT (src, "dropping %s event", GST_EVENT_TYPE_NAME (event)); - break; - } - - /* if we still have a ref to the event, unref it now */ - if (event) - gst_event_unref (event); - - return result; -} - -/* FIXME: post error messages for the misc. failures */ -static gboolean -gst_decklink_src_start (GstElement * element) -{ - GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element); - BMDAudioSampleType sample_depth; - int channels; - HRESULT ret; - const GstDecklinkMode *mode; - IDeckLinkConfiguration *config; - BMDVideoConnection conn; - BMDAudioConnection aconn; - - GST_DEBUG_OBJECT (decklinksrc, "start"); - - decklinksrc->decklink = - gst_decklink_get_nth_device (decklinksrc->device_number); - if (decklinksrc->decklink == NULL) { - return FALSE; - } - - decklinksrc->input = gst_decklink_get_nth_input (decklinksrc->device_number); - if (decklinksrc->input == NULL) { - GST_ERROR ("no input source for device %i", decklinksrc->device_number); - return FALSE; - } - - decklinksrc->delegate = new DeckLinkCaptureDelegate (); - decklinksrc->delegate->priv = decklinksrc; - ret = decklinksrc->input->SetCallback (decklinksrc->delegate); - if (ret != S_OK) { - GST_ERROR ("set callback failed (input source)"); - return FALSE; - } - - decklinksrc->config = - gst_decklink_get_nth_config (decklinksrc->device_number); - config = decklinksrc->config; - if (decklinksrc->config == NULL) { - GST_ERROR ("no config for device %i", decklinksrc->device_number); - return FALSE; - } - - switch (decklinksrc->connection) { - default: - case GST_DECKLINK_CONNECTION_SDI: - conn = bmdVideoConnectionSDI; - aconn = bmdAudioConnectionEmbedded; - break; - case GST_DECKLINK_CONNECTION_HDMI: - conn = bmdVideoConnectionHDMI; - aconn = bmdAudioConnectionEmbedded; - break; - case GST_DECKLINK_CONNECTION_OPTICAL_SDI: - conn = bmdVideoConnectionOpticalSDI; - aconn = bmdAudioConnectionEmbedded; - break; - case GST_DECKLINK_CONNECTION_COMPONENT: - conn = bmdVideoConnectionComponent; - aconn = bmdAudioConnectionAnalog; - break; - case GST_DECKLINK_CONNECTION_COMPOSITE: - conn = bmdVideoConnectionComposite; - aconn = bmdAudioConnectionAnalog; - break; - case GST_DECKLINK_CONNECTION_SVIDEO: - conn = bmdVideoConnectionSVideo; - aconn = bmdAudioConnectionAnalog; - break; - } - - ret = config->SetInt (bmdDeckLinkConfigVideoInputConnection, conn); - if (ret != S_OK) { - GST_ERROR ("set configuration (input source)"); - return FALSE; - } - - if (decklinksrc->connection == GST_DECKLINK_CONNECTION_COMPOSITE) { - ret = config->SetInt (bmdDeckLinkConfigAnalogVideoInputFlags, - bmdAnalogVideoFlagCompositeSetup75); - if (ret != S_OK) { - GST_ERROR ("set configuration (composite setup)"); - return FALSE; - } - } - - switch (decklinksrc->audio_connection) { - default: - case GST_DECKLINK_AUDIO_CONNECTION_AUTO: - /* set above */ - break; - case GST_DECKLINK_AUDIO_CONNECTION_EMBEDDED: - aconn = bmdAudioConnectionEmbedded; - break; - case GST_DECKLINK_AUDIO_CONNECTION_AES_EBU: - aconn = bmdAudioConnectionAESEBU; - break; - case GST_DECKLINK_AUDIO_CONNECTION_ANALOG: - aconn = bmdAudioConnectionAnalog; - break; - } - ret = config->SetInt (bmdDeckLinkConfigAudioInputConnection, aconn); - if (ret != S_OK) { - GST_ERROR ("set configuration (audio input connection)"); - return FALSE; - } - - mode = gst_decklink_get_mode (decklinksrc->mode); - - ret = decklinksrc->input->EnableVideoInput (mode->mode, bmdFormat8BitYUV, 0); - if (ret != S_OK) { - GST_ERROR ("enable video input failed"); - return FALSE; - } - - sample_depth = bmdAudioSampleType16bitInteger; - channels = 2; - ret = decklinksrc->input->EnableAudioInput (bmdAudioSampleRate48kHz, - sample_depth, channels); - if (ret != S_OK) { - GST_ERROR ("enable video input failed"); - return FALSE; - } - - ret = decklinksrc->input->StartStreams (); - if (ret != S_OK) { - GST_ERROR ("start streams failed"); - return FALSE; - } - - g_rec_mutex_lock (&decklinksrc->task_mutex); - gst_task_start (decklinksrc->task); - g_rec_mutex_unlock (&decklinksrc->task_mutex); - - return TRUE; -} - -static gboolean -gst_decklink_src_stop (GstElement * element) -{ - GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element); - - gst_task_stop (decklinksrc->task); - - g_mutex_lock (&decklinksrc->mutex); - decklinksrc->stop = TRUE; - g_cond_signal (&decklinksrc->cond); - g_mutex_unlock (&decklinksrc->mutex); - - gst_task_join (decklinksrc->task); - - decklinksrc->input->StopStreams (); - decklinksrc->input->DisableVideoInput (); - decklinksrc->input->DisableAudioInput (); - - /* This deletes the delegate for us already */ - decklinksrc->input->SetCallback (NULL); - decklinksrc->delegate = NULL; - - g_list_free_full (decklinksrc->pending_events, - (GDestroyNotify) gst_mini_object_unref); - decklinksrc->pending_events = NULL; - decklinksrc->have_events = FALSE; - decklinksrc->pending_eos = FALSE; - - return TRUE; -} - -static GstStateChangeReturn -gst_decklink_src_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - gboolean no_preroll = FALSE; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_decklink_src_start (element)) { - ret = GST_STATE_CHANGE_FAILURE; - goto out; - } - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - no_preroll = TRUE; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - no_preroll = TRUE; - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_decklink_src_stop (element); - break; - default: - break; - } - - if (no_preroll && ret == GST_STATE_CHANGE_SUCCESS) - ret = GST_STATE_CHANGE_NO_PREROLL; - -out: - return ret; -} - -static gboolean -gst_decklink_src_audio_src_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - gboolean res; - - GST_DEBUG_OBJECT (pad, "query: %" GST_PTR_FORMAT, query); - - switch (GST_QUERY_TYPE (query)) { - /* FIXME: report live-ness and latency for audio too */ - case GST_QUERY_LATENCY: - GST_FIXME_OBJECT (parent, "should report live-ness and audio latency"); - res = gst_pad_query_default (pad, parent, query); - break; - default: - res = gst_pad_query_default (pad, parent, query); - break; - } - - return res; -} - -static gboolean -gst_decklink_src_video_src_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - GstDecklinkSrc *decklinksrc; - gboolean ret = FALSE; - - decklinksrc = GST_DECKLINK_SRC (parent); - - GST_DEBUG_OBJECT (pad, "query: %" GST_PTR_FORMAT, query); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY:{ - GstClockTime min_latency, max_latency; - const GstDecklinkMode *mode; - - /* device must be open */ - if (decklinksrc->decklink == NULL) { - GST_WARNING_OBJECT (decklinksrc, - "Can't give latency since device isn't open !"); - goto done; - } - - mode = gst_decklink_get_mode (decklinksrc->mode); - - /* min latency is the time to capture one frame */ - min_latency = - gst_util_uint64_scale_int (GST_SECOND, mode->fps_d, mode->fps_n); - - /* max latency is total duration of the frame buffer */ - max_latency = 2 * min_latency; - - GST_DEBUG_OBJECT (decklinksrc, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - /* we are always live, the min latency is 1 frame and the max latency is - * the complete buffer of frames. */ - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - ret = TRUE; - break; - } - default: - ret = gst_pad_query_default (pad, parent, query); - break; - } - -done: - return ret; -} - -static void -video_frame_free (void *data) -{ - VideoFrame *video_frame = (VideoFrame *) data; - - video_frame->frame->Release (); - video_frame->input->Release (); - g_free (video_frame); -} - -static void -gst_decklink_src_send_initial_events (GstDecklinkSrc * src) -{ - GstSegment segment; - GstEvent *event; - guint group_id; - guint32 audio_id, video_id; - gchar stream_id[9]; - - /* stream-start */ - audio_id = g_random_int (); - video_id = g_random_int (); - while (video_id == audio_id) - video_id = g_random_int (); - - group_id = gst_util_group_id_next (); - g_snprintf (stream_id, sizeof (stream_id), "%08x", audio_id); - event = gst_event_new_stream_start (stream_id); - gst_event_set_group_id (event, group_id); - gst_pad_push_event (src->audiosrcpad, event); - - g_snprintf (stream_id, sizeof (stream_id), "%08x", video_id); - event = gst_event_new_stream_start (stream_id); - gst_event_set_group_id (event, group_id); - gst_pad_push_event (src->videosrcpad, event); - - /* caps */ - gst_pad_push_event (src->audiosrcpad, - gst_event_new_caps (gst_caps_new_simple ("audio/x-raw", - "format", G_TYPE_STRING, "S16LE", "channels", G_TYPE_INT, 2, - "rate", G_TYPE_INT, 48000, "layout", G_TYPE_STRING, "interleaved", - NULL))); - - gst_pad_push_event (src->videosrcpad, - gst_event_new_caps (gst_decklink_mode_get_caps (src->mode))); - - /* segment */ - gst_segment_init (&segment, GST_FORMAT_TIME); - event = gst_event_new_segment (&segment); - gst_pad_push_event (src->videosrcpad, gst_event_ref (event)); - gst_pad_push_event (src->audiosrcpad, event); -} - -static void -gst_decklink_src_task (void *priv) -{ - GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (priv); - GstBuffer *buffer; - GstBuffer *audio_buffer; - IDeckLinkVideoInputFrame *video_frame; - IDeckLinkAudioInputPacket *audio_frame; - void *data; - gsize data_size; - int n_samples; - GstFlowReturn video_flow, audio_flow, flow; - const GstDecklinkMode *mode; - gboolean discont = FALSE; - GstClockTime capture_time; - - GST_DEBUG_OBJECT (decklinksrc, "task"); - - g_mutex_lock (&decklinksrc->mutex); - while (decklinksrc->video_frame == NULL && !decklinksrc->stop && - !decklinksrc->pending_eos) { - g_cond_wait (&decklinksrc->cond, &decklinksrc->mutex); - } - video_frame = decklinksrc->video_frame; - audio_frame = decklinksrc->audio_frame; - capture_time = decklinksrc->capture_time; - decklinksrc->video_frame = NULL; - decklinksrc->audio_frame = NULL; - g_mutex_unlock (&decklinksrc->mutex); - - if (decklinksrc->stop) { - if (video_frame) - video_frame->Release (); - if (audio_frame) - audio_frame->Release (); - GST_DEBUG ("stopping task"); - return; - } - - if (g_atomic_int_compare_and_exchange (&decklinksrc->pending_eos, TRUE, - FALSE)) { - GST_INFO_OBJECT (decklinksrc, "EOS pending"); - flow = GST_FLOW_EOS; - goto pause; - } - - /* warning on dropped frames */ - /* FIXME: post QoS message */ - if (decklinksrc->dropped_frames - decklinksrc->dropped_frames_old > 0) { - GST_ELEMENT_WARNING (decklinksrc, RESOURCE, READ, - ("Dropped %d frame(s), for a total of %d frame(s)", - decklinksrc->dropped_frames - decklinksrc->dropped_frames_old, - decklinksrc->dropped_frames), (NULL)); - decklinksrc->dropped_frames_old = decklinksrc->dropped_frames; - /* FIXME: discont = TRUE; ? */ - } - - if (!decklinksrc->started) { - gst_decklink_src_send_initial_events (decklinksrc); - decklinksrc->started = TRUE; - } - - if (g_atomic_int_get (&decklinksrc->have_events)) { - GList *l; - - GST_OBJECT_LOCK (decklinksrc); - for (l = decklinksrc->pending_events; l != NULL; l = l->next) { - GstEvent *event = GST_EVENT (l->data); - - GST_DEBUG_OBJECT (decklinksrc, "pushing %s event", - GST_EVENT_TYPE_NAME (event)); - gst_pad_push_event (decklinksrc->videosrcpad, gst_event_ref (event)); - gst_pad_push_event (decklinksrc->audiosrcpad, event); - l->data = NULL; - } - g_list_free (decklinksrc->pending_events); - decklinksrc->pending_events = NULL; - g_atomic_int_set (&decklinksrc->have_events, FALSE); - GST_OBJECT_UNLOCK (decklinksrc); - } - - mode = gst_decklink_get_mode (decklinksrc->mode); - - video_frame->GetBytes (&data); - - data_size = mode->width * mode->height * 2; - - if (decklinksrc->copy_data) { - buffer = gst_buffer_new_and_alloc (data_size); - - gst_buffer_fill (buffer, 0, data, data_size); - - video_frame->Release (); - } else { - VideoFrame *vf; - - vf = (VideoFrame *) g_malloc0 (sizeof (VideoFrame)); - - buffer = gst_buffer_new_wrapped_full ((GstMemoryFlags) 0, data, data_size, - 0, data_size, vf, (GDestroyNotify) video_frame_free); - - vf->frame = video_frame; - vf->input = decklinksrc->input; - vf->input->AddRef (); - } - - GST_BUFFER_TIMESTAMP (buffer) = capture_time; - GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (GST_SECOND, - mode->fps_d, mode->fps_n); - GST_BUFFER_OFFSET (buffer) = decklinksrc->frame_num; - GST_BUFFER_OFFSET_END (buffer) = decklinksrc->frame_num; /* FIXME: +1? */ - - /* FIXME: set video meta */ - - if (decklinksrc->frame_num == 0) - discont = TRUE; - - if (discont) - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - else - GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); - - video_flow = gst_pad_push (decklinksrc->videosrcpad, buffer); - - if (gst_pad_is_linked (decklinksrc->audiosrcpad)) { - n_samples = audio_frame->GetSampleFrameCount (); - audio_frame->GetBytes (&data); - audio_buffer = gst_buffer_new_and_alloc (n_samples * 2 * 2); - gst_buffer_fill (audio_buffer, 0, data, n_samples * 2 * 2); - - GST_BUFFER_TIMESTAMP (audio_buffer) = capture_time; - /* FIXME: should be next_timestamp - timestamp for perfect stream */ - GST_BUFFER_DURATION (audio_buffer) = - gst_util_uint64_scale_int (n_samples * GST_SECOND, 1, 48000); - GST_BUFFER_OFFSET (audio_buffer) = decklinksrc->num_audio_samples; - GST_BUFFER_OFFSET_END (audio_buffer) = - GST_BUFFER_OFFSET (audio_buffer) + n_samples; - - decklinksrc->num_audio_samples += n_samples; - - if (discont) - GST_BUFFER_FLAG_SET (audio_buffer, GST_BUFFER_FLAG_DISCONT); - else - GST_BUFFER_FLAG_UNSET (audio_buffer, GST_BUFFER_FLAG_DISCONT); - - audio_flow = gst_pad_push (decklinksrc->audiosrcpad, audio_buffer); - } else { - audio_flow = GST_FLOW_NOT_LINKED; - } - - if (audio_flow == GST_FLOW_NOT_LINKED) - flow = video_flow; - else if (video_flow == GST_FLOW_NOT_LINKED) - flow = audio_flow; - else if (video_flow == GST_FLOW_FLUSHING || audio_flow == GST_FLOW_FLUSHING) - flow = GST_FLOW_FLUSHING; - else if (video_flow < GST_FLOW_EOS) - flow = video_flow; - else if (audio_flow < GST_FLOW_EOS) - flow = audio_flow; - else if (video_flow == GST_FLOW_EOS || audio_flow == GST_FLOW_EOS) - flow = GST_FLOW_EOS; - else - flow = video_flow; - - if (flow != GST_FLOW_OK) - goto pause; - -done: - - if (audio_frame) - audio_frame->Release (); - - return; - -pause: - { - const gchar *reason = gst_flow_get_name (flow); - GstEvent *event = NULL; - - GST_DEBUG_OBJECT (decklinksrc, "pausing task, reason %s", reason); - gst_task_pause (decklinksrc->task); - if (flow == GST_FLOW_EOS) { - /* perform EOS logic (very crude, we don't even keep a GstSegment) */ - event = gst_event_new_eos (); - } else if (flow == GST_FLOW_NOT_LINKED || flow < GST_FLOW_EOS) { - event = gst_event_new_eos (); - /* for fatal errors we post an error message, post the error - * first so the app knows about the error first. - * Also don't do this for FLUSHING because it happens - * due to flushing and posting an error message because of - * that is the wrong thing to do, e.g. when we're doing - * a flushing seek. */ - GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED, - ("Internal data flow error."), - ("streaming task paused, reason %s (%d)", reason, flow)); - } - if (event != NULL) { - GST_INFO_OBJECT (decklinksrc->videosrcpad, "pushing EOS event"); - gst_pad_push_event (decklinksrc->videosrcpad, gst_event_ref (event)); - GST_INFO_OBJECT (decklinksrc->audiosrcpad, "pushing EOS event"); - gst_pad_push_event (decklinksrc->audiosrcpad, event); - } - goto done; - } -} - -#if 0 -/* former device probe code, redux */ -static void -gst_decklinksrc_list_devices (void) -{ - IDeckLinkIterator *iterator; - IDeckLink *decklink; - int n_devices; - - n_devices = 0; - iterator = CreateDeckLinkIteratorInstance (); - if (iterator) { - while (iterator->Next (&decklink) == S_OK) { - n_devices++; - } - } - iterator->Release (); - - g_print ("%d devices\n", n_devices); -} -#endif diff --git a/sys/decklink/gstdecklinksrc.h b/sys/decklink/gstdecklinksrc.h deleted file mode 100644 index 5d8ae90f8f..0000000000 --- a/sys/decklink/gstdecklinksrc.h +++ /dev/null @@ -1,109 +0,0 @@ -/* GStreamer - * Copyright (C) 2011 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _GST_DECKLINK_SRC_H_ -#define _GST_DECKLINK_SRC_H_ - -#include -#include "gstdecklink.h" -#include "capture.h" - -G_BEGIN_DECLS - -GST_DEBUG_CATEGORY_EXTERN (gst_decklink_src_debug_category); - -#define GST_TYPE_DECKLINK_SRC (gst_decklink_src_get_type()) -#define GST_DECKLINK_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECKLINK_SRC,GstDecklinkSrc)) -#define GST_DECKLINK_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECKLINK_SRC,GstDecklinkSrcClass)) -#define GST_DECKLINK_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DECKLINK_SRC, GstDecklinkSrcClass)) -#define GST_IS_DECKLINK_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECKLINK_SRC)) -#define GST_IS_DECKLINK_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECKLINK_SRC)) - -typedef struct _GstDecklinkSrc GstDecklinkSrc; -typedef struct _GstDecklinkSrcClass GstDecklinkSrcClass; - -struct _GstDecklinkSrc -{ - GstElement base_decklinksrc; - - GstPad *audiosrcpad; - GstPad *videosrcpad; - - gboolean pending_eos; /* ATOMIC */ - - gboolean have_events; /* ATOMIC */ - GList *pending_events; /* OBJECT_LOCK */ - - IDeckLink *decklink; - IDeckLinkInput *input; - IDeckLinkConfiguration *config; - DeckLinkCaptureDelegate *delegate; - - GMutex mutex; - GCond cond; - int dropped_frames; - int dropped_frames_old; - gboolean stop; - GstClockTime capture_time; - IDeckLinkVideoInputFrame *video_frame; - IDeckLinkAudioInputPacket * audio_frame; - - GstTask *task; - GRecMutex task_mutex; - - guint64 num_audio_samples; - - guint64 frame_num; - int fps_n; - int fps_d; - int width; - int height; - gboolean interlaced; - BMDDisplayMode bmd_mode; - - /* so we send a stream-start, caps, and newsegment events before buffers */ - gboolean started; - - /* properties */ - gboolean copy_data; - GstDecklinkModeEnum mode; - GstDecklinkConnectionEnum connection; - GstDecklinkAudioConnectionEnum audio_connection; - int device_number; - -#ifdef _MSC_VER - gboolean comInitialized; - GMutex *com_init_lock; - GMutex *com_deinit_lock; - GCond *com_initialized; - GCond *com_uninitialize; - GCond *com_uninitialized; -#endif /* _MSC_VER */ -}; - -struct _GstDecklinkSrcClass -{ - GstElementClass base_decklinksrc_class; -}; - -GType gst_decklink_src_get_type (void); - -G_END_DECLS - -#endif