mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
decklinkvideosink: Add 3G-SDI Level A output support
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2544>
This commit is contained in:
parent
91b7d3679e
commit
1818374de2
5 changed files with 159 additions and 0 deletions
|
@ -11581,6 +11581,18 @@
|
||||||
"type": "GstDecklinkKeyerMode",
|
"type": "GstDecklinkKeyerMode",
|
||||||
"writable": true
|
"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": {
|
"mode": {
|
||||||
"blurb": "Video Mode to use for playback",
|
"blurb": "Video Mode to use for playback",
|
||||||
"conditionally-available": false,
|
"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": {
|
"GstDecklinkModes": {
|
||||||
"kind": "enum",
|
"kind": "enum",
|
||||||
"values": [
|
"values": [
|
||||||
|
|
|
@ -202,6 +202,36 @@ gst_decklink_profile_id_get_type (void)
|
||||||
return (GType) id;
|
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
|
GType
|
||||||
gst_decklink_timecode_format_get_type (void)
|
gst_decklink_timecode_format_get_type (void)
|
||||||
{
|
{
|
||||||
|
@ -386,6 +416,13 @@ enum ProfileSetOperationResult
|
||||||
PROFILE_SET_FAILURE
|
PROFILE_SET_FAILURE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MappingFormatSetOperationResult
|
||||||
|
{
|
||||||
|
MAPPING_FORMAT_SET_UNSUPPORTED,
|
||||||
|
MAPPING_FORMAT_SET_SUCCESS,
|
||||||
|
MAPPING_FORMAT_SET_FAILURE
|
||||||
|
};
|
||||||
|
|
||||||
enum DuplexModeSetOperationResult
|
enum DuplexModeSetOperationResult
|
||||||
{
|
{
|
||||||
DUPLEX_MODE_SET_UNSUPPORTED,
|
DUPLEX_MODE_SET_UNSUPPORTED,
|
||||||
|
@ -867,6 +904,8 @@ struct _Device
|
||||||
|
|
||||||
static ProfileSetOperationResult gst_decklink_configure_profile (Device *
|
static ProfileSetOperationResult gst_decklink_configure_profile (Device *
|
||||||
device, GstDecklinkProfileId profile_id);
|
device, GstDecklinkProfileId profile_id);
|
||||||
|
static MappingFormatSetOperationResult gst_decklink_configure_mapping_format (Device *
|
||||||
|
device, GstDecklinkMappingFormat mapping_format);
|
||||||
|
|
||||||
class GStreamerDecklinkInputCallback:public IDeckLinkInputCallback
|
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) {
|
videosink->profile_id) == PROFILE_SET_FAILURE) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (gst_decklink_configure_mapping_format (device,
|
||||||
|
videosink->mapping_format) == MAPPING_FORMAT_SET_FAILURE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_lock (&output->lock);
|
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);
|
G_DEFINE_TYPE (GstDecklinkClock, gst_decklink_clock, GST_TYPE_SYSTEM_CLOCK);
|
||||||
|
|
||||||
static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock);
|
static GstClockTime gst_decklink_clock_get_internal_time (GstClock * clock);
|
||||||
|
|
|
@ -173,6 +173,14 @@ typedef enum {
|
||||||
#define GST_TYPE_DECKLINK_PROFILE_ID (gst_decklink_profile_id_get_type ())
|
#define GST_TYPE_DECKLINK_PROFILE_ID (gst_decklink_profile_id_get_type ())
|
||||||
GType gst_decklink_profile_id_get_type (void);
|
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 {
|
typedef enum {
|
||||||
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1, /*bmdTimecodeRP188VITC1 */
|
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC1, /*bmdTimecodeRP188VITC1 */
|
||||||
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2, /*bmdTimecodeRP188VITC2 */
|
GST_DECKLINK_TIMECODE_FORMAT_RP188VITC2, /*bmdTimecodeRP188VITC2 */
|
||||||
|
|
|
@ -232,6 +232,14 @@ private:
|
||||||
gint m_refcount;
|
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
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -245,6 +253,7 @@ enum
|
||||||
PROP_HW_SERIAL_NUMBER,
|
PROP_HW_SERIAL_NUMBER,
|
||||||
PROP_CC_LINE,
|
PROP_CC_LINE,
|
||||||
PROP_AFD_BAR_LINE,
|
PROP_AFD_BAR_LINE,
|
||||||
|
PROP_MAPPING_FORMAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_decklink_video_sink_set_property (GObject * object,
|
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 |
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
G_PARAM_CONSTRUCT)));
|
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_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 */
|
||||||
|
@ -422,6 +445,8 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass)
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_decklink_video_sink_debug, "decklinkvideosink",
|
GST_DEBUG_CATEGORY_INIT (gst_decklink_video_sink_debug, "decklinkvideosink",
|
||||||
0, "debug category for decklinkvideosink element");
|
0, "debug category for decklinkvideosink element");
|
||||||
|
|
||||||
|
gst_type_mark_as_plugin_api(GST_TYPE_DECKLINK_MAPPING_FORMAT, (GstPluginAPIFlags)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -435,6 +460,7 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self)
|
||||||
self->timecode_format = bmdTimecodeRP188Any;
|
self->timecode_format = bmdTimecodeRP188Any;
|
||||||
self->caption_line = 0;
|
self->caption_line = 0;
|
||||||
self->afd_bar_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_max_lateness (GST_BASE_SINK_CAST (self), 20 * GST_MSECOND);
|
||||||
gst_base_sink_set_qos_enabled (GST_BASE_SINK_CAST (self), TRUE);
|
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:
|
case PROP_AFD_BAR_LINE:
|
||||||
self->afd_bar_line = g_value_get_int (value);
|
self->afd_bar_line = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MAPPING_FORMAT:
|
||||||
|
self->mapping_format = (GstDecklinkMappingFormat) g_value_get_enum (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;
|
||||||
|
@ -538,6 +567,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
|
||||||
case PROP_AFD_BAR_LINE:
|
case PROP_AFD_BAR_LINE:
|
||||||
g_value_set_int (value, self->afd_bar_line);
|
g_value_set_int (value, self->afd_bar_line);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MAPPING_FORMAT:
|
||||||
|
g_value_set_enum (value, self->mapping_format);
|
||||||
|
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;
|
||||||
|
|
|
@ -75,6 +75,7 @@ struct _GstDecklinkVideoSink
|
||||||
guint16 cdp_hdr_sequence_cntr;
|
guint16 cdp_hdr_sequence_cntr;
|
||||||
|
|
||||||
gint afd_bar_line;
|
gint afd_bar_line;
|
||||||
|
GstDecklinkMappingFormat mapping_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstDecklinkVideoSinkClass
|
struct _GstDecklinkVideoSinkClass
|
||||||
|
|
Loading…
Reference in a new issue