decklinkvideosink: Add 3G-SDI Level A output support

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2544>
This commit is contained in:
Eric Knapp 2022-06-02 10:32:28 -04:00 committed by Sebastian Dröge
parent 91b7d3679e
commit 1818374de2
5 changed files with 159 additions and 0 deletions

View file

@ -11581,6 +11581,18 @@
"type": "GstDecklinkKeyerMode",
"writable": true
},
"mapping-format": {
"blurb": "3G-SDI Mapping Format (Level A/B)",
"conditionally-available": false,
"construct": true,
"construct-only": false,
"controllable": false,
"default": "default (0)",
"mutable": "null",
"readable": true,
"type": "GstDecklinkMappingFormat",
"writable": true
},
"mode": {
"blurb": "Video Mode to use for playback",
"conditionally-available": false,
@ -11955,6 +11967,26 @@
}
]
},
"GstDecklinkMappingFormat": {
"kind": "enum",
"values": [
{
"desc": "Default, don't change mapping format",
"name": "default",
"value": "0"
},
{
"desc": "Level A",
"name": "level-a",
"value": "1"
},
{
"desc": "Level B",
"name": "level-b",
"value": "2"
}
]
},
"GstDecklinkModes": {
"kind": "enum",
"values": [

View file

@ -202,6 +202,36 @@ gst_decklink_profile_id_get_type (void)
return (GType) id;
}
/**
* GstDecklinkMappingFormat:
* @GST_DECKLINK_MAPPING_FORMAT_DEFAULT: Don't change the mapping format
* @GST_DECKLINK_MAPPING_FORMAT_LEVEL_A: Level A
* @GST_DECKLINK_MAPPING_FORMAT_LEVEL_B: Level B
*
* 3G-SDI mapping format (SMPTE ST 425-1:2017)
*
* Since: 1.22
*/
GType
gst_decklink_mapping_format_get_type (void)
{
static gsize id = 0;
static const GEnumValue mappingformats[] = {
{GST_DECKLINK_MAPPING_FORMAT_DEFAULT, "Default, don't change mapping format",
"default"},
{GST_DECKLINK_MAPPING_FORMAT_LEVEL_A, "Level A", "level-a"},
{GST_DECKLINK_MAPPING_FORMAT_LEVEL_B, "Level B", "level-b"},
{0, NULL, NULL}
};
if (g_once_init_enter (&id)) {
GType tmp = g_enum_register_static ("GstDecklinkMappingFormat", mappingformats);
g_once_init_leave (&id, tmp);
}
return (GType) id;
}
GType
gst_decklink_timecode_format_get_type (void)
{
@ -386,6 +416,13 @@ enum ProfileSetOperationResult
PROFILE_SET_FAILURE
};
enum MappingFormatSetOperationResult
{
MAPPING_FORMAT_SET_UNSUPPORTED,
MAPPING_FORMAT_SET_SUCCESS,
MAPPING_FORMAT_SET_FAILURE
};
enum DuplexModeSetOperationResult
{
DUPLEX_MODE_SET_UNSUPPORTED,
@ -867,6 +904,8 @@ struct _Device
static ProfileSetOperationResult gst_decklink_configure_profile (Device *
device, GstDecklinkProfileId profile_id);
static MappingFormatSetOperationResult gst_decklink_configure_mapping_format (Device *
device, GstDecklinkMappingFormat mapping_format);
class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
{
@ -1718,6 +1757,10 @@ gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio)
videosink->profile_id) == PROFILE_SET_FAILURE) {
return NULL;
}
if (gst_decklink_configure_mapping_format (device,
videosink->mapping_format) == MAPPING_FORMAT_SET_FAILURE) {
return NULL;
}
}
g_mutex_lock (&output->lock);
@ -1905,6 +1948,49 @@ gst_decklink_configure_profile (Device * device,
}
}
static MappingFormatSetOperationResult
gst_decklink_configure_mapping_format (Device * device,
GstDecklinkMappingFormat mapping_format)
{
HRESULT res;
bool level_a_output;
switch (mapping_format) {
case GST_DECKLINK_MAPPING_FORMAT_LEVEL_A:
level_a_output = true;
break;
case GST_DECKLINK_MAPPING_FORMAT_LEVEL_B:
level_a_output = false;
break;
default:
case GST_DECKLINK_MAPPING_FORMAT_DEFAULT:
return MAPPING_FORMAT_SET_SUCCESS;
}
// Make sure Level A is supported
bool supports_level_a_output = false;
res = device->output.attributes->GetFlag(BMDDeckLinkSupportsSMPTELevelAOutput,
&supports_level_a_output);
if (res != S_OK || !supports_level_a_output) {
if (level_a_output) {
GST_DEBUG ("Device does not support Level A mapping format");
return MAPPING_FORMAT_SET_UNSUPPORTED;
} else {
// Level B is the only supported option
return MAPPING_FORMAT_SET_SUCCESS;
}
}
res = device->input.config->SetFlag(bmdDeckLinkConfigSMPTELevelAOutput, level_a_output);
if (res == S_OK) {
GST_DEBUG ("Successfully set mapping format");
return MAPPING_FORMAT_SET_SUCCESS;
} else {
GST_ERROR ("Failed to set mapping format");
return MAPPING_FORMAT_SET_FAILURE;
}
}
G_DEFINE_TYPE (GstDecklinkClock, gst_decklink_clock, GST_TYPE_SYSTEM_CLOCK);
static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock);

