Commit 832764d2 authored by Vivia Nikolaidou's avatar Vivia Nikolaidou 🦆 Committed by Sebastian Dröge

decklink: Add initial 10bit support for YUV modes

https://bugzilla.gnome.org/show_bug.cgi?id=742878
parent 87503ac1
......@@ -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,13 +452,29 @@ 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_template_caps (void)
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;
......@@ -377,26 +482,41 @@ gst_decklink_mode_get_template_caps (void)
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);
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f);
caps = gst_caps_merge_structure (caps, s);
}
return caps;
}
GstCaps *
gst_decklink_mode_get_template_caps (void)
{
int i;
GstCaps *caps;
caps = gst_caps_new_empty ();
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);
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);
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment