mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-07 19:22:15 +00:00
Implement hopefully working dynamic framebuffer assignments
We try to allocate as many frames as were configured by looking for a big enough range of unused contiguous frames while taking the configured modes into account.
This commit is contained in:
parent
bfdf93ecd1
commit
484cb51445
4 changed files with 164 additions and 15 deletions
128
gstajacommon.cpp
128
gstajacommon.cpp
|
@ -684,6 +684,134 @@ ShmMutexLocker::~ShmMutexLocker() {
|
||||||
if (s != SEM_FAILED) sem_post(s);
|
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) {
|
GType gst_aja_audio_system_get_type(void) {
|
||||||
static gsize id = 0;
|
static gsize id = 0;
|
||||||
static const GEnumValue modes[] = {
|
static const GEnumValue modes[] = {
|
||||||
|
|
|
@ -65,6 +65,11 @@ GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device);
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device);
|
void gst_aja_ntv2_device_unref(GstAjaNtv2Device *device);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
gint gst_aja_ntv2_device_find_unallocated_frames(GstAjaNtv2Device *device,
|
||||||
|
NTV2Channel channel,
|
||||||
|
guint frame_count);
|
||||||
|
|
||||||
#define GST_AJA_ALLOCATOR_MEMTYPE "aja"
|
#define GST_AJA_ALLOCATOR_MEMTYPE "aja"
|
||||||
|
|
||||||
#define GST_TYPE_AJA_ALLOCATOR (gst_aja_allocator_get_type())
|
#define GST_TYPE_AJA_ALLOCATOR (gst_aja_allocator_get_type())
|
||||||
|
|
|
@ -1737,13 +1737,22 @@ restart:
|
||||||
guint16 start_frame = self->start_frame;
|
guint16 start_frame = self->start_frame;
|
||||||
guint16 end_frame = self->end_frame;
|
guint16 end_frame = self->end_frame;
|
||||||
|
|
||||||
// If nothing was configured, work with a number of frames that is half
|
// If both are the same, try to find queue_size/2 unallocated frames and
|
||||||
// the queue size and assume that all other channels work the same.
|
// use those.
|
||||||
if (start_frame == end_frame) {
|
if (start_frame == end_frame) {
|
||||||
guint16 num_frames = self->queue_size / 2;
|
guint16 num_frames = self->queue_size / 2;
|
||||||
|
|
||||||
start_frame = self->channel * num_frames;
|
gint assigned_start_frame = gst_aja_ntv2_device_find_unallocated_frames(
|
||||||
end_frame = (self->channel + 1) * num_frames - 1;
|
self->device, self->channel, num_frames);
|
||||||
|
|
||||||
|
if (assigned_start_frame == -1) {
|
||||||
|
GST_ELEMENT_ERROR(self, STREAM, FAILED, (NULL),
|
||||||
|
("Failed to allocate %u frames", num_frames));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_frame = assigned_start_frame;
|
||||||
|
end_frame = start_frame + num_frames - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT(
|
GST_DEBUG_OBJECT(
|
||||||
|
|
|
@ -42,8 +42,8 @@ GST_DEBUG_CATEGORY_STATIC(gst_aja_src_debug);
|
||||||
#define DEFAULT_TIMECODE_INDEX (GST_AJA_TIMECODE_INDEX_VITC)
|
#define DEFAULT_TIMECODE_INDEX (GST_AJA_TIMECODE_INDEX_VITC)
|
||||||
#define DEFAULT_REFERENCE_SOURCE (GST_AJA_REFERENCE_SOURCE_FREERUN)
|
#define DEFAULT_REFERENCE_SOURCE (GST_AJA_REFERENCE_SOURCE_FREERUN)
|
||||||
#define DEFAULT_QUEUE_SIZE (16)
|
#define DEFAULT_QUEUE_SIZE (16)
|
||||||
#define DEFAULT_START_FRAME (0)
|
#define DEFAULT_START_FRAME (8)
|
||||||
#define DEFAULT_END_FRAME (0)
|
#define DEFAULT_END_FRAME (8)
|
||||||
#define DEFAULT_CAPTURE_CPU_CORE (G_MAXUINT)
|
#define DEFAULT_CAPTURE_CPU_CORE (G_MAXUINT)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -156,8 +156,8 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) {
|
||||||
gobject_class, PROP_START_FRAME,
|
gobject_class, PROP_START_FRAME,
|
||||||
g_param_spec_uint(
|
g_param_spec_uint(
|
||||||
"start-frame", "Start Frame",
|
"start-frame", "Start Frame",
|
||||||
"Start frame buffer to be used for capturing (auto if same number as "
|
"Start frame buffer to be used for capturing (automatically assign "
|
||||||
"end-frame).",
|
"that many frames if same number as end-frame).",
|
||||||
0, G_MAXINT, DEFAULT_START_FRAME,
|
0, G_MAXINT, DEFAULT_START_FRAME,
|
||||||
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
|
@ -165,8 +165,8 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) {
|
||||||
gobject_class, PROP_END_FRAME,
|
gobject_class, PROP_END_FRAME,
|
||||||
g_param_spec_uint(
|
g_param_spec_uint(
|
||||||
"end-frame", "End Frame",
|
"end-frame", "End Frame",
|
||||||
"End frame buffer to be used for capturing (auto if same number as "
|
"End frame buffer to be used for capturing (automatically assign "
|
||||||
"start-frame).",
|
"that many frames if same number as start-frame).",
|
||||||
0, G_MAXINT, DEFAULT_END_FRAME,
|
0, G_MAXINT, DEFAULT_END_FRAME,
|
||||||
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
|
@ -1781,13 +1781,20 @@ restart:
|
||||||
guint16 start_frame = self->start_frame;
|
guint16 start_frame = self->start_frame;
|
||||||
guint16 end_frame = self->end_frame;
|
guint16 end_frame = self->end_frame;
|
||||||
|
|
||||||
// If nothing was configured, work with 8 frames and assume that all
|
// If both are set to the same value, try to find that many unallocated
|
||||||
// other channels work the same.
|
// frames and use those.
|
||||||
if (start_frame == end_frame) {
|
if (start_frame == end_frame) {
|
||||||
const guint16 num_frames = 8;
|
gint assigned_start_frame = gst_aja_ntv2_device_find_unallocated_frames(
|
||||||
|
self->device, self->channel, self->start_frame);
|
||||||
|
|
||||||
start_frame = self->channel * num_frames;
|
if (assigned_start_frame == -1) {
|
||||||
end_frame = (self->channel + 1) * num_frames - 1;
|
GST_ELEMENT_ERROR(self, STREAM, FAILED, (NULL),
|
||||||
|
("Failed to allocate %u frames", start_frame));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_frame = assigned_start_frame;
|
||||||
|
end_frame = start_frame + self->start_frame - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT(
|
GST_DEBUG_OBJECT(
|
||||||
|
|
Loading…
Reference in a new issue