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
@ -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[] = {
|
|||||||
{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)
|
|||||||
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)
|
|||||||
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,7 +452,39 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return caps;
|
||||||
}
|
}
|
||||||
@ -373,30 +494,29 @@ gst_decklink_mode_get_template_caps (void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstStructure *s;
|
|
||||||
|
|
||||||
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,
|
caps =
|
||||||
bmdFormat8BitYUV);
|
gst_caps_merge (caps,
|
||||||
gst_caps_append_structure (caps, s);
|
gst_decklink_mode_get_caps_all_formats ((GstDecklinkModeEnum) i));
|
||||||
s = gst_decklink_mode_get_structure ((GstDecklinkModeEnum) i,
|
|
||||||
bmdFormat8BitARGB);
|
|
||||||
gst_caps_append_structure (caps, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return caps;
|
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)
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
#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
|
|||||||
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
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
(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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
|||||||
|
|
||||||
GstDecklinkModeEnum mode;
|
GstDecklinkModeEnum mode;
|
||||||
gint device_number;
|
gint device_number;
|
||||||
|
GstDecklinkVideoFormat video_format;
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
caps = gst_decklink_mode_get_caps (f->mode, f->format);
|
||||||
gst_video_info_from_caps (&self->info, caps);
|
gst_video_info_from_caps (&self->info, caps);
|
||||||
gst_base_src_set_caps (GST_BASE_SRC_CAST (bsrc), caps);
|
gst_base_src_set_caps (GST_BASE_SRC_CAST (bsrc), caps);
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (self),
|
gst_element_post_message (GST_ELEMENT_CAST (self),
|
||||||
gst_message_new_latency (GST_OBJECT_CAST (self)));
|
gst_message_new_latency (GST_OBJECT_CAST (self)));
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
} else {
|
|
||||||
g_mutex_unlock (&self->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f->frame->GetBytes ((gpointer *) & data);
|
f->frame->GetBytes ((gpointer *) & data);
|
||||||
@ -576,10 +643,7 @@ gst_decklink_video_src_query (GstBaseSrc * bsrc, GstQuery * query)
|
|||||||
const GstDecklinkMode *mode;
|
const GstDecklinkMode *mode;
|
||||||
|
|
||||||
g_mutex_lock (&self->lock);
|
g_mutex_lock (&self->lock);
|
||||||
if (self->caps_mode != GST_DECKLINK_MODE_AUTO)
|
mode = gst_decklink_get_mode (self->caps_mode);
|
||||||
mode = gst_decklink_get_mode (self->caps_mode);
|
|
||||||
else
|
|
||||||
mode = gst_decklink_get_mode (self->mode);
|
|
||||||
g_mutex_unlock (&self->lock);
|
g_mutex_unlock (&self->lock);
|
||||||
|
|
||||||
min = gst_util_uint64_scale_ceil (GST_SECOND, mode->fps_d, mode->fps_n);
|
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;
|
ret = GST_STATE_CHANGE_FAILURE;
|
||||||
goto out;
|
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;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
g_mutex_lock (&self->input->lock);
|
g_mutex_lock (&self->input->lock);
|
||||||
|
@ -57,6 +57,7 @@ struct _GstDecklinkVideoSrc
|
|||||||
gint device_number;
|
gint device_number;
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
GstDecklinkVideoFormat video_format;
|
||||||
|
|
||||||
GstDecklinkInput *input;
|
GstDecklinkInput *input;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user