diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/decklink/gstdecklink.cpp | 32 | ||||
-rw-r--r-- | sys/decklink/gstdecklink.h | 29 | ||||
-rw-r--r-- | sys/decklink/gstdecklinksink.cpp | 225 | ||||
-rw-r--r-- | sys/decklink/gstdecklinksink.h | 1 | ||||
-rw-r--r-- | sys/decklink/gstdecklinksrc.cpp | 27 |
5 files changed, 225 insertions, 89 deletions
diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp index 9090c4695..d747fcf9d 100644 --- a/sys/decklink/gstdecklink.cpp +++ b/sys/decklink/gstdecklink.cpp @@ -95,7 +95,7 @@ gst_decklink_audio_connection_get_type (void) static const GEnumValue connections[] = { {GST_DECKLINK_AUDIO_CONNECTION_AUTO, "auto", "Automatic"}, {GST_DECKLINK_AUDIO_CONNECTION_EMBEDDED, "embedded", - "SDI/HDMI embedded audio"}, + "SDI/HDMI embedded audio"}, {GST_DECKLINK_AUDIO_CONNECTION_AES_EBU, "aes", "AES/EBU input"}, {GST_DECKLINK_AUDIO_CONNECTION_ANALOG, "analog", "Analog input"}, {0, NULL, NULL} @@ -186,6 +186,36 @@ gst_decklink_mode_get_template_caps (void) return caps; } +IDeckLink * +gst_decklink_get_nth_device (int n) +{ + IDeckLinkIterator *iterator; + IDeckLink *decklink = NULL; + HRESULT ret; + int i; + + iterator = CreateDeckLinkIteratorInstance (); + if (iterator == NULL) { + GST_ERROR ("no driver"); + return NULL; + } + + ret = iterator->Next (&decklink); + if (ret != S_OK) { + GST_ERROR ("no card"); + return NULL; + } + for (i = 0; i < n; i++) { + ret = iterator->Next (&decklink); + if (ret != S_OK) { + GST_ERROR ("no card"); + return NULL; + } + } + + return decklink; +} + static gboolean plugin_init (GstPlugin * plugin) { diff --git a/sys/decklink/gstdecklink.h b/sys/decklink/gstdecklink.h index bd1d1d30b..77c5cc43a 100644 --- a/sys/decklink/gstdecklink.h +++ b/sys/decklink/gstdecklink.h @@ -107,34 +107,7 @@ const GstDecklinkMode * gst_decklink_get_mode (GstDecklinkModeEnum e); GstCaps * gst_decklink_mode_get_caps (GstDecklinkModeEnum e); GstCaps * gst_decklink_mode_get_template_caps (void); -#define GST_DECKLINK_MODE_CAPS(w,h,n,d,i) \ - "video/x-raw-yuv,format=(fourcc){ UYVY, v210 },width=" #w ",height=" #h \ - ",framerate=" #n "/" #d ",interlaced=" #i - -#define GST_DECKLINK_CAPS \ - GST_DECKLINK_MODE_CAPS(720,486,30000,1001,true) ";" \ - GST_DECKLINK_MODE_CAPS(720,486,24000,1001,true) ";" \ - GST_DECKLINK_MODE_CAPS(720,576,25,1,true) ";" \ - GST_DECKLINK_MODE_CAPS(720,486,30000,1001,false) ";" \ - GST_DECKLINK_MODE_CAPS(720,576,25,1,false) ";" \ - \ - GST_DECKLINK_MODE_CAPS(1920,1080,24000,1001,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,24,1,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,25,1,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,30000,1001,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,30,1,false) ";" \ - \ - GST_DECKLINK_MODE_CAPS(1920,1080,25,1,true) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,30000,1001,true) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,30,1,true) ";" \ - \ - GST_DECKLINK_MODE_CAPS(1920,1080,50,1,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,60000,1001,false) ";" \ - GST_DECKLINK_MODE_CAPS(1920,1080,60,1,false) ";" \ - \ - GST_DECKLINK_MODE_CAPS(1280,720,50,1,false) ";" \ - GST_DECKLINK_MODE_CAPS(1280,720,60000,1001,false) ";" \ - GST_DECKLINK_MODE_CAPS(1280,720,60,1,false) +IDeckLink * gst_decklink_get_nth_device (int n); #endif diff --git a/sys/decklink/gstdecklinksink.cpp b/sys/decklink/gstdecklinksink.cpp index c979d0210..bbf08a73f 100644 --- a/sys/decklink/gstdecklinksink.cpp +++ b/sys/decklink/gstdecklinksink.cpp @@ -35,8 +35,8 @@ #endif #include <gst/gst.h> -#include <gst/glib-compat-private.h> #include <gst/video/video.h> +#include <gst/interfaces/propertyprobe.h> #include "gstdecklink.h" #include "gstdecklinksink.h" #include <string.h> @@ -118,24 +118,25 @@ static GstFlowReturn gst_decklink_sink_audiosink_bufferalloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); static GstIterator *gst_decklink_sink_audiosink_iterintlink (GstPad * pad); +static void +gst_decklink_sink_property_probe_interface_init (GstPropertyProbeInterface * + iface); + #ifdef _MSC_VER /* COM initialization/uninitialization thread */ -static void gst_decklink_sink_com_thread (GstDecklinkSink * src); +static void gst_decklink_sink_com_thread (GstDecklinkSink * sink); #endif /* _MSC_VER */ enum { PROP_0, - PROP_MODE + PROP_MODE, + PROP_DEVICE }; /* pad templates */ -static GstStaticPadTemplate gst_decklink_sink_videosink_template = -GST_STATIC_PAD_TEMPLATE ("videosink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_DECKLINK_CAPS)); +/* the video sink pad template is created on the fly */ static GstStaticPadTemplate gst_decklink_sink_audiosink_template = GST_STATIC_PAD_TEMPLATE ("audiosink", @@ -151,16 +152,37 @@ GST_STATIC_PAD_TEMPLATE ("audiosink", GST_DEBUG_CATEGORY_INIT (gst_decklink_sink_debug_category, "decklinksink", 0, \ "debug category for decklinksink element"); +static void +gst_decklink_sink_init_interfaces (GType type) +{ + static const GInterfaceInfo decklink_sink_propertyprobe_info = { + (GInterfaceInitFunc) gst_decklink_sink_property_probe_interface_init, + NULL, + NULL, + }; + + GST_DEBUG_CATEGORY_INIT (gst_decklink_sink_debug_category, "decklinksink", 0, + "debug category for decklinksink element"); + + g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, + &decklink_sink_propertyprobe_info); +} + + GST_BOILERPLATE_FULL (GstDecklinkSink, gst_decklink_sink, GstElement, - GST_TYPE_ELEMENT, DEBUG_INIT); + GST_TYPE_ELEMENT, gst_decklink_sink_init_interfaces); static void gst_decklink_sink_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstPadTemplate *pad_template; - gst_element_class_add_static_pad_template (element_class, - &gst_decklink_sink_videosink_template); + pad_template = + 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, pad_template); + gst_object_unref (pad_template); gst_element_class_add_static_pad_template (element_class, &gst_decklink_sink_audiosink_template); @@ -195,6 +217,12 @@ gst_decklink_sink_class_init (GstDecklinkSinkClass * klass) (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT))); + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_int ("device", "Device", "Capture device instance to use", + 0, G_MAXINT, 0, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT))); + } static void @@ -203,8 +231,8 @@ gst_decklink_sink_init (GstDecklinkSink * decklinksink, { decklinksink->videosinkpad = - gst_pad_new_from_static_template (&gst_decklink_sink_videosink_template, - "sink"); + gst_pad_new_from_template (gst_element_class_get_pad_template + (GST_ELEMENT_CLASS (decklinksink_class), "videosink"), "videosink"); gst_pad_set_getcaps_function (decklinksink->videosinkpad, GST_DEBUG_FUNCPTR (gst_decklink_sink_videosink_getcaps)); gst_pad_set_setcaps_function (decklinksink->videosinkpad, @@ -272,6 +300,7 @@ gst_decklink_sink_init (GstDecklinkSink * decklinksink, decklinksink->audio_mutex = g_mutex_new (); decklinksink->mode = GST_DECKLINK_MODE_NTSC; + decklinksink->device = 0; decklinksink->callback = new Output; decklinksink->callback->decklinksink = decklinksink; @@ -308,6 +337,9 @@ gst_decklink_sink_set_property (GObject * object, guint property_id, case PROP_MODE: decklinksink->mode = (GstDecklinkModeEnum) g_value_get_enum (value); break; + case PROP_DEVICE: + decklinksink->device = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -327,6 +359,9 @@ gst_decklink_sink_get_property (GObject * object, guint property_id, case PROP_MODE: g_value_set_enum (value, decklinksink->mode); break; + case PROP_DEVICE: + g_value_set_int (value, decklinksink->device); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -335,11 +370,11 @@ gst_decklink_sink_get_property (GObject * object, guint property_id, #ifdef _MSC_VER static void -gst_decklink_sink_com_thread (GstDecklinkSink * src) +gst_decklink_sink_com_thread (GstDecklinkSink * sink) { HRESULT res; - g_mutex_lock (src->com_init_lock); + 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 @@ -347,29 +382,29 @@ gst_decklink_sink_com_thread (GstDecklinkSink * src) res = CoInitializeEx (0, COINIT_MULTITHREADED); if (res == S_FALSE) - GST_WARNING_OBJECT (src, + GST_WARNING_OBJECT (sink, "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."); + GST_WARNING_OBJECT (sink, "The concurrency model of COM has changed."); else - GST_INFO_OBJECT (src, "COM intialized succesfully"); + GST_INFO_OBJECT (sink, "COM intialized succesfully"); - src->comInitialized = TRUE; + sink->comInitialized = TRUE; /* Signal other threads waiting on this condition that COM was initialized */ - g_cond_signal (src->com_initialized); + g_cond_signal (sink->com_initialized); - g_mutex_unlock (src->com_init_lock); + g_mutex_unlock (sink->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); + g_mutex_lock (sink->com_deinit_lock); + g_cond_wait (sink->com_uninitialize, sink->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); + 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 */ @@ -421,27 +456,19 @@ gst_decklink_sink_finalize (GObject * object) static gboolean gst_decklink_sink_start (GstDecklinkSink * decklinksink) { - IDeckLinkIterator *iterator; HRESULT ret; const GstDecklinkMode *mode; BMDAudioSampleType sample_depth; - iterator = CreateDeckLinkIteratorInstance (); - if (iterator == NULL) { - GST_ERROR ("no driver"); - return FALSE; - } - - ret = iterator->Next (&decklinksink->decklink); - if (ret != S_OK) { - GST_ERROR ("no card"); + decklinksink->decklink = gst_decklink_get_nth_device (decklinksink->device); + if (decklinksink->decklink) { return FALSE; } ret = decklinksink->decklink->QueryInterface (IID_IDeckLinkOutput, (void **) &decklinksink->output); if (ret != S_OK) { - GST_ERROR ("no output"); + GST_ERROR ("selected device does not have output interface"); return FALSE; } @@ -1135,3 +1162,125 @@ Output::RenderAudioSamples (bool preroll) return S_OK; } + + +static const GList * +gst_decklink_sink_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + static gsize init = 0; + + if (g_once_init_enter (&init)) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + + g_once_init_leave (&init, 1); + } + + return list; +} + + +static gboolean probed = FALSE; +static int n_devices; + +static void +gst_decklink_sink_class_probe_devices (GstElementClass * klass) +{ + IDeckLinkIterator *iterator; + IDeckLink *decklink; + + n_devices = 0; + iterator = CreateDeckLinkIteratorInstance (); + if (iterator) { + while (iterator->Next (&decklink) == S_OK) { + n_devices++; + } + } + + probed = TRUE; +} + +static void +gst_decklink_sink_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + + switch (prop_id) { + case PROP_DEVICE: + gst_decklink_sink_class_probe_devices (klass); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +static gboolean +gst_decklink_sink_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + gboolean ret = FALSE; + + switch (prop_id) { + case PROP_DEVICE: + ret = !probed; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + return ret; +} + +static GValueArray * +gst_decklink_sink_class_list_devices (GstElementClass * klass) +{ + GValueArray *array; + GValue value = { + 0}; + GList *item; + int i; + + array = g_value_array_new (n_devices); + g_value_init (&value, G_TYPE_INT); + for (i = 0; i < n_devices; i++) { + g_value_set_int (&value, i); + g_value_array_append (array, &value); + + item = item->next; + } + g_value_unset (&value); + + return array; +} + +static GValueArray * +gst_decklink_sink_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE: + array = gst_decklink_sink_class_list_devices (klass); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +static void +gst_decklink_sink_property_probe_interface_init (GstPropertyProbeInterface * + iface) +{ + iface->get_properties = gst_decklink_sink_probe_get_properties; + iface->probe_property = gst_decklink_sink_probe_probe_property; + iface->needs_probe = gst_decklink_sink_probe_needs_probe; + iface->get_values = gst_decklink_sink_probe_get_values; +} diff --git a/sys/decklink/gstdecklinksink.h b/sys/decklink/gstdecklinksink.h index 31d70cd78..20c47edc2 100644 --- a/sys/decklink/gstdecklinksink.h +++ b/sys/decklink/gstdecklinksink.h @@ -75,6 +75,7 @@ struct _GstDecklinkSink /* properties */ GstDecklinkModeEnum mode; + int device; #ifdef _MSC_VER gboolean comInitialized; diff --git a/sys/decklink/gstdecklinksrc.cpp b/sys/decklink/gstdecklinksrc.cpp index 9fa07176a..710802304 100644 --- a/sys/decklink/gstdecklinksrc.cpp +++ b/sys/decklink/gstdecklinksrc.cpp @@ -510,7 +510,6 @@ static gboolean gst_decklink_src_start (GstElement * element) { GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (element); - IDeckLinkIterator *iterator; DeckLinkCaptureDelegate *delegate; //IDeckLinkDisplayModeIterator *mode_iterator; //IDeckLinkDisplayMode *mode; @@ -521,33 +520,18 @@ gst_decklink_src_start (GstElement * element) IDeckLinkConfiguration *config; BMDVideoConnection conn; BMDAudioConnection aconn; - int i; GST_DEBUG_OBJECT (decklinksrc, "start"); - iterator = CreateDeckLinkIteratorInstance (); - if (iterator == NULL) { - GST_ERROR ("no driver"); - return FALSE; - } - - ret = iterator->Next (&decklinksrc->decklink); - if (ret != S_OK) { - GST_ERROR ("no card"); + decklinksrc->decklink = gst_decklink_get_nth_device (decklinksrc->device); + if (decklinksrc->decklink == NULL) { return FALSE; } - for (i = 0; i < decklinksrc->device; i++) { - ret = iterator->Next (&decklinksrc->decklink); - if (ret != S_OK) { - GST_ERROR ("no card"); - return FALSE; - } - } ret = decklinksrc->decklink->QueryInterface (IID_IDeckLinkInput, (void **) &decklinksrc->input); if (ret != S_OK) { - GST_ERROR ("query interface failed"); + GST_ERROR ("selected device does not have input interface"); return FALSE; } @@ -1401,8 +1385,7 @@ gst_decklinksrc_probe_get_properties (GstPropertyProbe * probe) static gsize init = 0; if (g_once_init_enter (&init)) { - list = - g_list_append (NULL, g_object_class_find_property (klass, "device")); + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); g_once_init_leave (&init, 1); } @@ -1411,7 +1394,7 @@ gst_decklinksrc_probe_get_properties (GstPropertyProbe * probe) } static gboolean probed = FALSE; -int n_devices; +static int n_devices; static void gst_decklinksrc_class_probe_devices (GstElementClass * klass) |