1 简介
1.1 起源与发展历程
FFmpeg诞生于2000年,由法国工程师Fabrice Bellard主导开发,其名称源自"Fast Forward MPEG",初期定位为多媒体编解码工具。2004年后由Michael Niedermayer接任维护,逐步发展成为包含音视频采集、格式转换、流媒体处理等完整功能的开源项目。经过25年迭代,当前最新7.x版本已支持H.266/VVC、AV1等新一代编码标准,在全球开发者社区贡献下形成包含7大核心库的生态系统。
1.2 核心功能与架构组成
该工具链以libavcodec编解码库为核心,涵盖libavformat(封装格式处理)、libswscale(图像缩放、颜色空间转化等)、libavfilter(滤镜系统)等模块,支持200+种媒体格式的相互转化。其命令行工具集可执行视频剪辑、帧率调整、硬件加速转码等操作,广泛应用于直播推流、视频会议、智能安防等领域。通过LGPL/GPL协议保障开源生态,已成为VLC、Blender等知名软件的基础依赖组件。
2 下载
为了避免复杂的编译过程,达到快速上手使用的目的,我们推荐使用官方预编译包。下载地址:官网
注意,一定选择含share字符的编译包。
3 VS2022开发FFMPEG的环境配置
FFMPEG作为一个标准的第三方库,其配置思路是与OpenCV、OpenVINO等是一样的。在工程里面,配置好头文件路径、库文件路径和名称以及二进制文件的路径。下面,我实际演示下如何一步步进行配置。
3.1 解压安装包
将下载的压缩包,解压至无中文路径的目录中,我把它解压在D:/Tool
目录下。
可以大致看下,FFMPEG的目录结构:
- bin:二进制文件目录。
- doc:使用帮助文档。
- include:头文件。
- lib:库文件。
- presets:一些标准分辨率的vpx的预设文件。
3.2 新建工程
使用VS2022新建控制台工程,空项目即可。
3.3 配置头文件
右键项目 →属性→VC++ 目录,包含目录增加D:\Tool\ffmpeg-7.1-full_build-shared\include
。
3.4 配置库文件
右键项目 →属性→VC++ 目录,库目录增加D:\Tool\ffmpeg-7.1-full_build-shared\lib
。
配置库名称:
3.5 配置二进制文件
建议直接使用环境变量进行配置,方便省事。
3.6 环境测试
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
}
int main() {
std::cout << "FFmpeg版本: " << avcodec_version() << std::endl;
return 0;
}
4、读取mp4文件,opencv显示。
为验证FFMPEG的环境是否彻底安装完成,我们采用一个小的例子程序,进行验证。读取一个mp4文件,使用FFMPEG进行格式解析,并转为RGB格式,使用opencv进行显示。
#include <iostream>
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
int main() {
// FFmpeg初始化
avformat_network_init();
AVFormatContext* fmt_ctx = nullptr;
// 打开媒体文件(替换为你的MP4路径)
const char* filename = "input.mp4";
if(avformat_open_input(&fmt_ctx, filename, nullptr, nullptr) != 0) {
std::cerr << "无法打开文件" << std::endl;
return -1;
}
// 查找视频流信息
if(avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
std::cerr << "无法获取流信息" << std::endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 定位视频流
int video_stream = -1;
AVCodecParameters* codec_par = nullptr;
for(int i = 0; i < fmt_ctx->nb_streams; i++) {
if(fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream = i;
codec_par = fmt_ctx->streams[i]->codecpar;
break;
}
}
if(video_stream == -1) {
std::cerr << "未找到视频流" << std::endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 获取解码器
const AVCodec* codec = avcodec_find_decoder(codec_par->codec_id);
if(!codec) {
std::cerr << "不支持的解码器" << std::endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 创建解码上下文
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx, codec_par);
if(avcodec_open2(codec_ctx, codec, nullptr) < 0) {
std::cerr << "无法打开解码器" << std::endl;
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
return -1;
}
// 初始化SWS转换上下文
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, nullptr, nullptr, nullptr);
// 分配帧内存
AVFrame* frame = av_frame_alloc();
AVFrame* rgb_frame = av_frame_alloc();
int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
uint8_t* buffer = (uint8_t*)av_malloc(buffer_size);
av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, buffer,
AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
AVPacket* pkt = av_packet_alloc();
cv::namedWindow("Video", cv::WINDOW_AUTOSIZE);
// 主解码循环
while(av_read_frame(fmt_ctx, pkt) >= 0) {
if(pkt->stream_index == video_stream) {
int ret = avcodec_send_packet(codec_ctx, pkt);
if(ret < 0) continue;
while(ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;
if(ret < 0) {
std::cerr << "解码错误" << std::endl;
break;
}
// 转换颜色空间
sws_scale(sws_ctx,
frame->data, frame->linesize, 0,
codec_ctx->height,
rgb_frame->data, rgb_frame->linesize);
// 创建OpenCV Mat并显示
cv::Mat img(codec_ctx->height, codec_ctx->width,
CV_8UC3, rgb_frame->data);
cv::imshow("Video", img);
if(cv::waitKey(25) == 27) break; // ESC退出
}
}
av_packet_unref(pkt);
}
// 清理资源
av_free(buffer);
av_frame_free(&frame);
av_frame_free(&rgb_frame);
av_packet_free(&pkt);
sws_freeContext(sws_ctx);
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
cv::destroyAllWindows();
return 0;
}
程序说明
-
FFmpeg初始化
使用avformat_open_input打开媒体文件
通过avformat_find_stream_info获取流信息 -
视频流处理
定位视频流索引
创建解码器上下文并打开 -
颜色空间转换
使用sws_getContext初始化转换上下文
将原始帧转换为RGB24格式 -
OpenCV显示
将转换后的RGB数据包装为cv::Mat
使用imshow显示视频帧
5 小结
VS2022配置FFMPEG库,在使用预编译包的情况下,没有特殊需要注意的,按照常规的第三方库配置思路进行配置即可。