mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-23 06:26:23 +00:00
Read colorimetry information from VPID and create caps from detected input format
This does not implement automatic mode selection yet, for which it is necessary to change the routing at runtime based on the detected format. It is a first step into that direction though.
This commit is contained in:
parent
86920489f8
commit
99c86891a4
2 changed files with 105 additions and 21 deletions
111
gstajasrc.cpp
111
gstajasrc.cpp
|
@ -24,6 +24,7 @@
|
||||||
#include <ajaanc/includes/ancillarydata_cea708.h>
|
#include <ajaanc/includes/ancillarydata_cea708.h>
|
||||||
#include <ajaanc/includes/ancillarylist.h>
|
#include <ajaanc/includes/ancillarylist.h>
|
||||||
#include <ajantv2/includes/ntv2rp188.h>
|
#include <ajantv2/includes/ntv2rp188.h>
|
||||||
|
#include <ajantv2/includes/ntv2vpid.h>
|
||||||
|
|
||||||
#include "gstajacommon.h"
|
#include "gstajacommon.h"
|
||||||
#include "gstajasrc.h"
|
#include "gstajasrc.h"
|
||||||
|
@ -72,6 +73,9 @@ typedef struct {
|
||||||
GstBuffer *audio_buffer;
|
GstBuffer *audio_buffer;
|
||||||
GstBuffer *anc_buffer, *anc_buffer2;
|
GstBuffer *anc_buffer, *anc_buffer2;
|
||||||
NTV2_RP188 tc;
|
NTV2_RP188 tc;
|
||||||
|
|
||||||
|
NTV2VideoFormat detected_format;
|
||||||
|
guint32 vpid;
|
||||||
} QueueItem;
|
} QueueItem;
|
||||||
|
|
||||||
static void gst_aja_src_set_property(GObject *object, guint property_id,
|
static void gst_aja_src_set_property(GObject *object, guint property_id,
|
||||||
|
@ -447,10 +451,8 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_clear_caps(&self->configured_caps);
|
|
||||||
gst_video_info_from_ntv2_video_format(&self->configured_info,
|
gst_video_info_from_ntv2_video_format(&self->configured_info,
|
||||||
self->video_format);
|
self->video_format);
|
||||||
self->configured_caps = gst_video_info_to_caps(&self->configured_info);
|
|
||||||
|
|
||||||
if (self->quad_mode) {
|
if (self->quad_mode) {
|
||||||
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
|
if (self->input_source >= GST_AJA_INPUT_SOURCE_HDMI1 &&
|
||||||
|
@ -995,9 +997,6 @@ static gboolean gst_aja_src_start(GstAjaSrc *self) {
|
||||||
self->device->device->SetEmbeddedAudioClock(
|
self->device->device->SetEmbeddedAudioClock(
|
||||||
::NTV2_EMBEDDED_AUDIO_CLOCK_VIDEO_INPUT, self->audio_system);
|
::NTV2_EMBEDDED_AUDIO_CLOCK_VIDEO_INPUT, self->audio_system);
|
||||||
|
|
||||||
gst_caps_set_simple(self->configured_caps, "audio-channels", G_TYPE_INT,
|
|
||||||
self->configured_audio_channels, NULL);
|
|
||||||
|
|
||||||
NTV2ReferenceSource reference_source;
|
NTV2ReferenceSource reference_source;
|
||||||
switch (self->reference_source) {
|
switch (self->reference_source) {
|
||||||
case GST_AJA_REFERENCE_SOURCE_AUTO:
|
case GST_AJA_REFERENCE_SOURCE_AUTO:
|
||||||
|
@ -1137,7 +1136,8 @@ static gboolean gst_aja_src_stop(GstAjaSrc *self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK(self);
|
GST_OBJECT_LOCK(self);
|
||||||
gst_clear_caps(&self->configured_caps);
|
memset(&self->current_info, 0, sizeof(self->current_info));
|
||||||
|
memset(&self->configured_info, 0, sizeof(self->configured_info));
|
||||||
self->configured_audio_channels = 0;
|
self->configured_audio_channels = 0;
|
||||||
GST_OBJECT_UNLOCK(self);
|
GST_OBJECT_UNLOCK(self);
|
||||||
|
|
||||||
|
@ -1243,12 +1243,12 @@ static gboolean gst_aja_src_query(GstBaseSrc *bsrc, GstQuery *query) {
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE(query)) {
|
switch (GST_QUERY_TYPE(query)) {
|
||||||
case GST_QUERY_LATENCY: {
|
case GST_QUERY_LATENCY: {
|
||||||
if (self->configured_caps) {
|
if (self->current_info.finfo &&
|
||||||
|
self->current_info.finfo->format != GST_VIDEO_FORMAT_UNKNOWN) {
|
||||||
GstClockTime min, max;
|
GstClockTime min, max;
|
||||||
|
|
||||||
min = gst_util_uint64_scale_ceil(GST_SECOND,
|
min = gst_util_uint64_scale_ceil(
|
||||||
3 * self->configured_info.fps_d,
|
GST_SECOND, 3 * self->current_info.fps_d, self->current_info.fps_n);
|
||||||
self->configured_info.fps_n);
|
|
||||||
max = self->queue_size * min;
|
max = self->queue_size * min;
|
||||||
|
|
||||||
gst_query_set_latency(query, TRUE, min, max);
|
gst_query_set_latency(query, TRUE, min, max);
|
||||||
|
@ -1421,8 +1421,77 @@ static GstFlowReturn gst_aja_src_create(GstPushSrc *psrc, GstBuffer **buffer) {
|
||||||
|
|
||||||
// TODO: Add AFD/Bar meta
|
// TODO: Add AFD/Bar meta
|
||||||
|
|
||||||
if (!gst_pad_has_current_caps(GST_BASE_SRC_PAD(self))) {
|
bool caps_changed = false;
|
||||||
gst_base_src_set_caps(GST_BASE_SRC_CAST(self), self->configured_caps);
|
|
||||||
|
CNTV2VPID vpid(item.vpid);
|
||||||
|
if (vpid.IsValid()) {
|
||||||
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
if (gst_video_info_from_ntv2_video_format(&info, item.detected_format)) {
|
||||||
|
switch (vpid.GetTransferCharacteristics()) {
|
||||||
|
default:
|
||||||
|
case NTV2_VPID_TC_SDR_TV:
|
||||||
|
// SDR is the default, do nothing here.
|
||||||
|
break;
|
||||||
|
case NTV2_VPID_TC_HLG:
|
||||||
|
info.colorimetry.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67;
|
||||||
|
break;
|
||||||
|
case NTV2_VPID_TC_PQ:
|
||||||
|
info.colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (vpid.GetColorimetry()) {
|
||||||
|
case NTV2_VPID_Color_Rec709:
|
||||||
|
info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
|
||||||
|
info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
|
||||||
|
break;
|
||||||
|
case NTV2_VPID_Color_UHDTV:
|
||||||
|
info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
|
||||||
|
info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Default handling
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (vpid.GetRGBRange()) {
|
||||||
|
case NTV2_VPID_Range_Full:
|
||||||
|
info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
|
||||||
|
break;
|
||||||
|
case NTV2_VPID_Range_Narrow:
|
||||||
|
info.colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_pad_has_current_caps(GST_BASE_SRC_PAD(self)) ||
|
||||||
|
!gst_video_info_is_equal(&info, &self->current_info)) {
|
||||||
|
self->current_info = info;
|
||||||
|
caps_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GstVideoInfo info;
|
||||||
|
|
||||||
|
if (gst_video_info_from_ntv2_video_format(&info, item.detected_format)) {
|
||||||
|
if (!gst_pad_has_current_caps(GST_BASE_SRC_PAD(self)) ||
|
||||||
|
!gst_video_info_is_equal(&info, &self->current_info)) {
|
||||||
|
self->current_info = info;
|
||||||
|
caps_changed = true;
|
||||||
|
}
|
||||||
|
} else if (!gst_pad_has_current_caps(GST_BASE_SRC_PAD(self))) {
|
||||||
|
self->current_info = self->configured_info;
|
||||||
|
caps_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps_changed) {
|
||||||
|
GstCaps *caps = gst_video_info_to_caps(&self->current_info);
|
||||||
|
gst_caps_set_simple(caps, "audio-channels", G_TYPE_INT,
|
||||||
|
self->configured_audio_channels, NULL);
|
||||||
|
GST_DEBUG_OBJECT(self, "Configuring caps %" GST_PTR_FORMAT, caps);
|
||||||
|
gst_base_src_set_caps(GST_BASE_SRC_CAST(self), caps);
|
||||||
|
gst_caps_unref(caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
return flow_ret;
|
return flow_ret;
|
||||||
|
@ -1516,6 +1585,15 @@ restart:
|
||||||
NTV2VideoFormat current_video_format =
|
NTV2VideoFormat current_video_format =
|
||||||
self->device->device->GetInputVideoFormat(
|
self->device->device->GetInputVideoFormat(
|
||||||
self->configured_input_source);
|
self->configured_input_source);
|
||||||
|
|
||||||
|
ULWord vpid_a = 0;
|
||||||
|
ULWord vpid_b = 0;
|
||||||
|
self->device->device->ReadSDIInVPID(self->channel, vpid_a, vpid_b);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT(self,
|
||||||
|
"Detected input video format %u with VPID %08x / %08x",
|
||||||
|
current_video_format, vpid_a, vpid_b);
|
||||||
|
|
||||||
NTV2VideoFormat effective_video_format = self->video_format;
|
NTV2VideoFormat effective_video_format = self->video_format;
|
||||||
// Can't call this unconditionally as it also maps e.g. 3840x2160p to 1080p
|
// Can't call this unconditionally as it also maps e.g. 3840x2160p to 1080p
|
||||||
if (self->quad_mode) {
|
if (self->quad_mode) {
|
||||||
|
@ -1729,13 +1807,18 @@ restart:
|
||||||
|
|
||||||
// TODO: Drift detection and compensation
|
// TODO: Drift detection and compensation
|
||||||
|
|
||||||
QueueItem item = {.type = QUEUE_ITEM_TYPE_FRAME,
|
QueueItem item = {
|
||||||
|
.type = QUEUE_ITEM_TYPE_FRAME,
|
||||||
.capture_time = now_gst,
|
.capture_time = now_gst,
|
||||||
.video_buffer = video_buffer,
|
.video_buffer = video_buffer,
|
||||||
.audio_buffer = audio_buffer,
|
.audio_buffer = audio_buffer,
|
||||||
.anc_buffer = anc_buffer,
|
.anc_buffer = anc_buffer,
|
||||||
.anc_buffer2 = anc_buffer2,
|
.anc_buffer2 = anc_buffer2,
|
||||||
.tc = time_code};
|
.tc = time_code,
|
||||||
|
.detected_format =
|
||||||
|
(self->quad_mode ? ::GetQuadSizedVideoFormat(current_video_format)
|
||||||
|
: current_video_format),
|
||||||
|
.vpid = vpid_a};
|
||||||
|
|
||||||
while (gst_queue_array_get_length(self->queue) >= self->queue_size) {
|
while (gst_queue_array_get_length(self->queue) >= self->queue_size) {
|
||||||
QueueItem *tmp =
|
QueueItem *tmp =
|
||||||
|
|
|
@ -79,8 +79,9 @@ struct _GstAjaSrc {
|
||||||
NTV2InputSource configured_input_source;
|
NTV2InputSource configured_input_source;
|
||||||
NTV2TCIndex tc_index;
|
NTV2TCIndex tc_index;
|
||||||
|
|
||||||
GstCaps *configured_caps;
|
GstVideoInfo configured_info; // Based on properties
|
||||||
GstVideoInfo configured_info;
|
GstVideoInfo current_info; // Based on properties + stream metadata
|
||||||
|
|
||||||
gint configured_audio_channels;
|
gint configured_audio_channels;
|
||||||
|
|
||||||
AJAThread *capture_thread;
|
AJAThread *capture_thread;
|
||||||
|
|
Loading…
Reference in a new issue