diff --git a/sys/decklink/gstdecklink.cpp b/sys/decklink/gstdecklink.cpp index df47797e74..8b4c5b6b55 100644 --- a/sys/decklink/gstdecklink.cpp +++ b/sys/decklink/gstdecklink.cpp @@ -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) \ diff --git a/sys/decklink/gstdecklink.h b/sys/decklink/gstdecklink.h index bfe7d9feac..6559206d5a 100644 --- a/sys/decklink/gstdecklink.h +++ b/sys/decklink/gstdecklink.h @@ -23,6 +23,7 @@ #define _GST_DECKLINK_H_ #include +#include #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 diff --git a/sys/decklink/gstdecklinkvideosink.cpp b/sys/decklink/gstdecklinkvideosink.cpp index eebeff3287..551e5d7c0b 100644 --- a/sys/decklink/gstdecklinkvideosink.cpp +++ b/sys/decklink/gstdecklinkvideosink.cpp @@ -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 (); } diff --git a/sys/decklink/gstdecklinkvideosink.h b/sys/decklink/gstdecklinkvideosink.h index 16b2fbb3fe..fb95591d20 100644 --- a/sys/decklink/gstdecklinkvideosink.h +++ b/sys/decklink/gstdecklinkvideosink.h @@ -51,6 +51,7 @@ struct _GstDecklinkVideoSink GstDecklinkModeEnum mode; gint device_number; + GstDecklinkVideoFormat video_format; GstVideoInfo info; diff --git a/sys/decklink/gstdecklinkvideosrc.cpp b/sys/decklink/gstdecklinkvideosrc.cpp index 2b304f9123..5dc69e56a0 100644 --- a/sys/decklink/gstdecklinkvideosrc.cpp +++ b/sys/decklink/gstdecklinkvideosrc.cpp @@ -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); diff --git a/sys/decklink/gstdecklinkvideosrc.h b/sys/decklink/gstdecklinkvideosrc.h index b83495f0ca..1309364b84 100644 --- a/sys/decklink/gstdecklinkvideosrc.h +++ b/sys/decklink/gstdecklinkvideosrc.h @@ -57,6 +57,7 @@ struct _GstDecklinkVideoSrc gint device_number; GstVideoInfo info; + GstDecklinkVideoFormat video_format; GstDecklinkInput *input;