mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 04:36:20 +00:00
decklinkvideosink: Add support for Decklink hardware keying
Add two properties (keyer-mode and keyer-level) to control the built-in hardware keyer of Decklink cards. https://bugzilla.gnome.org/show_bug.cgi?id=773660
This commit is contained in:
parent
cbf4a44426
commit
0cd1bf13e8
4 changed files with 131 additions and 1 deletions
|
@ -168,6 +168,25 @@ gst_decklink_timecode_format_get_type (void)
|
||||||
return (GType) id;
|
return (GType) id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_decklink_keyer_mode_get_type (void)
|
||||||
|
{
|
||||||
|
static gsize id = 0;
|
||||||
|
static const GEnumValue keyermodes[] = {
|
||||||
|
{GST_DECKLINK_KEYER_MODE_OFF, "Off", "off"},
|
||||||
|
{GST_DECKLINK_KEYER_MODE_INTERNAL, "Internal", "internal"},
|
||||||
|
{GST_DECKLINK_KEYER_MODE_EXTERNAL, "External", "external"},
|
||||||
|
{0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (g_once_init_enter (&id)) {
|
||||||
|
GType tmp = g_enum_register_static ("GstDecklinkKeyerMode", keyermodes);
|
||||||
|
g_once_init_leave (&id, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GType) id;
|
||||||
|
}
|
||||||
|
|
||||||
GType
|
GType
|
||||||
gst_decklink_audio_connection_get_type (void)
|
gst_decklink_audio_connection_get_type (void)
|
||||||
{
|
{
|
||||||
|
@ -298,6 +317,18 @@ static const struct
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
BMDKeyerMode keymode;
|
||||||
|
GstDecklinkKeyerMode gstkeymode;
|
||||||
|
} kmodes[] = {
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
{bmdKeyerModeOff, GST_DECKLINK_KEYER_MODE_OFF},
|
||||||
|
{bmdKeyerModeInternal, GST_DECKLINK_KEYER_MODE_INTERNAL},
|
||||||
|
{bmdKeyerModeExternal, GST_DECKLINK_KEYER_MODE_EXTERNAL}
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
};
|
||||||
|
|
||||||
const GstDecklinkMode *
|
const GstDecklinkMode *
|
||||||
gst_decklink_get_mode (GstDecklinkModeEnum e)
|
gst_decklink_get_mode (GstDecklinkModeEnum e)
|
||||||
{
|
{
|
||||||
|
@ -452,6 +483,25 @@ gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f)
|
||||||
return GST_DECKLINK_TIMECODE_FORMAT_RP188ANY;
|
return GST_DECKLINK_TIMECODE_FORMAT_RP188ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BMDKeyerMode
|
||||||
|
gst_decklink_keyer_mode_from_enum (GstDecklinkKeyerMode m)
|
||||||
|
{
|
||||||
|
return kmodes[m].keymode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GstDecklinkKeyerMode
|
||||||
|
gst_decklink_keyer_mode_to_enum (BMDKeyerMode m)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (kmodes); i++) {
|
||||||
|
if (kmodes[i].keymode == m)
|
||||||
|
return (GstDecklinkKeyerMode) i;
|
||||||
|
}
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return GST_DECKLINK_KEYER_MODE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
static const BMDVideoConnection connections[] = {
|
static const BMDVideoConnection connections[] = {
|
||||||
(BMDVideoConnection) 0, /* auto */
|
(BMDVideoConnection) 0, /* auto */
|
||||||
bmdVideoConnectionSDI,
|
bmdVideoConnectionSDI,
|
||||||
|
@ -1177,6 +1227,13 @@ init_devices (gpointer data)
|
||||||
"0x%08lx", (unsigned long) ret);
|
"0x%08lx", (unsigned long) ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = decklink->QueryInterface (IID_IDeckLinkKeyer,
|
||||||
|
(void **) &devices[i].output.keyer);
|
||||||
|
|
||||||
|
/* We only warn of failure to obtain the keyer interface if the keyer
|
||||||
|
* is enabled by keyer_mode
|
||||||
|
*/
|
||||||
|
|
||||||
ret = iterator->Next (&decklink);
|
ret = iterator->Next (&decklink);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
|
|
|
@ -156,11 +156,32 @@ typedef enum {
|
||||||
#define GST_TYPE_DECKLINK_TIMECODE_FORMAT (gst_decklink_timecode_format_get_type ())
|
#define GST_TYPE_DECKLINK_TIMECODE_FORMAT (gst_decklink_timecode_format_get_type ())
|
||||||
GType gst_decklink_timecode_format_get_type (void);
|
GType gst_decklink_timecode_format_get_type (void);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GST_DECKLINK_KEYER_MODE_OFF,
|
||||||
|
GST_DECKLINK_KEYER_MODE_INTERNAL,
|
||||||
|
GST_DECKLINK_KEYER_MODE_EXTERNAL
|
||||||
|
} GstDecklinkKeyerMode;
|
||||||
|
#define GST_TYPE_DECKLINK_KEYER_MODE (gst_decklink_keyer_mode_get_type ())
|
||||||
|
GType gst_decklink_keyer_mode_get_type (void);
|
||||||
|
|
||||||
|
/* Enum BMDKeyerMode options of off, internal and external @@@ DJ @@@ */
|
||||||
|
|
||||||
|
typedef uint32_t BMDKeyerMode;
|
||||||
|
enum _BMDKeyerMode
|
||||||
|
{
|
||||||
|
bmdKeyerModeOff = /* 'off' */ 0,
|
||||||
|
bmdKeyerModeInternal = /* 'int' */ 1,
|
||||||
|
bmdKeyerModeExternal = /* 'ext' */ 2
|
||||||
|
};
|
||||||
|
|
||||||
const BMDPixelFormat gst_decklink_pixel_format_from_type (GstDecklinkVideoFormat t);
|
const BMDPixelFormat gst_decklink_pixel_format_from_type (GstDecklinkVideoFormat t);
|
||||||
const gint gst_decklink_bpp_from_type (GstDecklinkVideoFormat t);
|
const gint gst_decklink_bpp_from_type (GstDecklinkVideoFormat t);
|
||||||
const GstDecklinkVideoFormat gst_decklink_type_from_video_format (GstVideoFormat f);
|
const GstDecklinkVideoFormat gst_decklink_type_from_video_format (GstVideoFormat f);
|
||||||
const BMDTimecodeFormat gst_decklink_timecode_format_from_enum (GstDecklinkTimecodeFormat f);
|
const BMDTimecodeFormat gst_decklink_timecode_format_from_enum (GstDecklinkTimecodeFormat f);
|
||||||
const GstDecklinkTimecodeFormat gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f);
|
const GstDecklinkTimecodeFormat gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f);
|
||||||
|
const BMDKeyerMode gst_decklink_keyer_mode_from_enum (GstDecklinkKeyerMode m);
|
||||||
|
const GstDecklinkKeyerMode gst_decklink_keyer_mode_to_enum (BMDKeyerMode m);
|
||||||
|
|
||||||
typedef struct _GstDecklinkMode GstDecklinkMode;
|
typedef struct _GstDecklinkMode GstDecklinkMode;
|
||||||
struct _GstDecklinkMode {
|
struct _GstDecklinkMode {
|
||||||
|
@ -187,6 +208,7 @@ struct _GstDecklinkOutput {
|
||||||
IDeckLink *device;
|
IDeckLink *device;
|
||||||
IDeckLinkOutput *output;
|
IDeckLinkOutput *output;
|
||||||
IDeckLinkAttributes *attributes;
|
IDeckLinkAttributes *attributes;
|
||||||
|
IDeckLinkKeyer *keyer;
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockTime clock_start_time, clock_last_time, clock_epoch;
|
GstClockTime clock_start_time, clock_last_time, clock_epoch;
|
||||||
GstClockTimeDiff clock_offset;
|
GstClockTimeDiff clock_offset;
|
||||||
|
|
|
@ -120,7 +120,9 @@ enum
|
||||||
PROP_MODE,
|
PROP_MODE,
|
||||||
PROP_DEVICE_NUMBER,
|
PROP_DEVICE_NUMBER,
|
||||||
PROP_VIDEO_FORMAT,
|
PROP_VIDEO_FORMAT,
|
||||||
PROP_TIMECODE_FORMAT
|
PROP_TIMECODE_FORMAT,
|
||||||
|
PROP_KEYER_MODE,
|
||||||
|
PROP_KEYER_LEVEL
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_decklink_video_sink_set_property (GObject * object,
|
static void gst_decklink_video_sink_set_property (GObject * object,
|
||||||
|
@ -227,6 +229,20 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
|
||||||
(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_KEYER_MODE,
|
||||||
|
g_param_spec_enum ("keyer-mode", "Keyer mode",
|
||||||
|
"Keyer mode to be enabled",
|
||||||
|
GST_TYPE_DECKLINK_KEYER_MODE,
|
||||||
|
GST_DECKLINK_KEYER_MODE_OFF,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_KEYER_LEVEL,
|
||||||
|
g_param_spec_int ("keyer-level", "Keyer level",
|
||||||
|
"Keyer level", 0, 255, 255,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
templ_caps = gst_decklink_mode_get_template_caps (FALSE);
|
templ_caps = gst_decklink_mode_get_template_caps (FALSE);
|
||||||
templ_caps = gst_caps_make_writable (templ_caps);
|
templ_caps = gst_caps_make_writable (templ_caps);
|
||||||
/* For output we support any framerate and only really care about timestamps */
|
/* For output we support any framerate and only really care about timestamps */
|
||||||
|
@ -289,6 +305,14 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
|
||||||
gst_decklink_timecode_format_from_enum ((GstDecklinkTimecodeFormat)
|
gst_decklink_timecode_format_from_enum ((GstDecklinkTimecodeFormat)
|
||||||
g_value_get_enum (value));
|
g_value_get_enum (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_KEYER_MODE:
|
||||||
|
self->keyer_mode =
|
||||||
|
gst_decklink_keyer_mode_from_enum ((GstDecklinkKeyerMode)
|
||||||
|
g_value_get_enum (value));
|
||||||
|
break;
|
||||||
|
case PROP_KEYER_LEVEL:
|
||||||
|
self->keyer_level = g_value_get_int (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -315,6 +339,13 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
|
||||||
g_value_set_enum (value,
|
g_value_set_enum (value,
|
||||||
gst_decklink_timecode_format_to_enum (self->timecode_format));
|
gst_decklink_timecode_format_to_enum (self->timecode_format));
|
||||||
break;
|
break;
|
||||||
|
case PROP_KEYER_MODE:
|
||||||
|
g_value_set_enum (value,
|
||||||
|
gst_decklink_keyer_mode_to_enum (self->keyer_mode));
|
||||||
|
break;
|
||||||
|
case PROP_KEYER_LEVEL:
|
||||||
|
g_value_set_int (value, self->keyer_level);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -387,6 +418,24 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
g_assert (mode != NULL);
|
g_assert (mode != NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* enable or disable keyer */
|
||||||
|
if (self->output->keyer != NULL) {
|
||||||
|
if (self->keyer_mode == bmdKeyerModeOff) {
|
||||||
|
self->output->keyer->Disable ();
|
||||||
|
} else if (self->keyer_mode == bmdKeyerModeInternal) {
|
||||||
|
self->output->keyer->Enable (false);
|
||||||
|
self->output->keyer->SetLevel (self->keyer_level);
|
||||||
|
} else if (self->keyer_mode == bmdKeyerModeExternal) {
|
||||||
|
self->output->keyer->Enable (true);
|
||||||
|
self->output->keyer->SetLevel (self->keyer_level);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
} else if (self->keyer_mode != bmdKeyerModeOff) {
|
||||||
|
GST_WARNING_OBJECT (self, "Failed to set keyer to mode %d",
|
||||||
|
self->keyer_mode);
|
||||||
|
}
|
||||||
|
|
||||||
/* The timecode_format itself is used when we embed the actual timecode data
|
/* The timecode_format itself is used when we embed the actual timecode data
|
||||||
* into the frame. Now we only need to know which of the two standards the
|
* into the frame. Now we only need to know which of the two standards the
|
||||||
* timecode format will adhere to: VITC or RP188, and send the appropriate
|
* timecode format will adhere to: VITC or RP188, and send the appropriate
|
||||||
|
|
|
@ -53,6 +53,8 @@ struct _GstDecklinkVideoSink
|
||||||
gint device_number;
|
gint device_number;
|
||||||
GstDecklinkVideoFormat video_format;
|
GstDecklinkVideoFormat video_format;
|
||||||
BMDTimecodeFormat timecode_format;
|
BMDTimecodeFormat timecode_format;
|
||||||
|
BMDKeyerMode keyer_mode;
|
||||||
|
gint keyer_level;
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue