From 0cd1bf13e8b7fb284dce97256a75e6162f42ecf6 Mon Sep 17 00:00:00 2001 From: Dave Johnstone Date: Tue, 15 Aug 2017 10:27:03 +0930 Subject: [PATCH] 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 --- sys/decklink/gstdecklink.cpp | 57 +++++++++++++++++++++++++++ sys/decklink/gstdecklink.h | 22 +++++++++++ sys/decklink/gstdecklinkvideosink.cpp | 51 +++++++++++++++++++++++- sys/decklink/gstdecklinkvideosink.h | 2 + 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp index 9c1b646f59..98021420be 100644 --- a/sys/decklink/gstdecklink.cpp +++ b/sys/decklink/gstdecklink.cpp @@ -168,6 +168,25 @@ gst_decklink_timecode_format_get_type (void) 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 gst_decklink_audio_connection_get_type (void) { @@ -298,6 +317,18 @@ static const struct /* *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 * gst_decklink_get_mode (GstDecklinkModeEnum e) { @@ -452,6 +483,25 @@ gst_decklink_timecode_format_to_enum (BMDTimecodeFormat f) 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[] = { (BMDVideoConnection) 0, /* auto */ bmdVideoConnectionSDI, @@ -1177,6 +1227,13 @@ init_devices (gpointer data) "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); i++; diff --git a/sys/decklink/gstdecklink.h b/sys/decklink/gstdecklink.h index 80ec1b9dca..3bcf72fa28 100644 --- a/sys/decklink/gstdecklink.h +++ b/sys/decklink/gstdecklink.h @@ -156,11 +156,32 @@ typedef enum { #define GST_TYPE_DECKLINK_TIMECODE_FORMAT (gst_decklink_timecode_format_get_type ()) 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 gint gst_decklink_bpp_from_type (GstDecklinkVideoFormat t); const GstDecklinkVideoFormat gst_decklink_type_from_video_format (GstVideoFormat f); const BMDTimecodeFormat gst_decklink_timecode_format_from_enum (GstDecklinkTimecodeFormat 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; struct _GstDecklinkMode { @@ -187,6 +208,7 @@ struct _GstDecklinkOutput { IDeckLink *device; IDeckLinkOutput *output; IDeckLinkAttributes *attributes; + IDeckLinkKeyer *keyer; GstClock *clock; GstClockTime clock_start_time, clock_last_time, clock_epoch; GstClockTimeDiff clock_offset; diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index 5477117956..4096941c24 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -120,7 +120,9 @@ enum PROP_MODE, PROP_DEVICE_NUMBER, 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, @@ -227,6 +229,20 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass) (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 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_caps_make_writable (templ_caps); /* 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) g_value_get_enum (value)); 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: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -315,6 +339,13 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id, g_value_set_enum (value, gst_decklink_timecode_format_to_enum (self->timecode_format)); 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: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -387,6 +418,24 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) 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 * 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 diff --git a/sys/decklink/gstdecklinkvideosink.h b/sys/decklink/gstdecklinkvideosink.h index b9aca283f3..1b60df196f 100644 --- a/sys/decklink/gstdecklinkvideosink.h +++ b/sys/decklink/gstdecklinkvideosink.h @@ -53,6 +53,8 @@ struct _GstDecklinkVideoSink gint device_number; GstDecklinkVideoFormat video_format; BMDTimecodeFormat timecode_format; + BMDKeyerMode keyer_mode; + gint keyer_level; GstVideoInfo info;