mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-31 19:42:26 +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);
|
||||
}
|
||||
|
||||
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[] = {
|
||||
|
|
|
@ -65,6 +65,11 @@ GstAjaNtv2Device *gst_aja_ntv2_device_ref(GstAjaNtv2Device *device);
|
|||
G_GNUC_INTERNAL
|
||||
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_TYPE_AJA_ALLOCATOR (gst_aja_allocator_get_type())
|
||||
|
|
|
@ -1737,13 +1737,22 @@ restart:
|
|||
guint16 start_frame = self->start_frame;
|
||||
guint16 end_frame = self->end_frame;
|
||||
|
||||
// If nothing was configured, work with a number of frames that is half
|
||||
// the queue size and assume that all other channels work the same.
|
||||
// If both are the same, try to find queue_size/2 unallocated frames and
|
||||
// use those.
|
||||
if (start_frame == end_frame) {
|
||||
guint16 num_frames = self->queue_size / 2;
|
||||
|
||||
start_frame = self->channel * num_frames;
|
||||
end_frame = (self->channel + 1) * num_frames - 1;
|
||||
gint assigned_start_frame = gst_aja_ntv2_device_find_unallocated_frames(
|
||||
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(
|
||||
|
|
|
@ -42,8 +42,8 @@ GST_DEBUG_CATEGORY_STATIC(gst_aja_src_debug);
|
|||
#define DEFAULT_TIMECODE_INDEX (GST_AJA_TIMECODE_INDEX_VITC)
|
||||
#define DEFAULT_REFERENCE_SOURCE (GST_AJA_REFERENCE_SOURCE_FREERUN)
|
||||
#define DEFAULT_QUEUE_SIZE (16)
|
||||
#define DEFAULT_START_FRAME (0)
|
||||
#define DEFAULT_END_FRAME (0)
|
||||
#define DEFAULT_START_FRAME (8)
|
||||
#define DEFAULT_END_FRAME (8)
|
||||
#define DEFAULT_CAPTURE_CPU_CORE (G_MAXUINT)
|
||||
|
||||
enum {
|
||||
|
@ -156,8 +156,8 @@ static void gst_aja_src_class_init(GstAjaSrcClass *klass) {
|
|||
gobject_class, PROP_START_FRAME,
|
||||
g_param_spec_uint(
|
||||
"start-frame", "Start Frame",
|
||||
"Start frame buffer to be used for capturing (auto if same number as "
|
||||
"end-frame).",
|
||||
"Start frame buffer to be used for capturing (automatically assign "
|
||||
"that many frames if same number as end-frame).",
|
||||
0, G_MAXINT, DEFAULT_START_FRAME,
|
||||
(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,
|
||||
g_param_spec_uint(
|
||||
"end-frame", "End Frame",
|
||||
"End frame buffer to be used for capturing (auto if same number as "
|
||||
"start-frame).",
|
||||
"End frame buffer to be used for capturing (automatically assign "
|
||||
"that many frames if same number as start-frame).",
|
||||
0, G_MAXINT, DEFAULT_END_FRAME,
|
||||
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
|
@ -1781,13 +1781,20 @@ restart:
|
|||
guint16 start_frame = self->start_frame;
|
||||
guint16 end_frame = self->end_frame;
|
||||
|
||||
// If nothing was configured, work with 8 frames and assume that all
|
||||
// other channels work the same.
|
||||
// If both are set to the same value, try to find that many unallocated
|
||||
// frames and use those.
|
||||
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;
|
||||
end_frame = (self->channel + 1) * num_frames - 1;
|
||||
if (assigned_start_frame == -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(
|
||||
|
|
Loading…
Reference in a new issue