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) ...@@ -111,6 +111,34 @@ gst_decklink_connection_get_type (void)
return (GType) id; 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 GType
gst_decklink_audio_connection_get_type (void) gst_decklink_audio_connection_get_type (void)
{ {
...@@ -183,6 +211,27 @@ static const GstDecklinkMode modes[] = { ...@@ -183,6 +211,27 @@ static const GstDecklinkMode modes[] = {
{bmdMode4K2160p60, 3840, 2160, 60, 1, false, UHD} {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 * const GstDecklinkMode *
gst_decklink_get_mode (GstDecklinkModeEnum e) gst_decklink_get_mode (GstDecklinkModeEnum e)
{ {
...@@ -293,6 +342,31 @@ gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode) ...@@ -293,6 +342,31 @@ gst_decklink_get_mode_enum_from_bmd (BMDDisplayMode mode)
return displayMode; 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[] = { static const BMDVideoConnection connections[] = {
0, /* auto */ 0, /* auto */
bmdVideoConnectionSDI, bmdVideoConnectionSDI,
...@@ -315,6 +389,21 @@ gst_decklink_get_connection (GstDecklinkConnectionEnum e) ...@@ -315,6 +389,21 @@ gst_decklink_get_connection (GstDecklinkConnectionEnum e)
return connections[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 * static GstStructure *
gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f) gst_decklink_mode_get_structure (GstDecklinkModeEnum e, BMDPixelFormat f)
{ {
...@@ -363,13 +452,29 @@ gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f) ...@@ -363,13 +452,29 @@ gst_decklink_mode_get_caps (GstDecklinkModeEnum e, BMDPixelFormat f)
GstCaps *caps; GstCaps *caps;
caps = gst_caps_new_empty (); 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; return caps;
} }
GstCaps * 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; int i;
GstCaps *caps; GstCaps *caps;
...@@ -377,26 +482,41 @@ gst_decklink_mode_get_template_caps (void) ...@@ -377,26 +482,41 @@ gst_decklink_mode_get_template_caps (void)
caps = gst_caps_new_empty (); caps = gst_caps_new_empty ();
for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) { for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i, f);
bmdFormat8BitYUV); caps = gst_caps_merge_structure (caps, s);
gst_caps_append_structure (caps, s);
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i,
bmdFormat8BitARGB);
gst_caps_append_structure (caps, s);
} }
return caps; 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 * const GstDecklinkMode *
gst_decklink_find_mode_for_caps (GstCaps * caps) gst_decklink_find_mode_and_format_for_caps (GstCaps * caps,
BMDPixelFormat * format)
{ {
int i; int i;
GstCaps *mode_caps; 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++) { for (i = 1; i < (int) G_N_ELEMENTS (modes); i++) {
mode_caps = mode_caps = gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, *format);
gst_decklink_mode_get_caps ((GstDecklinkModeEnum) i, bmdFormat8BitYUV);
if (gst_caps_can_intersect (caps, mode_caps)) { if (gst_caps_can_intersect (caps, mode_caps)) {
gst_caps_unref (mode_caps); gst_caps_unref (mode_caps);
return gst_decklink_get_mode ((GstDecklinkModeEnum) i); return gst_decklink_get_mode ((GstDecklinkModeEnum) i);
...@@ -407,6 +527,14 @@ gst_decklink_find_mode_for_caps (GstCaps * caps) ...@@ -407,6 +527,14 @@ gst_decklink_find_mode_for_caps (GstCaps * caps)
return NULL; 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 \ #define GST_TYPE_DECKLINK_CLOCK \
(gst_decklink_clock_get_type()) (gst_decklink_clock_get_type())
#define GST_DECKLINK_CLOCK(obj) \ #define GST_DECKLINK_CLOCK(obj) \
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define _GST_DECKLINK_H_ #define _GST_DECKLINK_H_
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h>
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
#include "linux/DeckLinkAPI.h" #include "linux/DeckLinkAPI.h"
#endif #endif
...@@ -109,6 +110,25 @@ typedef enum { ...@@ -109,6 +110,25 @@ typedef enum {
#define GST_TYPE_DECKLINK_AUDIO_CONNECTION (gst_decklink_audio_connection_get_type ()) #define GST_TYPE_DECKLINK_AUDIO_CONNECTION (gst_decklink_audio_connection_get_type ())
GType gst_decklink_audio_connection_get_type (void); 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; typedef struct _GstDecklinkMode GstDecklinkMode;
struct _GstDecklinkMode { struct _GstDecklinkMode {
BMDDisplayMode mode; BMDDisplayMode mode;
...@@ -195,5 +215,8 @@ GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, GstElement * src, gb ...@@ -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); 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_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 #endif
...@@ -118,7 +118,8 @@ enum ...@@ -118,7 +118,8 @@ enum
{ {
PROP_0, PROP_0,
PROP_MODE, PROP_MODE,
PROP_DEVICE_NUMBER PROP_DEVICE_NUMBER,
PROP_VIDEO_FORMAT
}; };
static void gst_decklink_video_sink_set_property (GObject * object, static void gst_decklink_video_sink_set_property (GObject * object,
...@@ -205,6 +206,13 @@ gst_decklink_video_sink_class_init (GstDecklinkVideoSinkClass * klass) ...@@ -205,6 +206,13 @@ 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_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_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 */
...@@ -226,6 +234,7 @@ gst_decklink_video_sink_init (GstDecklinkVideoSink * self) ...@@ -226,6 +234,7 @@ 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;
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);
...@@ -244,6 +253,21 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id, ...@@ -244,6 +253,21 @@ gst_decklink_video_sink_set_property (GObject * object, guint property_id,
case PROP_DEVICE_NUMBER: case PROP_DEVICE_NUMBER:
self->device_number = g_value_get_int (value); self->device_number = g_value_get_int (value);
break; 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: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break; break;
...@@ -263,6 +287,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id, ...@@ -263,6 +287,9 @@ gst_decklink_video_sink_get_property (GObject * object, guint property_id,
case PROP_DEVICE_NUMBER: case PROP_DEVICE_NUMBER:
g_value_set_int (value, self->device_number); g_value_set_int (value, self->device_number);
break; break;
case PROP_VIDEO_FORMAT:
g_value_set_enum (value, self->video_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;
...@@ -293,13 +320,23 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) ...@@ -293,13 +320,23 @@ gst_decklink_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
GStreamerVideoOutputCallback (self)); GStreamerVideoOutputCallback (self));
if (self->mode == GST_DECKLINK_MODE_AUTO) { 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) { if (mode == NULL) {
GST_WARNING_OBJECT (self, GST_WARNING_OBJECT (self,
"Failed to find compatible mode for caps %" GST_PTR_FORMAT, caps); "Failed to find compatible mode for caps %" GST_PTR_FORMAT, caps);
return FALSE; 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 { } 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); mode = gst_decklink_get_mode (self->mode);
g_assert (mode != NULL); g_assert (mode != NULL);
}; };
...@@ -327,10 +364,19 @@ gst_decklink_video_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) ...@@ -327,10 +364,19 @@ gst_decklink_video_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink); GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink);
GstCaps *mode_caps, *caps; 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 (); 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 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); mode_caps = gst_caps_make_writable (mode_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 */
gst_caps_map_in_place (mode_caps, reset_framerate, NULL); gst_caps_map_in_place (mode_caps, reset_framerate, NULL);
...@@ -454,6 +500,9 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) ...@@ -454,6 +500,9 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
GstClockTime latency, render_delay; GstClockTime latency, render_delay;
GstClockTimeDiff ts_offset; GstClockTimeDiff ts_offset;
gint i; gint i;
GstDecklinkVideoFormat caps_format;
BMDPixelFormat format;
gint bpp;
GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer); GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer);
...@@ -462,6 +511,10 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) ...@@ -462,6 +511,10 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
return GST_FLOW_ERROR; 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); timestamp = GST_BUFFER_TIMESTAMP (buffer);
duration = GST_BUFFER_DURATION (buffer); duration = GST_BUFFER_DURATION (buffer);
if (duration == GST_CLOCK_TIME_NONE) { if (duration == GST_CLOCK_TIME_NONE) {
...@@ -499,8 +552,8 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) ...@@ -499,8 +552,8 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
running_time = 0; running_time = 0;
ret = self->output->output->CreateVideoFrame (self->info.width, ret = self->output->output->CreateVideoFrame (self->info.width,
self->info.height, self->info.stride[0], bmdFormat8BitYUV, self->info.height, self->info.stride[0], format, bmdFrameFlagDefault,
bmdFrameFlagDefault, &frame); &frame);
if (ret != S_OK) { if (ret != S_OK) {
GST_ELEMENT_ERROR (self, STREAM, FAILED, GST_ELEMENT_ERROR (self, STREAM, FAILED,
(NULL), ("Failed to create video frame: 0x%08x", ret)); (NULL), ("Failed to create video frame: 0x%08x", ret));
...@@ -516,7 +569,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) ...@@ -516,7 +569,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
frame->GetBytes ((void **) &outdata); frame->GetBytes ((void **) &outdata);
indata = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); indata = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0);
for (i = 0; i < self->info.height; i++) { 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); indata += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
outdata += frame->GetRowBytes (); outdata += frame->GetRowBytes ();
} }
......
...@@ -51,6 +51,7 @@ struct _GstDecklinkVideoSink ...@@ -51,6 +51,7 @@ struct _GstDecklinkVideoSink
GstDecklinkModeEnum mode; GstDecklinkModeEnum mode;
gint device_number; gint device_number;
GstDecklinkVideoFormat video_format;
GstVideoInfo info; GstVideoInfo info;
......
...@@ -39,7 +39,8 @@ enum ...@@ -39,7 +39,8 @@ enum
PROP_MODE, PROP_MODE,
PROP_CONNECTION, PROP_CONNECTION,
PROP_DEVICE_NUMBER, PROP_DEVICE_NUMBER,
PROP_BUFFER_SIZE PROP_BUFFER_SIZE,
PROP_VIDEO_FORMAT
}; };
typedef struct typedef struct
...@@ -161,6 +162,13 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass) ...@@ -161,6 +162,13 @@ gst_decklink_video_src_class_init (GstDecklinkVideoSrcClass * klass)
G_MAXINT, DEFAULT_BUFFER_SIZE, G_MAXINT, DEFAULT_BUFFER_SIZE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); (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 (); templ_caps = gst_decklink_mode_get_template_caps ();
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, templ_caps)); gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, templ_caps));
...@@ -183,6 +191,7 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self) ...@@ -183,6 +191,7 @@ gst_decklink_video_src_init (GstDecklinkVideoSrc * self)
self->connection = DEFAULT_CONNECTION; self->connection = DEFAULT_CONNECTION;
self->device_number = 0; self->device_number = 0;
self->buffer_size = DEFAULT_BUFFER_SIZE; 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_live (GST_BASE_SRC (self), TRUE);
gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME); 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, ...@@ -202,6 +211,13 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id,
switch (property_id) { switch (property_id) {
case PROP_MODE: case PROP_MODE:
self->mode = (GstDecklinkModeEnum) g_value_get_enum (value); 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; break;
case PROP_CONNECTION: case PROP_CONNECTION:
self->connection = (GstDecklinkConnectionEnum) g_value_get_enum (value); self->connection = (GstDecklinkConnectionEnum) g_value_get_enum (value);
...@@ -212,6 +228,23 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id, ...@@ -212,6 +228,23 @@ gst_decklink_video_src_set_property (GObject * object, guint property_id,
case PROP_BUFFER_SIZE: case PROP_BUFFER_SIZE:
self->buffer_size = g_value_get_uint (value); self->buffer_size = g_value_get_uint (value);
break; 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: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break; break;
...@@ -237,6 +270,9 @@ gst_decklink_video_src_get_property (GObject * object, guint property_id, ...@@ -237,6 +270,9 @@ gst_decklink_video_src_get_property (GObject * object, guint property_id,
case PROP_BUFFER_SIZE: case PROP_BUFFER_SIZE:
g_value_set_uint (value, self->buffer_size); g_value_set_uint (value, self->buffer_size);
break; break;
case PROP_VIDEO_FORMAT:
g_value_set_enum (value, self->video_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;
...@@ -262,6 +298,7 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) ...@@ -262,6 +298,7 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
const GstDecklinkMode *mode; const GstDecklinkMode *mode;
BMDVideoInputFlags flags; BMDVideoInputFlags flags;
HRESULT ret; HRESULT ret;
BMDPixelFormat format;
GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (self, "Setting caps %" GST_PTR_FORMAT, caps);
...@@ -329,8 +366,8 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) ...@@ -329,8 +366,8 @@ gst_decklink_video_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
mode = gst_decklink_get_mode (self->mode); mode = gst_decklink_get_mode (self->mode);
g_assert (mode != NULL); g_assert (mode != NULL);
ret = self->input->input->EnableVideoInput (mode->mode, format = self->caps_format;
bmdFormat8BitYUV, flags); ret = self->input->input->EnableVideoInput (mode->mode, format, flags);
if (ret != S_OK) { if (ret != S_OK) {
GST_WARNING_OBJECT (self, "Failed to enable video input"); GST_WARNING_OBJECT (self, "Failed to enable video input");
return FALSE; return FALSE;
...@@ -351,14 +388,16 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter) ...@@ -351,14 +388,16 @@ gst_decklink_video_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
{ {
GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc); GstDecklinkVideoSrc *self = GST_DECKLINK_VIDEO_SRC_CAST (bsrc);
GstCaps *mode_caps, *caps; GstCaps *mode_caps, *caps;
BMDPixelFormat format;
GstDecklinkModeEnum mode;
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
if (self->caps_mode != GST_DECKLINK_MODE_AUTO) mode = self->caps_mode;
mode_caps = gst_decklink_mode_get_caps (self->caps_mode, self->caps_format); format = self->caps_format;
else
mode_caps = gst_decklink_mode_get_caps (self->mode, self->caps_format);
g_mutex_unlock (&self->lock); g_mutex_unlock (&self->lock);
mode_caps = gst_decklink_mode_get_caps (mode, format);
if (filter) { if (filter) {
caps = caps =
gst_caps_intersect_full (filter, mode_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_intersect_full (filter, mode_caps, GST_CAPS_INTERSECT_FIRST);
...@@ -501,6 +540,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer) ...@@ -501,6 +540,7 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
VideoFrame *vf; VideoFrame *vf;
CaptureFrame *f; CaptureFrame *f;
GstCaps *caps; GstCaps *caps;
gboolean caps_changed = FALSE;
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
while (g_queue_is_empty (&self->current_frames) && !self->flushing) { while (g_queue_is_empty (&self->current_frames) && !self->flushing) {
...@@ -518,21 +558,48 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer) ...@@ -518,21 +558,48 @@ gst_decklink_video_src_create (GstPushSrc * bsrc, GstBuffer ** buffer)
} }
g_mutex_lock (&self->lock); g_mutex_lock (&self->lock);
if (self->mode == GST_DECKLINK_MODE_AUTO && if (self->caps_mode != f->mode) {
(self->caps_mode != f->mode || self->caps_format != f->format)) { if (self->mode == GST_DECKLINK_MODE_AUTO) {
GST_DEBUG_OBJECT (self, "Mode/Format changed from %d/%d to %d/%d", GST_DEBUG_OBJECT (self, "Mode changed from %d to %d", self->caps_mode,
self->caps_mode, self->caps_format, f->mode, f->format); f->mode);
self->caps_mode = f->mode; caps_changed = TRUE;
self->caps_format = f->format; self->caps_mode = f->mode;
g_mutex_unlock (&self->lock); } 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;