ffmpeg源码简析(五)编码——avformat_alloc_output_context2(),avcodec_encode_video2()

本文详细解析了FFmpeg中的avformat_alloc_output_context2()函数,用于初始化输出的AVFormatContext,并探讨了avformat_write_header()和avcodec_encode_video2()在视频编码过程中的作用。avformat_alloc_output_context2()涉及avformat_alloc_context()和av_guess_format(),而avcodec_encode_video2()则负责编码一帧视频数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.avformat_alloc_output_context2()

在基于FFmpeg的视音频编码器程序中,该函数通常是第一个调用的函数(除了组件注册函数av_register_all())。avformat_alloc_output_context2()函数可以初始化一个用于输出的AVFormatContext结构体。它的声明位于libavformat\avformat.h,如下所示。

int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat,  
                                   const char *format_name, const char *filename);  

ctx:函数调用成功之后创建的AVFormatContext结构体。
oformat:指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式。
PS:使用该参数需要自己手动获取AVOutputFormat,相对于使用后两个参数来说要麻烦一些。
format_name:指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等。
filename:指定输出文件的名称。根据文件名称,FFmpeg会推测输出格式。文件名称可以是“xx.flv”,“yy.mkv”等等。

函数执行成功的话,其返回值大于等于0。

下面看一下avformat_alloc_output_context2()的函数定义。该函数的定义位于libavformat\mux.c中,如下所示。

int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat,  
                                   const char *format, const char *filename)  
{  
    AVFormatContext *s = avformat_alloc_context();  
    int ret = 0;  


    *avctx = NULL;  
    if (!s)  
        goto nomem;  


    if (!oformat) {  
        if (format) {  
            oformat = av_guess_format(format, NULL, NULL);  
            if (!oformat) {  
                av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);  
                ret = AVERROR(EINVAL);  
                goto error;  
            }  
        } else {  
            oformat = av_guess_format(NULL, filename, NULL);  
            if (!oformat) {  
                ret = AVERROR(EINVAL);  
                av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",  
                       filename);  
                goto error;  
            }  
        }  
    }  


    s->oformat = oformat;  
    if (s->oformat->priv_data_size > 0) {  
        s->priv_data = av_mallocz(s->oformat->priv_data_size);  
        if (!s->priv_data)  
            goto nomem;  
        if (s->oformat->priv_class) {  
            *(const AVClass**)s->priv_data= s->oformat->priv_class;  
            av_opt_set_defaults(s->priv_data);  
        }  
    } else  
        s->priv_data = NULL;  


    if (filename)  
        av_strlcpy(s->filename, filename, sizeof(s->filename));  
    *avctx = s;  
    return 
在C++中使用FFmpeg库(包括针对Rockchip编解码器的支持)编解码视频通常涉及到头文件的包含、上下文对象的初始化、媒体数据处理以及函数的调用。这里是一个简单的示例,假设你想编码H.264视频: ```cpp #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> int main() { // 初始化FFmpeg上下文 av_register_all(); avcodec_register_all(); // 创建编码AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_H264); if (!encoder) { std::cerr << "Failed to find H.264 encoder!" << std::endl; return -1; } // 检查是否支持Rockchip编解码器 if (encoder->name.find("Rockchip") == std::string::npos) { std::cerr << "Encoder does not support Rockchip codec!" << std::endl; avcodec_free(encoder); return -1; } // 创建编码上下文 AVCodecContext *enc_ctx = avcodec_alloc_context3(encoder); enc_ctx->bit_rate = 1000000; // 设置比特率 enc_ctx->width = 640; // 视频宽度 enc_ctx->height = 480; // 视频高度 // 打开编码器 int ret = avcodec_open2(enc_ctx, encoder, NULL); if (ret < 0) { std::cerr << "Failed to open encoder!" << std::endl; avcodec_free_context(&enc_ctx); return -1; } // 创建MPEG流 AVFormatContext *fmt_ctx = avformat_alloc_context(); fmt_ctx->oformat = av_guess_format(NULL, "output.mp4", NULL); // 添加流到格式上下文 AVStream *stream = avformat_new_stream(fmt_ctx, encoder); stream->time_base = {1, 30}; // 帧率设置为30 FPS stream->codecpar = enc_ctx; // 开始写入文件 ret = avio_open(&fmt_ctx->pb, "output.mp4", AVIO_FLAG_WRITE); if (ret < 0) { std::cerr << "Failed to open output file!" << std::endl; avcodec_close(enc_ctx); avformat_free_context(fmt_ctx); return -1; } if (avformat_write_header(fmt_ctx, NULL) < 0) { std::cerr << "Failed to write header!" << std::endl; avio_closep(&fmt_ctx->pb); avcodec_close(enc_ctx); avformat_free_context(fmt_ctx); return -1; } // 编码实际数据 AVPacket pkt; uint8_t buf[1024]; while (true) { // 这里需要替换为实际读取视频数据的循环 size_t len = read_video_data(buf); // 假设read_video_data()是你从源获取帧的函数 if (len <= 0) break; pkt.data = buf; pkt.size = len; ret = avcodec_encode_video2(enc_ctx, &pkt, buf, len); if (ret >= 0) { int written = avio_write(fmt_ctx->pb, &pkt, 1); if (written != pkt.size) { std::cerr << "Error writing packet!" << std::endl; return -1; } } else { std::cerr << "Failed to encode frame!" << std::endl; } } // 结束并清理 av_write_trailer(fmt_ctx); avio_closep(&fmt_ctx->pb); avcodec_close(enc_ctx); avformat_free_context(fmt_ctx); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值