VS2022配置FFMPEG库基础教程

news/2025/2/24 11:34:24

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库,在使用预编译包的情况下,没有特殊需要注意的,按照常规的第三方库配置思路进行配置即可。


http://www.niftyadmin.cn/n/5864277.html

相关文章

Fences 5深度解析:一键打造超高效整洁桌面

在信息爆炸的时代,电脑桌面往往成为各种文件、图标和快捷方式的“聚集地”。杂乱无章的桌面不仅影响视觉体验,还可能降低工作效率。而Fences 5,这款由Stardock公司精心打造的桌面管理工具,凭借其强大的功能和便捷的操作,成为了众多用户整理桌面的得力助手。本文将带大家深…

Python爬虫处理网页中的动态内容

文章目录 前言一、Python环境搭建1.Python安装2.选择Python开发环境 二、Python爬虫处理网页中的动态内容1. 使用 Selenium 库2. 使用 Pyppeteer 库3. 分析 API 请求 前言 在网页中&#xff0c;动态内容通常是指那些通过 JavaScript 在页面加载后动态生成或更新的内容&#xf…

深入解析:短轮询、长轮询、长连接与WebSocket(原理到实现)

从原理到实战&#xff1a;深度剖析短轮询、长轮询、长连接及 WebSocket 的实现与差异 在日常开发中&#xff0c;短轮询、长轮询、长连接和WebSocket是常见的几种通信技术&#xff0c;各自适用于不同的场景。本文将深入分析这四种技术&#xff0c;从原理到实现&#xff0c;并探讨…

插入排序(详解)c++

插⼊排序(Insertion Sort)类似于玩扑克牌插牌过程&#xff0c;每次将⼀个待排序的元素按照其关键字⼤⼩插⼊到前⾯已排好序的序列中&#xff0c;按照该种⽅式将所有元素全部插⼊完成即可 算法思想&#xff1a; 把待排序元素插入到已排序的序列中。想象一下一张一张整理扑克牌的…

【Python量化金融实战】-第1章:Python量化金融概述:1.2 Python在量化金融中的优势与生态

本小节学习建议&#xff1a;Python在量化金融领域的统治地位不仅体现在当前的技术栈中&#xff0c;更在于其持续进化的能力。随着AI、区块链等新技术的融合&#xff0c;Python开发者将始终处于金融创新的最前沿。建议学习者从构建完整的策略生产线开始&#xff0c;逐步深入高频…

【HarmonyOS Next】鸿蒙状态管理V2装饰器详解

【HarmonyOS Next】鸿蒙状态管理V2装饰器详解 一、为什么需要V2状态管理装饰器&#xff1f; 首先我们需要了解什么是状态管理&#xff1f;在鸿蒙应用开发中&#xff0c;状态管理指的是&#xff0c;管理数据变化去刷新UI的整个过程。 举个例子&#xff0c;比如在界面中标题文…

day58 第十一章:图论part08

拓扑排序精讲 关键&#xff1a; 先找到入度为0的节点&#xff0c;把这些节点加入队列/结果&#xff0c;然后依次循环再找。 #include <iostream> #include <vector> #include <queue> #include <unordered_map> using namespace std; int main() {int …

MybatisPlus-注解

TableName设定表名 1. MyBatis-Plus在确定操作的表时&#xff0c;由BaseMapper的泛型决定&#xff0c;即实体类型决 定&#xff0c;且默认操作的表名和实体类型的类名一致 2. 若实体类类型的类名和要操作的表的表名不一致&#xff0c;访问数据库表将会报错 3. 在实体类上添加…