------------------------------------------------------------
author: hjjdebug
date: 2024年 08月 09日 星期五 14:24:06 CST
description: av_buffersrc_add_frame_flags() 函数分析
------------------------------------------------------------
av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF)
这个函数是比较简单的,
就是把frame拷贝后(引用加1)av_frame_ref()
添加到buffersrc_ctx 的FrameQueue上就完事了. ff_filter_frame()
代码分析:
int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
{
AVFrame *copy;
if (!(copy = av_frame_alloc())) //这个只分配了一个frame头部,536字节
return AVERROR(ENOMEM);
if (refcounted && !(flags & AV_BUFFERSRC_FLAG_KEEP_REF)) {
av_frame_move_ref(copy, frame);
} else { // 下面是保留引用代码
//把传来的frame拷贝一份引用, 只需分配24*3 个bytes
//为什么这么少? 因为一个av_buffer_ref 才需要24字节(2个指针,一个长度)
//乘以3是因为一个frame保留有Y,U,V三个平面的数据,所以需构造3个ref,而不用构造3个大大的缓冲
ret = av_frame_ref(copy, frame);
if (ret < 0) {
av_frame_free(©);
return ret;
}
}
//ctx->outputs[0] 是一个AVFilterLink*
ret = ff_filter_frame(ctx->outputs[0], copy); //把拷贝的frame转移到ctx->outputs[0]
if (ret < 0) return ret;
if ((flags & AV_BUFFERSRC_FLAG_PUSH)) { // 这里不需要push
ret = push_frame(ctx->graph);
if (ret < 0)
return ret;
}
return 0;
}
//更新一下link 参数,并添加到link->fifo, link->fifo是一个FrameQueue
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
{
int ret;
link->frame_blocked_in = link->frame_wanted_out = 0;
link->frame_count_in++;
filter_unblock(link->dst);
ret = ff_framequeue_add(&link->fifo, frame); //把frame 加入FrameQueue
if (ret < 0) {
av_frame_free(&frame);
return ret;
}
ff_filter_set_ready(link->dst, 300);
return 0;
}
//FrameQueue 概念介绍
//FrameQueue 当然有一些必要的成员,记录queue的一些状态和行为,根据操作过程予以更新.
//FFFrameQueue 的结构我嫌它长,没有copy, 你可以参考libavfilter/framequeue.h
//但它的概念可以通过使用来体会.
//fq->queue 是FFFrameBucket*, 与fq->allocated 构成一个环形缓冲.
//fq->queued ,已经分配的queue中使用的个数
//fq->tail ,队列的尾巴.
//不妨看一个framequeue 的实例
(gdb) p *fq
$3 = {
queue = 0x4dad90,
allocated = 1,
tail = 0,
queued = 0,
first_bucket = {
frame = 0x4cb940
},
total_frames_head = 2,
total_frames_tail = 2,
total_samples_head = 0,
total_samples_tail = 0,
samples_skipped = 0
}
FFFrameBucket 是什么? 它就用来存储一个指针.
typedef struct FFFrameBucket {
AVFrame *frame;
} FFFrameBucket;
//下面看FrameQueue 的添加过程
int ff_framequeue_add(FFFrameQueue *fq, AVFrame *frame)
{
if (fq->queued == fq->allocated) {
if (fq->allocated == 1) {
size_t na = 8;
FFFrameBucket *nq = av_realloc_array(NULL, na, sizeof(*nq));
if (!nq)
return AVERROR(ENOMEM);
nq[0] = fq->queue[0];
fq->queue = nq;
fq->allocated = na;
} else {
size_t na = fq->allocated << 1;
FFFrameBucket *nq = av_realloc_array(fq->queue, na, sizeof(*nq));
if (!nq)
return AVERROR(ENOMEM);
if (fq->tail + fq->queued > fq->allocated)
memmove(nq + fq->allocated, nq,
(fq->tail + fq->queued - fq->allocated) * sizeof(*nq));
fq->queue = nq;
fq->allocated = na;
}
}
FFFrameBucket *b = bucket(fq, fq->queued); //FrameQueue 中还有一个FrameBuchet概念
b->frame = frame;
fq->queued++;
fq->total_frames_head++;
fq->total_samples_head += frame->nb_samples;
return 0;
}
static inline FFFrameBucket *bucket(FFFrameQueue *fq, size_t idx)
{
return &fq->queue[(fq->tail + idx) & (fq->allocated - 1)];
}