0

0

如何使用c++和FFmpeg进行视频编解码? (多媒体处理)

穿越時空

穿越時空

发布时间:2026-01-14 00:23:17

|

526人浏览过

|

来源于php中文网

原创

avcodec_open2调用失败主因是未初始化或参数不匹配:需用avcodec_alloc_context3分配上下文,H.264编码必须设pix_fmt为AV_PIX_FMT_YUV420P,解码MP4中H.264需转Annex-B格式。

如何使用c++和ffmpeg进行视频编解码? (多媒体处理)

ffmpeg\_avcodec\_open2 调用失败的常见原因

绝大多数初学者卡在第一步:调用 avcodec_open2 返回负值。这不是代码写错了,而是没完成前置初始化或参数不匹配。

  • avcodec_register_all() 已废弃,必须改用 avcodec_register() 或更推荐的 av_log_set_level(AV_LOG_DEBUG) + avcodec_find_encoder/decoder 前检查返回值是否为 nullptr
  • 编码器需手动分配 AVCodecContext:用 avcodec_alloc_context3(codec),不能直接上声明结构体
  • H.264 编码时,codec_ctx->pix_fmt 必须设为 AV_PIX_FMT_YUV420P(x264 不支持 RGB 直接编码),否则 avcodec_open2 静默失败
  • 解码时若输入是 MP4 容器里的 H.264,注意 AVPacketdata 可能带 AVCC 格式头(sps/pps 内嵌),需用 av_bsf_init + av_bsf_send_packet 转成 Annex-B 格式再送解码器

如何正确分配和填充 AVFrame 用于编码

AVFrame 不是“填完数据就能扔给编码器”,它的内存布局、对齐、生命周期都必须严格符合编码器要求。

  • 编码前必须调用 av_frame_get_buffer(frame, 32) 分配内部缓冲区(32 是内存对齐字节数),不能只 malloc frame->data[0]
  • YUV420P 布局下:frame->data[0] 是 Y 平面,frame->data[1] 是 U,frame->data[2] 是 V;frame->linesize[0] 是 Y 行字节数(可能 > width),U/V 行宽通常是 Y 的一半
  • 务必设置 frame->widthframe->heightframe->format(如 AV_PIX_FMT_YUV420P)和 frame->pts(时间戳,单位是 codec_ctx->time_base 的 tick 数)
  • 编码器可能重用 AVFrame 内部缓冲,所以每次填新帧前要调用 av_frame_make_writable(frame),否则写入可能崩溃

avcodec\_receive\_packet 接收不到输出帧?

这是最隐蔽的问题:你以为数据送进去了,其实编码器还在攒帧(B帧、延迟队列),或者你没按“推一帧 → 拉多帧”循环处理。

  • 编码流程必须是:avcodec_send_frame() → 循环调用 avcodec_receive_packet() 直到返回 AVERROR(EAGAIN)AVERROR_EOF
  • 解码同理:avcodec_send_packet() → 循环 avcodec_receive_frame(),尤其注意视频关键帧(IDR)后可能有多个非参考帧堆积
  • 编码结束时,必须传 nullptravcodec_send_frame() 触发 flush,否则最后一组帧永远出不来
  • 检查 avcodec_receive_packet() 返回值:0 成功,AVERROR(EAGAIN) 表示输入不足,AVERROR_EOF 表示已 flush 完毕,其他负值才是错误

为什么编码出来的视频播放卡顿或花屏?

大概率是时间基(time base)和 PTS/DTS 混乱,而不是画质参数问题。

玫瑰克隆工具
玫瑰克隆工具

AI图文笔记一键生成创作并自动发布助手

下载

立即学习C++免费学习笔记(深入)”;

  • 编码器输出的 AVPacket->ptsdts 默认基于 codec_ctx->time_base,但封装到 MP4 时 muxer 通常要求基于 AV_TIME_BASE 或流自己的 time_base —— 必须用 av_packet_rescale_ts(pkt, codec_ctx->time_base, stream->time_base)
  • 不要手动算 PTS:用 frame->pts = frame_index * (codec_ctx->time_base.den / codec_ctx->time_base.num) / fps 这类整数运算,浮点误差会累积导致音画不同步
  • 启用 B 帧时(codec_ctx->max_b_frames = 3),DTS 会小于 PTS,muxer 必须按 DTS 排序写包,否则播放器解码顺序错乱
  • MP4 封装前漏掉 avformat_write_header 或没写 AVStream->codecpar(从 codec_ctx 复制),会导致播放器无法解析时间戳
// 示例:正确发送 flush 并收完剩余 packet
avcodec_send_frame(codec_ctx, nullptr);
while (1) {
    int ret = avcodec_receive_packet(codec_ctx, &pkt);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        break;
    if (ret < 0) {
        fprintf(stderr, "Flush error: %s\n", av_err2str(ret));
        exit(1);
    }
    av_packet_rescale_ts(&pkt, codec_ctx->time_base, stream->time_base);
    av_interleaved_write_frame(fmt_ctx, &pkt);
    av_packet_unref(&pkt);
}

真正难的不是调哪个函数,而是理解每个 AVPacketAVFrame 在 pipeline 中携带的语义:它的时间基准是什么、内存是否可写、是否被引用计数持有、是否需要 rescale。这些信息不会报错,但会让结果不可预测。

相关专题

更多
format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python中的format是什么意思
python中的format是什么意思

python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

430

2024.06.27

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

195

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

187

2025.07.04

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

386

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

386

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Rust 教程
Rust 教程

共28课时 | 4.4万人学习

Git 教程
Git 教程

共21课时 | 2.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号