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

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.lryc.cn/news/617716.html

相关文章:

  • macOS 搭建 Gitea 私有 Git 服务器教程
  • wed前端第三次作业
  • 算法训练营DAY57 第十一章:图论part07
  • 缓存的三大问题分析与解决
  • STM32蓝牙模块驱动开发
  • 第10节 大模型分布式推理典型场景实战与架构设计
  • 《算法导论》第 19 章 - 斐波那契堆
  • 【SpringBoot】持久层 sql 注入问题
  • 一周学会Matplotlib3 Python 数据可视化-绘制直方图(Histogram)
  • 银河麒麟V10配置KVM的Ubuntu虚机GPU直通实战
  • 梯度裁剪总结
  • 做调度作业提交过程简单介绍一下
  • Spring Cloud Gateway 路由与过滤器实战:转发请求并添加自定义请求头(最新版本)
  • 如何安装 Git (windows/mac/linux)
  • 【数据可视化-85】海底捞门店数据分析与可视化:Python + pyecharts打造炫酷暗黑主题大屏
  • Java数据库编程之【JDBC数据库例程】【ResultSet作为表格的数据源】【七】
  • NY185NY190美光固态闪存NY193NY195
  • cf--思维训练
  • 【C++语法】输出的设置 iomanip 与 std::ios 中的流操纵符
  • Dashboard.vue 组件分析
  • 基于 Axios 的 HTTP 请求封装文件解析
  • 【Redis的安装与配置】
  • ESP32将DHT11温湿度传感器采集的数据上传到XAMPP的MySQL数据库
  • loading效果实现原理
  • 【JAVA】使用系统音频设置播放音频
  • 在线代码比对工具
  • Selenium元素定位不到原因以及怎么办?
  • 机器学习 TF-IDF提取关键词,从原理到实践的文本特征提取利器​
  • Effective C++ 条款36: 绝不重新定义继承而来的非虚函数
  • Excel 连接阿里云 RDS MySQL