当前位置: 首页 > news >正文

FFmpeg 核心 API 系列:avcodec_find_decoder / avcodec_alloc_context3 / avcodec_open2

🎬 FFmpeg 核心 API 系列:avcodec_find_decoder / avcodec_alloc_context3 / avcodec_open2 全解析
📅 更新时间:2025年10月2日
🏷️ 标签:FFmpeg | 多媒体处理 | 音视频编程 | C/C++ | 流媒体

文章目录

  • 📖 前言
  • 🎯 三个核心API详解
    • API 1️⃣:`avcodec_find_decoder` - 查找解码器
      • 函数原型
      • 参数说明
      • 返回值
      • 作用
      • 用法一:通过 `codec_id` 查找对应的解码器
      • 用法二:指定解码器名称查找
      • 练习小Demo
    • API 2️⃣:`avcodec_alloc_context3` - 分配解码器上下文
      • 函数原型
      • 参数说明
      • 返回值
      • 作用
      • 示例
    • 🔧 辅助API:`avcodec_parameters_to_context` - 复制参数
      • 为什么需要这一步?
      • 函数原型
      • 返回值
      • 示例
    • API 3️⃣:`avcodec_open2` - 打开解码器
      • 函数原型
      • 参数说明
      • 返回值
      • 作用
      • 示例
  • 🔑 关键数据结构
    • AVCodec(解码器)
    • AVCodecContext(解码器上下文)
  • 💻 完整小Demo
  • 📋 总结


📖 前言

