mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 00:58:12 +00:00
decklink: Add property probing
Renames the subdevice property to just device, and has it return the number of devices in the system in response to a probe. This is useful both for using multiple capture cards, and for detecting whether it's worth adding the element to a pipeline. Also cleans up the property descriptions.
This commit is contained in:
parent
b45c206647
commit
7cd0ac046a
4 changed files with 161 additions and 18 deletions
|
@ -11,6 +11,7 @@ libgstdecklink_la_LIBADD = \
|
||||||
$(GST_BASE_LIBS) \
|
$(GST_BASE_LIBS) \
|
||||||
$(GST_LIBS) \
|
$(GST_LIBS) \
|
||||||
-lgstvideo-@GST_MAJORMINOR@ \
|
-lgstvideo-@GST_MAJORMINOR@ \
|
||||||
|
-lgstinterfaces-@GST_MAJORMINOR@ \
|
||||||
$(DECKLINK_LIBS) \
|
$(DECKLINK_LIBS) \
|
||||||
$(LIBM)
|
$(LIBM)
|
||||||
libgstdecklink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstdecklink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
|
@ -189,7 +189,8 @@ gst_decklink_sink_class_init (GstDecklinkSinkClass * klass)
|
||||||
element_class->query = GST_DEBUG_FUNCPTR (gst_decklink_sink_query);
|
element_class->query = GST_DEBUG_FUNCPTR (gst_decklink_sink_query);
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_MODE,
|
g_object_class_install_property (gobject_class, PROP_MODE,
|
||||||
g_param_spec_enum ("mode", "Mode", "Mode",
|
g_param_spec_enum ("mode", "Playback Mode",
|
||||||
|
"Video Mode to use for playback",
|
||||||
GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC,
|
GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
#include "gstdecklinksrc.h"
|
#include "gstdecklinksrc.h"
|
||||||
#include "capture.h"
|
#include "capture.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <gst/interfaces/propertyprobe.h>
|
||||||
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_decklink_src_debug_category);
|
GST_DEBUG_CATEGORY (gst_decklink_src_debug_category);
|
||||||
#define GST_CAT_DEFAULT gst_decklink_src_debug_category
|
#define GST_CAT_DEFAULT gst_decklink_src_debug_category
|
||||||
|
@ -118,6 +120,10 @@ static gboolean gst_decklink_src_video_src_query (GstPad * pad,
|
||||||
GstQuery * query);
|
GstQuery * query);
|
||||||
static GstIterator *gst_decklink_src_video_src_iterintlink (GstPad * pad);
|
static GstIterator *gst_decklink_src_video_src_iterintlink (GstPad * pad);
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_decklinksrc_property_probe_interface_init (GstPropertyProbeInterface *
|
||||||
|
iface);
|
||||||
|
|
||||||
static void gst_decklink_src_task (void *priv);
|
static void gst_decklink_src_task (void *priv);
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -131,7 +137,7 @@ enum
|
||||||
PROP_MODE,
|
PROP_MODE,
|
||||||
PROP_CONNECTION,
|
PROP_CONNECTION,
|
||||||
PROP_AUDIO_INPUT,
|
PROP_AUDIO_INPUT,
|
||||||
PROP_SUBDEVICE
|
PROP_DEVICE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
@ -147,12 +153,24 @@ GST_STATIC_PAD_TEMPLATE ("audiosrc",
|
||||||
|
|
||||||
/* class initialization */
|
/* class initialization */
|
||||||
|
|
||||||
#define DEBUG_INIT(bla) \
|
static void
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_decklink_src_debug_category, "decklinksrc", 0, \
|
gst_decklinksrc_init_interfaces (GType type)
|
||||||
|
{
|
||||||
|
static const GInterfaceInfo decklinksrc_propertyprobe_info = {
|
||||||
|
(GInterfaceInitFunc) gst_decklinksrc_property_probe_interface_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_decklink_src_debug_category, "decklinksrc", 0,
|
||||||
"debug category for decklinksrc element");
|
"debug category for decklinksrc element");
|
||||||
|
|
||||||
|
g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
|
||||||
|
&decklinksrc_propertyprobe_info);
|
||||||
|
}
|
||||||
|
|
||||||
GST_BOILERPLATE_FULL (GstDecklinkSrc, gst_decklink_src, GstElement,
|
GST_BOILERPLATE_FULL (GstDecklinkSrc, gst_decklink_src, GstElement,
|
||||||
GST_TYPE_ELEMENT, DEBUG_INIT);
|
GST_TYPE_ELEMENT, gst_decklinksrc_init_interfaces);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_decklink_src_base_init (gpointer g_class)
|
gst_decklink_src_base_init (gpointer g_class)
|
||||||
|
@ -196,27 +214,29 @@ gst_decklink_src_class_init (GstDecklinkSrcClass * klass)
|
||||||
element_class->query = GST_DEBUG_FUNCPTR (gst_decklink_src_query);
|
element_class->query = GST_DEBUG_FUNCPTR (gst_decklink_src_query);
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_MODE,
|
g_object_class_install_property (gobject_class, PROP_MODE,
|
||||||
g_param_spec_enum ("mode", "Mode", "Mode",
|
g_param_spec_enum ("mode", "Mode", "Video Mode to use for capture",
|
||||||
GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC,
|
GST_TYPE_DECKLINK_MODE, GST_DECKLINK_MODE_NTSC,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_CONNECTION,
|
g_object_class_install_property (gobject_class, PROP_CONNECTION,
|
||||||
g_param_spec_enum ("connection", "Connection", "Connection",
|
g_param_spec_enum ("connection", "Connection",
|
||||||
|
"Video Input Connection to use",
|
||||||
GST_TYPE_DECKLINK_CONNECTION, GST_DECKLINK_CONNECTION_SDI,
|
GST_TYPE_DECKLINK_CONNECTION, GST_DECKLINK_CONNECTION_SDI,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_AUDIO_INPUT,
|
g_object_class_install_property (gobject_class, PROP_AUDIO_INPUT,
|
||||||
g_param_spec_enum ("audio-input", "Audio Input", "Audio Input Connection",
|
g_param_spec_enum ("audio-input", "Audio Input",
|
||||||
|
"Audio Input Connection",
|
||||||
GST_TYPE_DECKLINK_AUDIO_CONNECTION,
|
GST_TYPE_DECKLINK_AUDIO_CONNECTION,
|
||||||
GST_DECKLINK_AUDIO_CONNECTION_AUTO,
|
GST_DECKLINK_AUDIO_CONNECTION_AUTO,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_SUBDEVICE,
|
g_object_class_install_property (gobject_class, PROP_DEVICE,
|
||||||
g_param_spec_int ("subdevice", "Subdevice", "Subdevice",
|
g_param_spec_int ("device", "Device", "Capture device instance to use",
|
||||||
0, 3, 0,
|
0, G_MAXINT, 0,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
G_PARAM_CONSTRUCT)));
|
||||||
}
|
}
|
||||||
|
@ -297,7 +317,7 @@ gst_decklink_src_init (GstDecklinkSrc * decklinksrc,
|
||||||
decklinksrc->mode = GST_DECKLINK_MODE_NTSC;
|
decklinksrc->mode = GST_DECKLINK_MODE_NTSC;
|
||||||
decklinksrc->connection = GST_DECKLINK_CONNECTION_SDI;
|
decklinksrc->connection = GST_DECKLINK_CONNECTION_SDI;
|
||||||
decklinksrc->audio_connection = GST_DECKLINK_AUDIO_CONNECTION_AUTO;
|
decklinksrc->audio_connection = GST_DECKLINK_AUDIO_CONNECTION_AUTO;
|
||||||
decklinksrc->subdevice = 0;
|
decklinksrc->device = 0;
|
||||||
|
|
||||||
decklinksrc->stop = FALSE;
|
decklinksrc->stop = FALSE;
|
||||||
decklinksrc->dropped_frames = 0;
|
decklinksrc->dropped_frames = 0;
|
||||||
|
@ -344,8 +364,8 @@ gst_decklink_src_set_property (GObject * object, guint property_id,
|
||||||
decklinksrc->audio_connection =
|
decklinksrc->audio_connection =
|
||||||
(GstDecklinkAudioConnectionEnum) g_value_get_enum (value);
|
(GstDecklinkAudioConnectionEnum) g_value_get_enum (value);
|
||||||
break;
|
break;
|
||||||
case PROP_SUBDEVICE:
|
case PROP_DEVICE:
|
||||||
decklinksrc->subdevice = g_value_get_int (value);
|
decklinksrc->device = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
@ -372,8 +392,8 @@ gst_decklink_src_get_property (GObject * object, guint property_id,
|
||||||
case PROP_AUDIO_INPUT:
|
case PROP_AUDIO_INPUT:
|
||||||
g_value_set_enum (value, decklinksrc->audio_connection);
|
g_value_set_enum (value, decklinksrc->audio_connection);
|
||||||
break;
|
break;
|
||||||
case PROP_SUBDEVICE:
|
case PROP_DEVICE:
|
||||||
g_value_set_int (value, decklinksrc->subdevice);
|
g_value_set_int (value, decklinksrc->device);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
@ -516,7 +536,7 @@ gst_decklink_src_start (GstElement * element)
|
||||||
GST_ERROR ("no card");
|
GST_ERROR ("no card");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
for (i = 0; i < decklinksrc->subdevice; i++) {
|
for (i = 0; i < decklinksrc->device; i++) {
|
||||||
ret = iterator->Next (&decklinksrc->decklink);
|
ret = iterator->Next (&decklinksrc->decklink);
|
||||||
if (ret != S_OK) {
|
if (ret != S_OK) {
|
||||||
GST_ERROR ("no card");
|
GST_ERROR ("no card");
|
||||||
|
@ -1285,3 +1305,124 @@ gst_decklink_src_task (void *priv)
|
||||||
}
|
}
|
||||||
audio_frame->Release ();
|
audio_frame->Release ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const GList *
|
||||||
|
gst_decklinksrc_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;
|
||||||
|
int n_devices;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_decklinksrc_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_decklinksrc_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_decklinksrc_class_probe_devices (klass);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_decklinksrc_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_decklinksrc_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_decklinksrc_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_decklinksrc_class_list_devices (klass);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_decklinksrc_property_probe_interface_init (GstPropertyProbeInterface *
|
||||||
|
iface)
|
||||||
|
{
|
||||||
|
iface->get_properties = gst_decklinksrc_probe_get_properties;
|
||||||
|
iface->probe_property = gst_decklinksrc_probe_probe_property;
|
||||||
|
iface->needs_probe = gst_decklinksrc_probe_needs_probe;
|
||||||
|
iface->get_values = gst_decklinksrc_probe_get_values;
|
||||||
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ struct _GstDecklinkSrc
|
||||||
GstDecklinkModeEnum mode;
|
GstDecklinkModeEnum mode;
|
||||||
GstDecklinkConnectionEnum connection;
|
GstDecklinkConnectionEnum connection;
|
||||||
GstDecklinkAudioConnectionEnum audio_connection;
|
GstDecklinkAudioConnectionEnum audio_connection;
|
||||||
int subdevice;
|
int device;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
gboolean comInitialized;
|
gboolean comInitialized;
|
||||||
|
|
Loading…
Reference in a new issue