mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
decklinkvideosink: Add support for GstVideoTimeCode
The timecode will be fetched from the video buffer and outputted on the decklink video sink. https://bugzilla.gnome.org/show_bug.cgi?id=766419
This commit is contained in:
parent
8faa36e105
commit
de1f42a284
2 changed files with 68 additions and 3 deletions
|
@ -119,7 +119,8 @@ enum
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_MODE,
|
PROP_MODE,
|
||||||
PROP_DEVICE_NUMBER,
|
PROP_DEVICE_NUMBER,
|
||||||
PROP_VIDEO_FORMAT
|
PROP_VIDEO_FORMAT,
|
||||||
|
PROP_TIMECODE_FORMAT
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_decklink_video_sink_set_property (GObject * object,
|
static void gst_decklink_video_sink_set_property (GObject * object,
|
||||||
|
@ -213,6 +214,14 @@ 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_TIMECODE_FORMAT,
|
||||||
|
g_param_spec_enum ("timecode-format", "Timecode format",
|
||||||
|
"Timecode format type to use for playback",
|
||||||
|
GST_TYPE_DECKLINK_TIMECODE_FORMAT,
|
||||||
|
GST_DECKLINK_TIMECODE_FORMAT_RP188ANY,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
|
G_PARAM_CONSTRUCT)));
|
||||||
|
|
||||||
templ_caps = gst_decklink_mode_get_template_caps ();
|
templ_caps = gst_decklink_mode_get_template_caps ();
|
||||||
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 */
|
||||||
|
@ -235,6 +244,8 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self)
|
||||||
self->mode = GST_DECKLINK_MODE_NTSC;
|
self->mode = GST_DECKLINK_MODE_NTSC;
|
||||||
self->device_number = 0;
|
self->device_number = 0;
|
||||||
self->video_format = GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV;
|
self->video_format = GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV;
|
||||||
|
/* VITC is legacy, we should expect RP188 in modern use cases */
|
||||||
|
self->timecode_format = bmdTimecodeRP188Any;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -268,6 +279,11 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROP_TIMECODE_FORMAT:
|
||||||
|
self->timecode_format =
|
||||||
|
gst_decklink_timecode_format_from_enum ((GstDecklinkTimecodeFormat)
|
||||||
|
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;
|
||||||
|
@ -290,6 +306,10 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
|
||||||
case PROP_VIDEO_FORMAT:
|
case PROP_VIDEO_FORMAT:
|
||||||
g_value_set_enum (value, self->video_format);
|
g_value_set_enum (value, self->video_format);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TIMECODE_FORMAT:
|
||||||
|
g_value_set_enum (value,
|
||||||
|
gst_decklink_timecode_format_to_enum (self->timecode_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;
|
||||||
|
@ -310,6 +330,7 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
|
GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
|
||||||
const GstDecklinkMode *mode;
|
const GstDecklinkMode *mode;
|
||||||
HRESULT ret;
|
HRESULT ret;
|
||||||
|
BMDVideoOutputFlags flags;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
|
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
@ -341,8 +362,21 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
g_assert (mode != NULL);
|
g_assert (mode != NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = self->output->output->EnableVideoOutput (mode->mode,
|
/* The timecode_format itself is used when we embed the actual timecode data
|
||||||
bmdVideoOutputFlagDefault);
|
* 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
|
||||||
|
* flag to EnableVideoOutput. The exact format is specified later.
|
||||||
|
*
|
||||||
|
* Note that this flag will have no effect in practice if the video stream
|
||||||
|
* does not contain timecode metadata.
|
||||||
|
*/
|
||||||
|
if (self->timecode_format == GST_DECKLINK_TIMECODE_FORMAT_VITC ||
|
||||||
|
self->timecode_format == GST_DECKLINK_TIMECODE_FORMAT_VITCFIELD2)
|
||||||
|
flags = bmdVideoOutputVITC;
|
||||||
|
else
|
||||||
|
flags = bmdVideoOutputRP188;
|
||||||
|
|
||||||
|
ret = self->output->output->EnableVideoOutput (mode->mode, flags);
|
||||||
if (ret != S_OK) {
|
if (ret != S_OK) {
|
||||||
GST_WARNING_OBJECT (self, "Failed to enable video output");
|
GST_WARNING_OBJECT (self, "Failed to enable video output");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -503,6 +537,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
GstDecklinkVideoFormat caps_format;
|
GstDecklinkVideoFormat caps_format;
|
||||||
BMDPixelFormat format;
|
BMDPixelFormat format;
|
||||||
gint bpp;
|
gint bpp;
|
||||||
|
GstVideoTimeCodeMeta *tc_meta;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer);
|
GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer);
|
||||||
|
|
||||||
|
@ -575,6 +610,35 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
gst_video_frame_unmap (&vframe);
|
gst_video_frame_unmap (&vframe);
|
||||||
|
|
||||||
|
tc_meta = gst_buffer_get_video_time_code_meta (buffer);
|
||||||
|
if (tc_meta) {
|
||||||
|
BMDTimecodeFlags bflags = (BMDTimecodeFlags) 0;
|
||||||
|
gchar *tc_str;
|
||||||
|
|
||||||
|
if (((GstVideoTimeCodeFlags) (tc_meta->tc.
|
||||||
|
config.flags)) & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME)
|
||||||
|
bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeIsDropFrame);
|
||||||
|
else
|
||||||
|
bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeFlagDefault);
|
||||||
|
if (tc_meta->tc.field_count == 2)
|
||||||
|
bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeFieldMark);
|
||||||
|
|
||||||
|
tc_str = gst_video_time_code_to_string (&tc_meta->tc);
|
||||||
|
ret = frame->SetTimecodeFromComponents (self->timecode_format,
|
||||||
|
(uint8_t) tc_meta->tc.hours,
|
||||||
|
(uint8_t) tc_meta->tc.minutes,
|
||||||
|
(uint8_t) tc_meta->tc.seconds, (uint8_t) tc_meta->tc.frames, bflags);
|
||||||
|
if (ret != S_OK) {
|
||||||
|
GST_ERROR_OBJECT (self,
|
||||||
|
"Failed to set timecode %s to video frame: 0x%08x", tc_str, ret);
|
||||||
|
flow_ret = GST_FLOW_ERROR;
|
||||||
|
g_free (tc_str);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
GST_DEBUG_OBJECT (self, "Set frame timecode to %s", tc_str);
|
||||||
|
g_free (tc_str);
|
||||||
|
}
|
||||||
|
|
||||||
convert_to_internal_clock (self, &running_time, &running_time_duration);
|
convert_to_internal_clock (self, &running_time, &running_time_duration);
|
||||||
|
|
||||||
GST_LOG_OBJECT (self, "Scheduling video frame %p at %" GST_TIME_FORMAT
|
GST_LOG_OBJECT (self, "Scheduling video frame %p at %" GST_TIME_FORMAT
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct _GstDecklinkVideoSink
|
||||||
GstDecklinkModeEnum mode;
|
GstDecklinkModeEnum mode;
|
||||||
gint device_number;
|
gint device_number;
|
||||||
GstDecklinkVideoFormat video_format;
|
GstDecklinkVideoFormat video_format;
|
||||||
|
BMDTimecodeFormat timecode_format;
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue