简介:面向需要在 Windows 上把 VLC 播放能力集成到 Qt 工程的 C++/Qt 开发者,这份资料围绕 vlc-qt 1.1.1 的编译产物整理,适合音视频播放器开发、二次封装、环境搭建与编译验证。压缩包共 77 个文件,约 36.71MB,以 38 个 h 头文件、17 个 cmake 配置、10 个 dll 动态库和 8 个 lib 导入库为主,并附 vlc-3.0.0-win64.7z 与 vlc-qt-1.1.1.tar.gz,覆盖源码、运行时依赖和 debug/release 两套预编译库;头文件用于接口声明,CMake 文件便于工程查找依赖,dll/lib 可直接参与链接。目录按 VLCQtCore、VLCQtWidgets、VLCQtQml 等模块组织,并含 qmldir、qmltypes 等 QML 元数据。已有 1920 人学习下载。读者可据此复用编译后的库与依赖搭配,减少依赖获取与链接配置成本,也便于对照自身工程核对 debug 与 release 配置。
1. Windows 下编译 VLC-Qt,真正花时间的是让 DLL 出现在正确的位置,而不是输入那几行 CMake
桌面端要在 Qt 界面里嵌一路播放器,不想拖浏览器内核,最常见的落点就是把 libVLC 包一层,VLC-Qt 正是这层壳。它在 Linux 上一路cmake && make就过去了;到了 Windows,同样几条命令会先卡在“找不到 libvlc.lib”,再卡在“插件加载失败”,最后卡在“编过了但一直黑屏”。这篇只讲在 Windows 下把 VLC-Qt 从源码编出来、装进 Qt 工程、跑到能出画面的完整路径,包括位数对齐、Debug/Release 取舍、DLL 与 plugins 目录怎么放,这些才是真正消耗时间的环节。适合已经能用 CMake 和 Qt Creator 建工程、准备自建播放模块的桌面端开发者。
2. 编译前先对齐三件套:Qt 套件、libVLC SDK、CMake 生成器
2.1 VLC-Qt 只是薄壳,真正决定成败的是 libVLC 的二进制形态
VLC-Qt 这个名字容易让人误以为它是一个完整播放器,实际它只做一件事:把 libVLC 的 C 接口包成 QObject 风格的类,VlcInstance、VlcMediaPlayer、VlcWidgetVideo底下全是libvlc_*调用。编译 VLC-Qt 的整个过程中,libVLC 本体一行都不会被编译,你面对的是一个预编译好的二进制 SDK。
这件事直接决定了 Windows 上的动手顺序:先把 libVLC SDK 的形态确认清楚,再谈 VLC-Qt 怎么编。一个可用的 SDK 必须同时给出三样东西——头文件(以vlc/vlc.h为入口的那一套)、导入库(MSVC 下是.lib)、以及运行时(libvlc.dll、libvlccore.dll,加上整个plugins目录)。这三样少任何一样,后面都会以完全不同的报错形式还给你。
关键认知在于:导入库不是代码,它只是一张符号索引表。链接期 CMake 拿着这张表去核对符号名,运行期 Windows 加载器再去磁盘上找.dll。所以“链接通过”和“跑得起来”是两个独立关卡,报错长得完全不一样,这也是新手最容易把两类问题混在一起排查的地方。
还有一层容易被忽略:plugins目录才是 libVLC 真正的解码能力所在。dll 本身只有调度逻辑,解封装、解码、输出全靠插件。很多“能编译、能链接、能启动,就是不出画面”的案子,根子在插件目录没摆对,而不是代码写错了。
2.2 用 dumpbin 与 qmake -query 把位数和运行库固定下来
Windows 上最没技术含量、又最容易出错的一类问题是位数不匹配。x64 的 exe 链 x86 的 lib 会直接报 LNK1112,x64 进程加载 x86 的 dll 会在启动瞬间退出去,日志里只留一行看不懂的东西。开工前花两分钟确认,能省掉后面半小时的猜谜。
:: 在 “x64 Native Tools 命令提示符” 里执行,不要用普通 cmd :: 1) 看 libVLC 导入库的目标架构 dumpbin /headers "<VLC_SDK_DIR>\sdk\lib\libvlc.lib" | findstr /i "machine" :: 2) 看打算使用的 Qt 套件是什么架构 dumpbin /headers "<QT_DIR>\bin\Qt5Core.dll" | findstr /i "machine" :: 3) 看 libVLC 运行时依赖哪些 CRT,判断要不要装运行库 dumpbin /dependents "<VLC_SDK_DIR>\libvlc.dll"dumpbin /headers的输出里machine (x64)或machine (x86)就是答案,两处必须一致。第三条命令的输出同样值得看一眼:如果libvlc.dll依赖MSVCP140.dll、VCRUNTIME140.dll这类名字,说明目标机器上要有对应的运行库,否则用户那边会以“缺 dll”的形式失败——而你的开发机上往往早就装过了,根本复现不了。
qmake -query QT_INSTALL_PREFIX能告诉你当前 Qt 套件的安装前缀,把它记下来,后面CMAKE_PREFIX_PATH要用。Qt 5 和 Qt 6 在这一步就要做出选择:VLC-Qt 的主线代码长期围绕 Qt 5 演进,直接用 Qt 6 编大概率会在QDesktopWidget、QRegExp这类早已移除的 API 上翻车,Qt 6 需要你自己打补丁适配,别在这上面浪费时间。
提示:
dumpbin只在 Visual Studio 的开发者命令提示符里可用。如果你用 MinGW 工具链,用objdump -f看架构,用objdump -p看依赖。
2.3 先把目录摆成 CMake 认得的形状
拿到 SDK 压缩包后,别急着解压完就直接编。libVLC 的分发包里,include、lib和运行时的libvlc.dll、plugins通常不在同一层目录,混在一起会让后面的路径变量写得很难看。我一般会先手工整理成一个固定形状,写进一个文本文件备查:
| 目录 | 应该放什么 | 谁在用 |
|---|---|---|
<VLC_SDK_DIR>\sdk\include\vlc\vlc.h | libVLC 头文件入口 | 编译期 include |
<VLC_SDK_DIR>\sdk\lib\libvlc.lib | MSVC 导入库 | 链接期 |
<VLC_SDK_DIR>\sdk\lib\libvlccore.lib | 核心导入库,部分符号在这里 | 链接期 |
<VLC_SDK_DIR>\libvlc.dll | 运行时 | 部署 |
<VLC_SDK_DIR>\plugins\ | 全部解码/输出插件 | 运行时 |
对应地,CMake 侧要喂的变量也就那么几个:
| CMake 变量 | 指向 | 说明 |
|---|---|---|
CMAKE_PREFIX_PATH | Qt 前缀 + VLC-Qt 安装前缀 | 多个路径用分号分隔,别用逗号 |
LIBVLC_INCLUDE_DIR | ...\sdk\include | 目录下应当直接存在vlc\vlc.h |
LIBVLC_LIBRARY | ...\sdk\lib\libvlc.lib | 位数必须与目标一致 |
LIBVLC_LIBRARY_CORE | ...\sdk\lib\libvlccore.lib | 有些版本不强制,缺了会报未解析符号 |
不同发行版本的变量名可能是复数形式(LIBVLC_INCLUDE_DIRS、LIBVLC_LIBRARIES)。与其背,不如配一次就打开cmake-gui看缓存区里实际出现了哪些名字,照着填最稳。这一步做完,后面的 configure 才有意义。
3. 从源码到 .lib 和 .dll:VLC-Qt 的配置、构建与安装三段式
3.1 生成阶段:把 CMAKE_PREFIX_PATH 一次喂对
VLC-Qt 的构建分三段:configure 生成工程文件、build 出二进制、install 整理成一个可被find_package消费的前缀。第一段最容易反复,因为 CMake 会缓存上一次的错误结果,改完变量不删缓存就会一直报同样的错。
:: 建议每次重来都先删掉 build 目录,别在脏缓存上反复试 cmake -S "<VLCQT_SRC>" -B "<VLCQT_BUILD>" ^ -G "Visual Studio 17 2022" -A x64 ^ -DCMAKE_PREFIX_PATH="<QT_DIR>;<VLCQT_INSTALL>" ^ -DLIBVLC_INCLUDE_DIR="<VLC_SDK_DIR>/sdk/include" ^ -DLIBVLC_LIBRARY="<VLC_SDK_DIR>/sdk/lib/libvlc.lib" ^ -DLIBVLC_LIBRARY_CORE="<VLC_SDK_DIR>/sdk/lib/libvlccore.lib" ^ -DCMAKE_INSTALL_PREFIX="<VLCQT_INSTALL>" ^ -DBUILD_EXAMPLES=OFF ^ -DBUILD_TESTS=OFF逐项说清楚:-G的生成器字符串必须和你本机装的 VS 版本对应,敲cmake --help能看到全部可选值,写错了会直接提示找不到生成器;-A x64是平台参数,只对 VS 系列生成器有效,用 Ninja 或 MinGW Makefiles 时不要带。CMAKE_PREFIX_PATH里放 Qt 前缀是为了让 CMake 找到Qt5Config.cmake,放 VLC-Qt 前缀是为了让下游工程能找到VLCQtCoreConfig.cmake,两者用分号连接,用分号而不是逗号,这一点经常被写错。
BUILD_EXAMPLES和BUILD_TESTS关掉能明显缩短构建时间,也避免示例工程自身的额外依赖把 configure 拖挂。选项名在不同分支上可能是BUILD_TESTS也可能是别的写法,configure 完成后看输出里的 “Configuring done” 之前那段选项列表,比照着自己需要的改。
注意:多配置生成器(VS、Xcode)会忽略
CMAKE_BUILD_TYPE。在 VS 生成器下写-DCMAKE_BUILD_TYPE=Release不会有任何效果,配置由--config在构建期决定。
3.2 构建阶段:Debug 与 Release、静态与动态的真实取舍
:: 先只编 Release,跑通了再补 Debug,别一上来两个都编 cmake --build "<VLCQT_BUILD>" --config Release --target install --parallel :: 需要调试期符号时再补一次 cmake --build "<VLCQT_BUILD>" --config Debug --target install --parallel--target install一步到位,省掉单独再敲cmake --install。--parallel不带数字时按 CPU 核数走,机器内存小的话显式写--parallel 8之类,避免链接阶段 OOM。
关于 Debug/Release,血泪经验是:libVLC 那个 dll 是 Release 构建的,它的堆和 CRT 状态跟你的 Debug 版进程并不共享。只要你不跨 DLL 边界传递new出来的对象、不走 C++ 异常穿越边界,用 Debug 配置链接 Release 的导入库通常没事;但一旦你在 Debug 下把VlcMedia这类包装对象在自己模块里 new 了又交给库去 delete,堆断言就会在播放几秒后冒出来。稳妥做法是日常联调用 Release,要断点排查自己那层逻辑时再切 Debug。
静态链接是另一个常见误区。libVLC 在 Windows 下基本不提供可用的静态库,它的插件机制本身就依赖动态加载,WITH_STATIC_LIBVLC这个选项在 Windows 上大概率走不通。VLC-Qt 自身可以编成静态库,但那只是把壳静态化,底下的 libVLC 依然是 dll,收益有限,反而让部署时多一层困惑。默认走动态就好。
3.3 安装阶段:install 之后前缀下应该看到什么
构建成功不等于能被消费。install之后,到你指定的前缀下逐项核对,缺一项下游工程就会以一个看起来毫不相关的错误失败:
| 路径 | 内容 | 缺失后的典型症状 |
|---|---|---|
include/VLCQtCore/ | Core 模块头文件 | 编译期VLCQtCore/Media.h: No such file |
include/VLCQtWidgets/ | Widgets 模块头文件 | 只有 Core 编得过,Widgets 编不过 |
lib/VLCQtCore.lib | 导入库 | 链接期 LNK2019 一堆未解析符号 |
bin/VLCQtCore.dll | 运行时 | 启动即报缺 dll |
lib/cmake/VLCQtCore/ | CMake 包配置 | find_package直接失败 |
如果lib/cmake下面空空如也,说明这次构建没有生成包配置文件,下游只能退回到手工include_directories加target_link_libraries的土办法。能修就修,土办法一旦工程多了会非常难维护。
4. 把 VLC-Qt 接进 Qt 工程:一个能出画面的最小播放器
4.1 CMakeLists 里 find_package 与 target_link_libraries 怎么写
cmake_minimum_required(VERSION 3.16) project(MyPlayer LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) # VLC-Qt 的类带 Q_OBJECT,必须开 find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) find_package(VLCQtCore CONFIG REQUIRED) find_package(VLCQtWidgets CONFIG REQUIRED) add_executable(MyPlayer main.cpp playerwindow.cpp playerwindow.h) target_link_libraries(MyPlayer PRIVATE Qt5::Widgets VLCQtCore VLCQtWidgets)CONFIG是必须的,它告诉 CMake 走VLCQtCoreConfig.cmake这条路,而不是去FindXXX.cmake的模块目录里瞎找。CMAKE_AUTOMOC一定要开,VLC-Qt 的类全部带Q_OBJECT,漏了会在链接期出现vtable for ...未解析这种极其迷惑的错误。
如果find_package报找不到,先别怀疑人生,去<VLCQT_INSTALL>/lib/cmake/下面看目录名到底叫什么。有些构建出来的包名和你想的不一样,target 名也可能不是VLCQtCore。打开VLCQtCoreTargets.cmake,里面add_library(...)后面的那个名字才是能直接链接的 target 名。
4.2 初始化、挂窗口、播放:三段代码与它们的时序
// playerwindow.cpp —— 只保留能出画面的最小路径 #include "playerwindow.h" #include <VLCQtCore/Common.h> #include <VLCQtCore/Instance.h> #include <VLCQtCore/Media.h> #include <VLCQtCore/MediaPlayer.h> #include <VLCQtWidgets/WidgetVideo.h> #include <QVBoxLayout> PlayerWindow::PlayerWindow(QWidget *parent) : QWidget(parent) { // 1) 实例:带 --verbose=2 让 libVLC 把自己的日志吐出来 QStringList args = VlcCommon::args(); args << "--verbose=2"; m_instance = new VlcInstance(args, this); // 2) 播放器:所有播放状态挂在它身上,生命周期要比视频窗口长 m_player = new VlcMediaPlayer(m_instance, this); // 3) 视频窗口:先建窗口再 setVideoWidget,顺序反了就是永久黑屏 m_video = new VlcWidgetVideo(m_player, this); m_player->setVideoWidget(m_video); auto *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(m_video); } void PlayerWindow::playUrl(const QString &url) { // localFile=false 表示按 URL/流地址处理;读本地文件时传 true auto *media = new VlcMedia(url, false, m_instance); m_player->open(media); // open 是异步的,返回不代表已经出画面 }三个对象的依赖顺序不能乱:VlcInstance是全局上下文,VlcMediaPlayer依赖它,VlcWidgetVideo又依赖 player。setVideoWidget必须在窗口句柄已经创建之后调用,如果你把它写在构造函数的极早期、窗口还没show(),libVLC 拿到的窗口句柄是无效的,画面就永远出不来。稳妥做法是让VlcWidgetVideo先于setVideoWidget完成构造,再在showEvent之后确认一次。
VlcCommon::args()返回一组经过筛选的启动参数,比手工拼靠谱。加上--verbose=2是排查期最有用的一招,libVLC 会把插件加载、解码器选择、输出模块初始化全部打到 stderr,这是唯一的黑匣子。
VlcMedia的第二个参数是“是不是本地文件”,传错不会立刻报错,而是表现为一直缓冲、永远不播。传完open之后立刻返回是正常的,状态变化要走信号,别写成同步等待。
4.3 打包:windeployqt 之后还必须手工补的两样东西
:: 1) 先把 Qt 依赖铺开 windeployqt --release "<OUT_DIR>\MyPlayer.exe" :: 2) 补 libVLC 的两个运行时 dll copy "<VLC_SDK_DIR>\libvlc.dll" "<OUT_DIR>\" copy "<VLC_SDK_DIR>\libvlccore.dll" "<OUT_DIR>\" :: 3) 整目录拷插件,少一个就少一类格式 xcopy /E /I /Y "<VLC_SDK_DIR>\plugins" "<OUT_DIR>\plugins"windeployqt只认 Qt 自己的依赖图,它完全不知道 libVLC 的存在,上面第 2、3 步必须手工补。plugins目录必须和libvlc.dll保持相对位置关系,libVLC 会依据 dll 所在路径去推算插件目录;如果你把它挪到别处,就得通过环境变量或启动参数显式指过去,否则启动时会看到“插件加载失败”但程序不崩,只是什么都不能播。
5. 编译与运行阶段的避坑清单:五种典型翻车现场
5.1 LNK2019 找不到__imp_libvlc_*符号
现象:编译全过,链接阶段报一串unresolved external symbol __imp_libvlc_media_new_location之类的错误,数量从几个到几十个不等。
原因:__imp_前缀意味着链接器在找导入库,说明.lib根本没被链上,或者只链了libvlccore.lib而漏了libvlc.lib。也可能是LIBVLC_LIBRARY指到了一个不存在的路径,CMake 默默忽略,没报错。
解决:先确认LIBVLC_LIBRARY指向的文件真实存在,再用dumpbin /headers核对位数。如果两样都对还是报,就去 CMakeCache.txt 里搜LIBVLC,看最终生效的是哪个值——缓存里的旧值经常在作祟,删掉 build 目录重来一次往往就好了。
5.2 启动就报缺 dll,或者进程一闪而过
现象:开发机上跑得好好的,拷到干净机器上双击没反应,或者弹窗提示找不到libvlc.dll。
原因:运行时 dll 没跟 exe 放在同一目录。Windows 加载器按 exe 目录、系统目录、PATH 的顺序找,开发机上往往因为 PATH 里正好有 VLC 安装目录而侥幸通过,一到干净机器立刻暴露。
解决:把libvlc.dll和libvlccore.dll直接放到 exe 同级目录,plugins放成同级子目录。别依赖 PATH,也别指望安装程序帮你配环境变量,这两条在用户机器上都不可控。
5.3 窗口出来了但一直黑屏,日志里也没有明显报错
现象:播放器控件是黑的,进度条不走或走了没画面,控制台没异常。
原因有三类:setVideoWidget调用时机早于窗口句柄创建;VlcMedia的localFile参数传错导致一直在缓冲;plugins目录里缺视频输出模块(比如 Windows 下需要的几种 vout 插件)。
解决:先加--verbose=2看日志,重点找using video output module这句,没有就是输出模块没加载;有的话再检查setVideoWidget的调用位置,把它挪到窗口show()之后的初始化里;最后确认plugins目录是整目录拷贝而不是只挑了其中几个 dll。
5.4 Debug 配置下播放几秒就崩在堆上
现象:Release 完全正常,Debug 播放几秒后弹断言,停在_CrtIsValidHeapPointer之类的地方。
原因:Debug 版 CRT 和 libVLC 那个 Release dll 使用的是两套堆。只要发生跨边界的内存释放,就会命中堆校验。
解决:把联调配置切回 Release,只在自己那层逻辑需要断点时临时切 Debug,并且保证 Debug 下不把包装对象的所有权交给库。真要长期在 Debug 下开发,就得接受“播放核心部分只能看日志不能断点”这个现实。
5.5 find_package 报找不到 VLCQtCore 的配置文件
现象:下游工程 configure 阶段直接失败,提示Could not find a package configuration file provided by "VLCQtCore"。
原因:要么 install 没执行成功,lib/cmake下是空的;要么CMAKE_PREFIX_PATH只写了 Qt 没写 VLC-Qt 的安装前缀;要么写的是 build 目录而不是 install 前缀。
解决:去<VLCQT_INSTALL>/lib/cmake/下ls一遍,确认有VLCQtCoreConfig.cmake。有的话检查CMAKE_PREFIX_PATH是不是被下游工程覆盖了,用-DCMAKE_PREFIX_PATH="...;..."在命令行显式传一次,比改 CMakeLists 更可靠。
6. 把流程固化成脚本:换一台机器也能复现的检查清单
这套流程手动跑一遍要改十几处路径,第二次换机器还得重来。我的习惯是把所有可变项提到脚本最上面,下面全是固定动作,谁接手都只改前五行:
:: build-vlcqt.cmd —— 换机器只改这一段 set VLCQT_SRC=D:\src\vlc-qt set VLCQT_BUILD=D:\build\vlc-qt set VLCQT_INSTALL=D:\sdk\vlc-qt set QT_DIR=C:\Qt\5.15\msvc2019_64 set VLC_SDK=D:\sdk\vlc :: 下面不动 if exist "%VLCQT_BUILD%" rmdir /S /Q "%VLCQT_BUILD%" cmake -S "%VLCQT_SRC%" -B "%VLCQT_BUILD%" -G "Visual Studio 17 2022" -A x64 ^ -DCMAKE_PREFIX_PATH="%QT_DIR%;%VLCQT_INSTALL%" ^ -DLIBVLC_INCLUDE_DIR="%VLC_SDK%\sdk\include" ^ -DLIBVLC_LIBRARY="%VLC_SDK%\sdk\lib\libvlc.lib" ^ -DCMAKE_INSTALL_PREFIX="%VLCQT_INSTALL%" || exit /b 1 cmake --build "%VLCQT_BUILD%" --config Release --target install --parallel || exit /b 1配套的验证清单我会做成一张表,新机器上逐行打勾,比事后回溯快得多:
| 检查点 | 动作 | 通过标准 |
|---|---|---|
| 位数一致 | dumpbin /headers查 lib 与 Qt | 两者同为 x64 或同为 x86 |
| 导入库可链 | 编一个空工程链libvlc.lib | 无 LNK2019 |
| 包配置存在 | 看lib/cmake/目录 | 有VLCQtCoreConfig.cmake |
| 运行时完整 | 拷 dll 与 plugins 后启动 | 日志里出现视频输出模块加载记录 |
| 干净机可跑 | 在没装过相关运行库的机器上试 | 不弹缺 dll 提示 |
最后说一个我踩过很多次的坑:不要相信“开发机上能跑”。我最早一版在装了完整运行库的机器上验证通过就交付了,结果到目标机器上连窗口都出不来,排查半天才发现是 CRT 依赖。从那以后我的习惯是每次出包都留一台什么都没装过的虚拟机做最终验证,插件目录是不是整目录拷的、dll 有没有漏,一趟就能看明白。希望帮到你。
本文还有配套的精品资源,点击获取