回顾上一篇文章,我们已经能:

  • 打开文件 → 得到 AVFormatContext
  • 分析流信息 → 得到 AVStream(包含编码参数 codecpar

但是!这些信息只是"参数",并不能解码。就像你知道一个文件是H.264编码的,但还需要一个"H.264解码器"才能把压缩数据变成图像。

解码器的作用:将压缩的数据包(AVPacket)→ 解码成原始的帧(AVFrame


🎯 三个核心API详解

API 1️⃣:avcodec_find_decoder - 查找解码器

函数原型

const AVCodec *avcodec_find_decoder(enum AVCodecID id);

参数说明

参数说明
id编码ID(从 stream->codecpar->codec_id 获取)

返回值

  • 成功:返回解码器指针(AVCodec*
  • 失败:返回 NULL

作用

根据编码ID找到对应的解码器


用法一:通过 codec_id 查找对应的解码器

AVCodecID cid=stream->codecpar->codec_id;
//根据编码ID查找对应解码器
const AVCodec * decoder=avcodec_find_decoder(cid);

用法二:指定解码器名称查找

注意事项:要判断一下这个解码器是否能解码对应的流

const AVCodec *codec = avcodec_find_decoder_by_name("h264_qsv");
if (!codec) {qDebug() << "未找到 h264_qsv 解码器";
} else {if (codec->id == stream->codecpar->codec_id) {qDebug() << "此解码器可用于该流";} else {qDebug() << "此解码器和流的编码ID不匹配";}
}

练习小Demo

#include "mainwindow.h"
#include<QDebug>
#include <QApplication>extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
}int main(int argc, char *argv[])
{QApplication a(argc, argv);//MainWindow w;//w.show();AVFormatContext* con=nullptr;QString path="E:/BaiduNetdiskDownload/音视频资料/1、C++实战手把手教您用ffmpeg和QT开发播放器实战视频课程/1-02、音视频解封装和解码原理分析_ev.mp4";int r=avformat_open_input(&con,path.toUtf8().data(),nullptr,nullptr);if(r<0){qDebug()<<"avformat_open_input is error";}else{qDebug()<<"avformat_open_input is success";}r=avformat_find_stream_info(con,nullptr);if(r<0){qDebug()<<"avformat_find_stream_info is error";}else{qDebug()<<"avformat_find_stream_info is success";for(unsigned i=0;i<con->nb_streams;i++){AVStream* stream=con->streams[i];if(stream->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){qDebug()<<"找到视频流";AVCodecID cid=stream->codecpar->codec_id;//根据编码ID查找对应解码器const AVCodec * decoder=avcodec_find_decoder(cid);if(!decoder){qDebug()<<"此视频流找不到对应解码器";}else{qDebug()<<"此视频流的编码ID为:"<<cid;qDebug()<<"此视频流成功找到对应解码器";}}else if(stream->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){qDebug()<<"找到音频流";AVCodecID cid=stream->codecpar->codec_id;//根据编码ID查找对应解码器const AVCodec * decoder=avcodec_find_decoder(cid);if(!decoder){qDebug()<<"此音频流找不到对应解码器";}else{qDebug()<<"此音频流的编码ID为:"<<cid;qDebug()<<"此音频流成功找到对应解码器";}}else{qDebug()<<"找到其它未知流";}}}avformat_close_input(&con);return a.exec();
}

输出结果

avformat_open_input is success
avformat_find_stream_info is success
找到视频流
此视频流的编码ID为: 27
此视频流成功找到对应解码器
找到音频流
此音频流的编码ID为: 86018
此音频流成功找到对应解码器

API 2️⃣:avcodec_alloc_context3 - 分配解码器上下文

函数原型

AVCodecContext* avcodec_alloc_context3(const AVCodec* codec);

参数说明

参数说明
codec解码器指针(可以传 NULL,但通常传第一步找到的解码器)

返回值

  • 成功:返回解码器上下文指针(AVCodecContext*
  • 失败:返回 NULL

作用

为解码器分配一个工作环境(上下文)


示例

// 分配解码器上下文
AVCodecContext* codec_ctx = avcodec_alloc_context3(decoder); // decoder是通过avcodec_find_decoder找到的解码器
if (!codec_ctx) {qDebug() << "分配解码器上下文失败!";
}

🔧 辅助API:avcodec_parameters_to_context - 复制参数

为什么需要这一步?

  • AVStream 中的 codecpar 包含了编码参数(分辨率、帧率等)
  • AVCodecContext 刚分配时是空的
  • 需要把参数复制过去

函数原型

int avcodec_parameters_to_context(AVCodecContext* codec_ctx, const AVCodecParameters* par);

返回值

  • 0成功
  • < 0 → 失败(通常是负数错误码,比如 AVERROR(EINVAL)

示例

// 将流的参数复制到解码器上下文
int ret = avcodec_parameters_to_context(codec_ctx, video_stream->codecpar);
if (ret < 0) {qDebug() << "复制参数失败!";
}

API 3️⃣:avcodec_open2 - 打开解码器

函数原型

int avcodec_open2(AVCodecContext* avctx, const AVCodec* codec, AVDictionary** options);

参数说明

参数说明
avctx解码器上下文
codec解码器(传第一步找到的解码器)
options可选参数字典(通常传 NULL

返回值

  • 0成功
  • < 0:失败

作用

初始化并打开解码器,打开后才能真正使用


示例

// 打开解码器
int ret = avcodec_open2(codec_ctx, decoder, nullptr);
if (ret < 0) {qDebug() << "打开解码器失败!";
}

🔑 关键数据结构

AVCodec(解码器)

const AVCodec* decoder;
decoder->name;        // 解码器名称,如"h264"
decoder->long_name;   // 完整名称,如"H.264 / AVC / MPEG-4 AVC"
decoder->type;        // 类型:AVMEDIA_TYPE_VIDEO 或 AVMEDIA_TYPE_AUDIO
decoder->id;          // 编码ID

AVCodecContext(解码器上下文)

AVCodecContext* codec_ctx;// 视频相关字段
codec_ctx->width;           // 视频宽度
codec_ctx->height;          // 视频高度
codec_ctx->pix_fmt;         // 像素格式(如AV_PIX_FMT_YUV420P)
codec_ctx->framerate;       // 帧率// 音频相关字段
codec_ctx->sample_rate;     // 采样率(如44100)
codec_ctx->channel_layout;  // 声道布局
codec_ctx->sample_fmt;      // 采样格式(如AV_SAMPLE_FMT_FLTP)

💻 完整小Demo

目标:打开视频文件,为视频流和音频流找到并打开解码器,打印解码器信息

#include <QCoreApplication>
#include <QDebug>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);AVFormatContext* fmt_ctx = nullptr;AVCodecContext* video_codec_ctx = nullptr;AVCodecContext* audio_codec_ctx = nullptr;// ===== 阶段一:打开文件和分析流信息 =====QString path = "E:/BaiduNetdiskDownload/音视频资料/1、C++实战手把手教您用ffmpeg和QT开发播放器实战视频课程/1-02、音视频解封装和解码原理分析_ev.mp4";// 1. 打开文件if (avformat_open_input(&fmt_ctx, path.toUtf8().data(), nullptr, nullptr) < 0) {qDebug() << "打开文件失败!";return -1;}// 2. 分析流信息if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {qDebug() << "分析流信息失败!";avformat_close_input(&fmt_ctx);return -1;}// 3. 找到视频流和音频流int video_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);int audio_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);qDebug() << "========== 文件信息 ==========";qDebug() << "视频流索引:" << video_index;qDebug() << "音频流索引:" << audio_index;qDebug() << "";// ===== 阶段二:查找并打开解码器 =====// 处理视频流if (video_index >= 0) {AVStream* video_stream = fmt_ctx->streams[video_index];// 1. 查找解码器const AVCodec* video_decoder = avcodec_find_decoder(video_stream->codecpar->codec_id);if (!video_decoder) {qDebug() << "找不到视频解码器!";} else {qDebug() << "========== 视频解码器 ==========";qDebug() << "解码器名称:" << video_decoder->name;qDebug() << "解码器完整名称:" << video_decoder->long_name;// 2. 分配解码器上下文video_codec_ctx = avcodec_alloc_context3(video_decoder);if (!video_codec_ctx) {qDebug() << "分配视频解码器上下文失败!";} else {// 3. 复制参数到上下文if (avcodec_parameters_to_context(video_codec_ctx, video_stream->codecpar) < 0) {qDebug() << "复制视频参数失败!";} else {// 4. 打开解码器if (avcodec_open2(video_codec_ctx, video_decoder, nullptr) < 0) {qDebug() << "打开视频解码器失败!";} else {qDebug() << "视频解码器打开成功!";qDebug() << "分辨率:" << video_codec_ctx->width << "x" << video_codec_ctx->height;qDebug() << "像素格式:" << video_codec_ctx->pix_fmt;qDebug() << "帧率:" << av_q2d(video_stream->r_frame_rate) << "fps";}}}qDebug() << "";}}// 处理音频流if (audio_index >= 0) {AVStream* audio_stream = fmt_ctx->streams[audio_index];// 1. 查找解码器const AVCodec* audio_decoder = avcodec_find_decoder(audio_stream->codecpar->codec_id);if (!audio_decoder) {qDebug() << "找不到音频解码器!";} else {qDebug() << "========== 音频解码器 ==========";qDebug() << "解码器名称:" << audio_decoder->name;qDebug() << "解码器完整名称:" << audio_decoder->long_name;// 2. 分配解码器上下文audio_codec_ctx = avcodec_alloc_context3(audio_decoder);if (!audio_codec_ctx) {qDebug() << "分配音频解码器上下文失败!";} else {// 3. 复制参数到上下文if (avcodec_parameters_to_context(audio_codec_ctx, audio_stream->codecpar) < 0) {qDebug() << "复制音频参数失败!";} else {// 4. 打开解码器if (avcodec_open2(audio_codec_ctx, audio_decoder, nullptr) < 0) {qDebug() << "打开音频解码器失败!";} else {qDebug() << "音频解码器打开成功!";qDebug() << "采样率:" << audio_codec_ctx->sample_rate << "Hz";qDebug() << "采样格式:" << audio_codec_ctx->sample_fmt;}}}qDebug() << "";}}// ===== 清理资源 =====if (video_codec_ctx) {avcodec_free_context(&video_codec_ctx);}if (audio_codec_ctx) {avcodec_free_context(&audio_codec_ctx);}avformat_close_input(&fmt_ctx);qDebug() << "程序结束";return 0;
}

输出结果

========== 文件信息 ==========
视频流索引: 0
音频流索引: 1========== 视频解码器 ==========
解码器名称: h264
解码器完整名称: H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
视频解码器打开成功!
分辨率: 1280 x 720
像素格式: 0
帧率: 60 fps========== 音频解码器 ==========
解码器名称: aac
解码器完整名称: AAC (Advanced Audio Coding)
音频解码器打开成功!
采样率: 44100 Hz
采样格式: 8程序结束

📋 总结

核心流程

查找解码器 → 分配上下文 → 复制参数 → 打开解码器 → 开始使用

在这里插入图片描述

如果您觉得这篇文章对您有帮助,不妨点赞 + 收藏 + 关注,更多 FFmpeg 系列教程将持续更新 🔥!

http://www.dtcms.com/a/434823.html

相关文章:

  • 文件上传简单的绕过总结
  • Visual Studio Code中launch.json深度解析:C++调试的艺术
  • 天长市建设局网站惠来做网站
  • 51单片机红外遥控
  • Java 集合 “List + Set”面试清单(含超通俗生活案例与深度理解)
  • 云南网站建设哪个好软文广告平台
  • 《嵌入式 – GD32开发实战指南(RISC-V版本)》第8章 PWM输出实现
  • HNU 编译系统 第一次作业
  • 网站怎么做交易平台图片生成网页链接在线
  • 渗透测试中的信息收集:文档元数据
  • minikube 的 kubernetes 入门教程-kubeSphere
  • 深圳 手机网站建设彩妆做推广的网站
  • 网站跳转是什么意思郑州建站网站的公司
  • 老题新解|再求 f(x,n)
  • 【Android cmd命令的执行流程】
  • c++26新功能—constexpr在稳定排序中的应用
  • AI生成悬疑故事
  • 泰山派rk3566烧录
  • Phpstudy博客网站apache2日志分析python代码
  • asp网站程序优点做App和网站 聚马
  • 免费软件下载网站入口正能量微信开发公众平台
  • 【系统重装】Windows无法安装到这个磁盘提示选中的磁盘具有MBR分区表解决方法(亲测有效)
  • MySQL 查询与更新语句执行过程深度解析:从原理到实践​
  • Bella Beauty – Aesthetic Medical Clinic WordPress Theme: A Practical
  • 洗车店会员管理系统数据分析
  • 门户网站的意思wordpress 导航 防刷新
  • 虚幻基础:角色受击
  • unordered_set 与unordered_multiset?我们该如何选择
  • 网站建设与维护是什么可以在线观看的免费资源
  • Windows系统下的Git安装(2025年6月更新)