mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
decklink: Add initial 10bit support for YUV modes
https://bugzilla.gnome.org/show_bug.cgi?id=742878
This commit is contained in:
parent
87503ac174
commit
832764d2fd
6 changed files with 315 additions and 40 deletions
|
@ -111,6 +111,34 @@ gst_decklink_connection_get_type (void)
|
|||
return (GType) id;
|
||||
}
|
||||
|
||||
GType
|
||||
gst_decklink_video_format_get_type (void)
|
||||
{
|
||||
static gsize id = 0;
|
||||
static const GEnumValue types[] = {
|
||||
{GST_DECKLINK_VIDEO_FORMAT_AUTO, "auto", "Auto"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV, "8bit-yuv", "bmdFormat8BitYUV"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV, "10bit-yuv", "bmdFormat10BitYUV"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB, "8bit-argb", "bmdFormat8BitARGB"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA, "8bit-bgra", "bmdFormat8BitBGRA"},
|
||||
/*
|
||||
{GST_DECKLINK_VIDEO_FORMAT_10BIT_RGB, "10bit-rgb", "bmdFormat10BitRGB"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_12BIT_RGB, "12bit-rgb", "bmdFormat12BitRGB"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_12BIT_RGBLE, "12bit-rgble", "bmdFormat12BitRGBLE"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBXLE, "10bit-rgbxle", "bmdFormat10BitRGBXLE"},
|
||||
{GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBX, "10bit-rgbx", "bmdFormat10BitRGBX"},
|
||||
*/
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
if (g_once_init_enter (&id)) {
|
||||
GType tmp = g_enum_register_static ("GstDecklinkVideoFormat", types);
|
||||
g_once_init_leave (&id, tmp);
|
||||
}
|
||||
|
||||
return (GType) id;
|
||||
}
|
||||
|
||||
GType
|
||||
gst_decklink_audio_connection_get_type (void)
|
||||
{
|
||||
|
@ -183,6 +211,27 @@ static const GstDecklinkMode modes[] = {
|
|||
{bmdMode4K2160p60, 3840, 2160, 60, 1, false, UHD}
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
BMDPixelFormat format;
|
||||
gint bpp;
|
||||
GstVideoFormat vformat;
|
||||
} formats[] = {
|
||||
/* *INDENT-OFF* */
|
||||
{bmdFormat8BitYUV, 2, GST_VIDEO_FORMAT_UYVY}, /* auto */
|
||||
{bmdFormat8BitYUV, 2, GST_VIDEO_FORMAT_UYVY},
|
||||
{bmdFormat10BitYUV, 4, GST_VIDEO_FORMAT_v210},
|
||||
{bmdFormat8BitARGB, 4, GST_VIDEO_FORMAT_ARGB},
|
||||
{bmdFormat8BitBGRA, 4, GST_VIDEO_FORMAT_BGRA},
|
||||
/* Not yet supported
|
||||
{bmdFormat10BitRGB, FIXME, FIXME},
|
||||
{bmdFormat12BitRGB, FIXME, FIXME},
|
||||
{bmdFormat12BitRGBLE, FIXME, FIXME},
|
||||
{bmdFormat10BitRGBXLE, FIXME, FIXME},
|
||||
{bmdFormat10BitRGBX, FIXME, FIXME} */
|
||||
/* *INDENT-ON* */
|
||||
};
|
||||
|
||||
const GstDecklinkMode *
|
||||
gst_decklink_get_mode (GstDecklinkModeEnum e)
|
||||
{
|
||||
|
@ -293,6 +342,31 @@ gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode)
|
|||
return displayMode;
|
||||
}
|
||||
|
||||
const BMDPixelFormat
|
||||
gst_decklink_pixel_format_from_type (GstDecklinkVideoFormat t)
|
||||
{
|
||||
return formats[t].format;
|
||||
}
|
||||
|
||||
const gint
|
||||
gst_decklink_bpp_from_type (GstDecklinkVideoFormat t)
|
||||
{
|
||||
return formats[t].bpp;
|
||||
}
|
||||
|
||||
const GstDecklinkVideoFormat
|
||||
gst_decklink_type_from_video_format (GstVideoFormat f)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 1; i < G_N_ELEMENTS (formats); i++) {
|
||||
if (formats[i].vformat == f)
|
||||
return (GstDecklinkVideoFormat) i;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return GST_DECKLINK_VIDEO_FORMAT_AUTO;
|
||||
}
|
||||
|
||||
static const BMDVideoConnection connections[] = {
|
||||
0, /* auto */
|
||||
bmdVideoConnectionSDI,
|
||||
|
@ -315,6 +389,21 @@ gst_decklink_get_connection (GstDecklinkConnectionEnum e)
|
|||
return connections[e];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_decklink_caps_get_pixel_format (GstCaps * caps, BMDPixelFormat * format)
|
||||
{
|
||||
GstVideoInfo vinfo;
|
||||
GstVideoFormat f;
|
||||
|
||||
if (gst_video_info_from_caps (&vinfo, caps) == FALSE) {
|
||||
GST_ERROR ("Could not get video info from caps: %" GST_PTR_FORMAT, caps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
f = vinfo.finfo->format;
|
||||
return gst_decklink_type_from_video_format (f);
|
||||
}
|
||||
|
||||
static GstStructure *
|
||||
gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f)
|
||||
{
|
||||
|
@ -363,7 +452,39 @@ gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f)
|
|||
GstCaps *caps;
|
||||
|
||||
caps = gst_caps_new_empty ();
|
||||
gst_caps_append_structure (caps, gst_decklink_mode_get_structure (e, f));
|
||||
caps =
|
||||
gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e, f));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e)
|
||||
{
|
||||
GstCaps *caps;
|
||||
guint i;
|
||||
|
||||
caps = gst_caps_new_empty ();
|
||||
for (i = 1; i < G_N_ELEMENTS (formats); i++)
|
||||
caps =
|
||||
gst_caps_merge_structure (caps, gst_decklink_mode_get_structure (e,
|
||||
formats[i].format));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_decklink_pixel_format_get_caps (BMDPixelFormat f)
|
||||
{
|
||||
int i;
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
|
||||
caps = gst_caps_new_empty ();
|
||||
for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
|
||||
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f);
|
||||
caps = gst_caps_merge_structure (caps, s);
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
@ -373,30 +494,29 @@ gst_decklink_mode_get_template_caps (void)
|
|||
{
|
||||
int i;
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
|
||||
caps = gst_caps_new_empty ();
|
||||
for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
|
||||
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i,
|
||||
bmdFormat8BitYUV);
|
||||
gst_caps_append_structure (caps, s);
|
||||
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i,
|
||||
bmdFormat8BitARGB);
|
||||
gst_caps_append_structure (caps, s);
|
||||
}
|
||||
for (i = 1; i < (int) G_N_ELEMENTS (modes); i++)
|
||||
caps =
|
||||
gst_caps_merge (caps,
|
||||
gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
const GstDecklinkMode *
|
||||
gst_decklink_find_mode_for_caps (GstCaps * caps)
|
||||
gst_decklink_find_mode_and_format_for_caps (GstCaps * caps,
|
||||
BMDPixelFormat * format)
|
||||
{
|
||||
int i;
|
||||
GstCaps *mode_caps;
|
||||
|
||||
g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
|
||||
if (!gst_decklink_caps_get_pixel_format (caps, format))
|
||||
return NULL;
|
||||
|
||||
for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
|
||||
mode_caps =
|
||||
gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, bmdFormat8BitYUV);
|
||||
mode_caps = gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, *format);
|
||||
if (gst_caps_can_intersect (caps, mode_caps)) {
|
||||
gst_caps_unref (mode_caps);
|
||||
return gst_decklink_get_mode ((GstDecklinkModeEnum) i);
|
||||
|
@ -407,6 +527,14 @@ gst_decklink_find_mode_for_caps (GstCaps * caps)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const GstDecklinkMode *
|
||||
gst_decklink_find_mode_for_caps (GstCaps * caps)
|
||||
{
|
||||
BMDPixelFormat format;
|
||||
|
||||
return gst_decklink_find_mode_and_format_for_caps (caps, &format);
|
||||
}
|
||||
|
||||
#define GST_TYPE_DECKLINK_CLOCK \
|
||||
(gst_decklink_clock_get_type())
|
||||
#define GST_DECKLINK_CLOCK(obj) \
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define _GST_DECKLINK_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#ifdef G_OS_UNIX
|
||||
#include "linux/DeckLinkAPI.h"
|
||||
#endif
|
||||
|
@ -109,6 +110,25 @@ typedef enum {
|
|||
#define GST_TYPE_DECKLINK_AUDIO_CONNECTION (gst_decklink_audio_connection_get_type ())
|
||||
GType gst_decklink_audio_connection_get_type (void);
|
||||
|
||||
typedef enum {
|
||||
GST_DECKLINK_VIDEO_FORMAT_AUTO,
|
||||
GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV, /* bmdFormat8BitYUV */
|
||||
GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV, /* bmdFormat10BitYUV */
|
||||
GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB, /* bmdFormat8BitARGB */
|
||||
GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA, /* bmdFormat8BitBGRA */
|
||||
GST_DECKLINK_VIDEO_FORMAT_10BIT_RGB, /* bmdFormat10BitRGB */
|
||||
GST_DECKLINK_VIDEO_FORMAT_12BIT_RGB, /* bmdFormat12BitRGB */
|
||||
GST_DECKLINK_VIDEO_FORMAT_12BIT_RGBLE, /* bmdFormat12BitRGBLE */
|
||||
GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBXLE, /* bmdFormat10BitRGBXLE */
|
||||
GST_DECKLINK_VIDEO_FORMAT_10BIT_RGBX, /* bmdFormat10BitRGBX */
|
||||
} GstDecklinkVideoFormat;
|
||||
#define GST_TYPE_DECKLINK_VIDEO_FORMAT (gst_decklink_video_format_get_type ())
|
||||
GType gst_decklink_video_format_get_type (void);
|
||||
|
||||
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);
|
||||
|
||||
typedef struct _GstDecklinkMode GstDecklinkMode;
|
||||
struct _GstDecklinkMode {
|
||||
BMDDisplayMode mode;
|
||||
|
@ -195,5 +215,8 @@ GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, GstElement * src, gb
|
|||
void gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio);
|
||||
|
||||
const GstDecklinkMode * gst_decklink_find_mode_for_caps (GstCaps * caps);
|
||||
const GstDecklinkMode * gst_decklink_find_mode_and_format_for_caps (GstCaps * caps, BMDPixelFormat * format);
|
||||
GstCaps * gst_decklink_mode_get_caps_all_formats (GstDecklinkModeEnum e);
|
||||
GstCaps * gst_decklink_pixel_format_get_caps (BMDPixelFormat f);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -118,7 +118,8 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
PROP_MODE,
|
||||
PROP_DEVICE_NUMBER
|
||||
PROP_DEVICE_NUMBER,
|
||||
PROP_VIDEO_FORMAT
|
||||
};
|
||||
|
||||
static void gst_decklink_video_sink_set_property (GObject * object,
|
||||
|
@ -205,6 +206,13 @@ 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_VIDEO_FORMAT,
|
||||
g_param_spec_enum ("video-format", "Video format",
|
||||
"Video format type to use for playback",
|
||||
GST_TYPE_DECKLINK_VIDEO_FORMAT, GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
templ_caps = gst_decklink_mode_get_template_caps ();
|
||||
templ_caps = gst_caps_make_writable (templ_caps);
|
||||
/* For output we support any framerate and only really care about timestamps */
|
||||
|
@ -226,6 +234,7 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self)
|
|||
{
|
||||
self->mode = GST_DECKLINK_MODE_NTSC;
|
||||
self->device_number = 0;
|
||||
self->video_format = GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV;
|
||||
|
||||
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);
|
||||
|
@ -244,6 +253,21 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
|
|||
case PROP_DEVICE_NUMBER:
|
||||
self->device_number = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_VIDEO_FORMAT:
|
||||
self->video_format = (GstDecklinkVideoFormat) g_value_get_enum (value);
|
||||
switch (self->video_format) {
|
||||
case GST_DECKLINK_VIDEO_FORMAT_AUTO:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA:
|
||||
break;
|
||||
default:
|
||||
GST_ELEMENT_WARNING (GST_ELEMENT (self), CORE, NOT_IMPLEMENTED,
|
||||
("Format %d not supported", self->video_format), (NULL));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -263,6 +287,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
|
|||
case PROP_DEVICE_NUMBER:
|
||||
g_value_set_int (value, self->device_number);
|
||||
break;
|
||||
case PROP_VIDEO_FORMAT:
|
||||
g_value_set_enum (value, self->video_format);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -293,13 +320,23 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|||
GStreamerVideoOutputCallback (self));
|
||||
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO) {
|
||||
mode = gst_decklink_find_mode_for_caps (caps);
|
||||
BMDPixelFormat f;
|
||||
mode = gst_decklink_find_mode_and_format_for_caps (caps, &f);
|
||||
if (mode == NULL) {
|
||||
GST_WARNING_OBJECT (self,
|
||||
"Failed to find compatible mode for caps %" GST_PTR_FORMAT, caps);
|
||||
return FALSE;
|
||||
}
|
||||
if (self->video_format != GST_DECKLINK_VIDEO_FORMAT_AUTO &&
|
||||
gst_decklink_pixel_format_from_type (self->video_format) != f) {
|
||||
GST_WARNING_OBJECT (self, "Failed to set pixel format to %d",
|
||||
self->video_format);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* We don't have to give the format in EnableVideoOutput. Therefore,
|
||||
* even if it's AUTO, we have it stored in self->info and set it in
|
||||
* gst_decklink_video_sink_prepare */
|
||||
mode = gst_decklink_get_mode (self->mode);
|
||||
g_assert (mode != NULL);
|
||||
};
|
||||
|
@ -327,10 +364,19 @@ gst_decklink_video_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
|||
GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
|
||||
GstCaps *mode_caps, *caps;
|
||||
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO)
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO
|
||||
&& self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO)
|
||||
mode_caps = gst_decklink_mode_get_template_caps ();
|
||||
else if (self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO)
|
||||
mode_caps = gst_decklink_mode_get_caps_all_formats (self->mode);
|
||||
else if (self->mode == GST_DECKLINK_MODE_AUTO)
|
||||
mode_caps =
|
||||
gst_decklink_pixel_format_get_caps (gst_decklink_pixel_format_from_type
|
||||
(self->video_format));
|
||||
else
|
||||
mode_caps = gst_decklink_mode_get_caps (self->mode, bmdFormat8BitYUV);
|
||||
mode_caps =
|
||||
gst_decklink_mode_get_caps (self->mode,
|
||||
gst_decklink_pixel_format_from_type (self->video_format));
|
||||
mode_caps = gst_caps_make_writable (mode_caps);
|
||||
/* For output we support any framerate and only really care about timestamps */
|
||||
gst_caps_map_in_place (mode_caps, reset_framerate, NULL);
|
||||
|
@ -454,6 +500,9 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
GstClockTime latency, render_delay;
|
||||
GstClockTimeDiff ts_offset;
|
||||
gint i;
|
||||
GstDecklinkVideoFormat caps_format;
|
||||
BMDPixelFormat format;
|
||||
gint bpp;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer);
|
||||
|
||||
|
@ -462,6 +511,10 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
caps_format = gst_decklink_type_from_video_format (self->info.finfo->format);
|
||||
format = gst_decklink_pixel_format_from_type (caps_format);
|
||||
bpp = gst_decklink_bpp_from_type (caps_format);
|
||||
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
duration = GST_BUFFER_DURATION (buffer);
|
||||
if (duration == GST_CLOCK_TIME_NONE) {
|
||||
|
@ -499,8 +552,8 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
running_time = 0;
|
||||
|
||||
ret = self->output->output->CreateVideoFrame (self->info.width,
|
||||
self->info.height, self->info.stride[0], bmdFormat8BitYUV,
|
||||
bmdFrameFlagDefault, &frame);
|
||||
self->info.height, self->info.stride[0], format, bmdFrameFlagDefault,
|
||||
&frame);
|
||||
if (ret != S_OK) {
|
||||
GST_ELEMENT_ERROR (self, STREAM, FAILED,
|
||||
(NULL), ("Failed to create video frame: 0x%08x", ret));
|
||||
|
@ -516,7 +569,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
frame->GetBytes ((void **) &outdata);
|
||||
indata = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0);
|
||||
for (i = 0; i < self->info.height; i++) {
|
||||
memcpy (outdata, indata, GST_VIDEO_FRAME_WIDTH (&vframe) * 2);
|
||||
memcpy (outdata, indata, GST_VIDEO_FRAME_WIDTH (&vframe) * bpp);
|
||||
indata += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
|
||||
outdata += frame->GetRowBytes ();
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ struct _GstDecklinkVideoSink
|
|||
|
||||
GstDecklinkModeEnum mode;
|
||||
gint device_number;
|
||||
GstDecklinkVideoFormat video_format;
|
||||
|
||||
GstVideoInfo info;
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ enum
|
|||
PROP_MODE,
|
||||
PROP_CONNECTION,
|
||||
PROP_DEVICE_NUMBER,
|
||||
PROP_BUFFER_SIZE
|
||||
PROP_BUFFER_SIZE,
|
||||
PROP_VIDEO_FORMAT
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -161,6 +162,13 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
|
|||
G_MAXINT, DEFAULT_BUFFER_SIZE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_VIDEO_FORMAT,
|
||||
g_param_spec_enum ("video-format", "Video format",
|
||||
"Video format type to use for input (Only use auto for mode=auto)",
|
||||
GST_TYPE_DECKLINK_VIDEO_FORMAT, GST_DECKLINK_VIDEO_FORMAT_AUTO,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT)));
|
||||
|
||||
templ_caps = gst_decklink_mode_get_template_caps ();
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, templ_caps));
|
||||
|
@ -183,6 +191,7 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
|
|||
self->connection = DEFAULT_CONNECTION;
|
||||
self->device_number = 0;
|
||||
self->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
self->video_format = GST_DECKLINK_VIDEO_FORMAT_AUTO;
|
||||
|
||||
gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
|
||||
gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
|
||||
|
@ -202,6 +211,13 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id,
|
|||
switch (property_id) {
|
||||
case PROP_MODE:
|
||||
self->mode = (GstDecklinkModeEnum) g_value_get_enum (value);
|
||||
/* setting the default value for caps_mode here: if mode==auto then we
|
||||
* configure caps_mode from the caps, if mode!=auto we set caps_mode to
|
||||
* the same value as the mode. so self->caps_mode is essentially
|
||||
* self->mode with mode=auto filtered into whatever we got from the
|
||||
* negotiation */
|
||||
if (self->mode != GST_DECKLINK_MODE_AUTO)
|
||||
self->caps_mode = self->mode;
|
||||
break;
|
||||
case PROP_CONNECTION:
|
||||
self->connection = (GstDecklinkConnectionEnum) g_value_get_enum (value);
|
||||
|
@ -212,6 +228,23 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id,
|
|||
case PROP_BUFFER_SIZE:
|
||||
self->buffer_size = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_VIDEO_FORMAT:
|
||||
self->video_format = (GstDecklinkVideoFormat) g_value_get_enum (value);
|
||||
switch (self->video_format) {
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB:
|
||||
case GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA:
|
||||
self->caps_format =
|
||||
gst_decklink_pixel_format_from_type (self->video_format);
|
||||
case GST_DECKLINK_VIDEO_FORMAT_AUTO:
|
||||
break;
|
||||
default:
|
||||
GST_ELEMENT_WARNING (GST_ELEMENT (self), CORE, NOT_IMPLEMENTED,
|
||||
("Format %d not supported", self->video_format), (NULL));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -237,6 +270,9 @@ gst_decklink_video_src_get_property (GObject * object, guint property_id,
|
|||
case PROP_BUFFER_SIZE:
|
||||
g_value_set_uint (value, self->buffer_size);
|
||||
break;
|
||||
case PROP_VIDEO_FORMAT:
|
||||
g_value_set_enum (value, self->video_format);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
|
@ -262,6 +298,7 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
const GstDecklinkMode *mode;
|
||||
BMDVideoInputFlags flags;
|
||||
HRESULT ret;
|
||||
BMDPixelFormat format;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
|
@ -329,8 +366,8 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
mode = gst_decklink_get_mode (self->mode);
|
||||
g_assert (mode != NULL);
|
||||
|
||||
ret = self->input->input->EnableVideoInput (mode->mode,
|
||||
bmdFormat8BitYUV, flags);
|
||||
format = self->caps_format;
|
||||
ret = self->input->input->EnableVideoInput (mode->mode, format, flags);
|
||||
if (ret != S_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to enable video input");
|
||||
return FALSE;
|
||||
|
@ -351,14 +388,16 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
|
|||
{
|
||||
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
|
||||
GstCaps *mode_caps, *caps;
|
||||
BMDPixelFormat format;
|
||||
GstDecklinkModeEnum mode;
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
if (self->caps_mode != GST_DECKLINK_MODE_AUTO)
|
||||
mode_caps = gst_decklink_mode_get_caps (self->caps_mode, self->caps_format);
|
||||
else
|
||||
mode_caps = gst_decklink_mode_get_caps (self->mode, self->caps_format);
|
||||
mode = self->caps_mode;
|
||||
format = self->caps_format;
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
mode_caps = gst_decklink_mode_get_caps (mode, format);
|
||||
|
||||
if (filter) {
|
||||
caps =
|
||||
gst_caps_intersect_full (filter, mode_caps, GST_CAPS_INTERSECT_FIRST);
|
||||
|
@ -501,6 +540,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
|
|||
VideoFrame *vf;
|
||||
CaptureFrame *f;
|
||||
GstCaps *caps;
|
||||
gboolean caps_changed = FALSE;
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
while (g_queue_is_empty (&self->current_frames) && !self->flushing) {
|
||||
|
@ -518,21 +558,48 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
|
|||
}
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO &&
|
||||
(self->caps_mode != f->mode || self->caps_format != f->format)) {
|
||||
GST_DEBUG_OBJECT (self, "Mode/Format changed from %d/%d to %d/%d",
|
||||
self->caps_mode, self->caps_format, f->mode, f->format);
|
||||
self->caps_mode = f->mode;
|
||||
self->caps_format = f->format;
|
||||
g_mutex_unlock (&self->lock);
|
||||
if (self->caps_mode != f->mode) {
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO) {
|
||||
GST_DEBUG_OBJECT (self, "Mode changed from %d to %d", self->caps_mode,
|
||||
f->mode);
|
||||
caps_changed = TRUE;
|
||||
self->caps_mode = f->mode;
|
||||
} else {
|
||||
g_mutex_unlock (&self->lock);
|
||||
if (f)
|
||||
capture_frame_free (f);
|
||||
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
||||
("Invalid mode in captured frame"),
|
||||
("Mode set to %d but captured %d", self->caps_mode, f->mode));
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
}
|
||||
if (self->caps_format != f->format) {
|
||||
if (self->video_format == GST_DECKLINK_VIDEO_FORMAT_AUTO) {
|
||||
GST_DEBUG_OBJECT (self, "Format changed from %d to %d", self->caps_format,
|
||||
f->format);
|
||||
caps_changed = TRUE;
|
||||
self->caps_format = f->format;
|
||||
} else {
|
||||
g_mutex_unlock (&self->lock);
|
||||
if (f)
|
||||
capture_frame_free (f);
|
||||
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
||||
("Invalid pixel format in captured frame"),
|
||||
("Format set to %d but captured %d", self->caps_format, f->format));
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&self->lock);
|
||||
if (caps_changed) {
|
||||
caps = gst_decklink_mode_get_caps (f->mode, f->format);
|
||||
gst_video_info_from_caps (&self->info, caps);
|
||||
gst_base_src_set_caps (GST_BASE_SRC_CAST (bsrc), caps);
|
||||
gst_element_post_message (GST_ELEMENT_CAST (self),
|
||||
gst_message_new_latency (GST_OBJECT_CAST (self)));
|
||||
gst_caps_unref (caps);
|
||||
} else {
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
}
|
||||
|
||||
f->frame->GetBytes ((gpointer *) & data);
|
||||
|
@ -576,10 +643,7 @@ gst_decklink_video_src_query (GstBaseSrc * bsrc, GstQuery * query)
|
|||
const GstDecklinkMode *mode;
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
if (self->caps_mode != GST_DECKLINK_MODE_AUTO)
|
||||
mode = gst_decklink_get_mode (self->caps_mode);
|
||||
else
|
||||
mode = gst_decklink_get_mode (self->mode);
|
||||
mode = gst_decklink_get_mode (self->caps_mode);
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
min = gst_util_uint64_scale_ceil (GST_SECOND, mode->fps_d, mode->fps_n);
|
||||
|
@ -754,6 +818,11 @@ gst_decklink_video_src_change_state (GstElement * element,
|
|||
ret = GST_STATE_CHANGE_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
if (self->mode == GST_DECKLINK_MODE_AUTO &&
|
||||
self->video_format != GST_DECKLINK_VIDEO_FORMAT_AUTO) {
|
||||
GST_WARNING_OBJECT (self, "Warning: mode=auto and format!=auto may \
|
||||
not work");
|
||||
}
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
g_mutex_lock (&self->input->lock);
|
||||
|
|
|
@ -57,6 +57,7 @@ struct _GstDecklinkVideoSrc
|
|||
gint device_number;
|
||||
|
||||
GstVideoInfo info;
|
||||
GstDecklinkVideoFormat video_format;
|
||||
|
||||
GstDecklinkInput *input;
|
||||
|
||||
|
|
Loading…
Reference in a new issue