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

FFmpeg - 基本 API大全(视频编解码相关的)

FFmpeg 是一个强大的多媒体处理库,下面我将介绍其基本 API 并结合网络流/本地文件解码示例说明每个 API 的功能和用法。

一、核心 API 分类

1. 格式处理 API (libavformat)

2. 编解码 API (libavcodec)

3. 实用工具 API (libavutil)

4. 图像缩放/像素格式转换 API (libswscale)

二、基本 API 详解及示例

1. 初始化相关 API

c

// 注册所有编解码器和格式 (4.0+已废弃,但许多示例仍保留)
av_register_all();// 初始化网络库 (用于网络流)
avformat_network_init();

2. 打开输入流 API

c

AVFormatContext *pFormatCtx = NULL;// 本地文件打开
const char *url = "input.mp4";
if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0) {printf("无法打开输入文件\n");return -1;
}// 网络流打开 (如RTMP)
const char *rtmp_url = "rtmp://live.example.com/app/stream";
AVDictionary *options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", 0); // 设置RTSP over TCP
av_dict_set(&options, "stimeout", "5000000", 0);  // 设置超时5秒if (avformat_open_input(&pFormatCtx, rtmp_url, NULL, &options) != 0) {printf("无法打开网络流\n");return -1;
}

3. 获取流信息 API

c

if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {printf("无法获取流信息\n");return -1;
}// 打印流信息
av_dump_format(pFormatCtx, 0, url, 0);

4. 查找视频流 API

c

int videoStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStream = i;break;}
}
if (videoStream == -1) {printf("未找到视频流\n");return -1;
}

5. 编解码器设置 API

c

// 获取编解码器参数
AVCodecParameters *pCodecParams = pFormatCtx->streams[videoStream]->codecpar;// 查找解码器
const AVCodec *pCodec = avcodec_find_decoder(pCodecParams->codec_id);
if (!pCodec) {printf("不支持的解码器\n");return -1;
}// 创建解码器上下文
AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx) {printf("无法分配编解码器上下文\n");return -1;
}// 复制参数到上下文
if (avcodec_parameters_to_context(pCodecCtx, pCodecParams) < 0) {printf("无法复制编解码器参数\n");return -1;
}// 打开解码器
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {printf("无法打开解码器\n");return -1;
}

6. 帧和包处理 API

c

// 分配帧
AVFrame *pFrame = av_frame_alloc();
if (!pFrame) {printf("无法分配帧\n");return -1;
}// 初始化包
AVPacket packet;
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;

7. 解码循环 API

c

