av_buffersrc_add_frame_flags() 函数分析

------------------------------------------------------------
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(&copy);
            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)];
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值