从 0 到 1 ,手搓一个自己的绿色版视频播放器

发布时间:2026-08-22 阅读量:11 Go Gin
从 0 到 1 ,手搓一个自己的绿色版视频播放器
想看的视频格式太杂,Windows 自带播放器不认;装个播放器吧,总夹带广告、全家桶。不如自己动手,写一个干净、绿色、想加什么功能就加什么的播放器。本文全程记录我踩过的坑和实现细节。

一、为什么自己写一个播放器?

你有没有遇到过这些情况:

  • 下载了一个 .mkv / .rmvb / .ts,系统自带播放器直接罢工;
  • 主流播放器功能是强,但安装包捆绑、开机自启、各种弹窗;
  • 想要"断点续播、自动连播下一集、双击全屏、倍速"这些贴心功能,却没一个完全贴合自己的习惯;
  • 有的播放器连"打开文件就自动把同目录同格式的一起列出来"这种基本需求都做不到。

自己动手的好处:只保留你真正需要的功能,不想要的一行都不要。没有广告、没有捆绑、没有后台常驻,整个程序拷走就能用。

二、技术选型:为什么是 Qt + libVLC?

视频播放器的核心是解码。自己从零写解码器不现实,业界成熟方案是 FFmpeg,而 libVLC 正是基于 FFmpeg 的高层播放引擎,把解码、渲染、音频输出都封装好了,我们只需专注做界面。

方案

优点

缺点

C+ WPF

界面开发快、生态熟

音视频编解码要额外集成第三方库

Electron

跨平台、UI 漂亮

打包体积大(100MB+)、吃内存

C++ + Qt + libVLC(本文)

体积小、解码强、绿色便携

需要自己搭编译环境

libVLC 底层就是 FFmpeg,mp4 / mpeg / ts / mov / rm / rmvb / mkv / avi / flv 等格式通吃,rm 系列(RealVideo)也无需额外折腾,省心。

最关键是绿色部署:程序 = 你的 exe + libvlc.dll + libvlccore.dll + plugins/ 解码插件文件夹。整个目录拷走就能跑,无需安装、无注册表残留、无系统服务。

运行环境:基于 Qt 5.15 + MinGW 8.1 构建,兼容 Windows 7 / 8 / 8.1 / 10 / 11(64 位),解压即用,无需额外安装运行时。

为什么不直接用官方 VLC 或 FFplay?

官方 VLC 够用,但界面是别人定的,想加"断点续播、连播"要改它的逻辑;FFplay 是命令行工具,没有界面。自己写,界面和交互 100% 由你掌控。

三、搭建骨架

项目结构尽量清晰,每个类职责单一:

KzhPlayer/

├── CMakeLists.txt

# 自动探测 Qt(5/6) + VLC SDK

├── src/

│   ├── main.cpp

# 入口,开启高分屏缩放、支持命令行传参

│   ├── MainWindow.h/.cpp

# 主窗口 + 控制栏 + 播放列表界面

│   ├── Player.h/.cpp

# libVLC 封装(播放/进度/音量/倍速/事件)

│   ├── Playlist.h/.cpp

# 播放列表(上/下一集、循环)

│   ├── VideoWidget.h/.cpp

# 视频画面控件(绘制每帧)

│   └── SeekSlider.h/.cpp

# 点击进度条直接跳转

核心设计:把 libVLC 的 C 接口封装成 Qt 风格

Player 把所有 libVLC 调用封装起来,界面层完全不用碰 C 接口:

// 打开并播放

if

(!m_player->

open

(path))

return

;

m_player->play();

// 进度条跳转

m_player->setPosition(value /

1000.0f

);

// 倍速

m_player->setRate(rate);

// 音量

m_player->setVolume(volume);

// 播放结束自动下一集(事件回调)

connect(m_player, &Player::endReached,

this

, &MainWindow::onEndReached);

关键点 1:视频画面如何显示?

两种主流方式:

  • set_hwnd 嵌入:让 VLC 直接把画面画进窗口控件。简单,但 VLC 会接管视频区域的鼠标事件,导致"双击全屏""点击进度条"等交互全部失效。
  • 帧回调 + Qt 绘制(本文采用):让 libVLC 把解码出的每一帧 RGB 数据通过回调交给我们,Qt 自己画。鼠标事件完全由 Qt 处理,交互 100% 可控。

// 注册帧回调

libvlc_video_set_callbacks(m_player, lock, unlock, display,

this

);

libvlc_video_set_format(m_player, ”RV32”, width, height, width *

4

);

// 每一帧通过信号投递到 GUI 线程

connect(m_player, &Player::frameReady,

this

, [

this

]() {

m_videoWidget->setFrame(m_player->currentFrame());

});

关键点 2:进度条"点哪跳哪"

Qt 自带的 QSlider 点击轨道,默认只按 pageStep 挪一小步(不是跳到点击位置)。要实现"点哪跳哪",需要继承重写 mousePressEvent:

void

SeekSlider

::

mousePressEvent

(QMouseEvent *event) {

if

(event->

button

() ==

Qt

::

LeftButton

&&

orientation

() ==

Qt

::

Horizontal

) {

// 计算滑块句柄区域,若点在轨道空白处则直接跳到点击位置

QStyleOptionSlider opt;

initStyleOption

(&opt);

QRect handle =

style

()->

subControlRect

(

QStyle

::

CC_Slider

, &opt,

QStyle

::

SC_SliderHandle

, this);

if

(!handle.

contains

(event->

pos

())) {

double

ratio =

double

(event->

pos

().

x

()) /

width

();

setValue

(

minimum

() +

int

((

maximum

() -

minimum

()) * ratio));

emit

seekTo

(

value

());

// 触发跳转

return

;

}

}

QSlider

::

mousePressEvent

(event);

}

四、踩过的几个坑(真实经验)

坑 1:--plugin-path参数已废弃VLC 3.x 会自动在 exe 同级查找 plugins/ 目录。传这个参数反而报 option no longer exists,去掉即可。之前还因此踩了个内存 bug:QString::toUtf8().constData() 拿到的是临时对象的指针,语句结束就被销毁,导致插件路径是垃圾值。

坑 2:中文路径打不开libvlc_media_new_path 对非 ASCII 路径不可靠。改用 QUrl::fromLocalFile 转成 file:/// 形式,再交给 libvlc_media_new_location,中文文件名就正常了。

坑 3:进度条"点哪跳哪"不生效就是上面说的 pageStep 问题,用自定义 SeekSlider 解决。

坑 4:全屏界面要"磨砂悬浮"进全屏后控制栏做成半透明渐变 + 自动隐藏:鼠标一动显示,2.5 秒不动自动消失,和系统自带播放器一个体验。

坑 5:命令行黑窗CMake 里没设 WIN32_EXECUTABLE,exe 默认是控制台子系统,每次启动都弹黑窗。加一行 set_target_properties(KzhPlayer PROPERTIES WIN32_EXECUTABLE TRUE) 解决。

五、功能一览(详)

1. 播放与列表

  • 打开文件 / 打开文件夹:工具栏两个按钮。打开一个文件后,自动把同目录下同格式的视频全加进播放列表,上/下集无缝切换(按文件名排序,且同一文件不会重复添加);
  • 四种播放模式:顺序播放 / 单曲循环 / 列表循环 / 随机播放;
  • 播放结束自动连播下一集:用 VLC 的 MediaPlayerEndReached 事件回调触发,无需轮询;
  • 断点续播:用 QSettings 按文件路径哈希作键,记录每部视频的播放进度,下次打开自动接着播;开头/结尾位置不保存,避免误续播;
  • 记忆上次会话:记住窗口位置/大小、上次播放列表、上次播放的文件,启动直接恢复并自动续播。

2. 全屏与界面

  • 双击画面 = 全屏 / 退出全屏,Esc 也能退出,进全屏后自动隐藏鼠标;
  • 全屏时控制栏为磨砂半透明(渐变半透明底 + 细边框高光),鼠标一动显示,2.5 秒无操作自动隐藏;
  • 磨砂效果同样应用于顶部标题栏,界面统一。

3. 进度与倍速

  • 进度条点哪跳哪:点击轨道任意位置直接跳到对应时间(重写 SeekSlider::mousePressEvent,绕开 QSlider 默认的 pageStep 步进);
  • 拖拽进度条实时跳转,松开精确定位;
  • 倍速:0.5x / 1.0x / 1.5x / 2.0x 可调。

4. 快捷键

按键

功能

空格

播放 / 暂停

← / →

快退 / 快进 5 秒

↑ / ↓

音量加 / 减

Esc

退出全屏

小键盘 4 / 6

画面左移 / 右移

小键盘 8 / 2

画面上移 / 下移

小键盘 + / -

画面放大 / 缩小(1~5 倍)

5. AB 段重复(重点新功能)

用于反复练习某一片段(比如学外语、练舞蹈、看教学视频):

  • 播放到起点时点控制栏 A 按钮 → 记录 A 点,进度条上出现青绿色标记线;
  • 播放到终点时点 B 按钮 → 记录 B 点并开启循环,进度条上出现橙色标记线;
  • 之后播放到 B 点会自动跳回 A 点,在 A~B 之间循环播放;
  • 再次点 A 可清除 AB 循环,两条标记线消失;
  • 切换文件时自动清除上一部的 AB 状态。
实现要点:A/B 点以毫秒记录,放在 onTick 里判断——pos >= B 时用 set_time 跳回 A。用 m_abRewound 标志做"重新武装",避免跳回 A 后因 VLC 的 get_time 滞后而连续重复触发,保证每轮只跳一次、循环干净。

6. 画面平移 / 缩放

用小键盘可在播放时对画面进行平移和缩放(适合局部放大看细节、看画面边角):

  • +放大、-缩小,以画面中心为基准,范围 1-5 倍
  • 小键盘 4/6/8/2 左/右/上/下平移画面;
  • 底层在 VideoWidget::paintEvent 中,先按窗口等比缩放,再叠加缩放倍数与平移偏移绘制,不影响播放控制。

// 断点续播:媒体就绪后跳到上次位置

void

MainWindow

::

onMediaPlaying

() {

if

(m_resumeFraction >

0.

001f) {

float f = m_resumeFraction;

m_resumeFraction = -

1.

0f;

// 只恢复一次

m_player->

setPosition

(f);

}

}

六、绿色版部署与瘦身

把下面内容放进同一个文件夹,拷走即绿色版:

KzhPlayer.exe

libvlc.dll

libvlccore.dll

plugins/      ← VLC 的解码插件

plugins/ 必须存在,否则无法解码。

瘦身:完整 VLC 插件默认占130 多 MB,其中很多我们用不到:

  • 删 gui(我们有自己的界面)、access_output(不串流输出)、stream_out(不转码推流)、mux(不封装保存);
  • access 只留本地文件模块 filesystem,删掉全部网络/光驱/抓屏模块;
  • video_output 只留帧回调必需的 vmem,删掉 D3D/GL 显示模块;
  • 删 visualization、meta_engine、services_discovery、control 等。

实测删除后plugins 从 132MB 降到 76MB,且 mp4 / mov / mkv 三种格式均正常解码播放。codec / demux 是支持各种格式的核心,不能动。

七、试试看

一键编译(推荐)

仓库内自带build.cmd,双击或命令行运行即可完成「CMake 配置 → 编译 → 复制 exe 到 dist\KzhPlayer\」:

build.cmd

脚本默认使用 D:\Qt\5.15.2\mingw81_64(Qt)与 D:\Qt\Tools\mingw810_64(MinGW 8.1),若路径不同,改脚本开头的 QT_ROOT / MINGW_ROOT 即可。脚本为纯 ASCII,避免 cmd 中文编码乱码问题。

编译产物在 dist\KzhPlayer\KzhPlayer.exe,若需打包 zip:

Compress-Archive -

Path

dist/KzhPlayer

/* -DestinationPath dist/KzhPlayer.zip -Force

手动构建

构建(需 CMake + Qt + VLC SDK):

cmake

-S . -B build -DCMAKE_PREFIX_PATH=”你的Qt安装路径”

cmake --build build

命令行直接播:

KzhPlayer.exe ”D:\视频\追剧.mp4”

打包好的播放器,直接解压即可使用:

https

://ydjy-

1369590239

.cos.ap-nanjing.myqcloud.com/uploads/

20260808

/

1786158445781522352

.zip

八、下一步还能做什么

  • 自动加载字幕(.srt / .ass)并支持轨道切换;
  • 截屏、画面比例/旋转调节;
  • 硬件加速(GPU 硬解),4K 高码率更省 CPU;
  • 更精细的倍速(0.1 步进)。

自己写播放器的乐趣在于:每个功能都长成你想要的样子。代码已开源,欢迎一起折腾。

仓库地址:https://gitee.com/ydxjyjkzh/kzhplayer


温馨提示

知识产权声明:本软件已获国家版权局软件著作权登记(登记号:2022SR0558725),受《计算机软件保护条例》保护。未经书面授权,严禁对本软件进行反向工程、反编译、破解或任何形式的篡改。侵权必究。

官方指引:本文档为官方安装部署说明,仅适用于当前发布版本,后续版本请以最新官方文档为准。

环境要求:安装前请确认操作系统版本、运行环境(如 .NET、Java 等)及硬件配置满足软件运行要求,避免因环境不兼容导致异常。

操作风险与免责:安装配置涉及防火墙、注册表或环境变量等系统级变更,建议由具备相关经验的技术人员操作。因用户未严格遵循本官方指引或操作不当导致的任何数据丢失、系统异常或其他损失,我方不承担相关责任。如遇问题,请及时联系技术支持。

反馈渠道:如有未覆盖的问题,欢迎通过客服反馈,我们将持续更新与改进。

版本记录:最后更新于 2026-08-22

AI

智能问答助手

基于本手册内容回答问题
AI
你好,我是本手册的 AI 助手,有任何安装问题可以直接问我。
← 返回手册列表

相关手册