Add support for UHD/UHD2 modes and SDI quad-link modes

This commit is contained in:
Sebastian Dröge 2021-07-02 11:03:00 +03:00
parent fa5385bc8e
commit 735768b905
6 changed files with 1016 additions and 125 deletions

View file

@ -27,87 +27,288 @@
#include "gstajacommon.h"
GST_DEBUG_CATEGORY_STATIC(gst_aja_debug);
#define GST_CAT_DEFAULT gst_aja_debug
static const NTV2VideoFormat supported_video_formats[] = {
NTV2_FORMAT_1080i_5000, NTV2_FORMAT_1080i_5994,
NTV2_FORMAT_1080i_6000, NTV2_FORMAT_720p_5994,
NTV2_FORMAT_720p_6000, NTV2_FORMAT_1080p_2997,
NTV2_FORMAT_1080p_3000, NTV2_FORMAT_1080p_2500,
NTV2_FORMAT_1080p_2398, NTV2_FORMAT_1080p_2400,
NTV2_FORMAT_720p_5000, NTV2_FORMAT_720p_2398,
NTV2_FORMAT_720p_2500, NTV2_FORMAT_1080p_5000_A,
NTV2_FORMAT_1080p_5994_A, NTV2_FORMAT_1080p_6000_A,
NTV2_FORMAT_625_5000, NTV2_FORMAT_525_5994,
NTV2_FORMAT_525_2398, NTV2_FORMAT_525_2400};
typedef struct {
GstAjaVideoFormat gst_format;
NTV2VideoFormat aja_format;
NTV2VideoFormat quad_format;
} FormatMapEntry;
static const FormatMapEntry format_map[] = {
{GST_AJA_VIDEO_FORMAT_1080i_5000, NTV2_FORMAT_1080i_5000,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080i_5994, NTV2_FORMAT_1080i_5994,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080i_6000, NTV2_FORMAT_1080i_6000,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_720p_5994, NTV2_FORMAT_720p_5994,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_720p_6000, NTV2_FORMAT_720p_6000,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_2997, NTV2_FORMAT_1080p_2997,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_3000, NTV2_FORMAT_1080p_3000,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_2500, NTV2_FORMAT_1080p_2500,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_2398, NTV2_FORMAT_1080p_2398,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_2400, NTV2_FORMAT_1080p_2400,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_720p_5000, NTV2_FORMAT_720p_5000,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_720p_2398, NTV2_FORMAT_720p_2398,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_720p_5000, NTV2_FORMAT_720p_2500,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_3000, NTV2_FORMAT_1080p_5000_A,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_5994_A, NTV2_FORMAT_1080p_5994_A,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_1080p_6000_A, NTV2_FORMAT_1080p_6000_A,
NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_625_5000, NTV2_FORMAT_625_5000, NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_525_5994, NTV2_FORMAT_525_5994, NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_525_2398, NTV2_FORMAT_525_2398, NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_525_2400, NTV2_FORMAT_525_2400, NTV2_FORMAT_UNKNOWN},
{GST_AJA_VIDEO_FORMAT_2160p_2398, NTV2_FORMAT_3840x2160p_2398,
NTV2_FORMAT_4x1920x1080p_2398},
{GST_AJA_VIDEO_FORMAT_2160p_2400, NTV2_FORMAT_3840x2160p_2400,
NTV2_FORMAT_4x1920x1080p_2400},
{GST_AJA_VIDEO_FORMAT_2160p_2500, NTV2_FORMAT_3840x2160p_2500,
NTV2_FORMAT_4x1920x1080p_2500},
{GST_AJA_VIDEO_FORMAT_2160p_2997, NTV2_FORMAT_3840x2160p_2997,
NTV2_FORMAT_4x1920x1080p_2997},
{GST_AJA_VIDEO_FORMAT_2160p_3000, NTV2_FORMAT_3840x2160p_3000,
NTV2_FORMAT_4x1920x1080p_3000},
{GST_AJA_VIDEO_FORMAT_2160p_5000, NTV2_FORMAT_3840x2160p_5000,
NTV2_FORMAT_4x1920x1080p_5000},
{GST_AJA_VIDEO_FORMAT_2160p_5994, NTV2_FORMAT_3840x2160p_5994,
NTV2_FORMAT_4x1920x1080p_5994},
{GST_AJA_VIDEO_FORMAT_2160p_6000, NTV2_FORMAT_3840x2160p_6000,
NTV2_FORMAT_4x1920x1080p_6000},
{GST_AJA_VIDEO_FORMAT_4320p_2398, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_2398},
{GST_AJA_VIDEO_FORMAT_4320p_2400, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_2400},
{GST_AJA_VIDEO_FORMAT_4320p_2500, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_2500},
{GST_AJA_VIDEO_FORMAT_4320p_2997, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_2997},
{GST_AJA_VIDEO_FORMAT_4320p_3000, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_3000},
{GST_AJA_VIDEO_FORMAT_4320p_5000, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_5000},
{GST_AJA_VIDEO_FORMAT_4320p_5994, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_5994},
{GST_AJA_VIDEO_FORMAT_4320p_6000, NTV2_FORMAT_UNKNOWN,
NTV2_FORMAT_4x3840x2160p_6000},
};
GstCaps *gst_ntv2_supported_caps(NTV2DeviceID device_id) {
GstCaps *caps = gst_caps_new_empty();
for (gsize i = 0; i < G_N_ELEMENTS(supported_video_formats); i++) {
NTV2VideoFormat format = supported_video_formats[i];
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &format = format_map[i];
if (device_id == DEVICE_ID_INVALID ||
::NTV2DeviceCanDoVideoFormat(device_id, format)) {
gst_caps_append(caps, gst_ntv2_video_format_to_caps(format));
if (device_id == DEVICE_ID_INVALID) {
gst_caps_append(caps, gst_aja_video_format_to_caps(format.gst_format));
} else {
if ((format.aja_format != NTV2_FORMAT_UNKNOWN &&
::NTV2DeviceCanDoVideoFormat(device_id, format.aja_format)) ||
(format.quad_format != NTV2_FORMAT_UNKNOWN &&
::NTV2DeviceCanDoVideoFormat(device_id, format.quad_format))) {
gst_caps_append(caps, gst_aja_video_format_to_caps(format.gst_format));
}
}
}
return caps;
}
GstCaps *gst_aja_video_format_to_caps(GstAjaVideoFormat format) {
const FormatMapEntry *entry = NULL;
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &tmp = format_map[i];
if (tmp.gst_format == format) {
entry = &tmp;
break;
}
}
g_assert(entry != NULL);
if (entry->aja_format != NTV2_FORMAT_UNKNOWN)
return gst_ntv2_video_format_to_caps(entry->aja_format);
if (entry->quad_format != NTV2_FORMAT_UNKNOWN)
return gst_ntv2_video_format_to_caps(entry->quad_format);
g_assert_not_reached();
}
bool gst_video_info_from_aja_video_format(GstVideoInfo *info,
GstAjaVideoFormat format) {
const FormatMapEntry *entry = NULL;
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &tmp = format_map[i];
if (tmp.gst_format == format) {
entry = &tmp;
break;
}
}
g_assert(entry != NULL);
if (entry->aja_format != NTV2_FORMAT_UNKNOWN)
return gst_video_info_from_ntv2_video_format(info, entry->aja_format);
if (entry->quad_format != NTV2_FORMAT_UNKNOWN)
return gst_video_info_from_ntv2_video_format(info, entry->quad_format);
g_assert_not_reached();
}
GstCaps *gst_ntv2_video_format_to_caps(NTV2VideoFormat format) {
GstVideoInfo info;
if (!gst_video_info_from_ntv2_video_format(&info, format)) return NULL;
return gst_video_info_to_caps(&info);
}
bool gst_video_info_from_ntv2_video_format(GstVideoInfo *info,
NTV2VideoFormat format) {
if (format == NTV2_FORMAT_UNKNOWN) return false;
guint width = ::GetDisplayWidth(format);
guint height = ::GetDisplayHeight(format);
NTV2FrameRate fps = ::GetNTV2FrameRateFromVideoFormat(format);
guint fps_n, fps_d;
::GetFramesPerSecond(fps, fps_n, fps_d);
gst_video_info_set_format(&info, GST_VIDEO_FORMAT_v210, width, height);
info.fps_n = fps_n;
info.fps_d = fps_d;
gst_video_info_set_format(info, GST_VIDEO_FORMAT_v210, width, height);
info->fps_n = fps_n;
info->fps_d = fps_d;
if (NTV2_IS_525_FORMAT(format)) {
info.par_n = 10;
info.par_d = 11;
info->par_n = 10;
info->par_d = 11;
} else if (NTV2_IS_625_FORMAT(format)) {
info.par_n = 12;
info.par_d = 11;
info->par_n = 12;
info->par_d = 11;
}
info.interlace_mode = !::IsProgressiveTransport(format)
? GST_VIDEO_INTERLACE_MODE_INTERLEAVED
: GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
info->interlace_mode = !::IsProgressiveTransport(format)
? GST_VIDEO_INTERLACE_MODE_INTERLEAVED
: GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
return gst_video_info_to_caps(&info);
return true;
}
NTV2VideoFormat gst_ntv2_video_format_from_caps(GstCaps *caps) {
NTV2VideoFormat gst_ntv2_video_format_from_caps(const GstCaps *caps,
bool quad) {
GstVideoInfo info;
if (!gst_video_info_from_caps(&info, caps)) return NTV2_FORMAT_UNKNOWN;
for (gsize i = 0; i < G_N_ELEMENTS(supported_video_formats); i++) {
NTV2VideoFormat format = supported_video_formats[i];
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &format = format_map[i];
NTV2VideoFormat f = !quad ? format.aja_format : format.quad_format;
guint width = ::GetDisplayWidth(format);
guint height = ::GetDisplayHeight(format);
NTV2FrameRate fps = ::GetNTV2FrameRateFromVideoFormat(format);
if (f == NTV2_FORMAT_UNKNOWN) continue;
guint width = ::GetDisplayWidth(f);
guint height = ::GetDisplayHeight(f);
NTV2FrameRate fps = ::GetNTV2FrameRateFromVideoFormat(f);
guint fps_n, fps_d;
::GetFramesPerSecond(fps, fps_n, fps_d);
if (width == (guint)info.width && height == (guint)info.height &&
(guint)info.fps_n == fps_n && (guint)info.fps_d == fps_d &&
((!::IsProgressiveTransport(format) &&
((!::IsProgressiveTransport(f) &&
info.interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) ||
(::IsProgressiveTransport(format) &&
(::IsProgressiveTransport(f) &&
info.interlace_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)))
return format;
return f;
}
return NTV2_FORMAT_UNKNOWN;
}
GstAjaVideoFormat gst_aja_video_format_from_caps(const GstCaps *caps) {
GstVideoInfo info;
if (!gst_video_info_from_caps(&info, caps))
return GST_AJA_VIDEO_FORMAT_INVALID;
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &format = format_map[i];
NTV2VideoFormat f = (format.aja_format != NTV2_FORMAT_UNKNOWN)
? format.aja_format
: format.quad_format;
if (f == NTV2_FORMAT_UNKNOWN) continue;
guint width = ::GetDisplayWidth(f);
guint height = ::GetDisplayHeight(f);
NTV2FrameRate fps = ::GetNTV2FrameRateFromVideoFormat(f);
guint fps_n, fps_d;
::GetFramesPerSecond(fps, fps_n, fps_d);
if (width == (guint)info.width && height == (guint)info.height &&
(guint)info.fps_n == fps_n && (guint)info.fps_d == fps_d &&
((!::IsProgressiveTransport(f) &&
info.interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) ||
(::IsProgressiveTransport(f) &&
info.interlace_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)))
return format.gst_format;
}
return GST_AJA_VIDEO_FORMAT_INVALID;
}
GstAjaVideoFormat gst_aja_video_format_from_ntv2_format(
NTV2VideoFormat format) {
if (format == NTV2_FORMAT_UNKNOWN) return GST_AJA_VIDEO_FORMAT_INVALID;
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &entry = format_map[i];
if (entry.aja_format == format || entry.quad_format == format)
return entry.gst_format;
}
return GST_AJA_VIDEO_FORMAT_INVALID;
}
NTV2VideoFormat gst_ntv2_video_format_from_aja_format(GstAjaVideoFormat format,
bool quad) {
if (format == GST_AJA_VIDEO_FORMAT_INVALID) return NTV2_FORMAT_UNKNOWN;
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
const FormatMapEntry &entry = format_map[i];
if (entry.gst_format == format) {
if (!quad && entry.aja_format != NTV2_FORMAT_UNKNOWN)
return entry.aja_format;
if (quad && entry.quad_format != NTV2_FORMAT_UNKNOWN)
return entry.quad_format;
}
}
return NTV2_FORMAT_UNKNOWN;
}
bool gst_ntv2_video_format_is_quad(NTV2VideoFormat format) {
return (format >= NTV2_FORMAT_FIRST_4K_DEF_FORMAT &&
format < NTV2_FORMAT_END_4K_DEF_FORMATS) ||
(format >= NTV2_FORMAT_FIRST_4K_DEF_FORMAT2 &&
format < NTV2_FORMAT_END_4K_DEF_FORMATS2) ||
(format >= NTV2_FORMAT_FIRST_UHD2_DEF_FORMAT &&
format < NTV2_FORMAT_END_UHD2_DEF_FORMATS) ||
(format >= NTV2_FORMAT_FIRST_UHD2_FULL_DEF_FORMAT &&
format < NTV2_FORMAT_END_UHD2_FULL_DEF_FORMATS);
}
GType gst_aja_audio_meta_api_get_type(void) {
static volatile GType type;
@ -498,6 +699,22 @@ GType gst_aja_input_source_get_type(void) {
return (GType)id;
}
GType gst_aja_sdi_mode_get_type(void) {
static gsize id = 0;
static const GEnumValue modes[] = {
{GST_AJA_SDI_MODE_SINGLE_LINK, "single-link", "Single Link"},
{GST_AJA_SDI_MODE_QUAD_LINK_SQD, "quad-link-sqd", "Quad Link SQD"},
{GST_AJA_SDI_MODE_QUAD_LINK_TSI, "quad-link-tsi", "Quad Link TSI"},
{0, NULL, NULL}};
if (g_once_init_enter(&id)) {
GType tmp = g_enum_register_static("GstAjaSdiMode", modes);
g_once_init_leave(&id, tmp);
}
return (GType)id;
}
GType gst_aja_video_format_get_type(void) {
static gsize id = 0;
static const GEnumValue modes[] = {
@ -522,6 +739,22 @@ GType gst_aja_video_format_get_type(void) {
{GST_AJA_VIDEO_FORMAT_525_5994, "525-5994", "525 5994"},
{GST_AJA_VIDEO_FORMAT_525_2398, "525-2398", "525 2398"},
{GST_AJA_VIDEO_FORMAT_525_2400, "525-2400", "525 2400"},
{GST_AJA_VIDEO_FORMAT_2160p_2398, "2160p-2398", "2160p 2398"},
{GST_AJA_VIDEO_FORMAT_2160p_2400, "2160p-2400", "2160p 2400"},
{GST_AJA_VIDEO_FORMAT_2160p_2500, "2160p-2500", "2160p 2500"},
{GST_AJA_VIDEO_FORMAT_2160p_2997, "2160p-2997", "2160p 2997"},
{GST_AJA_VIDEO_FORMAT_2160p_3000, "2160p-3000", "2160p 3000"},
{GST_AJA_VIDEO_FORMAT_2160p_5000, "2160p-5000", "2160p 5000"},
{GST_AJA_VIDEO_FORMAT_2160p_5994, "2160p-5994", "2160p 5994"},
{GST_AJA_VIDEO_FORMAT_2160p_6000, "2160p-6000", "2160p 6000"},
{GST_AJA_VIDEO_FORMAT_4320p_2398, "4320p-2398", "4320p 2398"},
{GST_AJA_VIDEO_FORMAT_4320p_2400, "4320p-2400", "4320p 2400"},
{GST_AJA_VIDEO_FORMAT_4320p_2500, "4320p-2500", "4320p 2500"},
{GST_AJA_VIDEO_FORMAT_4320p_2997, "4320p-2997", "4320p 2997"},
{GST_AJA_VIDEO_FORMAT_4320p_3000, "4320p-3000", "4320p 3000"},
{GST_AJA_VIDEO_FORMAT_4320p_5000, "4320p-5000", "4320p 5000"},
{GST_AJA_VIDEO_FORMAT_4320p_5994, "4320p-5994", "4320p 5994"},
{GST_AJA_VIDEO_FORMAT_4320p_6000, "4320p-6000", "4320p 6000"},
{0, NULL, NULL}};
if (g_once_init_enter(&id)) {

View file

@ -54,13 +54,6 @@ G_GNUC_INTERNAL
GstAjaAudioMeta *gst_buffer_add_aja_audio_meta(GstBuffer *buffer,
GstBuffer *audio_buffer);
G_GNUC_INTERNAL
GstCaps *gst_ntv2_supported_caps(NTV2DeviceID device_id);
G_GNUC_INTERNAL
GstCaps *gst_ntv2_video_format_to_caps(NTV2VideoFormat format);
G_GNUC_INTERNAL
NTV2VideoFormat gst_ntv2_video_format_from_caps(GstCaps *caps);
typedef struct {
CNTV2Card *device;
} GstAjaDevice;
@ -178,6 +171,17 @@ G_GNUC_INTERNAL
GType gst_aja_input_source_get_type(void);
typedef enum {
GST_AJA_SDI_MODE_SINGLE_LINK,
GST_AJA_SDI_MODE_QUAD_LINK_SQD,
GST_AJA_SDI_MODE_QUAD_LINK_TSI,
} GstAjaSdiMode;
#define GST_TYPE_AJA_SDI_MODE (gst_aja_sdi_mode_get_type())
G_GNUC_INTERNAL
GType gst_aja_sdi_mode_get_type(void);
typedef enum {
GST_AJA_VIDEO_FORMAT_INVALID = -1,
// TODO: Implement: GST_AJA_VIDEO_FORMAT_AUTO,
GST_AJA_VIDEO_FORMAT_1080i_5000,
GST_AJA_VIDEO_FORMAT_1080i_5994,
@ -199,6 +203,22 @@ typedef enum {
GST_AJA_VIDEO_FORMAT_525_5994,
GST_AJA_VIDEO_FORMAT_525_2398,
GST_AJA_VIDEO_FORMAT_525_2400,
GST_AJA_VIDEO_FORMAT_2160p_2398,
GST_AJA_VIDEO_FORMAT_2160p_2400,
GST_AJA_VIDEO_FORMAT_2160p_2500,
GST_AJA_VIDEO_FORMAT_2160p_2997,
GST_AJA_VIDEO_FORMAT_2160p_3000,
GST_AJA_VIDEO_FORMAT_2160p_5000,
GST_AJA_VIDEO_FORMAT_2160p_5994,
GST_AJA_VIDEO_FORMAT_2160p_6000,
GST_AJA_VIDEO_FORMAT_4320p_2398,
GST_AJA_VIDEO_FORMAT_4320p_2400,
GST_AJA_VIDEO_FORMAT_4320p_2500,
GST_AJA_VIDEO_FORMAT_4320p_2997,
GST_AJA_VIDEO_FORMAT_4320p_3000,
GST_AJA_VIDEO_FORMAT_4320p_5000,
GST_AJA_VIDEO_FORMAT_4320p_5994,
GST_AJA_VIDEO_FORMAT_4320p_6000,
} GstAjaVideoFormat;
#define GST_TYPE_AJA_VIDEO_FORMAT (gst_aja_video_format_get_type())
@ -238,3 +258,31 @@ class ShmMutexLocker {
ShmMutexLocker();
~ShmMutexLocker();
};
G_GNUC_INTERNAL
GstCaps *gst_ntv2_supported_caps(NTV2DeviceID device_id);
G_GNUC_INTERNAL
GstCaps *gst_ntv2_video_format_to_caps(NTV2VideoFormat format);
G_GNUC_INTERNAL
bool gst_video_info_from_ntv2_video_format(GstVideoInfo *info,
NTV2VideoFormat format);
G_GNUC_INTERNAL
NTV2VideoFormat gst_ntv2_video_format_from_caps(const GstCaps *caps, bool quad);
G_GNUC_INTERNAL
GstCaps *gst_aja_video_format_to_caps(GstAjaVideoFormat format);
G_GNUC_INTERNAL
bool gst_video_info_from_aja_video_format(GstVideoInfo *info,
GstAjaVideoFormat format);
G_GNUC_INTERNAL
GstAjaVideoFormat gst_aja_video_format_from_caps(const GstCaps *caps);
G_GNUC_INTERNAL
GstAjaVideoFormat gst_aja_video_format_from_ntv2_format(NTV2VideoFormat format);
G_GNUC_INTERNAL
NTV2VideoFormat gst_ntv2_video_format_from_aja_format(GstAjaVideoFormat format,
bool quad);
G_GNUC_INTERNAL
bool gst_ntv2_video_format_is_quad(NTV2VideoFormat format);

View file

@ -35,6 +35,7 @@ GST_DEBUG_CATEGORY_STATIC(gst_aja_sink_debug);
#define DEFAULT_CHANNEL (::NTV2_CHANNEL1)
#define DEFAULT_AUDIO_SYSTEM (GST_AJA_AUDIO_SYSTEM_AUTO)
#define DEFAULT_OUTPUT_DESTINATION (GST_AJA_OUTPUT_DESTINATION_AUTO)
#define DEFAULT_SDI_MODE (GST_AJA_SDI_MODE_SINGLE_LINK)
#define DEFAULT_TIMECODE_INDEX (GST_AJA_TIMECODE_INDEX_VITC)
#define DEFAULT_REFERENCE_SOURCE (GST_AJA_REFERENCE_SOURCE_AUTO)
#define DEFAULT_QUEUE_SIZE (16)
@ -46,6 +47,7 @@ enum {
PROP_CHANNEL,
PROP_AUDIO_SYSTEM,
PROP_OUTPUT_DESTINATION,
PROP_SDI_MODE,
PROP_TIMECODE_INDEX,
PROP_REFERENCE_SOURCE,
PROP_QUEUE_SIZE,
@ -150,6 +152,14 @@ static void gst_aja_sink_class_init(GstAjaSinkClass *klass) {
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT)));
g_object_class_install_property(
gobject_class, PROP_SDI_MODE,
g_param_spec_enum(
"sdi-mode", "SDI Mode", "SDI mode to use", GST_TYPE_AJA_SDI_MODE,
DEFAULT_SDI_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT)));
g_object_class_install_property(
gobject_class, PROP_TIMECODE_INDEX,
g_param_spec_enum(
@ -241,6 +251,9 @@ void gst_aja_sink_set_property(GObject *object, guint property_id,
self->output_destination =
(GstAjaOutputDestination)g_value_get_enum(value);
break;
case PROP_SDI_MODE:
self->sdi_mode = (GstAjaSdiMode)g_value_get_enum(value);
break;
case PROP_TIMECODE_INDEX:
self->timecode_index = (GstAjaTimecodeIndex)g_value_get_enum(value);
break;
@ -276,6 +289,9 @@ void gst_aja_sink_get_property(GObject *object, guint property_id,
case PROP_OUTPUT_DESTINATION:
g_value_set_enum(value, self->output_destination);
break;
case PROP_SDI_MODE:
g_value_set_enum(value, self->sdi_mode);
break;
case PROP_TIMECODE_INDEX:
g_value_set_enum(value, self->timecode_index);
break;
@ -540,12 +556,14 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
gst_caps_replace(&self->configured_caps, caps);
GST_OBJECT_UNLOCK(self);
video_format = gst_ntv2_video_format_from_caps(caps);
bool quad_mode = (self->sdi_mode != GST_AJA_SDI_MODE_SINGLE_LINK);
video_format = gst_ntv2_video_format_from_caps(caps, quad_mode);
if (video_format == NTV2_FORMAT_UNKNOWN) {
GST_ERROR_OBJECT(self, "Unsupported caps %" GST_PTR_FORMAT, caps);
return FALSE;
}
self->quad_mode = quad_mode;
self->video_format = video_format;
// Configure render delay based on the framerate and queue size
@ -568,11 +586,21 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
}
self->device->device->SetMode(self->channel, NTV2_MODE_DISPLAY, false);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetMode((NTV2Channel)(self->channel + i),
NTV2_MODE_DISPLAY, false);
}
GST_DEBUG_OBJECT(self, "Configuring video format %d on channel %d",
(int)video_format, (int)self->channel);
self->device->device->SetVideoFormat(video_format, false, false,
self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetVideoFormat(video_format, false, false,
(NTV2Channel)(self->channel + i));
}
if (!::NTV2DeviceCanDoFrameBufferFormat(self->device_id,
::NTV2_FBF_10BIT_YCBCR)) {
@ -582,6 +610,11 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
}
self->device->device->SetFrameBufferFormat(self->channel,
::NTV2_FBF_10BIT_YCBCR);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetFrameBufferFormat(
(NTV2Channel)(self->channel + i), ::NTV2_FBF_10BIT_YCBCR);
}
NTV2ReferenceSource reference_source;
switch (self->reference_source) {
@ -628,11 +661,25 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
GST_ERROR_OBJECT(self, "Failed to enable channel");
return FALSE;
}
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
if (!self->device->device->EnableChannel(
(NTV2Channel)(self->channel + i))) {
GST_ERROR_OBJECT(self, "Failed to enable channel");
return FALSE;
}
}
}
self->device->device->DMABufferAutoLock(false, true, 0);
if (::NTV2DeviceHasBiDirectionalSDI(self->device_id))
self->device->device->SetSDITransmitEnable(self->channel, true);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetSDITransmitEnable(
(NTV2Channel)(self->channel + i), true);
}
if (self->configured_audio_channels) {
switch (self->audio_system_setting) {
@ -683,6 +730,14 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
self->audio_system);
self->device->device->SetSDIOutputDS2AudioSystem(self->channel,
self->audio_system);
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
self->device->device->SetSDIOutputAudioSystem(
(NTV2Channel)(self->channel + i), self->audio_system);
self->device->device->SetSDIOutputDS2AudioSystem(
(NTV2Channel)(self->channel + i), self->audio_system);
}
}
self->device->device->SetAudioLoopBack(::NTV2_AUDIO_LOOPBACK_OFF,
self->audio_system);
} else {
@ -805,6 +860,11 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
const NTV2Standard standard(::GetNTV2StandardFromVideoFormat(video_format));
self->device->device->SetSDIOutputStandard(self->channel, standard);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetSDIOutputStandard(
(NTV2Channel)(self->channel + i), standard);
}
const NTV2FrameGeometry geometry =
::GetNTV2FrameGeometryFromVideoFormat(video_format);
@ -813,12 +873,67 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
if (self->vanc_mode == ::NTV2_VANCMODE_OFF) {
self->device->device->SetFrameGeometry(geometry, false, self->channel);
self->device->device->SetVANCMode(self->vanc_mode, self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
self->device->device->SetFrameGeometry(
geometry, false, (NTV2Channel)(self->channel + i));
self->device->device->SetVANCMode(self->vanc_mode,
(NTV2Channel)(self->channel + i));
}
}
} else {
const NTV2FrameGeometry vanc_geometry =
::GetVANCFrameGeometry(geometry, self->vanc_mode);
self->device->device->SetFrameGeometry(vanc_geometry, false, self->channel);
self->device->device->SetVANCMode(self->vanc_mode, self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
self->device->device->SetFrameGeometry(
vanc_geometry, false, (NTV2Channel)(self->channel + i));
self->device->device->SetVANCMode(self->vanc_mode,
(NTV2Channel)(self->channel + i));
}
}
}
if (self->quad_mode) {
switch (self->sdi_mode) {
case GST_AJA_SDI_MODE_SINGLE_LINK:
g_assert_not_reached();
break;
case GST_AJA_SDI_MODE_QUAD_LINK_SQD:
if (self->configured_info.height > 2160) {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(true, self->channel);
self->device->device->SetQuadQuadSquaresEnable(true, self->channel);
} else {
self->device->device->SetQuadQuadFrameEnable(false, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
self->device->device->Set4kSquaresEnable(true, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
}
break;
case GST_AJA_SDI_MODE_QUAD_LINK_TSI:
if (self->configured_info.height > 2160) {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(true, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
} else {
self->device->device->SetQuadQuadFrameEnable(false, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(true, self->channel);
}
break;
}
} else {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(false, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
}
NTV2SmpteLineNumber smpte_line_num_info = ::GetSmpteLineNumber(standard);
@ -834,16 +949,209 @@ static gboolean gst_aja_sink_set_caps(GstBaseSink *bsink, GstCaps *caps) {
// Need to remove old routes for the output and framebuffer we're going to use
NTV2ActualConnections connections = router.GetConnections();
for (NTV2ActualConnectionsConstIter iter = connections.begin();
iter != connections.end(); iter++) {
if (iter->first == output_destination_id || iter->second == framebuffer_id)
router.RemoveConnection(iter->first, iter->second);
if (self->quad_mode) {
if (self->channel == NTV2_CHANNEL1) {
for (auto iter = connections.begin(); iter != connections.end(); iter++) {
if (iter->first == NTV2_XptSDIOut1Input ||
iter->first == NTV2_XptSDIOut1InputDS2 ||
iter->first == NTV2_XptSDIOut2Input ||
iter->first == NTV2_XptSDIOut2InputDS2 ||
iter->first == NTV2_XptSDIOut3Input ||
iter->first == NTV2_XptSDIOut4Input ||
iter->second == NTV2_Xpt425Mux1AYUV ||
iter->second == NTV2_Xpt425Mux1BYUV ||
iter->second == NTV2_Xpt425Mux2AYUV ||
iter->second == NTV2_Xpt425Mux2BYUV ||
iter->first == NTV2_Xpt425Mux1AInput ||
iter->first == NTV2_Xpt425Mux1BInput ||
iter->first == NTV2_Xpt425Mux2AInput ||
iter->first == NTV2_Xpt425Mux2BInput ||
iter->second == NTV2_XptFrameBuffer1YUV ||
iter->second == NTV2_XptFrameBuffer2YUV ||
iter->second == NTV2_XptFrameBuffer3YUV ||
iter->second == NTV2_XptFrameBuffer4YUV ||
iter->second == NTV2_XptFrameBuffer1_DS2YUV ||
iter->second == NTV2_XptFrameBuffer2_DS2YUV ||
iter->first == NTV2_XptSDIOut1Input ||
iter->first == NTV2_XptSDIOut2Input ||
iter->first == NTV2_XptSDIOut3Input ||
iter->first == NTV2_XptSDIOut4Input)
router.RemoveConnection(iter->first, iter->second);
}
} else if (self->channel == NTV2_CHANNEL5) {
for (auto iter = connections.begin(); iter != connections.end(); iter++) {
if (iter->first == NTV2_XptSDIOut5Input ||
iter->first == NTV2_XptSDIOut5InputDS2 ||
iter->first == NTV2_XptSDIOut6Input ||
iter->first == NTV2_XptSDIOut6InputDS2 ||
iter->first == NTV2_XptSDIOut7Input ||
iter->first == NTV2_XptSDIOut8Input ||
iter->second == NTV2_Xpt425Mux3AYUV ||
iter->second == NTV2_Xpt425Mux3BYUV ||
iter->second == NTV2_Xpt425Mux4AYUV ||
iter->second == NTV2_Xpt425Mux4BYUV ||
iter->first == NTV2_Xpt425Mux3AInput ||
iter->first == NTV2_Xpt425Mux3BInput ||
iter->first == NTV2_Xpt425Mux4AInput ||
iter->first == NTV2_Xpt425Mux4BInput ||
iter->second == NTV2_XptFrameBuffer5YUV ||
iter->second == NTV2_XptFrameBuffer6YUV ||
iter->second == NTV2_XptFrameBuffer7YUV ||
iter->second == NTV2_XptFrameBuffer8YUV ||
iter->second == NTV2_XptFrameBuffer3_DS2YUV ||
iter->second == NTV2_XptFrameBuffer4_DS2YUV ||
iter->second == NTV2_XptFrameBuffer5_DS2YUV ||
iter->second == NTV2_XptFrameBuffer6_DS2YUV ||
iter->first == NTV2_XptSDIOut5Input ||
iter->first == NTV2_XptSDIOut6Input ||
iter->first == NTV2_XptSDIOut7Input ||
iter->first == NTV2_XptSDIOut8Input)
router.RemoveConnection(iter->first, iter->second);
}
} else {
g_assert_not_reached();
}
} else {
for (auto iter = connections.begin(); iter != connections.end(); iter++) {
if (iter->first == output_destination_id ||
iter->second == framebuffer_id)
router.RemoveConnection(iter->first, iter->second);
if (((output_destination_id == NTV2_XptSDIOut6Input ||
output_destination_id == NTV2_XptSDIOut8Input) &&
iter->second == NTV2_XptFrameBuffer6_DS2YUV) ||
((output_destination_id == NTV2_XptSDIOut5Input ||
output_destination_id == NTV2_XptSDIOut6Input) &&
iter->second == NTV2_XptFrameBuffer5_DS2YUV) ||
((output_destination_id == NTV2_XptSDIOut2Input ||
output_destination_id == NTV2_XptSDIOut4Input) &&
iter->second == NTV2_XptFrameBuffer2_DS2YUV) ||
((output_destination_id == NTV2_XptSDIOut1Input ||
output_destination_id == NTV2_XptSDIOut2Input) &&
iter->second == NTV2_XptFrameBuffer1_DS2YUV))
router.RemoveConnection(iter->first, iter->second);
}
}
if (self->quad_mode) {
if (self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_TSI &&
!NTV2_IS_QUAD_QUAD_HFR_VIDEO_FORMAT(self->video_format) &&
!NTV2_IS_QUAD_QUAD_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1)
framebuffer_id = NTV2_Xpt425Mux1AYUV;
else if (self->channel == NTV2_CHANNEL5)
framebuffer_id = NTV2_Xpt425Mux3AYUV;
else
g_assert_not_reached();
}
}
GST_DEBUG_OBJECT(self, "Creating connection %d - %d", output_destination_id,
framebuffer_id);
router.AddConnection(output_destination_id, framebuffer_id);
if (self->quad_mode) {
if (self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_TSI) {
if (NTV2_IS_QUAD_QUAD_HFR_VIDEO_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptSDIOut2Input,
NTV2_XptFrameBuffer1_DS2YUV);
router.AddConnection(NTV2_XptSDIOut3Input, NTV2_XptFrameBuffer2YUV);
router.AddConnection(NTV2_XptSDIOut4Input,
NTV2_XptFrameBuffer2_DS2YUV);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptSDIOut6Input,
NTV2_XptFrameBuffer3_DS2YUV);
router.AddConnection(NTV2_XptSDIOut7Input, NTV2_XptFrameBuffer4YUV);
router.AddConnection(NTV2_XptSDIOut8Input,
NTV2_XptFrameBuffer4_DS2YUV);
} else {
g_assert_not_reached();
}
} else if (NTV2_IS_QUAD_QUAD_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptSDIOut1InputDS2,
NTV2_XptFrameBuffer1_DS2YUV);
router.AddConnection(NTV2_XptSDIOut2Input, NTV2_XptFrameBuffer2YUV);
router.AddConnection(NTV2_XptSDIOut2InputDS2,
NTV2_XptFrameBuffer2_DS2YUV);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptSDIOut5InputDS2,
NTV2_XptFrameBuffer3_DS2YUV);
router.AddConnection(NTV2_XptSDIOut6Input, NTV2_XptFrameBuffer4YUV);
router.AddConnection(NTV2_XptSDIOut6InputDS2,
NTV2_XptFrameBuffer4_DS2YUV);
} else {
g_assert_not_reached();
}
} else if (NTV2_IS_4K_HFR_VIDEO_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptSDIOut2Input, NTV2_Xpt425Mux1BYUV);
router.AddConnection(NTV2_XptSDIOut3Input, NTV2_Xpt425Mux2AYUV);
router.AddConnection(NTV2_XptSDIOut4Input, NTV2_Xpt425Mux2BYUV);
router.AddConnection(NTV2_Xpt425Mux1AInput, NTV2_XptFrameBuffer1YUV);
router.AddConnection(NTV2_Xpt425Mux1BInput,
NTV2_XptFrameBuffer1_DS2YUV);
router.AddConnection(NTV2_Xpt425Mux2AInput, NTV2_XptFrameBuffer2YUV);
router.AddConnection(NTV2_Xpt425Mux2BInput,
NTV2_XptFrameBuffer2_DS2YUV);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptSDIOut6Input, NTV2_Xpt425Mux3BYUV);
router.AddConnection(NTV2_XptSDIOut7Input, NTV2_Xpt425Mux4AYUV);
router.AddConnection(NTV2_XptSDIOut8Input, NTV2_Xpt425Mux4BYUV);
router.AddConnection(NTV2_Xpt425Mux3AInput, NTV2_XptFrameBuffer5YUV);
router.AddConnection(NTV2_Xpt425Mux3BInput,
NTV2_XptFrameBuffer5_DS2YUV);
router.AddConnection(NTV2_Xpt425Mux4AInput, NTV2_XptFrameBuffer6YUV);
router.AddConnection(NTV2_Xpt425Mux4BInput,
NTV2_XptFrameBuffer6_DS2YUV);
} else {
g_assert_not_reached();
}
} else {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptSDIOut1InputDS2, NTV2_Xpt425Mux1BYUV);
router.AddConnection(NTV2_XptSDIOut2Input, NTV2_Xpt425Mux2AYUV);
router.AddConnection(NTV2_XptSDIOut2InputDS2, NTV2_Xpt425Mux2BYUV);
router.AddConnection(NTV2_Xpt425Mux1AInput, NTV2_XptFrameBuffer1YUV);
router.AddConnection(NTV2_Xpt425Mux1BInput,
NTV2_XptFrameBuffer1_DS2YUV);
router.AddConnection(NTV2_Xpt425Mux2AInput, NTV2_XptFrameBuffer2YUV);
router.AddConnection(NTV2_Xpt425Mux2BInput,
NTV2_XptFrameBuffer2_DS2YUV);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptSDIOut5InputDS2, NTV2_Xpt425Mux3BYUV);
router.AddConnection(NTV2_XptSDIOut6Input, NTV2_Xpt425Mux4AYUV);
router.AddConnection(NTV2_XptSDIOut6InputDS2, NTV2_Xpt425Mux4BYUV);
router.AddConnection(NTV2_Xpt425Mux3AInput, NTV2_XptFrameBuffer5YUV);
router.AddConnection(NTV2_Xpt425Mux3BInput,
NTV2_XptFrameBuffer5_DS2YUV);
router.AddConnection(NTV2_Xpt425Mux4AInput, NTV2_XptFrameBuffer6YUV);
router.AddConnection(NTV2_Xpt425Mux4BInput,
NTV2_XptFrameBuffer6_DS2YUV);
} else {
g_assert_not_reached();
}
}
} else if (self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_SQD) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptSDIOut2Input, NTV2_XptFrameBuffer2YUV);
router.AddConnection(NTV2_XptSDIOut3Input, NTV2_XptFrameBuffer3YUV);
router.AddConnection(NTV2_XptSDIOut4Input, NTV2_XptFrameBuffer4YUV);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptSDIOut6Input, NTV2_XptFrameBuffer6YUV);
router.AddConnection(NTV2_XptSDIOut7Input, NTV2_XptFrameBuffer7YUV);
router.AddConnection(NTV2_XptSDIOut8Input, NTV2_XptFrameBuffer8YUV);
} else {
g_assert_not_reached();
}
}
}
{
std::stringstream os;
CNTV2SignalRouter oldRouter;
@ -1573,8 +1881,8 @@ restart:
// Trivial drift calculation
//
// TODO: Should probably take averages over a timespan (say 1 minute) into
// a ringbuffer and calculate a linear regression over them
// TODO: Should probably take averages over a timespan (say 1 minute)
// into a ringbuffer and calculate a linear regression over them
// FIXME: Add some compensation by dropping/duplicating frames as needed
// but make this configurable
if (frames_rendered_start_time == GST_CLOCK_TIME_NONE &&

View file

@ -73,11 +73,13 @@ struct _GstAjaSink {
GstAjaAudioSystem audio_system_setting;
GstAjaOutputDestination output_destination;
GstAjaSdiMode sdi_mode;
GstAjaTimecodeIndex timecode_index;
GstAjaReferenceSource reference_source;
NTV2AudioSystem audio_system;
NTV2VideoFormat video_format;
bool quad_mode;
NTV2VANCMode vanc_mode;
guint32 f2_start_line;
NTV2TCIndexes *tc_indexes;

View file

@ -37,6 +37,7 @@ GST_DEBUG_CATEGORY_STATIC(gst_aja_src_debug);
#define DEFAULT_VIDEO_FORMAT (GST_AJA_VIDEO_FORMAT_1080i_5000)
#define DEFAULT_AUDIO_SYSTEM (GST_AJA_AUDIO_SYSTEM_AUTO)
#define DEFAULT_INPUT_SOURCE (GST_AJA_INPUT_SOURCE_AUTO)
#define DEFAULT_SDI_MODE (GST_AJA_SDI_MODE_SINGLE_LINK)
#define DEFAULT_AUDIO_SOURCE (GST_AJA_AUDIO_SOURCE_EMBEDDED)
#define DEFAULT_TIMECODE_INDEX (GST_AJA_TIMECODE_INDEX_VITC)
#define DEFAULT_REFERENCE_SOURCE (GST_AJA_REFERENCE_SOURCE_FREERUN)
@ -50,6 +51,7 @@ enum {
PROP_VIDEO_FORMAT,
PROP_AUDIO_SYSTEM,
PROP_INPUT_SOURCE,
PROP_SDI_MODE,
PROP_AUDIO_SOURCE,
PROP_TIMECODE_INDEX,
PROP_REFERENCE_SOURCE,
@ -159,6 +161,14 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) {
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT)));
g_object_class_install_property(
gobject_class, PROP_SDI_MODE,
g_param_spec_enum(
"sdi-input-mode", "SDI Input Mode", "SDI input mode to use",
GST_TYPE_AJA_SDI_MODE, DEFAULT_SDI_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
G_PARAM_CONSTRUCT)));
g_object_class_install_property(
gobject_class, PROP_AUDIO_SOURCE,
g_param_spec_enum(
@ -262,6 +272,9 @@ void gst_aja_src_set_property(GObject *object, guint property_id,
case PROP_INPUT_SOURCE:
self->input_source = (GstAjaInputSource)g_value_get_enum(value);
break;
case PROP_SDI_MODE:
self->sdi_mode = (GstAjaSdiMode)g_value_get_enum(value);
break;
case PROP_AUDIO_SOURCE:
self->audio_source = (GstAjaAudioSource)g_value_get_enum(value);
break;
@ -303,6 +316,9 @@ void gst_aja_src_get_property(GObject *object, guint property_id, GValue *value,
case PROP_INPUT_SOURCE:
g_value_set_enum(value, self->input_source);
break;
case PROP_SDI_MODE:
g_value_set_enum(value, self->sdi_mode);
break;
case PROP_AUDIO_SOURCE:
g_value_set_enum(value, self->audio_source);
break;
@ -400,71 +416,21 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
// global shared state
ShmMutexLocker locker;
switch (self->video_format_setting) {
// TODO: GST_AJA_VIDEO_FORMAT_AUTO
case GST_AJA_VIDEO_FORMAT_1080i_5000:
self->video_format = ::NTV2_FORMAT_1080i_5000;
break;
case GST_AJA_VIDEO_FORMAT_1080i_5994:
self->video_format = ::NTV2_FORMAT_1080i_5994;
break;
case GST_AJA_VIDEO_FORMAT_1080i_6000:
self->video_format = ::NTV2_FORMAT_1080i_6000;
break;
case GST_AJA_VIDEO_FORMAT_720p_5994:
self->video_format = ::NTV2_FORMAT_720p_5994;
break;
case GST_AJA_VIDEO_FORMAT_720p_6000:
self->video_format = ::NTV2_FORMAT_720p_6000;
break;
case GST_AJA_VIDEO_FORMAT_1080p_2997:
self->video_format = ::NTV2_FORMAT_1080p_2997;
break;
case GST_AJA_VIDEO_FORMAT_1080p_3000:
self->video_format = ::NTV2_FORMAT_1080p_3000;
break;
case GST_AJA_VIDEO_FORMAT_1080p_2500:
self->video_format = ::NTV2_FORMAT_1080p_2500;
break;
case GST_AJA_VIDEO_FORMAT_1080p_2398:
self->video_format = ::NTV2_FORMAT_1080p_2398;
break;
case GST_AJA_VIDEO_FORMAT_1080p_2400:
self->video_format = ::NTV2_FORMAT_1080p_2400;
break;
case GST_AJA_VIDEO_FORMAT_720p_5000:
self->video_format = ::NTV2_FORMAT_720p_5000;
break;
case GST_AJA_VIDEO_FORMAT_720p_2398:
self->video_format = ::NTV2_FORMAT_720p_2398;
break;
case GST_AJA_VIDEO_FORMAT_720p_2500:
self->video_format = ::NTV2_FORMAT_720p_2500;
break;
case GST_AJA_VIDEO_FORMAT_1080p_5000_A:
self->video_format = ::NTV2_FORMAT_1080p_5000_A;
break;
case GST_AJA_VIDEO_FORMAT_1080p_5994_A:
self->video_format = ::NTV2_FORMAT_1080p_5994_A;
break;
case GST_AJA_VIDEO_FORMAT_1080p_6000_A:
self->video_format = ::NTV2_FORMAT_1080p_6000_A;
break;
case GST_AJA_VIDEO_FORMAT_625_5000:
self->video_format = ::NTV2_FORMAT_625_5000;
break;
case GST_AJA_VIDEO_FORMAT_525_5994:
self->video_format = ::NTV2_FORMAT_525_5994;
break;
case GST_AJA_VIDEO_FORMAT_525_2398:
self->video_format = ::NTV2_FORMAT_525_2398;
break;
case GST_AJA_VIDEO_FORMAT_525_2400:
self->video_format = ::NTV2_FORMAT_525_2400;
break;
default:
g_assert_not_reached();
break;
#define NEEDS_QUAD_MODE(self) \
(self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_SQD || \
self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_TSI || \
(self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 && \
self->input_source <= GST_AJA_INPUT_SOURCE_HDMI4))
self->quad_mode = NEEDS_QUAD_MODE(self);
self->video_format = gst_ntv2_video_format_from_aja_format(
self->video_format_setting, self->quad_mode);
#undef NEEDS_QUAD_MODE
if (self->video_format == NTV2_FORMAT_UNKNOWN) {
GST_ERROR_OBJECT(self, "Unsupported mode");
return FALSE;
}
if (!::NTV2DeviceCanDoVideoFormat(self->device_id, self->video_format)) {
@ -473,11 +439,78 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
return FALSE;
}
if (self->quad_mode) {
if (self->channel != ::NTV2_CHANNEL1 &&
self->channel != ::NTV2_CHANNEL5) {
GST_ERROR_OBJECT(self, "Quad modes require channels 1 or 5");
return FALSE;
}
}
gst_clear_caps(&self->configured_caps);
self->configured_caps = gst_ntv2_video_format_to_caps(self->video_format);
gst_video_info_from_caps(&self->configured_info, self->configured_caps);
gst_video_info_from_ntv2_video_format(&self->configured_info,
self->video_format);
self->configured_caps = gst_video_info_to_caps(&self->configured_info);
if (self->quad_mode) {
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
self->input_source <= GST_AJA_INPUT_SOURCE_HDMI4) {
self->device->device->SetQuadQuadFrameEnable(false, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
self->device->device->Set4kSquaresEnable(true, self->channel);
self->device->device->SetTsiFrameEnable(true, self->channel);
} else {
switch (self->sdi_mode) {
case GST_AJA_SDI_MODE_SINGLE_LINK:
g_assert_not_reached();
break;
case GST_AJA_SDI_MODE_QUAD_LINK_SQD:
if (self->configured_info.height > 2160) {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(true, self->channel);
self->device->device->SetQuadQuadSquaresEnable(true,
self->channel);
} else {
self->device->device->SetQuadQuadFrameEnable(false,
self->channel);
self->device->device->SetQuadQuadSquaresEnable(false,
self->channel);
self->device->device->Set4kSquaresEnable(true, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
}
break;
case GST_AJA_SDI_MODE_QUAD_LINK_TSI:
if (self->configured_info.height > 2160) {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(true, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false,
self->channel);
} else {
self->device->device->SetQuadQuadFrameEnable(false,
self->channel);
self->device->device->SetQuadQuadSquaresEnable(false,
self->channel);
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(true, self->channel);
}
break;
}
}
} else {
self->device->device->Set4kSquaresEnable(false, self->channel);
self->device->device->SetTsiFrameEnable(false, self->channel);
self->device->device->SetQuadQuadFrameEnable(false, self->channel);
self->device->device->SetQuadQuadSquaresEnable(false, self->channel);
}
self->device->device->SetMode(self->channel, NTV2_MODE_CAPTURE, false);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetMode((NTV2Channel)(self->channel + i),
NTV2_MODE_CAPTURE, false);
}
GST_DEBUG_OBJECT(self, "Configuring video format %d on channel %d",
(int)self->video_format, (int)self->channel);
@ -492,11 +525,22 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
}
self->device->device->SetFrameBufferFormat(self->channel,
::NTV2_FBF_10BIT_YCBCR);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetFrameBufferFormat(
(NTV2Channel)(self->channel + i), ::NTV2_FBF_10BIT_YCBCR);
}
self->device->device->DMABufferAutoLock(false, true, 0);
if (::NTV2DeviceHasBiDirectionalSDI(self->device_id))
if (::NTV2DeviceHasBiDirectionalSDI(self->device_id)) {
self->device->device->SetSDITransmitEnable(self->channel, false);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetSDITransmitEnable(
(NTV2Channel)(self->channel + i), false);
}
}
// Always use the framebuffer associated with the channel
NTV2InputCrosspointID framebuffer_id =
@ -591,6 +635,12 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
const NTV2Standard standard(
::GetNTV2StandardFromVideoFormat(self->video_format));
self->device->device->SetStandard(standard, self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++)
self->device->device->SetStandard(standard,
(NTV2Channel)(self->channel + i));
}
const NTV2FrameGeometry geometry =
::GetNTV2FrameGeometryFromVideoFormat(self->video_format);
@ -599,6 +649,15 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
if (self->vanc_mode == ::NTV2_VANCMODE_OFF) {
self->device->device->SetFrameGeometry(geometry, false, self->channel);
self->device->device->SetVANCMode(self->vanc_mode, self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
self->device->device->SetFrameGeometry(
geometry, false, (NTV2Channel)(self->channel + i));
self->device->device->SetVANCMode(self->vanc_mode,
(NTV2Channel)(self->channel + i));
}
}
} else {
const NTV2FrameGeometry vanc_geometry =
::GetVANCFrameGeometry(geometry, self->vanc_mode);
@ -606,6 +665,15 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
self->device->device->SetFrameGeometry(vanc_geometry, false,
self->channel);
self->device->device->SetVANCMode(self->vanc_mode, self->channel);
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
self->device->device->SetFrameGeometry(
vanc_geometry, false, (NTV2Channel)(self->channel + i));
self->device->device->SetVANCMode(self->vanc_mode,
(NTV2Channel)(self->channel + i));
}
}
}
CNTV2SignalRouter router;
@ -616,16 +684,225 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
// use
NTV2ActualConnections connections = router.GetConnections();
for (NTV2ActualConnectionsConstIter iter = connections.begin();
iter != connections.end(); iter++) {
if (iter->first == framebuffer_id || iter->second == input_source_id)
router.RemoveConnection(iter->first, iter->second);
if (self->quad_mode) {
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
self->input_source <= GST_AJA_INPUT_SOURCE_HDMI4) {
// Need to disconnect the 4 inputs corresponding to this channel from
// their framebuffers/muxers, and muxers from their framebuffers
for (auto iter = connections.begin(); iter != connections.end();
iter++) {
if (iter->first == NTV2_XptFrameBuffer1Input ||
iter->first == NTV2_XptFrameBuffer1BInput ||
iter->first == NTV2_XptFrameBuffer2Input ||
iter->first == NTV2_XptFrameBuffer2BInput ||
iter->second == NTV2_Xpt425Mux1AYUV ||
iter->second == NTV2_Xpt425Mux1BYUV ||
iter->second == NTV2_Xpt425Mux2AYUV ||
iter->second == NTV2_Xpt425Mux2BYUV ||
iter->first == NTV2_Xpt425Mux1AInput ||
iter->first == NTV2_Xpt425Mux1BInput ||
iter->first == NTV2_Xpt425Mux2AInput ||
iter->first == NTV2_Xpt425Mux2BInput ||
iter->second == NTV2_XptHDMIIn1 ||
iter->second == NTV2_XptHDMIIn1Q2 ||
iter->second == NTV2_XptHDMIIn1Q3 ||
iter->second == NTV2_XptHDMIIn1Q4)
router.RemoveConnection(iter->first, iter->second);
}
} else if (self->channel == NTV2_CHANNEL1) {
for (auto iter = connections.begin(); iter != connections.end();
iter++) {
if (iter->first == NTV2_XptFrameBuffer1Input ||
iter->first == NTV2_XptFrameBuffer1BInput ||
iter->first == NTV2_XptFrameBuffer1DS2Input ||
iter->first == NTV2_XptFrameBuffer2Input ||
iter->first == NTV2_XptFrameBuffer2BInput ||
iter->first == NTV2_XptFrameBuffer2DS2Input ||
iter->second == NTV2_Xpt425Mux1AYUV ||
iter->second == NTV2_Xpt425Mux1BYUV ||
iter->second == NTV2_Xpt425Mux2AYUV ||
iter->second == NTV2_Xpt425Mux2BYUV ||
iter->first == NTV2_Xpt425Mux1AInput ||
iter->first == NTV2_Xpt425Mux1BInput ||
iter->first == NTV2_Xpt425Mux2AInput ||
iter->first == NTV2_Xpt425Mux2BInput ||
iter->second == NTV2_XptSDIIn1 ||
iter->second == NTV2_XptSDIIn2 ||
iter->second == NTV2_XptSDIIn3 ||
iter->second == NTV2_XptSDIIn4 ||
iter->second == NTV2_XptSDIIn1DS2 ||
iter->second == NTV2_XptSDIIn2DS2 ||
iter->first == NTV2_XptFrameBuffer1Input ||
iter->first == NTV2_XptFrameBuffer2Input ||
iter->first == NTV2_XptFrameBuffer3Input ||
iter->first == NTV2_XptFrameBuffer4Input)
router.RemoveConnection(iter->first, iter->second);
}
} else if (self->channel == NTV2_CHANNEL5) {
for (auto iter = connections.begin(); iter != connections.end();
iter++) {
if (iter->first == NTV2_XptFrameBuffer5Input ||
iter->first == NTV2_XptFrameBuffer5BInput ||
iter->first == NTV2_XptFrameBuffer5DS2Input ||
iter->first == NTV2_XptFrameBuffer6Input ||
iter->first == NTV2_XptFrameBuffer6BInput ||
iter->first == NTV2_XptFrameBuffer6DS2Input ||
iter->second == NTV2_Xpt425Mux3AYUV ||
iter->second == NTV2_Xpt425Mux3BYUV ||
iter->second == NTV2_Xpt425Mux4AYUV ||
iter->second == NTV2_Xpt425Mux4BYUV ||
iter->first == NTV2_Xpt425Mux3AInput ||
iter->first == NTV2_Xpt425Mux3BInput ||
iter->first == NTV2_Xpt425Mux4AInput ||
iter->first == NTV2_Xpt425Mux4BInput ||
iter->second == NTV2_XptSDIIn5 ||
iter->second == NTV2_XptSDIIn6 ||
iter->second == NTV2_XptSDIIn7 ||
iter->second == NTV2_XptSDIIn8 ||
iter->second == NTV2_XptSDIIn5DS2 ||
iter->second == NTV2_XptSDIIn6DS2 ||
iter->first == NTV2_XptFrameBuffer5Input ||
iter->first == NTV2_XptFrameBuffer6Input ||
iter->first == NTV2_XptFrameBuffer7Input ||
iter->first == NTV2_XptFrameBuffer8Input)
router.RemoveConnection(iter->first, iter->second);
}
} else {
g_assert_not_reached();
}
} else {
for (auto iter = connections.begin(); iter != connections.end(); iter++) {
if (iter->first == framebuffer_id || iter->second == input_source_id)
router.RemoveConnection(iter->first, iter->second);
if (((input_source_id == NTV2_XptSDIIn6 ||
input_source_id == NTV2_XptSDIIn8) &&
iter->first == NTV2_XptFrameBuffer6BInput) ||
((input_source_id == NTV2_XptSDIIn5 ||
input_source_id == NTV2_XptSDIIn6) &&
iter->first == NTV2_XptFrameBuffer5BInput) ||
((input_source_id == NTV2_XptSDIIn4 ||
input_source_id == NTV2_XptSDIIn2) &&
iter->first == NTV2_XptFrameBuffer2BInput) ||
((input_source_id == NTV2_XptSDIIn1 ||
input_source_id == NTV2_XptSDIIn2) &&
iter->first == NTV2_XptFrameBuffer1BInput))
router.RemoveConnection(iter->first, iter->second);
}
}
if (self->quad_mode) {
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
self->input_source <= GST_AJA_INPUT_SOURCE_HDMI4) {
input_source_id = NTV2_Xpt425Mux1AYUV;
} else if (self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_TSI &&
!NTV2_IS_QUAD_QUAD_HFR_VIDEO_FORMAT(self->video_format) &&
!NTV2_IS_QUAD_QUAD_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1)
input_source_id = NTV2_Xpt425Mux1AYUV;
else if (self->channel == NTV2_CHANNEL5)
input_source_id = NTV2_Xpt425Mux3AYUV;
else
g_assert_not_reached();
}
}
GST_DEBUG_OBJECT(self, "Creating connection %d - %d", framebuffer_id,
input_source_id);
router.AddConnection(framebuffer_id, input_source_id);
if (self->quad_mode) {
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
self->input_source <= GST_AJA_INPUT_SOURCE_HDMI4) {
router.AddConnection(NTV2_XptFrameBuffer1BInput, NTV2_Xpt425Mux1BYUV);
router.AddConnection(NTV2_XptFrameBuffer2Input, NTV2_Xpt425Mux2AYUV);
router.AddConnection(NTV2_XptFrameBuffer2BInput, NTV2_Xpt425Mux2BYUV);
router.AddConnection(NTV2_Xpt425Mux1AInput, NTV2_XptHDMIIn1);
router.AddConnection(NTV2_Xpt425Mux1BInput, NTV2_XptHDMIIn1Q2);
router.AddConnection(NTV2_Xpt425Mux2AInput, NTV2_XptHDMIIn1Q3);
router.AddConnection(NTV2_Xpt425Mux2BInput, NTV2_XptHDMIIn1Q4);
} else {
if (self->sdi_mode == GST_AJA_SDI_MODE_QUAD_LINK_TSI) {
if (NTV2_IS_QUAD_QUAD_HFR_VIDEO_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptFrameBuffer1DS2Input,
NTV2_XptSDIIn2);
router.AddConnection(NTV2_XptFrameBuffer2Input, NTV2_XptSDIIn3);
router.AddConnection(NTV2_XptFrameBuffer2DS2Input,
NTV2_XptSDIIn4);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptFrameBuffer5DS2Input,
NTV2_XptSDIIn6);
router.AddConnection(NTV2_XptFrameBuffer5Input, NTV2_XptSDIIn7);
router.AddConnection(NTV2_XptFrameBuffer6DS2Input,
NTV2_XptSDIIn8);
} else {
g_assert_not_reached();
}
} else if (NTV2_IS_QUAD_QUAD_FORMAT(self->video_format)) {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptFrameBuffer1DS2Input,
NTV2_XptSDIIn1DS2);
router.AddConnection(NTV2_XptFrameBuffer2Input, NTV2_XptSDIIn2);
router.AddConnection(NTV2_XptFrameBuffer2DS2Input,
NTV2_XptSDIIn2DS2);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptFrameBuffer5DS2Input,
NTV2_XptSDIIn5DS2);
router.AddConnection(NTV2_XptFrameBuffer5Input, NTV2_XptSDIIn6);
router.AddConnection(NTV2_XptFrameBuffer6DS2Input,
NTV2_XptSDIIn6DS2);
} else {
g_assert_not_reached();
}
// FIXME: Need special handling of NTV2_IS_4K_HFR_VIDEO_FORMAT for
// TSI?
} else {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptFrameBuffer1BInput,
NTV2_Xpt425Mux1BYUV);
router.AddConnection(NTV2_XptFrameBuffer2Input,
NTV2_Xpt425Mux2AYUV);
router.AddConnection(NTV2_XptFrameBuffer2BInput,
NTV2_Xpt425Mux2BYUV);
router.AddConnection(NTV2_Xpt425Mux1AInput, NTV2_XptSDIIn1);
router.AddConnection(NTV2_Xpt425Mux1BInput, NTV2_XptSDIIn2);
router.AddConnection(NTV2_Xpt425Mux2AInput, NTV2_XptSDIIn3);
router.AddConnection(NTV2_Xpt425Mux2BInput, NTV2_XptSDIIn4);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptFrameBuffer5BInput,
NTV2_Xpt425Mux3BYUV);
router.AddConnection(NTV2_XptFrameBuffer6Input,
NTV2_Xpt425Mux4AYUV);
router.AddConnection(NTV2_XptFrameBuffer6BInput,
NTV2_Xpt425Mux4BYUV);
router.AddConnection(NTV2_Xpt425Mux3AInput, NTV2_XptSDIIn5);
router.AddConnection(NTV2_Xpt425Mux3BInput, NTV2_XptSDIIn6);
router.AddConnection(NTV2_Xpt425Mux4AInput, NTV2_XptSDIIn7);
router.AddConnection(NTV2_Xpt425Mux4BInput, NTV2_XptSDIIn8);
} else {
g_assert_not_reached();
}
}
} else {
if (self->channel == NTV2_CHANNEL1) {
router.AddConnection(NTV2_XptFrameBuffer2Input, NTV2_XptSDIIn2);
router.AddConnection(NTV2_XptFrameBuffer3Input, NTV2_XptSDIIn3);
router.AddConnection(NTV2_XptFrameBuffer4Input, NTV2_XptSDIIn4);
} else if (self->channel == NTV2_CHANNEL5) {
router.AddConnection(NTV2_XptFrameBuffer6Input, NTV2_XptSDIIn6);
router.AddConnection(NTV2_XptFrameBuffer7Input, NTV2_XptSDIIn7);
router.AddConnection(NTV2_XptFrameBuffer8Input, NTV2_XptSDIIn8);
} else {
g_assert_not_reached();
}
}
}
}
{
std::stringstream os;
CNTV2SignalRouter oldRouter;
@ -1194,6 +1471,17 @@ restart:
goto out;
}
if (self->quad_mode) {
for (int i = 1; i < 4; i++) {
if (!self->device->device->EnableChannel(
(NTV2Channel)(self->channel + i))) {
GST_ELEMENT_ERROR(self, STREAM, FAILED, (NULL),
("Failed to enable channel"));
goto out;
}
}
}
{
// Make sure to globally lock here as the routing settings and others are
// global shared state
@ -1228,6 +1516,13 @@ restart:
NTV2VideoFormat current_video_format =
self->device->device->GetInputVideoFormat(
self->configured_input_source);
NTV2VideoFormat effective_video_format = self->video_format;
// Can't call this unconditionally as it also maps e.g. 3840x2160p to 1080p
if (self->quad_mode) {
effective_video_format =
::GetQuarterSizedVideoFormat(effective_video_format);
}
if (current_video_format == ::NTV2_FORMAT_UNKNOWN) {
GST_DEBUG_OBJECT(self, "No signal, waiting");
g_mutex_unlock(&self->queue_lock);
@ -1240,11 +1535,14 @@ restart:
}
g_mutex_lock(&self->queue_lock);
continue;
} else if (current_video_format != self->video_format) {
} else if (current_video_format != effective_video_format &&
current_video_format != self->video_format) {
// TODO: Handle GST_AJA_VIDEO_FORMAT_AUTO here
GST_DEBUG_OBJECT(self,
"Different input format %u than configured %u, waiting",
current_video_format, self->video_format);
"Different input format %u than configured %u "
"(effective %u), waiting",
current_video_format, self->video_format,
effective_video_format);
g_mutex_unlock(&self->queue_lock);
self->device->device->WaitForInputVerticalInterrupt(self->channel);
frames_dropped_last = G_MAXUINT64;

View file

@ -64,6 +64,7 @@ struct _GstAjaSrc {
NTV2Channel channel;
GstAjaAudioSystem audio_system_setting;
GstAjaVideoFormat video_format_setting;
GstAjaSdiMode sdi_mode;
GstAjaInputSource input_source;
GstAjaAudioSource audio_source;
GstAjaTimecodeIndex timecode_index;
@ -73,6 +74,7 @@ struct _GstAjaSrc {
NTV2AudioSystem audio_system;
NTV2VideoFormat video_format;
bool quad_mode;
NTV2VANCMode vanc_mode;
NTV2InputSource configured_input_source;
NTV2TCIndex tc_index;