一、FFmpeg常规处理流程
文字说明:
- 初始化容器格式和编解码器
- 打开输入文件建立连接
- 解析媒体流信息(时长/分辨率/编码格式等)
- 遍历找到视频流索引
- 根据编码器ID查找对应解码器
- 初始化并配置解码器上下文
- 循环读取压缩数据包
- 判断数据包类型并解码视频帧
- 对原始帧进行格式转换或处理
- 释放所有分配的资源
二、FFmpeg核心模块解析
2.1 模块预览
FFmpeg由多个功能模块组成,以下是8个核心模块的详细说明:
模块名称 | 功能描述 | 典型应用场景 |
---|---|---|
libavcodec | 编解码库,包含主流音视频编码器的实现 | H.264解码、MP3编码、音频重采样 |
libavformat | 封装/解封装库,处理多媒体容器格式(MP4/MKV/FLV等) | 解析MP4文件头信息、将H.264流封装为TS格式 |
libavutil | 基础工具库,提供通用数据结构、数学运算等基础功能 | 时间戳计算、内存管理、日志输出 |
libswscale | 图像处理库,实现色彩空间转换和图像缩放 | YUV420转RGB24、4K视频缩放到1080p |
libavfilter | 滤镜处理库,支持多路视频流的复杂滤镜处理 | 添加水印、视频画中画、音频混音 |
libavdevice | 设备访问库,支持采集显示设备数据 | 摄像头抓取画面、屏幕录制、音频采集卡输入 |
libswresample | 音频重采样库,处理音频格式转换 | 48kHz转44.1kHz、单声道转立体声、PCM格式转换 |
libpostproc | 后处理库,提供视频后期效果处理 | 视频去块效应、MPEG视频补偿 |
模块依赖关系:
avformat → avcodec → avutil
avfilter → avformat
swscale/swresample → avutil
2.2 部分模块说明详解:
libavcodec 工作机理:
libavfilter 处理链示例:
// 创建滤镜图:视频缩放+叠加水印
filter_graph = avfilter_graph_alloc();
avfilter_graph_create_filter(&buffer_src_ctx, "输入源");
avfilter_graph_create_filter(&scale_filter, "scale=640:480");
avfilter_graph_create_filter(&overlay_filter, "overlay=10:10");
avfilter_graph_create_filter(&buffer_sink_ctx, "输出端");// 连接滤镜节点
avfilter_link(buffer_src_ctx, 0, scale_filter, 0);
avfilter_link(scale_filter, 0, overlay_filter, 0);
avfilter_link(overlay_filter, 0, buffer_sink_ctx, 0);
模块选择原则:
- 文件操作:优先使用avformat
- 编解码处理:使用avcodec
- 图像处理:使用swscale或avfilter
- 实时流采集:配合avdevice使用
三、核心API函数说明
函数名称 | 功能描述 | 关键参数说明 |
---|---|---|
av_register_all() | 注册所有封装格式与编解码器(新版本已弃用) | 无参数 |
avformat_open_input() | 打开媒体文件并初始化AVFormatContext | ps: 上下文指针地址 url: 文件路径 fmt: 强制指定格式(可NULL) |
avformat_find_stream_info() | 获取媒体流详细信息 | ic: 上下文指针 options: 额外选项(通常NULL) |
avcodec_find_decoder() | 根据编码ID查找解码器 | id: 编码格式ID(如AV_CODEC_ID_H264) |
avcodec_open2() | 打开解码器 | avctx: 解码器上下文 codec: 解码器指针 options: 额外参数 |
av_read_frame() | 读取媒体文件中的数据包 | s: 上下文指针 pkt: 输出的数据包 |
avcodec_send_packet() | 发送压缩数据到解码器 | avctx: 解码器上下文 avpkt: 输入数据包 |
avcodec_receive_frame() | 从解码器获取解码后的帧 | avctx: 解码器上下文 frame: 输出的原始帧 |
sws_getContext() | 初始化图像缩放转换上下文 | 参数包含源/目标分辨率、格式等图像特征 |
sws_scale() | 执行像素格式转换和缩放 | sws_ctx: 转换上下文 srcSlice: 源数据指针 |
四、视频解码显示实战
实现一个ffmpeg读取视频文件,并使用opencv进行显示的例子。
4.1 实现流程图
4.2 完整实现代码
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}int main() {// 初始化FFmpegavformat_network_init();AVFormatContext* fmt_ctx = NULL;// 打开输入文件if(avformat_open_input(&fmt_ctx, "test.mp4", NULL, NULL) != 0){printf("无法打开文件\n");return -1;}// 获取流信息if(avformat_find_stream_info(fmt_ctx, NULL) < 0){printf("无法获取流信息\n");return -1;}// 查找视频流索引int video_stream = -1;for(int i=0; i<fmt_ctx->nb_streams; i++){if(fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){video_stream = i;break;}}// 获取解码器参数AVCodecParameters* codec_par = fmt_ctx->streams[video_stream]->codecpar;const AVCodec* decoder = avcodec_find_decoder(codec_par->codec_id);// 初始化解码器上下文AVCodecContext* codec_ctx = avcodec_alloc_context3(decoder);avcodec_parameters_to_context(codec_ctx, codec_par);avcodec_open2(codec_ctx, decoder, NULL);// 准备转换上下文(YUV->RGB)SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24,SWS_BILINEAR, NULL, NULL, NULL);// 准备帧结构AVFrame* frame = av_frame_alloc();AVFrame* rgb_frame = av_frame_alloc();uint8_t* buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1));av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);AVPacket pkt;while(av_read_frame(fmt_ctx, &pkt) >= 0){if(pkt.stream_index == video_stream){// 发送到解码器avcodec_send_packet(codec_ctx, &pkt);// 接收解码帧while(avcodec_receive_frame(codec_ctx, frame) == 0){// 格式转换sws_scale(sws_ctx, (const uint8_t* const*)frame->data, frame->linesize,0, codec_ctx->height,rgb_frame->data, rgb_frame->linesize);// OpenCV显示cv::Mat img(codec_ctx->height, codec_ctx->width, CV_8UC3, rgb_frame->data[0]);cv::imshow("Video", img);cv::waitKey(1);}}av_packet_unref(&pkt);}// 释放资源av_frame_free(&frame);av_frame_free(&rgb_frame);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);sws_freeContext(sws_ctx);return 0;
}
4.3 关键代码解析
- 图像转换配置:
sws_ctx = sws_getContext( // 创建转换器实例srcW, srcH, srcFormat, // 源图像参数dstW, dstH, dstFormat, // 目标图像参数flags, // 缩放算法选择...); // 其他可选参数
- OpenCV显示核心:
cv::Mat img(height, width, // 创建Mat对象CV_8UC3, // 数据类型:8位无符号3通道rgb_frame->data[0], // RGB数据首地址rgb_frame->linesize[0]); // 每行字节数(步长)
- 解码循环逻辑:
while(av_read_frame() >=0){ // 读取压缩包if(视频流){avcodec_send_packet(); // 送入解码队列while(avcodec_receive_frame() ==0){ // 获取解码帧// 处理帧数据}}av_packet_unref(); // 必须释放数据包
}
五、常见问题处理
- 颜色显示异常:检查像素格式转换参数(AV_PIX_FMT_RGB24)
- 无法打开文件:检查文件路径和FFmpeg的协议支持
- 内存泄漏:确保每个av_malloc都有对应的av_free
- 花屏现象:检查解码器是否成功初始化,数据包是否完整