mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
decklink: Add new persistent-id property and sort devices by persistent ID
The order of the devices iterator from the SDK is undefined and can randomly change. Keep the device-number property for backwards compatibility and simplicity but prefer the persistent-id property and also use it for the device provider implementation. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3078>
This commit is contained in:
parent
67caa45a4c
commit
505f48f237
12 changed files with 296 additions and 31 deletions
|
@ -11460,6 +11460,20 @@
|
|||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": false
|
||||
},
|
||||
"persistent-id": {
|
||||
"blurb": "Output device instance to use. Higher priority than \"device-number\".",
|
||||
"conditionally-available": false,
|
||||
"construct": true,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "18446744073709551615",
|
||||
"max": "9223372036854775807",
|
||||
"min": "-1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gint64",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "none"
|
||||
|
@ -11577,6 +11591,20 @@
|
|||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": false
|
||||
},
|
||||
"persistent-id": {
|
||||
"blurb": "Output device instance to use. Higher priority than \"device-number\".",
|
||||
"conditionally-available": false,
|
||||
"construct": true,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "18446744073709551615",
|
||||
"max": "9223372036854775807",
|
||||
"min": "-1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gint64",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "none"
|
||||
|
@ -11706,6 +11734,20 @@
|
|||
"type": "GstDecklinkModes",
|
||||
"writable": true
|
||||
},
|
||||
"persistent-id": {
|
||||
"blurb": "Output device instance to use. Higher priority than \"device-number\".",
|
||||
"conditionally-available": false,
|
||||
"construct": true,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "18446744073709551615",
|
||||
"max": "9223372036854775807",
|
||||
"min": "-1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gint64",
|
||||
"writable": true
|
||||
},
|
||||
"profile": {
|
||||
"blurb": "Certain DeckLink devices such as the DeckLink 8K Pro, the DeckLink Quad 2 and the DeckLink Duo 2 support multiple profiles to configure the capture and playback behavior of its sub-devices.For the DeckLink Duo 2 and DeckLink Quad 2, a profile is shared between any 2 sub-devices that utilize the same connectors. For the DeckLink 8K Pro, a profile is shared between all 4 sub-devices. Any sub-devices that share a profile are considered to be part of the same profile group.DeckLink Duo 2 support configuration of the duplex mode of individual sub-devices.",
|
||||
"conditionally-available": false,
|
||||
|
@ -11879,6 +11921,20 @@
|
|||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"persistent-id": {
|
||||
"blurb": "Output device instance to use. Higher priority than \"device-number\".",
|
||||
"conditionally-available": false,
|
||||
"construct": true,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "18446744073709551615",
|
||||
"max": "9223372036854775807",
|
||||
"min": "-1",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gint64",
|
||||
"writable": true
|
||||
},
|
||||
"profile": {
|
||||
"blurb": "Certain DeckLink devices such as the DeckLink 8K Pro, the DeckLink Quad 2 and the DeckLink Duo 2 support multiple profiles to configure the capture and playback behavior of its sub-devices.For the DeckLink Duo 2 and DeckLink Quad 2, a profile is shared between any 2 sub-devices that utilize the same connectors. For the DeckLink 8K Pro, a profile is shared between all 4 sub-devices. Any sub-devices that share a profile are considered to be part of the same profile group.DeckLink Duo 2 support configuration of the duplex mode of individual sub-devices.",
|
||||
"conditionally-available": false,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_decklink_debug);
|
||||
#define GST_CAT_DEFAULT gst_decklink_debug
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
GType
|
||||
gst_decklink_mode_get_type (void)
|
||||
|
@ -1033,6 +1034,18 @@ static ProfileSetOperationResult gst_decklink_configure_profile (Device *
|
|||
static MappingFormatSetOperationResult gst_decklink_configure_mapping_format (Device *
|
||||
device, GstDecklinkMappingFormat mapping_format);
|
||||
|
||||
static gboolean
|
||||
persistent_id_is_equal_input (const Device * a, const gint64 * b)
|
||||
{
|
||||
return a->input.persistent_id == *b;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
persistent_id_is_equal_output (const Device * a, const gint64 * b)
|
||||
{
|
||||
return a->output.persistent_id == *b;
|
||||
}
|
||||
|
||||
class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
|
||||
{
|
||||
private:
|
||||
|
@ -1541,9 +1554,9 @@ static GPtrArray *devices; /* array of Device */
|
|||
|
||||
static GstDecklinkDevice *
|
||||
gst_decklink_device_new (const gchar * model_name, const gchar * display_name,
|
||||
const gchar * serial_number, gboolean supports_format_detection,
|
||||
GstCaps * video_caps, guint max_channels, gboolean video, gboolean capture,
|
||||
guint device_number)
|
||||
const gchar * serial_number, gint64 persistent_id,
|
||||
gboolean supports_format_detection, GstCaps * video_caps,
|
||||
guint max_channels, gboolean video, gboolean capture, guint device_number)
|
||||
{
|
||||
GstDevice *ret;
|
||||
gchar *name;
|
||||
|
@ -1592,6 +1605,10 @@ gst_decklink_device_new (const gchar * model_name, const gchar * display_name,
|
|||
gst_structure_set (properties, "serial-number", G_TYPE_STRING,
|
||||
serial_number, NULL);
|
||||
|
||||
if (persistent_id)
|
||||
gst_structure_set (properties, "persistent-id", G_TYPE_INT64,
|
||||
persistent_id, NULL);
|
||||
|
||||
ret = GST_DEVICE (g_object_new (GST_TYPE_DECKLINK_DEVICE,
|
||||
"display-name", name,
|
||||
"device-class", device_class, "caps", caps, "properties", properties,
|
||||
|
@ -1603,11 +1620,19 @@ gst_decklink_device_new (const gchar * model_name, const gchar * display_name,
|
|||
|
||||
GST_DECKLINK_DEVICE (ret)->video = video;
|
||||
GST_DECKLINK_DEVICE (ret)->capture = capture;
|
||||
GST_DECKLINK_DEVICE (ret)->device_number = device_number;
|
||||
GST_DECKLINK_DEVICE (ret)->persistent_id = persistent_id;
|
||||
|
||||
return GST_DECKLINK_DEVICE (ret);
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_persistent_id (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const Device *const dev1 = *(Device **) a;
|
||||
const Device *const dev2 = *(Device **) b;
|
||||
return dev1->input.persistent_id - dev2->input.persistent_id;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
init_devices (gpointer data)
|
||||
{
|
||||
|
@ -1646,6 +1671,7 @@ init_devices (gpointer data)
|
|||
gchar *model_name = NULL;
|
||||
gchar *display_name = NULL;
|
||||
gchar *serial_number = NULL;
|
||||
gint64 persistent_id = 0;
|
||||
gboolean supports_format_detection = 0;
|
||||
gint64 max_channels = 2;
|
||||
GstCaps *video_input_caps = gst_caps_new_empty ();
|
||||
|
@ -1776,12 +1802,28 @@ init_devices (gpointer data)
|
|||
} else {
|
||||
bool tmp_bool = false;
|
||||
int64_t tmp_int = 2;
|
||||
int64_t tmp_int_persistent_id = 0;
|
||||
|
||||
dev->input.attributes->GetInt (BMDDeckLinkMaximumAudioChannels, &tmp_int);
|
||||
dev->input.attributes->GetFlag (BMDDeckLinkSupportsInputFormatDetection,
|
||||
&tmp_bool);
|
||||
supports_format_detection = tmp_bool;
|
||||
max_channels = tmp_int;
|
||||
|
||||
ret =
|
||||
dev->input.attributes->GetInt (BMDDeckLinkPersistentID,
|
||||
&tmp_int_persistent_id);
|
||||
if (ret == S_OK) {
|
||||
persistent_id = tmp_int_persistent_id;
|
||||
dev->output.persistent_id = persistent_id;
|
||||
dev->input.persistent_id = persistent_id;
|
||||
GST_DEBUG ("device %d has persistent id %" G_GINT64_FORMAT, i, persistent_id);
|
||||
} else {
|
||||
persistent_id = i;
|
||||
dev->output.persistent_id = i;
|
||||
dev->input.persistent_id = i;
|
||||
GST_DEBUG ("device %d does not have persistent id. Value set to %d", i, i);
|
||||
}
|
||||
}
|
||||
|
||||
decklink->GetModelName ((COMSTR_T *) & model_name);
|
||||
|
@ -1794,22 +1836,22 @@ init_devices (gpointer data)
|
|||
if (capture) {
|
||||
dev->devices[0] =
|
||||
gst_decklink_device_new (model_name, display_name, serial_number,
|
||||
supports_format_detection, video_input_caps, max_channels, TRUE, TRUE,
|
||||
i);
|
||||
persistent_id, supports_format_detection, video_input_caps,
|
||||
max_channels, TRUE, TRUE, i);
|
||||
dev->devices[1] =
|
||||
gst_decklink_device_new (model_name, display_name, serial_number,
|
||||
supports_format_detection, video_input_caps, max_channels, FALSE,
|
||||
TRUE, i);
|
||||
persistent_id, supports_format_detection, video_input_caps,
|
||||
max_channels, FALSE, TRUE, i);
|
||||
}
|
||||
if (output) {
|
||||
dev->devices[2] =
|
||||
gst_decklink_device_new (model_name, display_name, serial_number,
|
||||
supports_format_detection, video_output_caps, max_channels, TRUE,
|
||||
FALSE, i);
|
||||
persistent_id, supports_format_detection, video_output_caps,
|
||||
max_channels, TRUE, FALSE, i);
|
||||
dev->devices[3] =
|
||||
gst_decklink_device_new (model_name, display_name, serial_number,
|
||||
supports_format_detection, video_output_caps, max_channels, FALSE,
|
||||
FALSE, i);
|
||||
persistent_id, supports_format_detection, video_output_caps,
|
||||
max_channels, FALSE, FALSE, i);
|
||||
}
|
||||
|
||||
if (model_name)
|
||||
|
@ -1838,6 +1880,8 @@ init_devices (gpointer data)
|
|||
|
||||
iterator->Release ();
|
||||
|
||||
g_ptr_array_sort (devices, compare_persistent_id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1875,16 +1919,28 @@ gst_decklink_get_devices (void)
|
|||
}
|
||||
|
||||
GstDecklinkOutput *
|
||||
gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio)
|
||||
gst_decklink_acquire_nth_output (gint n, gint64 persistent_id,
|
||||
GstElement * sink, gboolean is_audio)
|
||||
{
|
||||
GstDecklinkOutput *output;
|
||||
Device *device;
|
||||
guint found_index;
|
||||
|
||||
g_once (&devices_once, init_devices, NULL);
|
||||
|
||||
if (devices == NULL)
|
||||
return NULL;
|
||||
|
||||
if (persistent_id != DEFAULT_PERSISTENT_ID) {
|
||||
if (g_ptr_array_find_with_equal_func (devices, &persistent_id,
|
||||
(GEqualFunc) persistent_id_is_equal_output, &found_index)) {
|
||||
n = found_index;
|
||||
GST_DEBUG ("Persistent ID: %" G_GINT64_FORMAT ", used", persistent_id);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0 || (guint) n >= devices->len)
|
||||
return NULL;
|
||||
|
||||
|
@ -1924,14 +1980,26 @@ gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio)
|
|||
}
|
||||
|
||||
void
|
||||
gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio)
|
||||
gst_decklink_release_nth_output (gint n, gint64 persistent_id,
|
||||
GstElement * sink, gboolean is_audio)
|
||||
{
|
||||
GstDecklinkOutput *output;
|
||||
Device *device;
|
||||
guint found_index;
|
||||
|
||||
if (devices == NULL)
|
||||
return;
|
||||
|
||||
if (persistent_id != DEFAULT_PERSISTENT_ID) {
|
||||
if (g_ptr_array_find_with_equal_func (devices, &persistent_id,
|
||||
(GEqualFunc) persistent_id_is_equal_output, &found_index)) {
|
||||
n = found_index;
|
||||
GST_DEBUG ("Persistent ID: %" G_GINT64_FORMAT ", used", persistent_id);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0 || (guint) n >= devices->len)
|
||||
return;
|
||||
|
||||
|
@ -1953,16 +2021,28 @@ gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio)
|
|||
}
|
||||
|
||||
GstDecklinkInput *
|
||||
gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
|
||||
gst_decklink_acquire_nth_input (gint n, gint64 persistent_id, GstElement * src,
|
||||
gboolean is_audio)
|
||||
{
|
||||
GstDecklinkInput *input;
|
||||
Device *device;
|
||||
guint found_index;
|
||||
|
||||
g_once (&devices_once, init_devices, NULL);
|
||||
|
||||
if (devices == NULL)
|
||||
return NULL;
|
||||
|
||||
if (persistent_id != DEFAULT_PERSISTENT_ID) {
|
||||
if (g_ptr_array_find_with_equal_func (devices, &persistent_id,
|
||||
(GEqualFunc) persistent_id_is_equal_input, &found_index)) {
|
||||
n = found_index;
|
||||
GST_DEBUG ("Persistent ID: %" G_GINT64_FORMAT ", used", persistent_id);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0 || (guint) n >= devices->len)
|
||||
return NULL;
|
||||
|
||||
|
@ -2001,14 +2081,26 @@ gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
|
|||
}
|
||||
|
||||
void
|
||||
gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio)
|
||||
gst_decklink_release_nth_input (gint n, gint64 persistent_id, GstElement * src,
|
||||
gboolean is_audio)
|
||||
{
|
||||
GstDecklinkInput *input;
|
||||
Device *device;
|
||||
guint found_index;
|
||||
|
||||
if (devices == NULL)
|
||||
return;
|
||||
|
||||
if (persistent_id != DEFAULT_PERSISTENT_ID) {
|
||||
if (g_ptr_array_find_with_equal_func (devices, &persistent_id,
|
||||
(GEqualFunc) persistent_id_is_equal_input, &found_index)) {
|
||||
n = found_index;
|
||||
GST_DEBUG ("Persistent ID: %" G_GINT64_FORMAT ", used", persistent_id);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0 || (guint) n >= devices->len)
|
||||
return;
|
||||
|
||||
|
|
|
@ -401,6 +401,7 @@ struct _GstDecklinkOutput {
|
|||
IDeckLinkKeyer *keyer;
|
||||
|
||||
gchar *hw_serial_number;
|
||||
gint64 persistent_id;
|
||||
|
||||
GstClock *clock;
|
||||
GstClockTime clock_start_time, clock_last_time, clock_epoch;
|
||||
|
@ -431,6 +432,7 @@ struct _GstDecklinkInput {
|
|||
IDeckLinkProfileAttributes *attributes;
|
||||
|
||||
gchar *hw_serial_number;
|
||||
gint64 persistent_id;
|
||||
|
||||
/* Everything below protected by mutex */
|
||||
GMutex lock;
|
||||
|
@ -452,11 +454,11 @@ struct _GstDecklinkInput {
|
|||
void (*start_streams) (GstElement *videosrc);
|
||||
};
|
||||
|
||||
GstDecklinkOutput * gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio);
|
||||
void gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio);
|
||||
GstDecklinkOutput * gst_decklink_acquire_nth_output (gint n, gint64 persistent_id, GstElement * sink, gboolean is_audio);
|
||||
void gst_decklink_release_nth_output (gint n, gint64 persistent_id, GstElement * sink, gboolean is_audio);
|
||||
|
||||
GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio);
|
||||
void gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio);
|
||||
GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, gint64 persistent_id, GstElement * src, gboolean is_audio);
|
||||
void gst_decklink_release_nth_input (gint n, gint64 persistent_id, GstElement * src, gboolean is_audio);
|
||||
|
||||
const GstDecklinkMode * gst_decklink_find_mode_for_caps (GstCaps * caps);
|
||||
const GstDecklinkMode * gst_decklink_find_mode_and_format_for_caps (GstCaps * caps, BMDPixelFormat * format);
|
||||
|
@ -479,7 +481,7 @@ struct _GstDecklinkDevice
|
|||
GstDevice parent;
|
||||
gboolean video;
|
||||
gboolean capture;
|
||||
guint device_number;
|
||||
gint64 persistent_id;
|
||||
};
|
||||
|
||||
GType gst_decklink_device_get_type (void);
|
||||
|
|
|
@ -52,6 +52,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_decklink_audio_sink_debug);
|
|||
// Microseconds for audiobasesink compatibility...
|
||||
#define DEFAULT_BUFFER_TIME (50 * GST_MSECOND / 1000)
|
||||
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -60,6 +62,7 @@ enum
|
|||
PROP_ALIGNMENT_THRESHOLD,
|
||||
PROP_DISCONT_WAIT,
|
||||
PROP_BUFFER_TIME,
|
||||
PROP_PERSISTENT_ID
|
||||
};
|
||||
|
||||
static void gst_decklink_audio_sink_set_property (GObject * object,
|
||||
|
@ -141,6 +144,23 @@ gst_decklink_audio_sink_class_init (GstDecklinkAudioSinkClass * klass)
|
|||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
/**
|
||||
* GstDecklinkAudioSink:persistent-id
|
||||
*
|
||||
* Decklink device to use. Higher priority than "device-number".
|
||||
* BMDDeckLinkPersistentID is a device specific, 32-bit unique identifier.
|
||||
* It is stable even when the device is plugged in a different connector,
|
||||
* across reboots, and when plugged into different computers.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PERSISTENT_ID,
|
||||
g_param_spec_int64 ("persistent-id", "Persistent id",
|
||||
"Output device instance to use. Higher priority than \"device-number\".",
|
||||
DEFAULT_PERSISTENT_ID, G_MAXINT64, DEFAULT_PERSISTENT_ID,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_HW_SERIAL_NUMBER,
|
||||
g_param_spec_string ("hw-serial-number", "Hardware serial number",
|
||||
"The serial number (hardware ID) of the Decklink card",
|
||||
|
@ -188,6 +208,8 @@ gst_decklink_audio_sink_init (GstDecklinkAudioSink * self)
|
|||
DEFAULT_DISCONT_WAIT);
|
||||
self->buffer_time = DEFAULT_BUFFER_TIME * 1000;
|
||||
|
||||
self->persistent_id = DEFAULT_PERSISTENT_ID;
|
||||
|
||||
gst_base_sink_set_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND);
|
||||
}
|
||||
|
||||
|
@ -218,6 +240,9 @@ gst_decklink_audio_sink_set_property (GObject * object, guint property_id,
|
|||
self->buffer_time = g_value_get_uint64 (value) * 1000;
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
self->persistent_id = g_value_get_int64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -257,6 +282,9 @@ gst_decklink_audio_sink_get_property (GObject * object, guint property_id,
|
|||
g_value_set_uint64 (value, self->buffer_time / 1000);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
g_value_set_int64 (value, self->persistent_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -799,7 +827,7 @@ gst_decklink_audio_sink_open (GstBaseSink * bsink)
|
|||
GST_DEBUG_OBJECT (self, "Starting");
|
||||
|
||||
self->output =
|
||||
gst_decklink_acquire_nth_output (self->device_number,
|
||||
gst_decklink_acquire_nth_output (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), TRUE);
|
||||
if (!self->output) {
|
||||
GST_ERROR_OBJECT (self, "Failed to acquire output");
|
||||
|
@ -827,7 +855,7 @@ gst_decklink_audio_sink_close (GstBaseSink * bsink)
|
|||
g_mutex_unlock (&self->output->lock);
|
||||
|
||||
self->output->output->DisableAudioOutput ();
|
||||
gst_decklink_release_nth_output (self->device_number,
|
||||
gst_decklink_release_nth_output (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), TRUE);
|
||||
self->output = NULL;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ struct _GstDecklinkAudioSink
|
|||
GstAudioStreamAlign *stream_align;
|
||||
GstAudioResampler *resampler;
|
||||
guint resampler_in_rate, resampler_out_rate;
|
||||
|
||||
gint64 persistent_id;
|
||||
};
|
||||
|
||||
struct _GstDecklinkAudioSinkClass
|
||||
|
|
|
@ -57,6 +57,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_decklink_audio_src_debug);
|
|||
#define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -66,7 +68,8 @@ enum
|
|||
PROP_DISCONT_WAIT,
|
||||
PROP_BUFFER_SIZE,
|
||||
PROP_CHANNELS,
|
||||
PROP_HW_SERIAL_NUMBER
|
||||
PROP_HW_SERIAL_NUMBER,
|
||||
PROP_PERSISTENT_ID
|
||||
};
|
||||
|
||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
|
@ -180,6 +183,23 @@ gst_decklink_audio_src_class_init (GstDecklinkAudioSrcClass * klass)
|
|||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
/**
|
||||
* GstDecklinkAudioSrc:persistent-id
|
||||
*
|
||||
* Decklink device to use. Higher priority than "device-number".
|
||||
* BMDDeckLinkPersistentID is a device specific, 32-bit unique identifier.
|
||||
* It is stable even when the device is plugged in a different connector,
|
||||
* across reboots, and when plugged into different computers.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PERSISTENT_ID,
|
||||
g_param_spec_int64 ("persistent-id", "Persistent id",
|
||||
"Output device instance to use. Higher priority than \"device-number\".",
|
||||
DEFAULT_PERSISTENT_ID, G_MAXINT64, DEFAULT_PERSISTENT_ID,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ALIGNMENT_THRESHOLD,
|
||||
g_param_spec_uint64 ("alignment-threshold", "Alignment Threshold",
|
||||
"Timestamp alignment threshold in nanoseconds", 0,
|
||||
|
@ -246,6 +266,8 @@ gst_decklink_audio_src_init (GstDecklinkAudioSrc * self)
|
|||
self->skipped_last = 0;
|
||||
self->skip_from_timestamp = GST_CLOCK_TIME_NONE;
|
||||
self->skip_to_timestamp = GST_CLOCK_TIME_NONE;
|
||||
|
||||
self->persistent_id = DEFAULT_PERSISTENT_ID;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -274,6 +296,9 @@ gst_decklink_audio_src_set_property (GObject * object, guint property_id,
|
|||
case PROP_CHANNELS:
|
||||
self->channels = (GstDecklinkAudioChannelsEnum) g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
self->persistent_id = g_value_get_int64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -311,6 +336,9 @@ gst_decklink_audio_src_get_property (GObject * object, guint property_id,
|
|||
else
|
||||
g_value_set_string (value, NULL);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
g_value_set_int64 (value, self->persistent_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -939,7 +967,7 @@ gst_decklink_audio_src_open (GstDecklinkAudioSrc * self)
|
|||
GST_DEBUG_OBJECT (self, "Opening");
|
||||
|
||||
self->input =
|
||||
gst_decklink_acquire_nth_input (self->device_number,
|
||||
gst_decklink_acquire_nth_input (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), TRUE);
|
||||
if (!self->input) {
|
||||
GST_ERROR_OBJECT (self, "Failed to acquire input");
|
||||
|
@ -986,7 +1014,7 @@ gst_decklink_audio_src_close (GstDecklinkAudioSrc * self)
|
|||
self->input->got_audio_packet = NULL;
|
||||
g_mutex_unlock (&self->input->lock);
|
||||
|
||||
gst_decklink_release_nth_input (self->device_number,
|
||||
gst_decklink_release_nth_input (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), TRUE);
|
||||
self->input = NULL;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ struct _GstDecklinkAudioSrc
|
|||
GstDecklinkModeEnum mode;
|
||||
GstDecklinkAudioConnectionEnum connection;
|
||||
gint device_number;
|
||||
gint64 persistent_id;
|
||||
GstDecklinkAudioChannelsEnum channels;
|
||||
gint64 channels_found;
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "gstdecklinkdeviceprovider.h"
|
||||
#include "gstdecklink.h"
|
||||
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
G_DEFINE_TYPE (GstDecklinkDeviceProvider, gst_decklink_device_provider,
|
||||
GST_TYPE_DEVICE_PROVIDER);
|
||||
GST_DEVICE_PROVIDER_REGISTER_DEFINE (decklinkdeviceprovider, "decklinkdeviceprovider",
|
||||
|
@ -77,7 +79,7 @@ gst_decklink_device_create_element (GstDevice * device, const gchar * name)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
g_object_set (ret, "device-number", self->device_number, NULL);
|
||||
g_object_set (ret, "persistent-id", self->persistent_id, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -140,6 +140,8 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_decklink_video_sink_debug);
|
||||
#define GST_CAT_DEFAULT gst_decklink_video_sink_debug
|
||||
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
class GStreamerVideoOutputCallback:public IDeckLinkVideoOutputCallback
|
||||
{
|
||||
public:
|
||||
|
@ -521,6 +523,7 @@ enum
|
|||
PROP_CC_LINE,
|
||||
PROP_AFD_BAR_LINE,
|
||||
PROP_MAPPING_FORMAT,
|
||||
PROP_PERSISTENT_ID
|
||||
};
|
||||
|
||||
static void gst_decklink_video_sink_set_property (GObject * object,
|
||||
|
@ -612,6 +615,22 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
|
|||
"Output device instance to use", 0, G_MAXINT, 0,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
/**
|
||||
* GstDecklinkVideoSink:persistent-id
|
||||
*
|
||||
* Decklink device to use. Higher priority than "device-number".
|
||||
* BMDDeckLinkPersistentID is a device specific, 32-bit unique identifier.
|
||||
* It is stable even when the device is plugged in a different connector,
|
||||
* across reboots, and when plugged into different computers.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PERSISTENT_ID,
|
||||
g_param_spec_int64 ("persistent-id", "Persistent id",
|
||||
"Output device instance to use. Higher priority than \"device-number\".",
|
||||
DEFAULT_PERSISTENT_ID, G_MAXINT64, DEFAULT_PERSISTENT_ID,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_VIDEO_FORMAT,
|
||||
g_param_spec_enum ("video-format", "Video format",
|
||||
|
@ -723,6 +742,7 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self)
|
|||
{
|
||||
self->mode = GST_DECKLINK_MODE_NTSC;
|
||||
self->device_number = 0;
|
||||
self->persistent_id = DEFAULT_PERSISTENT_ID;
|
||||
self->video_format = GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV;
|
||||
self->profile_id = GST_DECKLINK_PROFILE_ID_DEFAULT;
|
||||
/* VITC is legacy, we should expect RP188 in modern use cases */
|
||||
|
@ -789,6 +809,9 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
|
|||
self->mapping_format =
|
||||
(GstDecklinkMappingFormat) g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
self->persistent_id = g_value_get_int64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -840,6 +863,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
|
|||
case PROP_MAPPING_FORMAT:
|
||||
g_value_set_enum (value, self->mapping_format);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
g_value_set_int64 (value, self->persistent_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -1673,7 +1699,7 @@ gst_decklink_video_sink_open (GstBaseSink * bsink)
|
|||
GST_DEBUG_OBJECT (self, "Starting");
|
||||
|
||||
self->output =
|
||||
gst_decklink_acquire_nth_output (self->device_number,
|
||||
gst_decklink_acquire_nth_output (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), FALSE);
|
||||
if (!self->output) {
|
||||
GST_ERROR_OBJECT (self, "Failed to acquire output");
|
||||
|
@ -1718,7 +1744,7 @@ gst_decklink_video_sink_close (GstBaseSink * bsink)
|
|||
g_mutex_unlock (&self->output->lock);
|
||||
|
||||
self->output->output->DisableVideoOutput ();
|
||||
gst_decklink_release_nth_output (self->device_number,
|
||||
gst_decklink_release_nth_output (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), FALSE);
|
||||
self->output = NULL;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ struct _GstDecklinkVideoSink
|
|||
|
||||
GstDecklinkModeEnum mode;
|
||||
gint device_number;
|
||||
gint64 persistent_id;
|
||||
GstDecklinkVideoFormat video_format;
|
||||
GstDecklinkProfileId profile_id;
|
||||
BMDTimecodeFormat timecode_format;
|
||||
|
|
|
@ -149,6 +149,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_decklink_video_src_debug);
|
|||
#define DEFAULT_DROP_NO_SIGNAL_FRAMES (FALSE)
|
||||
#define DEFAULT_OUTPUT_CC (FALSE)
|
||||
#define DEFAULT_OUTPUT_AFD_BAR (FALSE)
|
||||
#define DEFAULT_PERSISTENT_ID (-1)
|
||||
|
||||
#ifndef ABSDIFF
|
||||
#define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
|
||||
|
@ -169,6 +170,7 @@ enum
|
|||
PROP_DROP_NO_SIGNAL_FRAMES,
|
||||
PROP_SIGNAL,
|
||||
PROP_HW_SERIAL_NUMBER,
|
||||
PROP_PERSISTENT_ID,
|
||||
PROP_OUTPUT_CC,
|
||||
PROP_OUTPUT_AFD_BAR,
|
||||
};
|
||||
|
@ -290,6 +292,23 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
|
|||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
/**
|
||||
* GstDecklinkVideoSrc:persistent-id
|
||||
*
|
||||
* Decklink device to use. Higher priority than "device-number".
|
||||
* BMDDeckLinkPersistentID is a device specific, 32-bit unique identifier.
|
||||
* It is stable even when the device is plugged in a different connector,
|
||||
* across reboots, and when plugged into different computers.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PERSISTENT_ID,
|
||||
g_param_spec_int64 ("persistent-id", "Persistent id",
|
||||
"Output device instance to use. Higher priority than \"device-number\".",
|
||||
DEFAULT_PERSISTENT_ID, G_MAXINT64, DEFAULT_PERSISTENT_ID,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
|
||||
g_param_spec_uint ("buffer-size", "Buffer Size",
|
||||
"Size of internal buffer in number of video frames", 1,
|
||||
|
@ -396,6 +415,7 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
|
|||
self->caps_format = bmdFormat8BitYUV;
|
||||
self->connection = DEFAULT_CONNECTION;
|
||||
self->device_number = 0;
|
||||
self->persistent_id = DEFAULT_PERSISTENT_ID;
|
||||
self->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
self->video_format = GST_DECKLINK_VIDEO_FORMAT_AUTO;
|
||||
self->profile_id = GST_DECKLINK_PROFILE_ID_DEFAULT;
|
||||
|
@ -490,6 +510,9 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id,
|
|||
case PROP_DROP_NO_SIGNAL_FRAMES:
|
||||
self->drop_no_signal_frames = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
self->persistent_id = g_value_get_int64 (value);
|
||||
break;
|
||||
case PROP_OUTPUT_CC:
|
||||
self->output_cc = g_value_get_boolean (value);
|
||||
break;
|
||||
|
@ -540,6 +563,9 @@ gst_decklink_video_src_get_property (GObject * object, guint property_id,
|
|||
case PROP_DROP_NO_SIGNAL_FRAMES:
|
||||
g_value_set_boolean (value, self->drop_no_signal_frames);
|
||||
break;
|
||||
case PROP_PERSISTENT_ID:
|
||||
g_value_set_int64 (value, self->persistent_id);
|
||||
break;
|
||||
case PROP_SIGNAL:
|
||||
g_value_set_boolean (value, self->signal_state == SIGNAL_STATE_AVAILABLE);
|
||||
break;
|
||||
|
@ -1523,7 +1549,7 @@ gst_decklink_video_src_open (GstDecklinkVideoSrc * self)
|
|||
GST_DEBUG_OBJECT (self, "Opening");
|
||||
|
||||
self->input =
|
||||
gst_decklink_acquire_nth_input (self->device_number,
|
||||
gst_decklink_acquire_nth_input (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), FALSE);
|
||||
if (!self->input) {
|
||||
GST_ERROR_OBJECT (self, "Failed to acquire input");
|
||||
|
@ -1559,7 +1585,7 @@ gst_decklink_video_src_close (GstDecklinkVideoSrc * self)
|
|||
self->input->start_streams = NULL;
|
||||
g_mutex_unlock (&self->input->lock);
|
||||
|
||||
gst_decklink_release_nth_input (self->device_number,
|
||||
gst_decklink_release_nth_input (self->device_number, self->persistent_id,
|
||||
GST_ELEMENT_CAST (self), FALSE);
|
||||
self->input = NULL;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ struct _GstDecklinkVideoSrc
|
|||
BMDPixelFormat caps_format;
|
||||
GstDecklinkConnectionEnum connection;
|
||||
gint device_number;
|
||||
gint64 persistent_id;
|
||||
gboolean output_stream_time;
|
||||
GstClockTime skip_first_time;
|
||||
gboolean drop_no_signal_frames;
|
||||
|
|
Loading…
Reference in a new issue