avfilter/framepool: stack-allocate FFFramePool

Saves a pointless free/alloc cycle on reinit. For the vast majority of filter
links, this going to be allocated anyway; and on the occasions that it's not,
the waste is marginal.

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas
2026-03-29 17:10:40 +02:00
parent a2ca55c563
commit fe2691b3bb
5 changed files with 77 additions and 84 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
link->format, align) < 0)
return NULL;
frame = ff_frame_pool_get(li->frame_pool);
frame = ff_frame_pool_get(&li->frame_pool);
if (!frame)
return NULL;
+5 -1
View File
@@ -29,12 +29,16 @@
#include "avfilter.h"
#include "filters.h"
#include "framepool.h"
#include "framequeue.h"
typedef struct FilterLinkInternal {
FilterLink l;
struct FFFramePool *frame_pool;
/**
* Pool of frames used for allocations.
*/
FFFramePool frame_pool;
/**
* Queue of frames waiting to be filtered.
+63 -72
View File
@@ -28,21 +28,19 @@
#include "libavutil/mem.h"
#include "libavutil/pixfmt.h"
static av_cold FFFramePool *frame_pool_video_init(int width, int height,
enum AVPixelFormat format,
int align)
static av_cold int frame_pool_video_init(int width, int height,
enum AVPixelFormat format,
int align, FFFramePool *pool)
{
int ret;
FFFramePool *pool = av_mallocz(sizeof(FFFramePool));
if (!pool)
return NULL;
pool->type = AVMEDIA_TYPE_VIDEO;
pool->width = width;
pool->height = height;
pool->pix_fmt = format;
pool->align = align;
*pool = (FFFramePool) {
.type = AVMEDIA_TYPE_VIDEO,
.width = width,
.height = height,
.pix_fmt = format,
.align = align,
};
if ((ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL)) < 0)
goto fail;
@@ -60,11 +58,11 @@ static av_cold FFFramePool *frame_pool_video_init(int width, int height,
linesizes[i] = pool->linesize[i];
size_t sizes[4];
if (av_image_fill_plane_sizes(sizes, pool->pix_fmt,
FFALIGN(pool->height, align),
linesizes) < 0) {
ret = av_image_fill_plane_sizes(sizes, pool->pix_fmt,
FFALIGN(pool->height, align),
linesizes);
if (ret < 0)
goto fail;
}
for (int i = 0; i < 4 && sizes[i]; i++) {
if (sizes[i] > SIZE_MAX - align)
@@ -73,53 +71,58 @@ static av_cold FFFramePool *frame_pool_video_init(int width, int height,
CONFIG_MEMORY_POISONING
? NULL
: av_buffer_allocz);
if (!pool->pools[i])
if (!pool->pools[i]) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
return pool;
return 0;
fail:
ff_frame_pool_uninit(&pool);
return NULL;
ff_frame_pool_uninit(pool);
return ret;
}
static av_cold FFFramePool *frame_pool_audio_init(int channels, int nb_samples,
enum AVSampleFormat format,
int align)
static av_cold int frame_pool_audio_init(int channels, int nb_samples,
enum AVSampleFormat format,
int align, FFFramePool *pool)
{
int ret;
FFFramePool *pool = av_mallocz(sizeof(FFFramePool));
if (!pool)
return NULL;
int planar = av_sample_fmt_is_planar(format);
pool->type = AVMEDIA_TYPE_AUDIO;
pool->planes = planar ? channels : 1;
pool->channels = channels;
pool->nb_samples = nb_samples;
pool->sample_fmt = format;
pool->align = align;
*pool = (FFFramePool) {
.type = AVMEDIA_TYPE_AUDIO,
.planes = planar ? channels : 1,
.channels = channels,
.nb_samples = nb_samples,
.sample_fmt = format,
.align = align,
};
ret = av_samples_get_buffer_size(&pool->linesize[0], channels,
nb_samples, format, 0);
if (ret < 0)
goto fail;
if (pool->linesize[0] > SIZE_MAX - align)
if (pool->linesize[0] > SIZE_MAX - align) {
ret = AVERROR(EINVAL);
goto fail;
}
pool->pools[0] = av_buffer_pool_init(pool->linesize[0] + align,
av_buffer_allocz);
if (!pool->pools[0])
if (!pool->pools[0]) {
ret = AVERROR(ENOMEM);
goto fail;
}
return pool;
return 0;
fail:
ff_frame_pool_uninit(&pool);
return NULL;
ff_frame_pool_uninit(pool);
return ret;
}
AVFrame *ff_frame_pool_get(FFFramePool *pool)
@@ -209,65 +212,53 @@ fail:
return NULL;
}
av_cold void ff_frame_pool_uninit(FFFramePool **pool)
av_cold void ff_frame_pool_uninit(FFFramePool *pool)
{
if (!*pool)
if (!pool->type)
return;
for (int i = 0; i < 4; i++)
av_buffer_pool_uninit(&(*pool)->pools[i]);
av_buffer_pool_uninit(&pool->pools[i]);
av_freep(pool);
memset(pool, 0, sizeof(*pool));
}
int ff_frame_pool_video_reinit(FFFramePool **pool,
int ff_frame_pool_video_reinit(FFFramePool *pool,
int width,
int height,
enum AVPixelFormat format,
int align)
{
FFFramePool *cur = *pool;
if (cur && cur->pix_fmt == format &&
FFALIGN(cur->width, cur->align) == FFALIGN(width, align) &&
FFALIGN(cur->height, cur->align) == FFALIGN(height, align) &&
cur->align == align)
if (pool->type == AVMEDIA_TYPE_VIDEO &&
pool->pix_fmt == format &&
FFALIGN(pool->width, pool->align) == FFALIGN(width, align) &&
FFALIGN(pool->height, pool->align) == FFALIGN(height, align) &&
pool->align == align)
{
av_assert1(cur->type == AVMEDIA_TYPE_VIDEO);
cur->width = width;
cur->height = height;
pool->width = width;
pool->height = height;
return 0;
}
FFFramePool *new = frame_pool_video_init(width, height, format, align);
if (!new)
return AVERROR(ENOMEM);
*pool = new;
ff_frame_pool_uninit(&cur);
return 0;
ff_frame_pool_uninit(pool);
return frame_pool_video_init(width, height, format, align, pool);
}
int ff_frame_pool_audio_reinit(FFFramePool **pool,
int ff_frame_pool_audio_reinit(FFFramePool *pool,
int channels,
int nb_samples,
enum AVSampleFormat format,
int align)
{
FFFramePool *cur = *pool;
if (cur && cur->sample_fmt == format &&
cur->channels == channels &&
cur->nb_samples == nb_samples &&
cur->align == align)
if (pool->type == AVMEDIA_TYPE_AUDIO &&
pool->sample_fmt == format &&
pool->channels == channels &&
pool->nb_samples == nb_samples &&
pool->align == align)
{
av_assert1(cur->type == AVMEDIA_TYPE_AUDIO);
return 0;
}
FFFramePool *new = frame_pool_audio_init(channels, nb_samples, format, align);
if (!new)
return AVERROR(ENOMEM);
*pool = new;
ff_frame_pool_uninit(&cur);
return 0;
ff_frame_pool_uninit(pool);
return frame_pool_audio_init(channels, nb_samples, format, align, pool);
}
+7 -9
View File
@@ -26,7 +26,7 @@
#include "libavutil/internal.h"
/**
* Frame pool. This structure must be allocated with
* Frame pool. This structure must be initialized with
* ff_frame_pool_{video,audio}_reinit() and freed with ff_frame_pool_uninit().
*/
typedef struct FFFramePool {
@@ -58,15 +58,14 @@ typedef struct FFFramePool {
* provided configuration. If initialization fails, the old pool is kept
* unchanged.
*
* @param pool pointer to the frame pool to be reinitialized, or a pointer to
* NULL to create a new pool.
* @param pool pointer to the frame pool to be (re)initialized
* @param width width of each frame in this pool
* @param height height of each frame in this pool
* @param format format of each frame in this pool
* @param align buffers alignment of each frame in this pool
* @return 0 on success, a negative AVERROR otherwise.
*/
int ff_frame_pool_video_reinit(FFFramePool **pool,
int ff_frame_pool_video_reinit(FFFramePool *pool,
int width,
int height,
enum AVPixelFormat format,
@@ -77,15 +76,14 @@ int ff_frame_pool_video_reinit(FFFramePool **pool,
* provided configuration. If initialization fails, the old pool is kept
* unchanged.
*
* @param pool pointer to the frame pool to be reinitialized, or a pointer to
* NULL to create a new pool.
* @param pool pointer to the frame pool to be (re)initialized
* @param channels channels of each frame in this pool
* @param nb_samples number of samples of each frame in this pool
* @param format format of each frame in this pool
* @param align buffers alignment of each frame in this pool
* @return 0 on success, a negative AVERROR otherwise.
*/
int ff_frame_pool_audio_reinit(FFFramePool **pool,
int ff_frame_pool_audio_reinit(FFFramePool *pool,
int channels,
int nb_samples,
enum AVSampleFormat format,
@@ -95,9 +93,9 @@ int ff_frame_pool_audio_reinit(FFFramePool **pool,
* Deallocate the frame pool. It is safe to call this function while
* some of the allocated frame are still in use.
*
* @param pool pointer to the frame pool to be freed. It will be set to NULL.
* @param pool pointer to the frame pool to be uninitialized
*/
void ff_frame_pool_uninit(FFFramePool **pool);
void ff_frame_pool_uninit(FFFramePool *pool);
/**
* Allocate a new AVFrame, reusing old buffers from the pool when available.
+1 -1
View File
@@ -69,7 +69,7 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig
if (ff_frame_pool_video_reinit(&li->frame_pool, w, h, link->format, align) < 0)
return NULL;
frame = ff_frame_pool_get(li->frame_pool);
frame = ff_frame_pool_get(&li->frame_pool);
if (!frame)
return NULL;