赞
踩
文章转移:https://cloud.tencent.com/developer/article/2389370
FFmpeg是一个开源的多媒体框架,底层可对接实现多种编解码器,下面参考文件doc/examples/encode_video.c
分析编码一帧的流程
统一的编码流程如下图所示
FFmpeg使用的是引用计数的思想,对于一块buffer,刚申请时引用计数为1,每有一个模块进行使用,引用计数加1,使用完毕后引用计数减1,当减为0时释放buffer。
此流程中需要关注buffer的分配,对于编码器来说,输入buffer是yuv,也就是上图中的frame,输出buffer是码流包,也就是上图中的pkt,下面对这两个buffer进行分析
av_frame_alloc
分配的,但这里并没有分配yuv的内存,yuv内存是av_frame_get_buffer
分配的,可见这里输入buffer完全是来自外部的,不需要编码器来管理,编码器只需要根据所给的yuv地址来进行编码就行了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表示编码器内部已经没有码流。
此处分析编码一帧的内部流程,首先看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;
下面结合送帧和收流的接口进行介绍
buffer_frame
,然后触发一帧编码,将编码出的码流赋值到buffer_pkt
buffer_pkt
,如果有则将其返回,如果没有再触发一帧编码,将编码好的码流返回可见send和receive接口均
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。