【FFmpeg】自定义编码器适配

文章转移:https://cloud.tencent.com/developer/article/2389370























































































































1 编码流程

FFmpeg是一个开源的多媒体框架,底层可对接实现多种编解码器,下面参考文件doc/examples/encode_video.c分析编码一帧的流程

1.1 整体流程

统一的编码流程如下图所示
在这里插入图片描述
FFmpeg使用的是引用计数的思想,对于一块buffer,刚申请时引用计数为1,每有一个模块进行使用,引用计数加1,使用完毕后引用计数减1,当减为0时释放buffer。
此流程中需要关注buffer的分配,对于编码器来说,输入buffer是yuv,也就是上图中的frame,输出buffer是码流包,也就是上图中的pkt,下面对这两个buffer进行分析

  1. frame:这个结构体是由av_frame_alloc分配的,但这里并没有分配yuv的内存,yuv内存是av_frame_get_buffer分配的,可见这里输入buffer完全是来自外部的,不需要编码器来管理,编码器只需要根据所给的yuv地址来进行编码就行了
  2. pkt:这个结构体是由av_packet_alloc分配的,也没有分配码流包的内存,可见这里pkt仅仅是一个引用,pkt直接传到了avcodec_receive_packet接口进行编码,完成之后将pkt中码流的内容写到文件,最后调用av_packet_unref接口减引用计数,因此这里pkt是编码器内部分配的,分配完成之后会减pkt的引用计数加1,然后输出到外部,外部使用完毕之后再减引用计数来释放buffer

编码一帧的相关代码如下:

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *outfile)
{
   
    int ret;

    /* send the frame to the encoder */
    if (frame)
        printf("Send frame %3"PRId64"\n", frame->pts);

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
   
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }

    while (ret >= 0) {
   
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
   
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }

        printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
}

其中avcodec_receive_packet返回EAGAIN表示送下一帧,返回EOF表示编码器内部已经没有码流。

1.2 内部流程

此处分析编码一帧的内部流程,首先看FFmpeg内部编码器的上下文,其中有三个重要结构体

typedef struct AVCodecInternal {
   
	...
    /**
     * The input frame is stored here for encoders implementing the simple
     * encode API.
     *
     * Not allocated in other cases.
     */
    AVFrame *in_frame;

    /**
     * Temporary buffers for newly received or not yet output packets/frames.
     */
    AVPacket *buffer_pkt;
    AVFrame *buffer_frame;
    ...
} AVCodecInternal;

下面结合送帧和收流的接口进行介绍

  • avcodec_send_frame: 送帧接口,将yuv的帧信息赋值到buffer_frame,然后触发一帧编码,将编码出的码流赋值到buffer_pkt
  • avcodec_receive_packet: 收流接口,检查上下文中是否有已经编码好的码流buffer_pkt,如果有则将其返回,如果没有再触发一帧编码,将编码好的码流返回

可见send和receive接口均

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值