View file

@ -173,6 +173,14 @@ typedef enum {
#define GST_TYPE_DECKLINK_PROFILE_ID (gst_decklink_profile_id_get_type ())
GType gst_decklink_profile_id_get_type (void);
typedef enum {
GST_DECKLINK_MAPPING_FORMAT_DEFAULT,
GST_DECKLINK_MAPPING_FORMAT_LEVEL_A, /* bmdDeckLinkConfigSMPTELevelAOutput = true */
GST_DECKLINK_MAPPING_FORMAT_LEVEL_B, /* bmdDeckLinkConfigSMPTELevelAOutput = false */
} GstDecklinkMappingFormat;
#define GST_TYPE_DECKLINK_MAPPING_FORMAT (gst_decklink_mapping_format_get_type ())
GType gst_decklink_mapping_format_get_type (void);
typedef enum {
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1, /*bmdTimecodeRP188VITC1 */
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2, /*bmdTimecodeRP188VITC2 */

View file

@ -232,6 +232,14 @@ private:
gint m_refcount;
};
/**
* GstDecklinkMappingFormat:
* @GST_DECKLINK_MAPPING_FORMAT_DEFAULT: Don't change the mapping format
* @GST_DECKLINK_MAPPING_FORMAT_LEVEL_A: Level A
* @GST_DECKLINK_MAPPING_FORMAT_LEVEL_B: Level B
*
* Since: 1.22
*/
enum
{
PROP_0,
@ -245,6 +253,7 @@ enum
PROP_HW_SERIAL_NUMBER,
PROP_CC_LINE,
PROP_AFD_BAR_LINE,
PROP_MAPPING_FORMAT,
};
static void gst_decklink_video_sink_set_property (GObject * object,
@ -407,6 +416,20 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT)));
/**
* GstDecklinkVideoSink:mapping-format
*
* Specifies the 3G-SDI mapping format to use (SMPTE ST 425-1:2017).
*
* Since: 1.22
*/
g_object_class_install_property (gobject_class, PROP_MAPPING_FORMAT,
g_param_spec_enum ("mapping-format", "3G-SDI Mapping Format",
"3G-SDI Mapping Format (Level A/B)",
GST_TYPE_DECKLINK_MAPPING_FORMAT, GST_DECKLINK_MAPPING_FORMAT_DEFAULT,
(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 */
@ -422,6 +445,8 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
GST_DEBUG_CATEGORY_INIT (gst_decklink_video_sink_debug, "decklinkvideosink",
0, "debug category for decklinkvideosink element");
gst_type_mark_as_plugin_api(GST_TYPE_DECKLINK_MAPPING_FORMAT, (GstPluginAPIFlags)0);
}
static void
@ -435,6 +460,7 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self)
self->timecode_format = bmdTimecodeRP188Any;
self->caption_line = 0;
self->afd_bar_line = 0;
self->mapping_format = GST_DECKLINK_MAPPING_FORMAT_DEFAULT;
gst_base_sink_set_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND);
gst_base_sink_set_qos_enabled (GST_BASE_SINK_CAST (self), TRUE);
@ -490,6 +516,9 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
case PROP_AFD_BAR_LINE:
self->afd_bar_line = g_value_get_int (value);
break;
case PROP_MAPPING_FORMAT:
self->mapping_format = (GstDecklinkMappingFormat) g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -538,6 +567,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
case PROP_AFD_BAR_LINE:
g_value_set_int (value, self->afd_bar_line);
break;
case PROP_MAPPING_FORMAT:
g_value_set_enum (value, self->mapping_format);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;

View file

@ -75,6 +75,7 @@ struct _GstDecklinkVideoSink
guint16 cdp_hdr_sequence_cntr;
gint afd_bar_line;
GstDecklinkMappingFormat mapping_format;
};
struct _GstDecklinkVideoSinkClass