mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
1b117e666b
Also remove the `gst-inspect-1.0` output from the README.md. This is listed in the actual documentation and more up to date there.
1197 lines
44 KiB
C++
1197 lines
44 KiB
C++
/* GStreamer
|
|
* Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
|
|
* Boston, MA 02110-1335, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
#include <semaphore.h>
|
|
|
|
#include "gstajacommon.h"
|
|
|
|
GST_DEBUG_CATEGORY_STATIC(gst_aja_debug);
|
|
|
|
#define GST_CAT_DEFAULT gst_aja_debug
|
|
|
|
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_1080psf_2398, NTV2_FORMAT_1080psf_2398,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2400, NTV2_FORMAT_1080psf_2400,
|
|
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_1080p_5000_A, 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_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_1080psf_2500_2, NTV2_FORMAT_1080psf_2500_2,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2997_2, NTV2_FORMAT_1080psf_2997_2,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_3000_2, NTV2_FORMAT_1080psf_3000_2,
|
|
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_1080p_DCI_2398, NTV2_FORMAT_1080p_2K_2398,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2400, NTV2_FORMAT_1080p_2K_2400,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2500, NTV2_FORMAT_1080p_2K_2500,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2997, NTV2_FORMAT_1080p_2K_2997,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_3000, NTV2_FORMAT_1080p_2K_3000,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_5000_A, NTV2_FORMAT_1080p_2K_5000_A,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_5994_A, NTV2_FORMAT_1080p_2K_5994_A,
|
|
NTV2_FORMAT_UNKNOWN},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_6000_A, NTV2_FORMAT_1080p_2K_6000_A,
|
|
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_2160p_DCI_2398, NTV2_FORMAT_4096x2160p_2398,
|
|
NTV2_FORMAT_4x2048x1080p_2398},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2400, NTV2_FORMAT_4096x2160p_2400,
|
|
NTV2_FORMAT_4x2048x1080p_2400},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2500, NTV2_FORMAT_4096x2160p_2500,
|
|
NTV2_FORMAT_4x2048x1080p_2500},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2997, NTV2_FORMAT_4096x2160p_2997,
|
|
NTV2_FORMAT_4x2048x1080p_2997},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_3000, NTV2_FORMAT_4096x2160p_3000,
|
|
NTV2_FORMAT_4x2048x1080p_3000},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_5000, NTV2_FORMAT_4096x2160p_5000,
|
|
NTV2_FORMAT_4x2048x1080p_5000},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_5994, NTV2_FORMAT_4096x2160p_5994,
|
|
NTV2_FORMAT_4x2048x1080p_5994},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_6000, NTV2_FORMAT_4096x2160p_6000,
|
|
NTV2_FORMAT_4x2048x1080p_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},
|
|
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2398, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_2398},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2400, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_2400},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2500, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_2500},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2997, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_2997},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_3000, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_3000},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_5000, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_5000},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_5994, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_5994},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_6000, NTV2_FORMAT_UNKNOWN,
|
|
NTV2_FORMAT_4x4096x2160p_6000},
|
|
};
|
|
|
|
GstCaps *gst_ntv2_supported_caps(NTV2DeviceID device_id) {
|
|
GstCaps *caps = gst_caps_new_empty();
|
|
|
|
for (gsize i = 0; i < G_N_ELEMENTS(format_map); i++) {
|
|
const FormatMapEntry &format = format_map[i];
|
|
GstCaps *tmp = NULL;
|
|
|
|
if (device_id == DEVICE_ID_INVALID) {
|
|
tmp = 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))) {
|
|
tmp = gst_aja_video_format_to_caps(format.gst_format);
|
|
}
|
|
|
|
if (tmp) {
|
|
// Widescreen PAL/NTSC
|
|
if (format.gst_format == GST_AJA_VIDEO_FORMAT_525_2398 ||
|
|
format.gst_format == GST_AJA_VIDEO_FORMAT_525_2400 ||
|
|
format.gst_format == GST_AJA_VIDEO_FORMAT_525_5994) {
|
|
GstCaps *tmp2 = gst_caps_copy(tmp);
|
|
gst_caps_set_simple(tmp2, "pixel-aspect-ratio", GST_TYPE_FRACTION, 40,
|
|
33, NULL);
|
|
gst_caps_append(tmp, tmp2);
|
|
} else if (format.gst_format == GST_AJA_VIDEO_FORMAT_625_5000) {
|
|
GstCaps *tmp2 = gst_caps_copy(tmp);
|
|
gst_caps_set_simple(tmp2, "pixel-aspect-ratio", GST_TYPE_FRACTION, 16,
|
|
11, NULL);
|
|
gst_caps_append(tmp, tmp2);
|
|
}
|
|
|
|
gst_caps_append(caps, tmp);
|
|
}
|
|
}
|
|
|
|
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;
|
|
GstCaps *caps;
|
|
|
|
if (!gst_video_info_from_ntv2_video_format(&info, format)) return NULL;
|
|
|
|
caps = gst_video_info_to_caps(&info);
|
|
if (!caps) return caps;
|
|
|
|
guint n = gst_caps_get_size(caps);
|
|
for (guint i = 0; i < n; i++) {
|
|
GstStructure *s = gst_caps_get_structure(caps, i);
|
|
|
|
gst_structure_remove_fields(s, "chroma-site", "colorimetry", NULL);
|
|
}
|
|
|
|
return caps;
|
|
}
|
|
|
|
bool gst_video_info_from_ntv2_video_format(GstVideoInfo *info,
|
|
NTV2VideoFormat format) {
|
|
if (format == NTV2_FORMAT_UNKNOWN) return false;
|
|
|
|
NTV2Standard standard = ::GetNTV2StandardFromVideoFormat(format);
|
|
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;
|
|
if (NTV2_IS_525_FORMAT(format)) {
|
|
info->par_n = 10;
|
|
info->par_d = 11;
|
|
} else if (NTV2_IS_625_FORMAT(format)) {
|
|
info->par_n = 12;
|
|
info->par_d = 11;
|
|
}
|
|
info->interlace_mode =
|
|
(!::IsProgressivePicture(format) && !NTV2_IS_PSF_VIDEO_FORMAT(format))
|
|
? GST_VIDEO_INTERLACE_MODE_INTERLEAVED
|
|
: GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
|
|
|
|
if (!::IsProgressiveTransport(format) && !NTV2_IS_PSF_VIDEO_FORMAT(format)) {
|
|
NTV2SmpteLineNumber line_number = ::GetSmpteLineNumber(standard);
|
|
|
|
if (line_number.firstFieldTop) {
|
|
GST_VIDEO_INFO_FIELD_ORDER(info) = GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
|
|
} else {
|
|
GST_VIDEO_INFO_FIELD_ORDER(info) =
|
|
GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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(format_map); i++) {
|
|
const FormatMapEntry &format = format_map[i];
|
|
NTV2VideoFormat f = !quad ? 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 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 GType type;
|
|
|
|
if (g_once_init_enter(&type)) {
|
|
static const gchar *tags[] = {NULL};
|
|
GType _type = gst_meta_api_type_register("GstAjaAudioMetaAPI", tags);
|
|
GST_INFO("registering");
|
|
g_once_init_leave(&type, _type);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static gboolean gst_aja_audio_meta_transform(GstBuffer *dest, GstMeta *meta,
|
|
GstBuffer *buffer, GQuark type,
|
|
gpointer data) {
|
|
GstAjaAudioMeta *dmeta, *smeta;
|
|
|
|
if (GST_META_TRANSFORM_IS_COPY(type)) {
|
|
smeta = (GstAjaAudioMeta *)meta;
|
|
|
|
GST_TRACE("copy AJA audio metadata");
|
|
dmeta = gst_buffer_add_aja_audio_meta(dest, smeta->buffer);
|
|
if (!dmeta) return FALSE;
|
|
} else {
|
|
/* return FALSE, if transform type is not supported */
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean gst_aja_audio_meta_init(GstMeta *meta, gpointer params,
|
|
GstBuffer *buffer) {
|
|
GstAjaAudioMeta *emeta = (GstAjaAudioMeta *)meta;
|
|
|
|
emeta->buffer = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void gst_aja_audio_meta_free(GstMeta *meta, GstBuffer *buffer) {
|
|
GstAjaAudioMeta *emeta = (GstAjaAudioMeta *)meta;
|
|
|
|
gst_buffer_replace(&emeta->buffer, NULL);
|
|
}
|
|
|
|
const GstMetaInfo *gst_aja_audio_meta_get_info(void) {
|
|
static const GstMetaInfo *meta_info = NULL;
|
|
|
|
if (g_once_init_enter((GstMetaInfo **)&meta_info)) {
|
|
const GstMetaInfo *mi = gst_meta_register(
|
|
GST_AJA_AUDIO_META_API_TYPE, "GstAjaAudioMeta", sizeof(GstAjaAudioMeta),
|
|
gst_aja_audio_meta_init, gst_aja_audio_meta_free,
|
|
gst_aja_audio_meta_transform);
|
|
g_once_init_leave((GstMetaInfo **)&meta_info, (GstMetaInfo *)mi);
|
|
}
|
|
return meta_info;
|
|
}
|
|
|
|
GstAjaAudioMeta *gst_buffer_add_aja_audio_meta(GstBuffer *buffer,
|
|
GstBuffer *audio_buffer) {
|
|
GstAjaAudioMeta *meta;
|
|
|
|
g_return_val_if_fail(buffer != NULL, NULL);
|
|
g_return_val_if_fail(audio_buffer != NULL, NULL);
|
|
|
|
meta = (GstAjaAudioMeta *)gst_buffer_add_meta(buffer, GST_AJA_AUDIO_META_INFO,
|
|
NULL);
|
|
|
|
meta->buffer = gst_buffer_ref(audio_buffer);
|
|
|
|
return meta;
|
|
}
|
|
|
|
typedef struct {
|
|
GstMemory mem;
|
|
|
|
guint8 *data;
|
|
} GstAjaMemory;
|
|
|
|
typedef struct {
|
|
guint8 *data;
|
|
gsize size;
|
|
} FreedMemory;
|
|
|
|
G_DEFINE_TYPE(GstAjaAllocator, gst_aja_allocator, GST_TYPE_ALLOCATOR);
|
|
|
|
static inline void _aja_memory_init(GstAjaAllocator *alloc, GstAjaMemory *mem,
|
|
GstMemoryFlags flags, GstMemory *parent,
|
|
gpointer data, gsize maxsize, gsize offset,
|
|
gsize size) {
|
|
gst_memory_init(GST_MEMORY_CAST(mem), flags, GST_ALLOCATOR(alloc), parent,
|
|
maxsize, 4095, offset, size);
|
|
|
|
mem->data = (guint8 *)data;
|
|
}
|
|
|
|
static inline GstAjaMemory *_aja_memory_new(GstAjaAllocator *alloc,
|
|
GstMemoryFlags flags,
|
|
GstAjaMemory *parent, gpointer data,
|
|
gsize maxsize, gsize offset,
|
|
gsize size) {
|
|
GstAjaMemory *mem;
|
|
|
|
mem = (GstAjaMemory *)g_new0(GstAjaMemory, 1);
|
|
_aja_memory_init(alloc, mem, flags, (GstMemory *)parent, data, maxsize,
|
|
offset, size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
static GstAjaMemory *_aja_memory_new_block(GstAjaAllocator *alloc,
|
|
GstMemoryFlags flags, gsize maxsize,
|
|
gsize offset, gsize size) {
|
|
GstAjaMemory *mem;
|
|
guint8 *data = NULL;
|
|
|
|
mem = (GstAjaMemory *)g_new0(GstAjaMemory, 1);
|
|
|
|
GST_OBJECT_LOCK(alloc);
|
|
guint n = gst_queue_array_get_length(alloc->freed_mems);
|
|
for (guint i = 0; i < n; i++) {
|
|
FreedMemory *fmem =
|
|
(FreedMemory *)gst_queue_array_peek_nth_struct(alloc->freed_mems, i);
|
|
|
|
if (fmem->size == size) {
|
|
data = fmem->data;
|
|
GST_TRACE_OBJECT(
|
|
alloc, "Using cached freed memory of size %" G_GSIZE_FORMAT " at %p",
|
|
fmem->size, fmem->data);
|
|
gst_queue_array_drop_struct(alloc->freed_mems, i, NULL);
|
|
break;
|
|
}
|
|
}
|
|
GST_OBJECT_UNLOCK(alloc);
|
|
|
|
if (!data) {
|
|
data = (guint8 *)AJAMemory::AllocateAligned(maxsize, 4096);
|
|
GST_TRACE_OBJECT(alloc,
|
|
"Allocated memory of size %" G_GSIZE_FORMAT " at %p",
|
|
maxsize, data);
|
|
if (!alloc->device->device->DMABufferLock((ULWord *)data, maxsize, true)) {
|
|
GST_WARNING_OBJECT(alloc, "Failed to pre-lock memory");
|
|
}
|
|
}
|
|
|
|
_aja_memory_init(alloc, mem, flags, NULL, data, maxsize, offset, size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
static gpointer _aja_memory_map(GstAjaMemory *mem, gsize maxsize,
|
|
GstMapFlags flags) {
|
|
return mem->data;
|
|
}
|
|
|
|
static gboolean _aja_memory_unmap(GstAjaMemory *mem) { return TRUE; }
|
|
|
|
static GstMemory *_aja_memory_copy(GstAjaMemory *mem, gssize offset,
|
|
gsize size) {
|
|
GstMemory *copy;
|
|
GstMapInfo map;
|
|
|
|
if (size == (gsize)-1)
|
|
size = mem->mem.size > (gsize)offset ? mem->mem.size - offset : 0;
|
|
|
|
copy = gst_allocator_alloc(mem->mem.allocator, size, NULL);
|
|
gst_memory_map(copy, &map, GST_MAP_READ);
|
|
GST_DEBUG("memcpy %" G_GSIZE_FORMAT " memory %p -> %p", size, mem, copy);
|
|
memcpy(map.data, mem->data + mem->mem.offset + offset, size);
|
|
gst_memory_unmap(copy, &map);
|
|
|
|
return copy;
|
|
}
|
|
|
|
static GstAjaMemory *_aja_memory_share(GstAjaMemory *mem, gssize offset,
|
|
gsize size) {
|
|
GstAjaMemory *sub;
|
|
GstAjaMemory *parent;
|
|
|
|
/* find the real parent */
|
|
if ((parent = (GstAjaMemory *)mem->mem.parent) == NULL)
|
|
parent = (GstAjaMemory *)mem;
|
|
|
|
if (size == (gsize)-1) size = mem->mem.size - offset;
|
|
|
|
sub = _aja_memory_new(GST_AJA_ALLOCATOR(parent->mem.allocator),
|
|
(GstMemoryFlags)(GST_MINI_OBJECT_FLAGS(parent) |
|
|
GST_MINI_OBJECT_FLAG_LOCK_READONLY),
|
|
parent, parent->data, mem->mem.maxsize,
|
|
mem->mem.offset + offset, size);
|
|
|
|
return sub;
|
|
}
|
|
|
|
static GstMemory *gst_aja_allocator_alloc(GstAllocator *alloc, gsize size,
|
|
GstAllocationParams *params) {
|
|
g_warn_if_fail(params->prefix == 0);
|
|
g_warn_if_fail(params->padding == 0);
|
|
|
|
return (GstMemory *)_aja_memory_new_block(GST_AJA_ALLOCATOR(alloc),
|
|
params->flags, size, 0, size);
|
|
}
|
|
|
|
static void gst_aja_allocator_free(GstAllocator *alloc, GstMemory *mem) {
|
|
GstAjaMemory *dmem = (GstAjaMemory *)mem;
|
|
|
|
if (!mem->parent) {
|
|
GstAjaAllocator *aja_alloc = GST_AJA_ALLOCATOR(alloc);
|
|
|
|
GST_OBJECT_LOCK(aja_alloc);
|
|
while (gst_queue_array_get_length(aja_alloc->freed_mems) > 8) {
|
|
FreedMemory *fmem =
|
|
(FreedMemory *)gst_queue_array_pop_head_struct(aja_alloc->freed_mems);
|
|
|
|
GST_TRACE_OBJECT(
|
|
alloc, "Freeing cached memory of size %" G_GSIZE_FORMAT " at %p",
|
|
fmem->size, fmem->data);
|
|
aja_alloc->device->device->DMABufferUnlock((ULWord *)fmem->data,
|
|
fmem->size);
|
|
AJAMemory::FreeAligned(fmem->data);
|
|
}
|
|
|
|
FreedMemory fmem;
|
|
GST_TRACE_OBJECT(alloc,
|
|
"Caching freed memory of size %" G_GSIZE_FORMAT " at %p",
|
|
mem->maxsize, dmem->data);
|
|
fmem.data = dmem->data;
|
|
fmem.size = mem->size;
|
|
gst_queue_array_push_tail_struct(aja_alloc->freed_mems, &fmem);
|
|
GST_OBJECT_UNLOCK(aja_alloc);
|
|
}
|
|
|
|
g_free(dmem);
|
|
}
|
|
|
|
static void gst_aja_allocator_finalize(GObject *alloc) {
|
|
GstAjaAllocator *aja_alloc = GST_AJA_ALLOCATOR(alloc);
|
|
|
|
GST_DEBUG_OBJECT(alloc, "Freeing allocator");
|
|
|
|
FreedMemory *mem;
|
|
while ((mem = (FreedMemory *)gst_queue_array_pop_head_struct(
|
|
aja_alloc->freed_mems))) {
|
|
GST_TRACE_OBJECT(alloc, "Freeing cached memory at %p", mem->data);
|
|
aja_alloc->device->device->DMABufferUnlock((ULWord *)mem->data, mem->size);
|
|
AJAMemory::FreeAligned(mem->data);
|
|
}
|
|
|
|
gst_aja_ntv2_device_unref(aja_alloc->device);
|
|
|
|
G_OBJECT_CLASS(gst_aja_allocator_parent_class)->finalize(alloc);
|
|
}
|
|
|
|
static void gst_aja_allocator_class_init(GstAjaAllocatorClass *klass) {
|
|
GObjectClass *gobject_class;
|
|
GstAllocatorClass *allocator_class;
|
|
|
|
gobject_class = (GObjectClass *)klass;
|
|
allocator_class = (GstAllocatorClass *)klass;
|
|
|
|
gobject_class->finalize = gst_aja_allocator_finalize;
|
|
|
|
allocator_class->alloc = gst_aja_allocator_alloc;
|
|
allocator_class->free = gst_aja_allocator_free;
|
|
}
|
|
|
|
static void gst_aja_allocator_init(GstAjaAllocator *aja_alloc) {
|
|
GstAllocator *alloc = GST_ALLOCATOR_CAST(aja_alloc);
|
|
|
|
alloc->mem_type = GST_AJA_ALLOCATOR_MEMTYPE;
|
|
alloc->mem_map = (GstMemoryMapFunction)_aja_memory_map;
|
|
alloc->mem_unmap = (GstMemoryUnmapFunction)_aja_memory_unmap;
|
|
alloc->mem_copy = (GstMemoryCopyFunction)_aja_memory_copy;
|
|
alloc->mem_share = (GstMemoryShareFunction)_aja_memory_share;
|
|
}
|
|
|
|
GstAllocator *gst_aja_allocator_new(GstAjaNtv2Device *device) {
|
|
GstAjaAllocator *alloc =
|
|
(GstAjaAllocator *)g_object_new(GST_TYPE_AJA_ALLOCATOR, NULL);
|
|
|
|
alloc->device = gst_aja_ntv2_device_ref(device);
|
|
alloc->freed_mems = gst_queue_array_new_for_struct(sizeof(FreedMemory), 16);
|
|
|
|
GST_DEBUG_OBJECT(alloc, "Creating allocator for device %d",
|
|
device->device->GetIndexNumber());
|
|
|
|
return GST_ALLOCATOR(alloc);
|
|
}
|
|
|
|
GstAjaNtv2Device *gst_aja_ntv2_device_obtain(const gchar *device_identifier) {
|
|
CNTV2Device *device = new CNTV2Device();
|
|
|
|
if (!CNTV2DeviceScanner::GetFirstDeviceFromArgument(device_identifier,
|
|
*device)) {
|
|
delete device;
|
|
return NULL;
|
|
}
|
|
|
|
GstAjaNtv2Device *dev = g_atomic_rc_box_new0(GstAjaNtv2Device);
|
|
dev->device = device;
|
|
|
|
return dev;
|
|
}
|
|
|
|
GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device) {
|
|
return (GstAjaNtv2Device *)g_atomic_rc_box_acquire(device);
|
|
}
|
|
|
|
void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device) {
|
|
g_atomic_rc_box_release_full(device, [](gpointer data) {
|
|
GstAjaNtv2Device *dev = (GstAjaNtv2Device *)data;
|
|
|
|
delete dev->device;
|
|
});
|
|
}
|
|
|
|
static gpointer init_setup_mutex(gpointer data) {
|
|
sem_t *s = SEM_FAILED;
|
|
s = sem_open("/gstreamer-aja-sem", O_CREAT, S_IRUSR | S_IWUSR, 1);
|
|
if (s == SEM_FAILED) {
|
|
g_critical("Failed to create SHM semaphore for GStreamer AJA plugin: %s",
|
|
g_strerror(errno));
|
|
}
|
|
return s;
|
|
}
|
|
|
|
static sem_t *get_setup_mutex(void) {
|
|
static GOnce once = G_ONCE_INIT;
|
|
|
|
g_once(&once, init_setup_mutex, NULL);
|
|
|
|
return (sem_t *)once.retval;
|
|
}
|
|
|
|
ShmMutexLocker::ShmMutexLocker() {
|
|
sem_t *s = get_setup_mutex();
|
|
if (s != SEM_FAILED) sem_wait(s);
|
|
}
|
|
|
|
ShmMutexLocker::~ShmMutexLocker() {
|
|
sem_t *s = get_setup_mutex();
|
|
if (s != SEM_FAILED) sem_post(s);
|
|
}
|
|
|
|
static guint gst_aja_device_get_frame_multiplier(GstAjaNtv2Device *device,
|
|
NTV2Channel channel) {
|
|
// quad formats use 4x as many frames, quad-quad formats 8x
|
|
bool quad_enabled = false;
|
|
device->device->GetQuadFrameEnable(quad_enabled, channel);
|
|
bool quad_quad_enabled = false;
|
|
device->device->GetQuadQuadFrameEnable(quad_quad_enabled, channel);
|
|
|
|
NTV2VideoFormat format = NTV2_FORMAT_UNKNOWN;
|
|
device->device->GetVideoFormat(format, channel);
|
|
|
|
GST_TRACE("Channel %d uses mode %d (quad: %d, quad quad: %d)", (gint)channel,
|
|
(gint)format, quad_enabled, quad_quad_enabled);
|
|
|
|
// Similarly, 2k/UHD use 4x as many frames and 4k/UHD2 use 8x as many
|
|
// frames
|
|
if (format != NTV2_FORMAT_UNKNOWN) {
|
|
guint width = ::GetDisplayWidth(format);
|
|
guint height = ::GetDisplayHeight(format);
|
|
|
|
if (height <= 1080 && width <= 1920) {
|
|
// SD and HD but not 2k!
|
|
} else if (height <= 2160 && width <= 3840) {
|
|
// 2k and UHD but not 4k
|
|
quad_enabled = true;
|
|
} else if (height <= 4320 && width <= 7680) {
|
|
// 4k and UHD2 but not 8k
|
|
quad_quad_enabled = true;
|
|
} else {
|
|
// 8k FIXME
|
|
quad_quad_enabled = true;
|
|
}
|
|
}
|
|
|
|
if (quad_enabled) {
|
|
g_assert(!quad_quad_enabled);
|
|
|
|
return 4;
|
|
} else if (quad_quad_enabled) {
|
|
g_assert(!quad_enabled);
|
|
|
|
return 8;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Returns -1 on failure or otherwise the start_frame.
|
|
// end_frame would be start_frame + frame_count - 1
|
|
gint gst_aja_ntv2_device_find_unallocated_frames(GstAjaNtv2Device *device,
|
|
NTV2Channel channel,
|
|
guint frame_count) {
|
|
g_assert(frame_count != 0);
|
|
g_assert(device != NULL);
|
|
g_assert(device->device->IsOpen());
|
|
|
|
// Adapted from CNTV2Card::FindUnallocatedFrames() with
|
|
// quad/quad-quad/UHD/UHD2 support
|
|
std::set<guint16> used_frames;
|
|
|
|
for (NTV2Channel c = ::NTV2_CHANNEL1; c < NTV2_MAX_NUM_CHANNELS;
|
|
c = (NTV2Channel)(c + 1)) {
|
|
AUTOCIRCULATE_STATUS ac_status;
|
|
|
|
if (device->device->AutoCirculateGetStatus(c, ac_status) &&
|
|
!ac_status.IsStopped()) {
|
|
guint16 start_frame = ac_status.GetStartFrame();
|
|
guint16 end_frame = ac_status.GetEndFrame();
|
|
|
|
guint multiplier = gst_aja_device_get_frame_multiplier(device, c);
|
|
|
|
GST_TRACE("Channel %d uses frames %u-%u (multiplier: %u)", c, start_frame,
|
|
end_frame, multiplier);
|
|
|
|
start_frame *= multiplier;
|
|
end_frame *= multiplier;
|
|
end_frame += (multiplier - 1);
|
|
|
|
GST_TRACE("Channel %d uses HD frames %u-%u", c, start_frame, end_frame);
|
|
for (guint16 i = start_frame; i <= end_frame; i++) {
|
|
used_frames.insert(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
guint multiplier = gst_aja_device_get_frame_multiplier(device, channel);
|
|
frame_count *= multiplier;
|
|
|
|
const guint16 last_frame =
|
|
::NTV2DeviceGetNumberFrameBuffers(device->device->GetDeviceID()) - 1;
|
|
guint16 start_frame = 0;
|
|
guint16 end_frame = start_frame + frame_count - 1;
|
|
|
|
auto iter = used_frames.cbegin();
|
|
while (iter != used_frames.cend()) {
|
|
guint16 allocated_start_frame = *iter;
|
|
guint16 allocated_end_frame = allocated_start_frame;
|
|
|
|
// Find end of the allocation
|
|
while (++iter != used_frames.cend() && *iter == (allocated_end_frame + 1))
|
|
allocated_end_frame++;
|
|
|
|
// Free block before this allocation
|
|
if (start_frame < allocated_start_frame &&
|
|
end_frame < allocated_start_frame)
|
|
break;
|
|
|
|
// Move after this allocation and check if there is enough space before
|
|
// the next allocation
|
|
start_frame = GST_ROUND_UP_N(allocated_end_frame + 1, multiplier);
|
|
end_frame = start_frame + frame_count - 1;
|
|
}
|
|
|
|
// If above we moved after the end of the available frames error out
|
|
if (start_frame > last_frame || end_frame > last_frame) {
|
|
GST_WARNING("Did not find a contiguous unused range of %u frames",
|
|
frame_count);
|
|
return -1;
|
|
}
|
|
|
|
// Otherwise we have enough space after the last allocation
|
|
GST_INFO("Using HD frames %u-%u", start_frame, end_frame);
|
|
GST_INFO("Using frames %u-%u", start_frame / multiplier,
|
|
start_frame / multiplier + frame_count / multiplier - 1);
|
|
|
|
return start_frame / multiplier;
|
|
}
|
|
|
|
GType gst_aja_audio_system_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_AUDIO_SYSTEM_AUTO, "auto", "Auto (based on selected channel)"},
|
|
{GST_AJA_AUDIO_SYSTEM_1, "1", "Audio system 1"},
|
|
{GST_AJA_AUDIO_SYSTEM_2, "2", "Audio system 2"},
|
|
{GST_AJA_AUDIO_SYSTEM_3, "3", "Audio system 3"},
|
|
{GST_AJA_AUDIO_SYSTEM_4, "4", "Audio system 4"},
|
|
{GST_AJA_AUDIO_SYSTEM_5, "5", "Audio system 5"},
|
|
{GST_AJA_AUDIO_SYSTEM_6, "6", "Audio system 6"},
|
|
{GST_AJA_AUDIO_SYSTEM_7, "7", "Audio system 7"},
|
|
{GST_AJA_AUDIO_SYSTEM_8, "8", "Audio system 8"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaAudioSystem", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_output_destination_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_OUTPUT_DESTINATION_AUTO, "auto",
|
|
"Auto (based on selected channel)"},
|
|
{GST_AJA_OUTPUT_DESTINATION_ANALOG, "analog", "Analog Output"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI1, "sdi-1", "SDI Output 1"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI2, "sdi-2", "SDI Output 2"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI3, "sdi-3", "SDI Output 3"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI4, "sdi-4", "SDI Output 4"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI5, "sdi-5", "SDI Output 5"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI6, "sdi-6", "SDI Output 6"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI7, "sdi-7", "SDI Output 7"},
|
|
{GST_AJA_OUTPUT_DESTINATION_SDI8, "sdi-8", "SDI Output 8"},
|
|
{GST_AJA_OUTPUT_DESTINATION_HDMI, "hdmi", "HDMI Output"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaOutputDestination", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_reference_source_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_REFERENCE_SOURCE_AUTO, "auto", "Auto"},
|
|
{GST_AJA_REFERENCE_SOURCE_FREERUN, "freerun", "Freerun"},
|
|
{GST_AJA_REFERENCE_SOURCE_EXTERNAL, "external", "External"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_1, "input-1", "SDI Input 1"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_2, "input-2", "SDI Input 2"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_3, "input-3", "SDI Input 3"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_4, "input-4", "SDI Input 4"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_5, "input-5", "SDI Input 5"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_6, "input-6", "SDI Input 6"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_7, "input-7", "SDI Input 7"},
|
|
{GST_AJA_REFERENCE_SOURCE_INPUT_8, "input-8", "SDI Input 8"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaReferenceSource", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_input_source_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_INPUT_SOURCE_AUTO, "auto", "Auto (based on selected channel)"},
|
|
{GST_AJA_INPUT_SOURCE_ANALOG1, "analog-1", "Analog Input 1"},
|
|
{GST_AJA_INPUT_SOURCE_SDI1, "sdi-1", "SDI Input 1"},
|
|
{GST_AJA_INPUT_SOURCE_SDI2, "sdi-2", "SDI Input 2"},
|
|
{GST_AJA_INPUT_SOURCE_SDI3, "sdi-3", "SDI Input 3"},
|
|
{GST_AJA_INPUT_SOURCE_SDI4, "sdi-4", "SDI Input 4"},
|
|
{GST_AJA_INPUT_SOURCE_SDI5, "sdi-5", "SDI Input 5"},
|
|
{GST_AJA_INPUT_SOURCE_SDI6, "sdi-6", "SDI Input 6"},
|
|
{GST_AJA_INPUT_SOURCE_SDI7, "sdi-7", "SDI Input 7"},
|
|
{GST_AJA_INPUT_SOURCE_SDI8, "sdi-8", "SDI Input 8"},
|
|
{GST_AJA_INPUT_SOURCE_HDMI1, "hdmi-1", "HDMI Input 1"},
|
|
{GST_AJA_INPUT_SOURCE_HDMI2, "hdmi-2", "HDMI Input 2"},
|
|
{GST_AJA_INPUT_SOURCE_HDMI3, "hdmi-3", "HDMI Input 3"},
|
|
{GST_AJA_INPUT_SOURCE_HDMI4, "hdmi-4", "HDMI Input 4"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaInputSource", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
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[] = {
|
|
{GST_AJA_VIDEO_FORMAT_AUTO, "auto", "Auto detect format"},
|
|
{GST_AJA_VIDEO_FORMAT_1080i_5000, "1080i-5000", "1080i 5000"},
|
|
{GST_AJA_VIDEO_FORMAT_1080i_5994, "1080i-5994", "1080i 5994"},
|
|
{GST_AJA_VIDEO_FORMAT_1080i_6000, "1080i-6000", "1080i 6000"},
|
|
{GST_AJA_VIDEO_FORMAT_720p_5994, "720p-5994", "720p 5994"},
|
|
{GST_AJA_VIDEO_FORMAT_720p_6000, "720p-6000", "720p 6000"},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2398, "1080psf-2398", "1080psf 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2400, "1080psf-2400", "1080psf 2400"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_2997, "1080p-2997", "1080p 2997"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_3000, "1080p-3000", "1080p 3000"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_2500, "1080p-2500", "1080p 2500"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_2398, "1080p-2398", "1080p 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_2400, "1080p-2400", "1080p 2400"},
|
|
{GST_AJA_VIDEO_FORMAT_720p_5000, "720p-5000", "720p 5000"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_5000_A, "1080p-5000-a", "1080p 5000 A"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_5994_A, "1080p-5994-a", "1080p 5994 A"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_6000_A, "1080p-6000-a", "1080p 6000 A"},
|
|
{GST_AJA_VIDEO_FORMAT_720p_2398, "720p-2398", "720p 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_720p_2500, "720p-2500", "720p 2500"},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2500_2, "1080psf-2500-2", "1080psf 2500 2"},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_2997_2, "1080psf-2997-2", "1080psf 2997 2"},
|
|
{GST_AJA_VIDEO_FORMAT_1080psf_3000_2, "1080psf-3000-2", "1080psf 3000 2"},
|
|
|
|
{GST_AJA_VIDEO_FORMAT_625_5000, "625-5000", "625 5000"},
|
|
{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_1080p_DCI_2398, "1080p-dci-2398", "1080p DCI 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2400, "1080p-dci-2400", "1080p DCI 2400"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2500, "1080p-dci-2500", "1080p DCI 2500"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_2997, "1080p-dci-2997", "1080p DCI 2997"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_3000, "1080p-dci-3000", "1080p DCI 3000"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_5000_A, "1080p-dci-5000-a",
|
|
"1080p DCI 5000 A"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_5994_A, "1080p-dci-5994-a",
|
|
"1080p DCI 5994 A"},
|
|
{GST_AJA_VIDEO_FORMAT_1080p_DCI_6000_A, "1080p-dci-6000-a",
|
|
"1080p DCI 6000 A"},
|
|
|
|
{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_2160p_DCI_2398, "2160p-dci-2398", "2160p DCI 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2400, "2160p-dci-2400", "2160p DCI 2400"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2500, "2160p-dci-2500", "2160p DCI 2500"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_2997, "2160p-dci-2997", "2160p DCI 2997"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_3000, "2160p-dci-3000", "2160p DCI 3000"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_5000, "2160p-dci-5000", "2160p DCI 5000"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_5994, "2160p-dci-5994", "2160p DCI 5994"},
|
|
{GST_AJA_VIDEO_FORMAT_2160p_DCI_6000, "2160p-dci-6000", "2160p DCI 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"},
|
|
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2398, "4320p-dci-2398", "4320p DCI 2398"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2400, "4320p-dci-2400", "4320p DCI 2400"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2500, "4320p-dci-2500", "4320p DCI 2500"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_2997, "4320p-dci-2997", "4320p DCI 2997"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_3000, "4320p-dci-3000", "4320p DCI 3000"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_5000, "4320p-dci-5000", "4320p DCI 5000"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_5994, "4320p-dci-5994", "4320p DCI 5994"},
|
|
{GST_AJA_VIDEO_FORMAT_4320p_DCI_6000, "4320p-dci-6000", "4320p DCI 6000"},
|
|
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaVideoFormat", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_audio_source_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_AUDIO_SOURCE_EMBEDDED, "embedded", "Embedded"},
|
|
{GST_AJA_AUDIO_SOURCE_AES, "aes", "AES"},
|
|
{GST_AJA_AUDIO_SOURCE_ANALOG, "analog", "Analog"},
|
|
{GST_AJA_AUDIO_SOURCE_HDMI, "hdmi", "HDMI"},
|
|
{GST_AJA_AUDIO_SOURCE_MIC, "mic", "Microphone"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaAudioSource", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_embedded_audio_input_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_AUTO, "auto", "auto"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO1, "video-1", "Video 1"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO2, "video-2", "Video 2"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO3, "video-3", "Video 3"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO4, "video-4", "Video 4"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO5, "video-5", "Video 5"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO6, "video-6", "Video 6"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO7, "video-7", "Video 7"},
|
|
{GST_AJA_EMBEDDED_AUDIO_INPUT_VIDEO8, "video-8", "Video 8"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaEmbeddedAudioInput", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_timecode_index_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_TIMECODE_INDEX_VITC, "vitc", "Embedded SDI VITC"},
|
|
{GST_AJA_TIMECODE_INDEX_ATC_LTC, "atc-ltc", "Embedded SDI ATC LTC"},
|
|
{GST_AJA_TIMECODE_INDEX_LTC1, "ltc-1", "Analog LTC 1"},
|
|
{GST_AJA_TIMECODE_INDEX_LTC2, "ltc-2", "Analog LTC 2"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaTimecodeIndex", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
GType gst_aja_closed_caption_capture_mode_get_type(void) {
|
|
static gsize id = 0;
|
|
static const GEnumValue modes[] = {
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_AND_CEA608,
|
|
"cea708-and-cea608",
|
|
"CEA708 S334-2 and CEA608 S334-1 Annex A Closed Captions"},
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_OR_CEA608, "cea708-or-cea608",
|
|
"CEA708 S334-2 or if not existing CEA608 S334-1 Annex A Closed "
|
|
"Captions"},
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA608_OR_CEA708, "cea608-or-cea708",
|
|
"CEA608 S334-1 Annex A or if not existing CEA708 S334-2 Closed "
|
|
"Captions"},
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA708_ONLY, "cea708-only",
|
|
"CEA708 S334-2 Closed Captions only"},
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_CEA608_ONLY, "cea608-only",
|
|
"CEA608 S334-1 Annex A Closed Captions only"},
|
|
{GST_AJA_CLOSED_CAPTION_CAPTURE_MODE_NONE, "none",
|
|
"Don't capture Closed Captions"},
|
|
{0, NULL, NULL}};
|
|
|
|
if (g_once_init_enter(&id)) {
|
|
GType tmp = g_enum_register_static("GstAjaClosedCaptionCaptureMode", modes);
|
|
g_once_init_leave(&id, tmp);
|
|
}
|
|
|
|
return (GType)id;
|
|
}
|
|
|
|
void gst_aja_common_init(void) {
|
|
GST_DEBUG_CATEGORY_INIT(gst_aja_debug, "aja", 0,
|
|
"Debug category for AJA plugin");
|
|
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_AUDIO_SYSTEM, (GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_OUTPUT_DESTINATION,
|
|
(GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_REFERENCE_SOURCE,
|
|
(GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_INPUT_SOURCE, (GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_SDI_MODE, (GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_VIDEO_FORMAT, (GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_AUDIO_SOURCE, (GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_EMBEDDED_AUDIO_INPUT,
|
|
(GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_TIMECODE_INDEX,
|
|
(GstPluginAPIFlags)0);
|
|
gst_type_mark_as_plugin_api(GST_TYPE_AJA_CLOSED_CAPTION_CAPTURE_MODE,
|
|
(GstPluginAPIFlags)0);
|
|
}
|