while (av_read_frame(pFormatCtx, &packet) >= 0) {if (packet.stream_index == videoStream) {// 发送数据包到解码器int ret = avcodec_send_packet(pCodecCtx, &packet);if (ret < 0) {printf("发送解码包出错\n");continue;}// 接收解码后的帧while (ret >= 0) {ret = avcodec_receive_frame(pCodecCtx, pFrame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;} else if (ret < 0) {printf("解码出错\n");return -1;}// 成功解码一帧,可以处理帧数据printf("解码帧: width=%d, height=%d, format=%d, pts=%lld\n",pFrame->width, pFrame->height, pFrame->format, pFrame->pts);// 这里可以添加帧处理代码...}}av_packet_unref(&packet); // 释放包
}

8. 刷新解码器 API

c

// 发送空包刷新解码器
avcodec_send_packet(pCodecCtx, NULL);// 接收剩余的帧
while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {printf("刷新解码器获取的帧: pts=%lld\n", pFrame->pts);// 处理帧...
}

9. 资源释放 API

c

av_frame_free(&pFrame);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
avformat_network_deinit(); // 如果之前调用了avformat_network_init()

三、完整网络流解码示例

c

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <stdio.h>int main() {AVFormatContext *pFormatCtx = NULL;AVCodecContext *pCodecCtx = NULL;const AVCodec *pCodec = NULL;AVFrame *pFrame = NULL;AVPacket packet;int videoStream = -1;// 初始化网络库avformat_network_init();// 打开网络流 (这里使用RTMP示例)const char *url = "rtmp://live.example.com/app/stream";AVDictionary *options = NULL;av_dict_set(&options, "rtsp_transport", "tcp", 0);av_dict_set(&options, "stimeout", "5000000", 0);if (avformat_open_input(&pFormatCtx, url, NULL, &options) != 0) {printf("无法打开网络流\n");return -1;}// 获取流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {printf("无法获取流信息\n");return -1;}// 查找视频流for (int i = 0; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStream = i;break;}}if (videoStream == -1) {printf("未找到视频流\n");return -1;}// 设置解码器AVCodecParameters *pCodecParams = pFormatCtx->streams[videoStream]->codecpar;pCodec = avcodec_find_decoder(pCodecParams->codec_id);if (!pCodec) {printf("不支持的解码器\n");return -1;}pCodecCtx = avcodec_alloc_context3(pCodec);avcodec_parameters_to_context(pCodecCtx, pCodecParams);if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {printf("无法打开解码器\n");return -1;}// 准备帧和包pFrame = av_frame_alloc();av_init_packet(&packet);// 解码循环while (av_read_frame(pFormatCtx, &packet) >= 0) {if (packet.stream_index == videoStream) {if (avcodec_send_packet(pCodecCtx, &packet) < 0) {printf("发送解码包出错\n");continue;}while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {printf("解码帧: width=%d, height=%d, format=%d, pts=%lld\n",pFrame->width, pFrame->height, pFrame->format, pFrame->pts);// 实际应用中这里可以处理帧数据}}av_packet_unref(&packet);}// 刷新解码器avcodec_send_packet(pCodecCtx, NULL);while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {printf("刷新解码器获取的帧\n");}// 清理av_frame_free(&pFrame);avcodec_free_context(&pCodecCtx);avformat_close_input(&pFormatCtx);avformat_network_deinit();return 0;
}

四、关键 API 功能总结

API功能描述常用场景
av_register_all()注册所有编解码器和格式旧版本初始化 (4.0+已废弃)
avformat_network_init()初始化网络库处理网络流前调用
avformat_open_input()打开媒体文件或流本地文件/网络流输入
avformat_find_stream_info()获取流信息打开输入后获取详细信息
avcodec_find_decoder()查找解码器根据codec_id查找解码器
avcodec_alloc_context3()创建编解码器上下文解码器/编码器设置
avcodec_parameters_to_context()复制参数到上下文设置解码器参数
avcodec_open2()打开编解码器初始化编解码器
av_read_frame()读取数据包解码循环中获取数据
avcodec_send_packet()发送数据包到解码器现代解码流程
avcodec_receive_frame()接收解码后的帧现代解码流程
av_packet_unref()释放数据包处理完包后释放资源
av_frame_free()释放帧处理完帧后释放资源

五、不同场景下的注意事项

  1. 本地文件解码:

    • 不需要调用avformat_network_init()

    • 通常不需要设置超时等网络参数

  2. 网络流解码:

    • 必须调用avformat_network_init()

    • 建议设置合理的超时参数

    • 对于RTSP流,建议强制使用TCP传输

  3. 实时流处理:

    • 可能需要设置realtime标志

    • 可能需要禁用缓冲av_dict_set(&options, "fflags", "nobuffer", 0)

  4. 错误处理:

    • 所有API调用都应检查返回值

    • 网络流需要更健壮的错误恢复机制

这个指南涵盖了FFmpeg解码的基本API和使用方法,实际应用中可能需要根据具体需求进行调整和扩展。

http://www.xdnf.cn/news/17673.html

相关文章:

  • 【数据结构】深入理解顺序表与通讯录项目的实现
  • leetcode-hot-100 (图论)
  • CobaltStrike的搭建和使用
  • 爬虫与数据分析实战
  • 【09-神经网络介绍2】
  • 一文读懂 C# 中的 Lazy<T>
  • 第10节 大模型分布式推理典型场景实战与架构设计
  • Godot ------ 平滑拖动02
  • Apache Ignite 核心组件:GridClosureProcessor解析
  • C# 异步编程(计时器)
  • Python: configparser库 ini文件操作库
  • 使用MAS(Microsoft Activation Scripts)永久获得win10专业版和office全套
  • Edit Distance
  • react中父子数据流动和事件互相调用(和vue做比较)
  • GO学习记录三
  • 基于MongoDB/HBase的知识共享平台的设计与实现
  • 【Dv3Admin】菜单转换选项卡平铺到页面
  • Excel 连接阿里云 RDS MySQL
  • 5G 非地面网络(NTN)最专业的方案
  • 高并发场景下分布式ID生成方案对比与实践指南
  • 在 .NET Core 5.0 中启用 Gzip 压缩
  • 从ELF到进程间通信:剖析Linux程序的加载与交互机制
  • 玩转Docker | 使用Docker部署Trilium Notes知识库工具
  • 5G NTN 卫星测试产品
  • word格式设置-论文写作,样式,字号等
  • WPF之绑定!
  • LeetCode——241.为运算表达式设计优先级
  • 在 RHEL9 上搭建企业级 Web 服务(Tomcat)
  • Android Audio实战——获取活跃音频类型(十五)
  • 深度学习与遥感入门(五)|GAT 构图消融 + 分块全图预测:更稳更快的高光谱图分类(PyTorch Geometric 实战)