简介:这是一份基于Qt5.15.2与VLC3.0.14、使用MinGW64工具链在Windows环境下交叉编译生成的集成开发包,面向需要在Qt界面中嵌入VLC播放能力的C++开发者与音视频应用爱好者。压缩包内已预先完成libVLCQt系列动态库的编译,并提供对应的头文件与CMake配置文件,开发者可直接将VLCQtCore、VLCQtWidgets、VLCQtQml等模块引用至自己的Qt工程,免去手动搭建MinGW编译环境和排查依赖链的繁琐过程,适合具备一定Qt基础、希望加快播放器功能落地的中级开发者参考使用。
包内共399个文件,其中338个dll为运行时所需的动态链接库,38个h头文件和14个cmake配置文件用于工程引用与构建,另有少量静态库及pkg-config描述文件辅助链接,压缩包整体43.28MB,结构较为紧凑。目前已有435人浏览学习,说明该集成方案具备一定的参考价值。需要注意的是,此构建并非VLC官方发行版本,下载后仅限24小时内本地验证使用,建议读者将其作为学习Qt与VLC集成原理的样例,在此基础上结合自身项目需求重新编译定制。
1. 拿到 vlc-qt 的 mingw64 构建包:先确认它就是你要的那套 Qt + VLC 组合
vlc-qt 在 mingw64 下从源码 build 到 install,流程长且容易翻车,而这个 vlc-qt_build_mingw64_install.zip 直接把人编译好的产物打包成了 zip:版本固定 Qt5.15.2 + VLC3.0.14,工具链 mingw8.1.0_64,导入库和 CMake 配置齐全。这个库本质是 libVLC 的 C++ 封装,把 C 接口包成 VlcInstance、VlcMedia、VlcMediaPlayer 三个类,还带能嵌进 QWidget 的播放控件。当 QMediaPlayer 被系统解码器卡住时,这套组合是 Qt 客户端内嵌播放的最快路线。适合用 Qt 5.15.2 MinGW 版、想把解码交给 VLC 的开发者。提醒一句:非官方构建,作者声明仅供交流、下载后 24 小时内删除,商用请自行确认授权。
2. VLC-Qt 的构成与工具链配套:Qt5.15.2、VLC3.0.14、mingw8.1.0 为什么必须绑死
2.1 VLC-Qt 到底封装了什么
libVLC 本身是纯 C 接口,最常见的三个对象是 libvlc_instance_t、libvlc_media_t、libvlc_media_player_t,所有操作都要手动管理内存和引用计数。VLC-Qt 做的就是把这套 C 接口包成 C++ 类:VlcInstance 负责 libvlc_new 和 libvlc_release,VlcMedia 负责媒体源解析,VlcMediaPlayer 负责 Play、Pause、Stop 以及视频输出窗口绑定。Widgets 模块在核心之上又做了一层 QWidget 封装,相当于给你一个拖进 UI 就能用的播放器控件。
对照压缩包里的文件名,模块划分很清楚:libVLCQt.dll.a 是公共核心壳,所有模块共用;libVLCQtCore.dll.a 是核心类库;libVLCQtWidgets.dll.a 是 QWidget 控件模块;libVLCQtQml.dll.a 是给 QML 场景用的模块。文件名里的 .dll.a 是 MinGW 导入库,链接期使用,运行时真正干活的是 libVLC 自己的 libvlc.dll、libvlccore.dll 和 plugins 插件目录。这一点很多人搞混,拿了一堆 .a 文件就以为万事大吉,结果一运行就提示找不到 libvlc.dll。
我一般拿到这类预编译包,第一反应不是看导入库体积,而是先看 .cmake 配置文件里的版本号,确认它和我要用的 Qt 是不是同一个 ABI。MinGW 和 MSVC 的 C++ 类布局不同,符号修饰规则也不同,用 MSVC 的 Qt 去链 MinGW 的导入库,基本就是玄学范畴。运气好能过编译,运行起来大概率在某个字符串构造处直接崩溃,这种问题查起来非常难受,因为你面对的是两个编译器的黑匣子。
2.2 三个版本为什么必须绑在一起看
这套包的核心版本组合是 Qt5.15.2、VLC3.0.14、mingw8.1.0_64。Qt5.15.2 是 Qt 5 系列最后一条 LTS 分支上的版本,官方在这个版本保留了 MinGW 8.1.0 64-bit 的预编译安装包,很多人选 5.15.2 就是为了这套干净的 MinGW 环境。VLC 3.0.14 是 libVLC 3.0 分支的稳定点,插件体系成熟。mingw8.1.0_64 对应 GCC 8.1.0,是 Qt 官方工具链匹配版本,太新的 GCC 可能踩 Qt 内部对旧编译器的兼容假设,太旧又缺 C++14 标准库支持。
三者的关系可以理解成:Qt 决定你的 C++ ABI,mingw 决定代码怎么编译,libVLC 决定你链哪个版本的导入库和头文件。任何一个换掉,包内 Targets.cmake 记录的路径和版本就可能对不上,编译期或运行期总有一个地方要出事。实际生产里我用 8.1.0 和 8.3.0 都编译通过,但没跨到 10、11 代以上,这不是保守,是不想给自己找无谓的排查成本。
组件 | 当前包里的版本 | 选型理由 Qt | 5.15.2(MinGW 64-bit) | Qt 5 LTS,官方保留 MinGW 配套安装包,适合 Windows 桌面客户端 libVLC | 3.0.14 SDK | 3.0 分支 API 稳定,解码器与插件体系成熟 工具链 | mingw-w64 GCC 8.1.0 64 位 | 与 Qt 官方安装包工具链一致,规避 ABI 兼容问题
2.3 拿到包以后先验证三件事
第一步,确认本机 Qt 是 MinGW 版。终端跑qmake -v,看输出里的编译器信息,如果是 MSVC 版,后面全白搭,先去装 Qt 5.15.2 MinGW 64-bit 版本再回来。第二步,确认 GCC 版本,运行g++ --version,只要在 8.x 附近即可,跨到 10 代以上就得留个心眼。第三步,检查 libVLC 运行时,确认 libvlc.dll、libvlccore.dll 和 plugins 插件目录在你的程序能找到的位置。3.0.14 的导入库配 3.0 系列新一点的 dll 一般能跑,反过来用新 SDK 头文件链旧 dll 很容易出兼容问题。
注意:三步验证顺序不能反。先确认 Qt 编译器类型,这是全局性问题,改不了只能换 Qt;再确认工具链版本,正常不会有乱子;最后看 libVLC 运行时,属于细节问题,环境变量就能修正。把最容易修的放最后,排查效率才高。
3. 安装与路径规划:把 .dll.a 和 .cmake 放进 CMake 找得到的地方
3.1 先分清压缩包里两类文件
解压出来的 10 个文件分两堆。第一堆是四个导入库:libVLCQt.dll.a、libVLCQtCore.dll.a、libVLCQtWidgets.dll.a、libVLCQtQml.dll.a,对应 VLC-Qt 的四个模块,链接期使用。第二堆是六个 CMake 文件,VLCQtCoreConfigVersion.cmake、VLCQtWidgetsConfigVersion.cmake、VLCQtQmlConfigVersion.cmake 负责版本校验,VLCQtCoreTargets.cmake、VLCQtWidgetsTargets.cmake、VLCQtQmlTargets.cmake 负责把导入库和头文件路径打包成具体 target。
有个细节容易被忽略:这个包里我没有看到 VLCQtCoreConfig.cmake 这种 Config 入口文件,只有 ConfigVersion 和 Targets。如果直接把包路径写进 CMAKE_PREFIX_PATH 然后 find_package(VLCQtCore),CMake 找的是 VLCQtCoreConfig.cmake,入口缺失就会直接报找不到包。标题里的 install 指的是 CMake install 导出的产物,不是双击运行的安装程序,所以这种情况在预编译包里很常见。
解决办法是自己补一个最小入口,放到<prefix>/lib/cmake/VLCQtCore/下:
# 最小可用的 VLCQtCoreConfig.cmake,用于补全 find_package 入口 include("${CMAKE_CURRENT_LIST_DIR}/VLCQtCoreTargets.cmake") set(VLCQtCore_FOUND TRUE)这个文件的核心作用是把 Targets.cmake 拉进来。Targets.cmake 里面记录了 include 路径、导入库路径以及 VLCQt::Core 这类 target 定义,手动 include 和走 find_package 最终效果一样,差别只是你有没有提供一个 CMake 能识别的文件名入口。Widgets、Qml 两个模块按同方式各补一份。
3.2 目录结构与 ZIP 解压步骤
解压这个 zip 时,我建议把释放出来的东西当“虚拟安装前缀”处理,不要散到桌面。完整规划一个 VLC_QT_DIR,内部结构按下面来:
# 先解压,再手动组织目录结构 mkdir -p /d/dev/vlc-qt cd /d/dev/vlc-qt # 解压 zip 到临时目录,Windows 下没 unzip 命令就用资源管理器解压或 tar -xf 处理 unzip ../vlc-qt_build_mingw64_install.zip -d extracted cd extracted # 把 include 与 lib 归位,config 文件放 lib/cmake 下的模块目录 mkdir -p ../include ../lib/cmake/VLCQtCore ../lib/cmake/VLCQtWidgets ../lib/cmake/VLCQtQml # 按解压后的真实目录调整复制动作,原则是 .h 放 ../include,.a 与 .cmake 按模块归位不要急着写死路径,先把 include 和 lib 两个顶层目录落位。CMake 的 find_package 在<prefix>/lib/cmake/<Name>/位置找 Config 文件,所以 CMAKE_PREFIX_PATH 必须指向 vlc-qt 根目录,而不是指向 lib。路径层级配错是预编译包最常见的翻车点,很多人把 prefix 指到 lib/cmake 层,然后纠结为什么 find_package 还是找不到。
3.3 把路径交给 CMake 而不是写死在工程里
我一般用环境变量 VLC_QT_DIR 传递安装前缀,这样 CMakeLists.txt 里不需要出现任何本机绝对路径。Windows 下在系统环境变量里加VLC_QT_DIR=D:/dev/vlc-qt,或者用 CMakePresets.json 的 cacheVariables 注入。CMake 里这样读取:
# 从环境变量读取安装前缀,并对缺失做保护 if(NOT DEFINED VLC_QT_DIR AND DEFINED ENV{VLC_QT_DIR}) set(VLC_QT_DIR "$ENV{VLC_QT_DIR}") endif() list(APPEND CMAKE_PREFIX_PATH "${VLC_QT_DIR}")这样处理的好处是工程文件可移植。同事 clone 之后只需要改一个环境变量,不需要动 CMakeLists。加一层保护逻辑也很有必要,环境变量没设置时,CMake 错误信息会明确指向这个变量,而不是报一个误导性的“找不到 VLCQtCore”。
提示:CMAKE_PREFIX_PATH 是按前缀拼接目录的,只要你的目录结构是 include/、lib/cmake 这种标准 layout,就不需要为每个模块手动 append 路径。
4. 用 CMake 接进工程:从 find_package 到第一个能拖动窗口的播放器
4.1 最小 CMakeLists.txt
实际项目里我不会把 VLC 相关的东西散布到子目录的 CMakeLists,而是集中在顶层。下面是能跑通的最小编译配置:
cmake_minimum_required(VERSION 3.16) project(vlcqt_demo LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) # 读取环境变量指向的安装前缀 if(NOT DEFINED VLC_QT_DIR AND DEFINED ENV{VLC_QT_DIR}) set(VLC_QT_DIR "$ENV{VLC_QT_DIR}") endif() list(APPEND CMAKE_PREFIX_PATH "${VLC_QT_DIR}") # 找 VLC-Qt 两个模块:Core 提供核心类,Widgets 提供播放控件 find_package(VLCQtCore REQUIRED) find_package(VLCQtWidgets REQUIRED) add_executable(vlcqt_demo WIN32 main.cpp ) target_link_libraries(vlcqt_demo PRIVATE VLCQt::Widgets VLCQt::Core )这里有个链接顺序的讲究:MinGW 的链接器是单遍扫描,静态库和导入库从左到右解析符号,后面的库不会回头补前面缺失的符号。VLCQtWidgets 依赖 VLCQtCore,VLCQtCore 依赖公共库 VLCQt,所以顺序必须从上层控件到内核,写反了就是一堆 undefined reference。没有显式写 VLCQt 是因为 Widgets 和 Core 的 Targets.cmake 通常会把公共库作为 PUBLIC 依赖串进去,你不需要自己手动追加。
4.2 main.cpp 最小实现
#include <QApplication> #include <QWidget> #include <QVBoxLayout> #include <VlcInstance.h> #include <VlcMedia.h> #include <VlcMediaPlayer.h> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 实例化和媒体对象挂在主窗口父对象上,析构交给 Qt 管理 VlcInstance *instance = new VlcInstance(VlcCommon::args(), &app); VlcMediaPlayer *player = new VlcMediaPlayer(instance); QWidget window; window.resize(800, 450); // VlcWidgetVideo 是 Widgets 模块自带的视频输出控件 VlcWidgetVideo *videoWidget = new VlcWidgetVideo(&window); QVBoxLayout *layout = new QVBoxLayout(&window); layout->addWidget(videoWidget); // 把视频输出绑定到控件,注意要在 setMedia 之前调用 player->setVideoWidget(videoWidget); // 本地文件必须用 file:/// 前缀,Windows 路径写 file:///C:/videos/test.mp4 VlcMedia *media = new VlcMedia("file:///C:/videos/test.mp4", instance); player->setMedia(media); window.show(); player->play(); return app.exec(); }这段代码有几个容易写错的地方。setVideoWidget 必须在 setMedia 之前调用,顺序反了画面出不来,播放器也不报错,表现出来就是黑屏。文件路径必须用 file:/// 协议前缀,直接传 C:/videos/test.mp4 会被解析成相对路径,然后告诉你 media 打开失败。VlcCommon::args() 返回初始化 libVLC 所需的默认参数列表,不同版本可能略有差异,但基本都能用;生产项目里我一般会再追加--no-video-title-show这类参数关掉默认标题覆盖。
4.3 运行时的文件布局
编译通过只是第一步,运行时还要保证 exe 旁边有正确的 DLL 和插件目录。这一步不加当,最常见现象是双击程序弹窗提示找不到 Qt 平台插件,或者播放器黑屏只有声音没有画面。我一般把部署目录组织成三层:
| 文件/目录 | 来源 | 是否必需 | | libvlc.dll | libVLC 官方运行时 | 必需 | | libvlccore.dll | libVLC 官方运行时 | 必需 | | plugins/ | VLC 插件目录 | 必需 | | libgcc_s_seh-1.dll、libstdc++-6.dll 等 | MinGW 工具链运行时 | 必需 | | platforms/qwindows.dll | Qt 平台插件 | 必需 |
其中 plugins 一定不能漏。libVLC 的解码器、demux、输出模块都从这里加载,缺了它的表现就是黑屏或直接无响应,日志里写 cannot open access。可以用环境变量 VLC_PLUGIN_PATH 指向部署目录里的 plugins,Qt 平台插件则用 QCoreApplication::addLibraryPath 指定,两者不是一回事,别混在一起。
注意:不要迷信把整个 VideoLAN 安装目录拷过来,体积太大。只需要 libvlc.dll、libvlccore.dll 和 plugins 目录,VLC 安装目录里那些 exe 和 locale 文件都用不上。
5. 避坑指南:链接顺序、运行时 DLL 与授权条款的五个踩坑现场
这个包实际用起来坑不少,我按踩过的频率从高到低排一遍。每条都是现象、原因、解决三段,不是抽象警告。
1. find_package 报错:找不到 VLCQtCore 包配置文件
现象:cmake 配置阶段报By not providing "FindVLCQtCore.cmake"或直接提示找不到包配置文件。
原因:压缩包里没有 VLCQtCoreConfig.cmake,只有 VLCQtCoreConfigVersion.cmake 和 VLCQtCoreTargets.cmake。find_package 优先找 Config 入口文件,版本文件是入口找到之后才读的,入口缺失等于模块整体不可见。另一个常见原因是 CMAKE_PREFIX_PATH 指到了 lib 或 lib/cmake 层,而不是根目录。
解决:按第 3 章的方式,用 include 手动引入 Targets.cmake,补一个 VLCQtCoreConfig.cmake 到<prefix>/lib/cmake/VLCQtCore/下。顺手检查路径拼接,prefix 是根目录,不是 module 目录。
2. 链接阶段一大片 undefined reference
现象:链接时输出几十个 undefined reference,集中在 VlcMediaPlayer 相关符号上,编译阶段一切正常。
原因:MinGW 的链接器单遍扫描依赖库,VLCQt::Widgets、VLCQt::Core、公共库 VLCQt 三者顺序不对,符号没有被正确解析。尤其把 VLCQt::Core 写在 VLCQt::Widgets 前面时,Widgets 里的符号就没人管了。
解决:target_link_libraries 顺序固定成 VLCQt::Widgets VLCQt::Core,显式引用公共库时把 VLCQt 放最后。还有一个技巧是用 --start-group 把一组库包起来,但静态库互相引用严重时才需要,正常情况调顺序就够了,不要上 group 这种大锤。
3. 运行时黑屏:有声音没画面,或者直接闪退
现象:程序跑起来,窗口正常显示,但播放区全黑;有些机器上直接闪退,没有任何 Qt 报错。
原因:libVLC 插件没加载。VLC 的解码器、demuxer、video output 全部在 plugins 目录里,exe 旁边没有这个目录时 libVLC 只加载基础模块,常见 mp4 都打不开。另一个可能是 setVideoWidget 写在 setMedia 后面,视频输出绑定错过了。
解决:把 plugins 目录放到 exe 同目录,设置 VLC_PLUGIN_PATH 指向它,或者在初始化 libVLC 时用代码设置插件路径。先处理这个,再检查代码里 setVideoWidget 和 setMedia 的顺序。我每次打完包都会把这两件事列成部署清单逐项勾。
4. 用 MSVC 的 Qt 工程链这个 MinGW 导入库
现象:有人在 Qt Creator 建了 MSVC 套件的工程,硬塞这个包的 .a 和头文件,编译过了一些警告,但运行起来在字符串赋值处崩溃。
原因:MSVC 和 MinGW 的 C++ ABI 不兼容,类内存布局、异常处理、动态链接运行时都不同。导入库是给 MinGW 链接器认的,MSVC 的 link.exe 根本不该吃这个文件。
解决:整个工程切换成 Qt 5.15.2 MinGW 64-bit 套件,确认构建的 g++ 是 8.1.0 一代。如果项目被 MSVC 第三方库锁死,就老实用 VLC-Qt 官方源码在 MSVC 下重新编一套,这个包救不了你,别硬凑。
5. 授权条款与 24 小时删除约定
现象:有人把这个预编译产物直接塞进商业产品发布,或者在公司内部大规模分发。
原因:这是非官方个人构建,包内声明仅供爱好者交流、下载后 24 小时内删除。把它当生产依赖,等于把第三方个人构建的无保证产物引入了供应链,出了问题没人给你兜底,也没法重放构建过程。我不展开法律分析,但至少要尊重作者写的约定。
解决:学习、验证、对比代码行为,用它没问题;上线商用,建议自己用相同参数从源码编一套,另存一份构建日志。这样出了问题能重放构建过程,链路完整。
6. 进阶技巧:用十秒自检包验证构建,再精简部署目录
我拿到任何新的 VLC-Qt 构建包,第一件事不是写业务代码,而是编一个十秒自检程序。说白了这个包是不是真的能用,取决于三个事实:qmake 是 MinGW、libvlc.dll 能被加载、plugins 里有能用的解码器。把第 4 章那个 main.cpp 改一下,播放一个 10 秒的本地测试视频,运行后满足三点就算通过:窗口能看到画面而不是黑屏、拖动播放进度条能暂停和恢复、任务管理器里 CPU 占用从启动瞬间的高位回落到几个百分点。整个过程不到十分钟,能筛掉八成的问题包。
自检通过之后,部署目录不要全量拷贝。VLC 官方安装目录里有大量用不到的东西,精简打包才是落地形态。我一般只留 plugins 里的几个子目录:access、demux、packetizer、codec、audio_output、video_output,其余 playList、services_discovery、spu 这类的先不用就不拷。
# 在部署目录下执行,按实际 plugins 内容保留最小组 cd deploy/vlc mkdir -p plugins/access plugins/demux plugins/packetizer \ plugins/codec plugins/audio_output plugins/video_output cp -r libvlc.dll libvlccore.dll .这个命令在部署目录就地操作,先建好最小插件子目录,再把 libVLC 运行时两个核心 dll 拷回来。之后删掉 plugins 里没用到的原始目录,整个 deploy 目录就是一份干净可发布的播放组件。做完把它打成 zip 备份,以后每次换 Qt 或 VLC 版本,解压这个 zip、替换 dll 和 plugins、重跑一遍十秒自检就能验证新包。从那以后,我每次拿到 vlc-qt 的构建包都会强制走一遍这套流程:先验证工具链,再补 Config 入口,链接顺序固定,部署清单逐项勾选,最后十分钟自检收尾。这套流程帮我避开了两次很坑的集成事故,希望帮到你。
本文还有配套的精品资源,点击获取