当前位置:   article > 正文

【FFmpeg】自定义编码器适配_ffcodec

ffcodec

文章转移: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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

其中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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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

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

可见send和receive接口均

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/446361
推荐阅读
相关标签
  

闽ICP备14008679号