mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-20 21:16:24 +00:00
Add support for UHD/UHD2 modes and SDI quad-link modes
This commit is contained in:
parent
fa5385bc8e
commit
735768b905
6 changed files with 1016 additions and 125 deletions
305
gstajacommon.cpp
305
gstajacommon.cpp
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
322
gstajasink.cpp
322
gstajasink.cpp
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
|
|
448
gstajasrc.cpp
448
gstajasrc.cpp
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue