播放本地流媒体文件;
播放基于http协议的网络流媒体内容;
提供播放、暂停、停止、快进、快退、全屏以及音量控制等功能;
回显并可随机调整播放进度;
至少支持Windows和Ubuntu两种操作系统:
在Windows系统上运行的QtPlayerWin.exe
在Ubuntu系统上运行的QtPlayer
视频窗口的显式,可在内嵌窗口和独立窗口之间任选其一。
xxxxxxxxxx
401QT += core gui
2INCLUDEPATH += D:\vlc-3.0.10\win64\sdk\include
3LIBS += D:\vlc-3.0.10\win64\sdk\lib\libvlccore.lib \
4 D:\vlc-3.0.10\win64\sdk\lib\libvlc.lib
5
6greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
7
8CONFIG += c++11
9
10# The following define makes your compiler emit warnings if you use
11# any Qt feature that has been marked deprecated (the exact warnings
12# depend on your compiler). Please consult the documentation of the
13# deprecated API in order to know how to port your code away from it.
14DEFINES += QT_DEPRECATED_WARNINGS
15
16# You can also make your code fail to compile if it uses deprecated APIs.
17# In order to do so, uncomment the following line.
18# You can also select to disable deprecated APIs only up to a certain version of Qt.
19#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
20
21SOURCES += \
22 MainWindow.cpp \
23 QtPlayer.cpp
24
25HEADERS += \
26 MainWindow.h
27
28FORMS += \
29 MainWindow.ui
30
31TRANSLATIONS += \
32 QtPlayer_zh_CN.ts
33
34# Default rules for deployment.
35qnx: target.path = /tmp/$${TARGET}/bin
36else: unix:!android: target.path = /opt/$${TARGET}/bin
37!isEmpty(target.path): INSTALLS += target
38
39RESOURCES += \
40 QtPlayer.qrc
xxxxxxxxxx
391QT += core gui
2RC_ICONS += images\QtPlayer.ico
3LIBS += -lvlc
4
5greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
6
7CONFIG += c++11
8
9# The following define makes your compiler emit warnings if you use
10# any Qt feature that has been marked deprecated (the exact warnings
11# depend on your compiler). Please consult the documentation of the
12# deprecated API in order to know how to port your code away from it.
13DEFINES += QT_DEPRECATED_WARNINGS
14
15# You can also make your code fail to compile if it uses deprecated APIs.
16# In order to do so, uncomment the following line.
17# You can also select to disable deprecated APIs only up to a certain version of Qt.
18#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
19
20SOURCES += \
21 MainWindow.cpp \
22 QtPlayer.cpp
23
24HEADERS += \
25 MainWindow.h
26
27FORMS += \
28 MainWindow.ui
29
30TRANSLATIONS += \
31 QtPlayer_zh_CN.ts
32
33# Default rules for deployment.
34qnx: target.path = /tmp/$${TARGET}/bin
35else: unix:!android: target.path = /opt/$${TARGET}/bin
36!isEmpty(target.path): INSTALLS += target
37
38RESOURCES += \
39 QtPlayer.qrc
xxxxxxxxxx
141<RCC>
2 <qresource prefix="/">
3 <file>images/QtPlayer.bmp</file>
4 <file>images/QtPlayer.ico</file>
5 <file>images/Play.ico</file>
6 <file>images/Pause.ico</file>
7 <file>images/Stop.ico</file>
8 <file>images/FastForward.ico</file>
9 <file>images/FastBackward.ico</file>
10 <file>images/About.ico</file>
11 <file>images/Quit.ico</file>
12 <file>translations/qtbase_zh_TW.qm</file>
13 </qresource>
14</RCC>
xxxxxxxxxx
201
2
3
4
5
6
7int main(int argc, char *argv[])
8{
9 QApplication a(argc, argv);
10
11 QTranslator tr;
12 // Qt5以后,内置标准窗口翻译文件已从qt_xxx.qm更新至qtbase_xxx.qm中,
13 // 但并未提供简体中文翻译文件,权以繁体中文代之,与政治立场无关,特此声明
14 if (tr.load(":/translations/qtbase_zh_TW"))
15 a.installTranslator(&tr);
16
17 MainWindow w(nullptr, true);
18 w.show();
19 return a.exec();
20}
xxxxxxxxxx
4401
2<ui version="4.0">
3 <class>MainWindow</class>
4 <widget class="QMainWindow" name="MainWindow">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>826</width>
10 <height>609</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>坏老头儿播放器</string>
15 </property>
16 <property name="windowIcon">
17 <iconset resource="QtPlayer.qrc">
18 <normaloff>:/images/QtPlayer.ico</normaloff>:/images/QtPlayer.ico</iconset>
19 </property>
20 <property name="toolTip">
21 <string>坏老头儿播放器</string>
22 </property>
23 <widget class="QWidget" name="widgetCentral">
24 <layout class="QVBoxLayout" name="layoutCentral">
25 <item>
26 <widget class="QLabel" name="labFullscreen">
27 <property name="toolTip">
28 <string>全屏</string>
29 </property>
30 <property name="styleSheet">
31 <string notr="true">color:red</string>
32 </property>
33 <property name="text">
34 <string>温馨提示:在视频区域双击鼠标以切换全屏和窗口模式╮(╯ɛ╰)╭</string>
35 </property>
36 </widget>
37 </item>
38 <item>
39 <widget class="QFrame" name="frmScreen">
40 <property name="enabled">
41 <bool>true</bool>
42 </property>
43 <property name="sizePolicy">
44 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
45 <horstretch>0</horstretch>
46 <verstretch>0</verstretch>
47 </sizepolicy>
48 </property>
49 <property name="minimumSize">
50 <size>
51 <width>0</width>
52 <height>0</height>
53 </size>
54 </property>
55 <property name="mouseTracking">
56 <bool>false</bool>
57 </property>
58 <property name="toolTip">
59 <string>视频</string>
60 </property>
61 <property name="toolTipDuration">
62 <number>-1</number>
63 </property>
64 <property name="frameShape">
65 <enum>QFrame::Box</enum>
66 </property>
67 <property name="frameShadow">
68 <enum>QFrame::Raised</enum>
69 </property>
70 <property name="lineWidth">
71 <number>2</number>
72 </property>
73 <layout class="QGridLayout" name="layoutScreen">
74 <property name="leftMargin">
75 <number>0</number>
76 </property>
77 <property name="topMargin">
78 <number>0</number>
79 </property>
80 <property name="rightMargin">
81 <number>0</number>
82 </property>
83 <property name="bottomMargin">
84 <number>0</number>
85 </property>
86 <property name="spacing">
87 <number>0</number>
88 </property>
89 <item row="0" column="0">
90 <widget class="QFrame" name="frmVideo">
91 <property name="enabled">
92 <bool>true</bool>
93 </property>
94 <property name="sizePolicy">
95 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
96 <horstretch>0</horstretch>
97 <verstretch>0</verstretch>
98 </sizepolicy>
99 </property>
100 <property name="minimumSize">
101 <size>
102 <width>0</width>
103 <height>64</height>
104 </size>
105 </property>
106 <property name="mouseTracking">
107 <bool>false</bool>
108 </property>
109 <property name="toolTip">
110 <string/>
111 </property>
112 <property name="autoFillBackground">
113 <bool>false</bool>
114 </property>
115 <property name="styleSheet">
116 <string notr="true">border-image: url(:/images/QtPlayer.bmp);</string>
117 </property>
118 <property name="frameShape">
119 <enum>QFrame::NoFrame</enum>
120 </property>
121 <property name="frameShadow">
122 <enum>QFrame::Plain</enum>
123 </property>
124 <property name="lineWidth">
125 <number>0</number>
126 </property>
127 </widget>
128 </item>
129 </layout>
130 </widget>
131 </item>
132 <item>
133 <widget class="QFrame" name="frmControl">
134 <property name="toolTip">
135 <string>控制</string>
136 </property>
137 <property name="accessibleName">
138 <string/>
139 </property>
140 <property name="frameShape">
141 <enum>QFrame::Box</enum>
142 </property>
143 <property name="frameShadow">
144 <enum>QFrame::Sunken</enum>
145 </property>
146 <layout class="QVBoxLayout" name="layoutControl">
147 <item>
148 <layout class="QHBoxLayout" name="layoutURL">
149 <item>
150 <widget class="QLabel" name="labURL">
151 <property name="toolTip">
152 <string>URL</string>
153 </property>
154 <property name="text">
155 <string>URL:</string>
156 </property>
157 </widget>
158 </item>
159 <item>
160 <widget class="QLineEdit" name="editURL">
161 <property name="enabled">
162 <bool>false</bool>
163 </property>
164 <property name="sizePolicy">
165 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
166 <horstretch>0</horstretch>
167 <verstretch>0</verstretch>
168 </sizepolicy>
169 </property>
170 <property name="toolTip">
171 <string>URL</string>
172 </property>
173 <property name="text">
174 <string>http://192.168.0.11:8080/Group1/M00/00/00/wKgADV7PZeSAYq-HA8xf__JA1NA431.mp4</string>
175 </property>
176 <property name="readOnly">
177 <bool>false</bool>
178 </property>
179 </widget>
180 </item>
181 </layout>
182 </item>
183 <item>
184 <layout class="QHBoxLayout" name="layoutProgress">
185 <item>
186 <widget class="QSlider" name="sliderProgress">
187 <property name="enabled">
188 <bool>false</bool>
189 </property>
190 <property name="toolTip">
191 <string>进度</string>
192 </property>
193 <property name="maximum">
194 <number>10000</number>
195 </property>
196 <property name="pageStep">
197 <number>100</number>
198 </property>
199 <property name="orientation">
200 <enum>Qt::Horizontal</enum>
201 </property>
202 <property name="tickPosition">
203 <enum>QSlider::TicksBelow</enum>
204 </property>
205 <property name="tickInterval">
206 <number>100</number>
207 </property>
208 </widget>
209 </item>
210 <item>
211 <widget class="QLabel" name="labProgress">
212 <property name="toolTip">
213 <string>进度</string>
214 </property>
215 <property name="styleSheet">
216 <string notr="true">color:blue</string>
217 </property>
218 <property name="frameShape">
219 <enum>QFrame::Panel</enum>
220 </property>
221 <property name="frameShadow">
222 <enum>QFrame::Sunken</enum>
223 </property>
224 <property name="text">
225 <string>00:00:00.000/00:00:00.000</string>
226 </property>
227 <property name="alignment">
228 <set>Qt::AlignCenter</set>
229 </property>
230 <property name="margin">
231 <number>1</number>
232 </property>
233 </widget>
234 </item>
235 </layout>
236 </item>
237 <item>
238 <layout class="QHBoxLayout" name="layoutButtons">
239 <item>
240 <widget class="QPushButton" name="btnPlay">
241 <property name="enabled">
242 <bool>false</bool>
243 </property>
244 <property name="toolTip">
245 <string>播放</string>
246 </property>
247 <property name="text">
248 <string>播放</string>
249 </property>
250 <property name="icon">
251 <iconset resource="QtPlayer.qrc">
252 <normaloff>:/images/Play.ico</normaloff>:/images/Play.ico</iconset>
253 </property>
254 <property name="flat">
255 <bool>false</bool>
256 </property>
257 </widget>
258 </item>
259 <item>
260 <widget class="QPushButton" name="btnPause">
261 <property name="enabled">
262 <bool>false</bool>
263 </property>
264 <property name="toolTip">
265 <string>暂停</string>
266 </property>
267 <property name="text">
268 <string>暂停</string>
269 </property>
270 <property name="icon">
271 <iconset resource="QtPlayer.qrc">
272 <normaloff>:/images/Pause.ico</normaloff>:/images/Pause.ico</iconset>
273 </property>
274 </widget>
275 </item>
276 <item>
277 <widget class="QPushButton" name="btnStop">
278 <property name="enabled">
279 <bool>false</bool>
280 </property>
281 <property name="toolTip">
282 <string>停止</string>
283 </property>
284 <property name="text">
285 <string>停止</string>
286 </property>
287 <property name="icon">
288 <iconset resource="QtPlayer.qrc">
289 <normaloff>:/images/Stop.ico</normaloff>:/images/Stop.ico</iconset>
290 </property>
291 </widget>
292 </item>
293 <item>
294 <widget class="QPushButton" name="btnFastForward">
295 <property name="enabled">
296 <bool>false</bool>
297 </property>
298 <property name="toolTip">
299 <string>快进</string>
300 </property>
301 <property name="text">
302 <string>快进</string>
303 </property>
304 <property name="icon">
305 <iconset resource="QtPlayer.qrc">
306 <normaloff>:/images/FastForward.ico</normaloff>:/images/FastForward.ico</iconset>
307 </property>
308 </widget>
309 </item>
310 <item>
311 <widget class="QPushButton" name="btnFastBackward">
312 <property name="enabled">
313 <bool>false</bool>
314 </property>
315 <property name="toolTip">
316 <string>快退</string>
317 </property>
318 <property name="text">
319 <string>快退</string>
320 </property>
321 <property name="icon">
322 <iconset resource="QtPlayer.qrc">
323 <normaloff>:/images/FastBackward.ico</normaloff>:/images/FastBackward.ico</iconset>
324 </property>
325 </widget>
326 </item>
327 <item>
328 <spacer name="spacerVolume">
329 <property name="orientation">
330 <enum>Qt::Horizontal</enum>
331 </property>
332 <property name="sizeHint" stdset="0">
333 <size>
334 <width>40</width>
335 <height>20</height>
336 </size>
337 </property>
338 </spacer>
339 </item>
340 <item>
341 <widget class="QLabel" name="labVolume">
342 <property name="toolTip">
343 <string>音量</string>
344 </property>
345 <property name="text">
346 <string>音量:</string>
347 </property>
348 </widget>
349 </item>
350 <item>
351 <widget class="QSlider" name="sliderVolume">
352 <property name="enabled">
353 <bool>true</bool>
354 </property>
355 <property name="minimumSize">
356 <size>
357 <width>64</width>
358 <height>0</height>
359 </size>
360 </property>
361 <property name="toolTip">
362 <string>音量</string>
363 </property>
364 <property name="maximum">
365 <number>100</number>
366 </property>
367 <property name="value">
368 <number>80</number>
369 </property>
370 <property name="orientation">
371 <enum>Qt::Horizontal</enum>
372 </property>
373 <property name="tickPosition">
374 <enum>QSlider::TicksBelow</enum>
375 </property>
376 <property name="tickInterval">
377 <number>10</number>
378 </property>
379 </widget>
380 </item>
381 <item>
382 <spacer name="spacerAbout">
383 <property name="orientation">
384 <enum>Qt::Horizontal</enum>
385 </property>
386 <property name="sizeHint" stdset="0">
387 <size>
388 <width>40</width>
389 <height>20</height>
390 </size>
391 </property>
392 </spacer>
393 </item>
394 <item>
395 <widget class="QPushButton" name="btnAbout">
396 <property name="enabled">
397 <bool>true</bool>
398 </property>
399 <property name="toolTip">
400 <string>关于</string>
401 </property>
402 <property name="text">
403 <string>关于...</string>
404 </property>
405 <property name="icon">
406 <iconset resource="QtPlayer.qrc">
407 <normaloff>:/images/About.ico</normaloff>:/images/About.ico</iconset>
408 </property>
409 </widget>
410 </item>
411 <item>
412 <widget class="QPushButton" name="btnQuit">
413 <property name="enabled">
414 <bool>true</bool>
415 </property>
416 <property name="toolTip">
417 <string>退出</string>
418 </property>
419 <property name="text">
420 <string>退出</string>
421 </property>
422 <property name="icon">
423 <iconset resource="QtPlayer.qrc">
424 <normaloff>:/images/Quit.ico</normaloff>:/images/Quit.ico</iconset>
425 </property>
426 </widget>
427 </item>
428 </layout>
429 </item>
430 </layout>
431 </widget>
432 </item>
433 </layout>
434 </widget>
435 </widget>
436 <resources>
437 <include location="QtPlayer.qrc"/>
438 </resources>
439 <connections/>
440</ui>
xxxxxxxxxx
941
2
3
4
5
6
7
8// Q_OS_WIN
9
10
11QT_BEGIN_NAMESPACE
12namespace Ui { class MainWindow; }
13QT_END_NAMESPACE
14
15class MainWindow : public QMainWindow
16{
17 Q_OBJECT
18
19public:
20 // 构造函数
21 MainWindow(QWidget *parent = nullptr, bool embed = false);
22 // 析构函数
23 ~MainWindow();
24
25private:
26 // 响应媒体长度改变事件的静态处理函数
27 static void onMediaPlayerLengthChanged(
28 libvlc_event_t const* event, void* data);
29 // 响应媒体长度改变事件的普通处理函数
30 void onMediaPlayerLengthChanged(libvlc_time_t length);
31
32
33 // 子窗口枚举回调函数
34 static BOOL CALLBACK onEnumVLCWindow(HWND hwnd, LPARAM);
35 // 响应视频输出启动事件的静态处理函数
36 static void onMediaPlayerVout(
37 libvlc_event_t const*, void* data);
38 // 响应视频输出启动事件的普通处理函数
39 void onMediaPlayerVout(void);
40// Q_OS_WINDOWS
41
42 // 响应时间改变事件的静态处理函数
43 static void onMediaPlayerTimeChanged(
44 libvlc_event_t const* event, void* data);
45 // 响应时间改变事件的普通处理函数
46 void onMediaPlayerTimeChanged(libvlc_time_t time);
47
48 // 响应终点到达事件的静态处理函数
49 static void onMediaPlayerEndReached(
50 libvlc_event_t const*, void* data);
51 // 响应终点到达事件的普通处理函数
52 void onMediaPlayerEndReached(void);
53
54 // 显示窗口时被调用的虚函数
55 void showEvent(QShowEvent*);
56 // 视频框控件有事件时被调用的虚函数
57 bool eventFilter(QObject* obj, QEvent* event);
58
59private slots:
60 // 响应进度滑块移动信号的槽函数(拖拽滑块)
61 void on_sliderProgress_sliderMoved(int position);
62 // 响应进度滑块值改变信号的槽函数(点击滑轨)
63 void on_sliderProgress_valueChanged(int value);
64 // 响应播放按钮点击信号的槽函数
65 void on_btnPlay_clicked();
66 // 响应暂停按钮点击信号的槽函数
67 void on_btnPause_clicked();
68 // 响应停止按钮点击信号的槽函数
69 void on_btnStop_clicked();
70 // 响应快进按钮点击信号的槽函数
71 void on_btnFastForward_clicked();
72 // 响应快退按钮点击信号的槽函数
73 void on_btnFastBackward_clicked();
74 // 响应音量滑块移动信号的槽函数(拖拽滑块)
75 void on_sliderVolume_sliderMoved(int position);
76 // 响应音量滑块值改变信号的槽函数(点击滑轨)
77 void on_sliderVolume_valueChanged(int value);
78 // 响应关于按钮点击信号的槽函数
79 void on_btnAbout_clicked();
80 // 响应退出按钮点击信号的槽函数
81 void on_btnQuit_clicked();
82
83private:
84 Ui::MainWindow *ui;
85
86 bool embed; // 内嵌视频
87
88 libvlc_instance_t* vlcInstance; // VLC实例
89 libvlc_media_player_t* vlcMediaPlayer; // VLC媒体播放器
90 libvlc_event_manager_t* vlcEventManager; // VLC事件管理器
91 libvlc_media_t* vlcMedia; // VLC媒体
92 libvlc_time_t vlcMediaLength; // VLC媒体长度
93};
94// MAINWINDOW_H
xxxxxxxxxx
4741
2
3
4
5
6using namespace std;
7
8
9
10// 构造函数
11MainWindow::MainWindow(QWidget *parent, bool embed)
12 : QMainWindow(parent)
13 , ui(new Ui::MainWindow)
14 , embed(embed)
15 , vlcInstance(NULL)
16 , vlcMediaPlayer(NULL)
17 , vlcEventManager(NULL)
18{
19 ui->setupUi(this);
20
21 // VLC参数列表
22 char const* const vlcArgs[] = {
23 "-I", "dumy", "--ignore-config", "--plugin-path=./plugins"};
24
25 // 创建VLC实例
26 if (!(vlcInstance = libvlc_new(sizeof(vlcArgs) / sizeof(vlcArgs[0]),
27 vlcArgs)))
28 {
29 QMessageBox(QMessageBox::Critical, windowTitle(),
30 "无法创建VLC实例!", QMessageBox::Ok, this).exec();
31 return;
32 }
33
34 // 创建VLC媒体播放器
35 if (!(vlcMediaPlayer = libvlc_media_player_new(vlcInstance)))
36 {
37 QMessageBox(QMessageBox::Critical, windowTitle(),
38 "无法创建VLC媒体播放器!", QMessageBox::Ok, this).exec();
39 return;
40 }
41
42 // 若内嵌视频...
43 if (embed)
44 {
45 // 将视频框控件设置为VLC播放器的输出窗口
46
47 libvlc_media_player_set_hwnd(
48 vlcMediaPlayer, reinterpret_cast<void*>(ui->frmVideo->winId()));
49
50 libvlc_media_player_set_xwindow(vlcMediaPlayer, ui->frmVideo->winId());
51// Q_OS_WINDOWS
52
53 // 为视频框控件安装事件过滤器,以截获鼠标双击事件,切换全屏和窗口模式
54 ui->frmVideo->installEventFilter(this);
55 }
56 else // 否则...
57 // 销毁屏幕框控件(及其子控件————视频框控件)
58 delete ui->frmScreen;
59
60 // 创建VLC事件管理器
61 if (!(vlcEventManager = libvlc_media_player_event_manager(vlcMediaPlayer)))
62 {
63 QMessageBox(QMessageBox::Critical, windowTitle(),
64 "无法创建VLC事件管理器!", QMessageBox::Ok, this).exec();
65 return;
66 }
67
68 // 设置VLC事件回调
69
70 // 响应媒体长度改变事件————设置进度滑块控件
71 libvlc_event_attach(
72 vlcEventManager, libvlc_MediaPlayerLengthChanged,
73 onMediaPlayerLengthChanged, this);
74
75 // 若内嵌视频...
76 if (embed)
77 // 响应视频输出启动事件————枚举视频框控件的所有子窗口并禁用之
78 // 在Windows上若不禁用视频框控件的子窗口,即VLC视频输出窗口,
79 // 鼠标停留其上将导致界面崩溃
80 libvlc_event_attach(
81 vlcEventManager, libvlc_MediaPlayerVout,
82 onMediaPlayerVout, this);
83// Q_OS_WINDOWS
84 // 响应时间改变事件————同步进度滑块控件和进度标签控件
85 libvlc_event_attach(
86 vlcEventManager, libvlc_MediaPlayerTimeChanged,
87 onMediaPlayerTimeChanged, this);
88 // 响应终点到达事件————停止播放
89 libvlc_event_attach(
90 vlcEventManager, libvlc_MediaPlayerEndReached,
91 onMediaPlayerEndReached, this);
92
93 // 初始化界面
94 ui->editURL->setEnabled(true);
95 ui->btnPlay->setEnabled(true);
96
97 // 初始化音量
98 libvlc_audio_set_volume(vlcMediaPlayer, ui->sliderVolume->value());
99}
100
101// 析构函数
102MainWindow::~MainWindow()
103{
104 // 销毁VLC媒体播放器
105 if (vlcMediaPlayer)
106 {
107 libvlc_media_player_release(vlcMediaPlayer);
108 vlcMediaPlayer = NULL;
109 }
110
111 // 销毁VLC实例
112 if (vlcInstance)
113 {
114 libvlc_release(vlcInstance);
115 vlcInstance = NULL;
116 }
117
118 delete ui;
119}
120
121// 响应媒体长度改变事件的静态处理函数
122void MainWindow::onMediaPlayerLengthChanged(
123 libvlc_event_t const* event, void* data)
124{
125 // 调用普通处理函数
126 reinterpret_cast<MainWindow*>(data)->onMediaPlayerLengthChanged(
127 event->u.media_player_length_changed.new_length);
128}
129
130// 响应媒体长度改变事件的普通处理函数
131void MainWindow::onMediaPlayerLengthChanged(libvlc_time_t length)
132{
133 // 将媒体长度毫秒值设置为进度滑块控件的最大值
134 ui->sliderProgress->setMaximum(length);
135 // 将媒体长度毫秒值的十分之一设置为进度滑块控件的页步距
136 ui->sliderProgress->setPageStep(length / 10);
137 // 将媒体长度毫秒值的百分之一设置为进度滑块控件的刻度间隔
138 ui->sliderProgress->setTickInterval(length / 100);
139 // 将媒体长度毫秒值保存到成员变量中以备后用
140 vlcMediaLength = length;
141}
142
143
144
145// 子窗口枚举回调函数
146BOOL CALLBACK MainWindow::onEnumVLCWindow(HWND hwnd, LPARAM)
147{
148 // 禁用该子窗口,即VLC视频输出窗口,避免鼠标停留引发界面崩溃
149 EnableWindow(hwnd, FALSE);
150 return TRUE;
151}
152
153// 响应视频输出启动事件的静态处理函数
154void MainWindow::onMediaPlayerVout(
155 libvlc_event_t const*, void* data)
156{
157 // 调用普通处理函数
158 reinterpret_cast<MainWindow*>(data)->onMediaPlayerVout();
159}
160
161// 响应视频输出启动事件的普通处理函数
162void MainWindow::onMediaPlayerVout(void)
163{
164 // 枚举视频框控件的所有子窗口,即VLC视频输出窗口
165 // 每个子窗口的句柄将作为参数,传递给枚举回调函数
166 EnumChildWindows((HWND)ui->frmVideo->winId(), onEnumVLCWindow, 0);
167}
168
169// Q_OS_WINDOWS
170
171// 响应时间改变事件的静态处理函数
172void MainWindow::onMediaPlayerTimeChanged(
173 libvlc_event_t const* event, void* data)
174{
175 // 调用普通处理函数
176 reinterpret_cast<MainWindow*>(data)->onMediaPlayerTimeChanged(
177 event->u.media_player_time_changed.new_time);
178}
179
180// 响应时间改变事件的普通处理函数
181void MainWindow::onMediaPlayerTimeChanged(libvlc_time_t time)
182{
183 // 根据媒体时间毫秒值同步进度滑块控件
184 ui->sliderProgress->setValue(time);
185 // 根据媒体时间毫秒值同步进度标签控件
186 ui->labProgress->setText(
187 QTime::fromMSecsSinceStartOfDay(time).toString("hh:mm:ss.zzz") + "/" +
188 QTime::fromMSecsSinceStartOfDay(vlcMediaLength).toString("hh:mm:ss.zzz"));
189}
190
191// 响应终点到达事件的静态处理函数
192void MainWindow::onMediaPlayerEndReached(
193 libvlc_event_t const*, void* data)
194{
195 // 调用普通处理函数
196 reinterpret_cast<MainWindow*>(data)->onMediaPlayerEndReached();
197}
198
199// 响应终点到达事件的普通处理函数
200void MainWindow::onMediaPlayerEndReached(void)
201{
202 // 向停止按钮发射点击信号
203 emit ui->btnStop->click();
204}
205
206// 显示窗口时被调用的虚函数
207void MainWindow::showEvent(QShowEvent*)
208{
209 // 若内嵌视频...
210 if (! embed)
211 // 将窗口收缩至最小
212 resize(minimumSize());
213}
214
215// 视频框控件有事件时被调用的虚函数
216bool MainWindow::eventFilter(QObject* obj, QEvent* event)
217{
218 // 若视频框控件发生鼠标双击事件...
219 if (obj == ui->frmVideo && event->type() == QEvent::MouseButtonDblClick)
220 {
221 static bool fullscreen = false; // 全屏模式
222
223 static int minHeight; // 最小高度
224 static QSize winSize; // 窗口大小
225
226 static QMargins cntMargins; // 中心布局的边缘大小
227 static int frmStyle; // 屏幕框控件的边框风格
228// Q_OS_WINDOWS
229
230 if (fullscreen) // 全屏->窗口
231 {
232
233 // 调整界面
234 setMinimumHeight(minHeight);
235 resize(winSize);
236 ui->frmScreen->show();
237 // 退出全屏
238 ui->frmVideo->setWindowFlags(Qt::SubWindow);
239 ui->frmVideo->showNormal();
240
241 // 调整界面
242 ui->labFullscreen->show();
243 ui->frmControl->show();
244 ui->layoutCentral->setContentsMargins(cntMargins);
245 ui->frmScreen->setFrameStyle(frmStyle);
246 // 退出全屏
247 showNormal();
248// Q_OS_WINDOWS
249 // 恢复光标
250 ui->frmVideo->unsetCursor();
251 // 激活窗口
252 qApp->setActiveWindow(this);
253 }
254 else // 窗口->全屏
255 {
256 // 隐藏光标
257 ui->frmVideo->setCursor(Qt::BlankCursor);
258
259 // 进入全屏
260 ui->frmVideo->setWindowFlags(Qt::Window);
261 ui->frmVideo->showFullScreen();
262 // 调整界面
263 ui->frmScreen->hide();
264 minHeight = minimumHeight();
265 winSize = size();
266 setMinimumHeight(
267 ui->layoutCentral->contentsMargins().top() +
268 ui->labFullscreen->size().height() +
269 ui->layoutCentral->spacing() +
270 ui->frmControl->size().height() +
271 ui->layoutCentral->contentsMargins().bottom());
272 resize(size().width(), minimumHeight());
273
274 // 进入全屏
275 showFullScreen();
276 // 调整界面
277 ui->labFullscreen->hide();
278 ui->frmControl->hide();
279 cntMargins = ui->layoutCentral->contentsMargins();
280 ui->layoutCentral->setContentsMargins(QMargins());
281 frmStyle = ui->frmScreen->frameStyle();
282 ui->frmScreen->setFrameStyle(QFrame::NoFrame);
283// Q_OS_WINDOWS
284 }
285
286 fullscreen = !fullscreen;
287 return true;
288 }
289
290 return QMainWindow::eventFilter(obj, event);
291}
292
293// 响应进度滑块移动信号的槽函数(拖拽滑块)
294void MainWindow::on_sliderProgress_sliderMoved(int position)
295{
296 if (position <= vlcMediaLength)
297 // 定位VLC媒体
298 libvlc_media_player_set_time(vlcMediaPlayer, position);
299}
300
301// 响应进度滑块值改变信号的槽函数(点击滑轨)
302void MainWindow::on_sliderProgress_valueChanged(int value)
303{
304 // 在响应时间改变事件的处理函数中,根据媒体时间的毫秒值调整进度
305 // 滑块的位置,也会引发值改变信号,此处若不加判断势必构成死循环
306 if (libvlc_media_player_get_time(vlcMediaPlayer) != value)
307 // 定位VLC媒体
308 libvlc_media_player_set_time(vlcMediaPlayer, value);
309}
310
311// 响应播放按钮点击信号的槽函数
312void MainWindow::on_btnPlay_clicked()
313{
314 string url = ui->editURL->text().toStdString();
315
316 vector<string> protocols;
317 protocols.push_back("http");
318 protocols.push_back("https");
319 protocols.push_back("ftp");
320 protocols.push_back("rstp");
321
322 vector<string>::const_iterator it;
323 for (it = protocols.begin(); it != protocols.end(); ++it)
324 if (!url.compare(0, it->size(), *it))
325 break;
326
327 // 若网络媒体...
328 if (it != protocols.end())
329 {
330 // 创建VLC媒体
331 if (!(vlcMedia = libvlc_media_new_location(vlcInstance, url.c_str())))
332 {
333 QMessageBox(QMessageBox::Critical, windowTitle(),
334 "无法创建VLC媒体!", QMessageBox::Ok, this).exec();
335 return;
336 }
337 }
338 else // 否则,即本地媒体...
339 {
340 // 创建VLC媒体
341 if (!(vlcMedia = libvlc_media_new_path(vlcInstance, url.c_str())))
342 {
343 QMessageBox(QMessageBox::Critical, windowTitle(),
344 "无法创建VLC媒体!", QMessageBox::Ok, this).exec();
345 return;
346 }
347 }
348
349 // 将VLC媒体设置到VLC媒体播放器中
350 libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia);
351
352 // 播放VLC媒体
353 if (libvlc_media_player_play(vlcMediaPlayer) == -1)
354 {
355 QMessageBox(QMessageBox::Critical, windowTitle(),
356 "无法播放VLC媒体!", QMessageBox::Ok, this).exec();
357 return;
358 }
359
360 // 若内嵌视频...
361 if (embed)
362 // 禁止视频框控件更新显示,避免闪烁
363 ui->frmVideo->setUpdatesEnabled(false);
364
365 // 调整界面
366 ui->sliderProgress->setEnabled(true);
367 ui->btnPlay->setEnabled(false);
368 ui->btnPause->setEnabled(true);
369 ui->btnStop->setEnabled(true);
370 ui->btnFastForward->setEnabled(true);
371 ui->btnFastBackward->setEnabled(true);
372}
373
374// 响应暂停按钮点击信号的槽函数
375void MainWindow::on_btnPause_clicked()
376{
377 if (libvlc_media_player_is_playing(vlcMediaPlayer))
378 {
379 // 暂停VLC媒体
380 libvlc_media_player_pause(vlcMediaPlayer);
381 ui->btnPause->setText("继续");
382 }
383 else
384 {
385 // 播放VLC媒体
386 libvlc_media_player_play(vlcMediaPlayer);
387 ui->btnPause->setText("暂停");
388 }
389}
390
391// 响应停止按钮点击信号的槽函数
392void MainWindow::on_btnStop_clicked()
393{
394 // 停止VLC媒体
395 libvlc_media_player_stop(vlcMediaPlayer);
396
397 // 若内嵌视频...
398 if (embed)
399 // 激活视频框控件更新显示
400 ui->frmVideo->setUpdatesEnabled(true);
401
402 // 调整界面
403 ui->sliderProgress->setValue(0);
404 ui->sliderProgress->setEnabled(false);
405 ui->labProgress->setText("00:00:00.000/00:00:00.000");
406 ui->btnPlay->setEnabled(true);
407 ui->btnPause->setEnabled(false);
408 ui->btnPause->setText("暂停");
409 ui->btnStop->setEnabled(false);
410 ui->btnFastForward->setEnabled(false);
411 ui->btnFastBackward->setEnabled(false);
412}
413
414// 响应快进按钮点击信号的槽函数
415void MainWindow::on_btnFastForward_clicked()
416{
417 // 向前步进媒体长度的百分之一
418 libvlc_time_t time = libvlc_media_player_get_time(vlcMediaPlayer) +
419 vlcMediaLength / 100;
420
421 // 定位VLC媒体
422 libvlc_media_player_set_time(
423 vlcMediaPlayer, time < vlcMediaLength ? time : vlcMediaLength);
424}
425
426// 响应快退按钮点击信号的槽函数
427void MainWindow::on_btnFastBackward_clicked()
428{
429 // 向后步进媒体长度的百分之一
430 libvlc_time_t time = libvlc_media_player_get_time(vlcMediaPlayer) -
431 vlcMediaLength / 100;
432
433 // 定位VLC媒体
434 libvlc_media_player_set_time(vlcMediaPlayer, time ? time : 0);
435}
436
437// 响应音量滑块移动信号的槽函数(拖拽滑块)
438void MainWindow::on_sliderVolume_sliderMoved(int position)
439{
440 // 调整音量
441 libvlc_audio_set_volume(vlcMediaPlayer, position);
442 // 设置静音
443 libvlc_audio_set_mute(vlcMediaPlayer, !position);
444}
445
446// 响应音量滑块值改变信号的槽函数(点击滑轨)
447void MainWindow::on_sliderVolume_valueChanged(int value)
448{
449 if (libvlc_audio_get_volume(vlcMediaPlayer) != value)
450 {
451 // 调整音量
452 libvlc_audio_set_volume(vlcMediaPlayer, value);
453 // 设置静音
454 libvlc_audio_set_mute(vlcMediaPlayer, !value);
455 }
456}
457
458// 响应关于按钮点击信号的槽函数
459void MainWindow::on_btnAbout_clicked()
460{
461 // 显示版本
462 QMessageBox(QMessageBox::Information, windowTitle(),
463 "基于Qt和libVLC的流媒体播放器\n\n"
464 "版本:1.0\n\n"
465 "版权所有 (C) 达内科技, 2020",
466 QMessageBox::Ok, this).exec();
467}
468
469// 响应退出按钮点击信号的槽函数
470void MainWindow::on_btnQuit_clicked()
471{
472 // 关闭窗口
473 close();
474}
启动Qt 5.12.8 (MinGW 7.3.0 64-bit)命令行,执行如下命令:
xxxxxxxxxx
21D:\Qt5.12.8\5.12.8\mingw73_64>cd /d E:\Projects\Tarena\C++\QtPlayer\Win64Release\release
2E:\Projects\Tarena\C++\QtPlayer\Win64Release\release> windeployqt QtPlayerWin.exe
达内集团◇C++/嵌入式◇闵卫