xxxxxxxxxx
4721
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
23 if (setenv("VLC_PLUGIN_PATH", "/usr/lib/vlc/plugins", 0) == -1)
24 {
25 QMessageBox(QMessageBox::Critical, windowTitle(),
26 "无法设置VLC插件路径环境变量!", QMessageBox::Ok, this).exec();
27 return;
28 }
29// Q_OS_WINDOWS
30
31 // 创建VLC实例
32 if (!(vlcInstance = libvlc_new(0, NULL)))
33 {
34 QMessageBox(QMessageBox::Critical, windowTitle(),
35 "无法创建VLC实例!", QMessageBox::Ok, this).exec();
36 return;
37 }
38
39 // 创建VLC媒体播放器
40 if (!(vlcMediaPlayer = libvlc_media_player_new(vlcInstance)))
41 {
42 QMessageBox(QMessageBox::Critical, windowTitle(),
43 "无法创建VLC媒体播放器!", QMessageBox::Ok, this).exec();
44 return;
45 }
46
47 // 若内嵌视频...
48 if (embed)
49 {
50 // 将视频框控件设置为VLC媒体播放器的输出窗口
51
52 libvlc_media_player_set_hwnd(
53 vlcMediaPlayer, reinterpret_cast<void*>(ui->frmVideo->winId()));
54
55 libvlc_media_player_set_xwindow(vlcMediaPlayer, ui->frmVideo->winId());
56// Q_OS_WINDOWS
57
58 // 为视频框控件安装事件过滤器,以截获鼠标双击事件,切换全屏和窗口模式
59 ui->frmVideo->installEventFilter(this);
60 }
61 else // 否则...
62 // 销毁屏幕框控件(及其子控件————视频框控件)
63 delete ui->frmScreen;
64
65 // 获取VLC事件管理器
66 if (!(vlcEventManager = libvlc_media_player_event_manager(vlcMediaPlayer)))
67 {
68 QMessageBox(QMessageBox::Critical, windowTitle(),
69 "无法获取VLC事件管理器!", QMessageBox::Ok, this).exec();
70 return;
71 }
72
73 // 设置VLC事件回调
74
75 // 响应媒体长度改变事件————设置进度滑块控件
76 libvlc_event_attach(
77 vlcEventManager, libvlc_MediaPlayerLengthChanged,
78 onMediaPlayerLengthChanged, this);
79
80 // 若内嵌视频...
81 if (embed)
82 // 响应视频输出启动事件————枚举视频框控件的所有子窗口并禁用之
83 // 在Windows上若不禁用视频框控件的子窗口,即VLC视频输出窗口,
84 // 鼠标停留其上将导致界面崩溃
85 libvlc_event_attach(
86 vlcEventManager, libvlc_MediaPlayerVout,
87 onMediaPlayerVout, this);
88// Q_OS_WINDOWS
89 // 响应时间改变事件————同步进度滑块控件和进度标签控件
90 libvlc_event_attach(
91 vlcEventManager, libvlc_MediaPlayerTimeChanged,
92 onMediaPlayerTimeChanged, this);
93 // 响应终点到达事件————停止播放
94 libvlc_event_attach(
95 vlcEventManager, libvlc_MediaPlayerEndReached,
96 onMediaPlayerEndReached, this);
97
98 // 初始化界面
99 ui->editURL->setEnabled(true);
100 ui->btnPlay->setEnabled(true);
101
102 // 初始化音量
103 libvlc_audio_set_volume(vlcMediaPlayer, ui->sliderVolume->value());
104}
105
106// 析构函数
107MainWindow::~MainWindow()
108{
109 // 销毁VLC媒体播放器
110 if (vlcMediaPlayer)
111 {
112 libvlc_media_player_release(vlcMediaPlayer);
113 vlcMediaPlayer = NULL;
114 }
115
116 // 销毁VLC实例
117 if (vlcInstance)
118 {
119 libvlc_release(vlcInstance);
120 vlcInstance = NULL;
121 }
122
123 delete ui;
124}
125
126// 响应媒体长度改变事件的静态处理函数
127void MainWindow::onMediaPlayerLengthChanged(
128 libvlc_event_t const* event, void* data)
129{
130 // 调用普通处理函数
131 reinterpret_cast<MainWindow*>(data)->onMediaPlayerLengthChanged(
132 event->u.media_player_length_changed.new_length);
133}
134
135// 响应媒体长度改变事件的普通处理函数
136void MainWindow::onMediaPlayerLengthChanged(libvlc_time_t length)
137{
138 // 将媒体长度毫秒值设置为进度滑块控件的最大值
139 ui->sliderProgress->setMaximum(length);
140 // 将媒体长度毫秒值的十分之一设置为进度滑块控件的页步距
141 ui->sliderProgress->setPageStep(length / 10);
142 // 将媒体长度毫秒值的百分之一设置为进度滑块控件的刻度间隔
143 ui->sliderProgress->setTickInterval(length / 100);
144 // 将媒体长度毫秒值保存到成员变量中以备后用
145 vlcMediaLength = length;
146}
147
148
149
150// 子窗口枚举回调函数
151BOOL CALLBACK MainWindow::onEnumVLCWindow(HWND hwnd, LPARAM)
152{
153 // 禁用该子窗口,即VLC视频输出窗口,避免鼠标停留引发界面崩溃
154 EnableWindow(hwnd, FALSE);
155 return TRUE;
156}
157
158// 响应视频输出启动事件的静态处理函数
159void MainWindow::onMediaPlayerVout(
160 libvlc_event_t const*, void* data)
161{
162 // 调用普通处理函数
163 reinterpret_cast<MainWindow*>(data)->onMediaPlayerVout();
164}
165
166// 响应视频输出启动事件的普通处理函数
167void MainWindow::onMediaPlayerVout(void)
168{
169 // 枚举视频框控件的所有子窗口,即VLC视频输出窗口
170 // 每个子窗口的句柄将作为参数,传递给枚举回调函数
171 EnumChildWindows((HWND)ui->frmVideo->winId(), onEnumVLCWindow, 0);
172}
173
174// Q_OS_WINDOWS
175
176// 响应时间改变事件的静态处理函数
177void MainWindow::onMediaPlayerTimeChanged(
178 libvlc_event_t const* event, void* data)
179{
180 // 调用普通处理函数
181 reinterpret_cast<MainWindow*>(data)->onMediaPlayerTimeChanged(
182 event->u.media_player_time_changed.new_time);
183}
184
185// 响应时间改变事件的普通处理函数
186void MainWindow::onMediaPlayerTimeChanged(libvlc_time_t time)
187{
188 // 根据媒体时间毫秒值同步进度滑块控件
189 ui->sliderProgress->setValue(time);
190 // 根据媒体时间毫秒值同步进度标签控件
191 ui->labProgress->setText(
192 QTime::fromMSecsSinceStartOfDay(time).toString("hh:mm:ss.zzz") + "/" +
193 QTime::fromMSecsSinceStartOfDay(vlcMediaLength).toString("hh:mm:ss.zzz"));
194}
195
196// 响应终点到达事件的静态处理函数
197void MainWindow::onMediaPlayerEndReached(
198 libvlc_event_t const*, void* data)
199{
200 // 调用普通处理函数
201 reinterpret_cast<MainWindow*>(data)->onMediaPlayerEndReached();
202}
203
204// 响应终点到达事件的普通处理函数
205void MainWindow::onMediaPlayerEndReached(void)
206{
207 // 向停止按钮发射点击信号
208 emit ui->btnStop->click();
209}
210
211// 显示窗口时被调用的虚函数
212void MainWindow::showEvent(QShowEvent*)
213{
214 // 若非内嵌视频...
215 if (!embed)
216 // 将窗口收缩至最小
217 resize(minimumSize());
218}
219
220// 视频框控件有事件时被调用的虚函数
221bool MainWindow::eventFilter(QObject* obj, QEvent* event)
222{
223 // 若视频框控件发生鼠标双击事件...
224 if (obj == ui->frmVideo && event->type() == QEvent::MouseButtonDblClick)
225 {
226 static bool fullscreen = false; // 全屏模式
227
228 static int minHeight; // 最小高度
229 static QSize winSize; // 窗口大小
230
231 static QMargins cntMargins; // 中心布局的边缘大小
232 static int frmStyle; // 屏幕框控件的边框风格
233// Q_OS_WINDOWS
234
235 if (fullscreen) // 全屏->窗口
236 {
237
238 // 调整界面
239 setMinimumHeight(minHeight);
240 resize(winSize);
241 ui->frmScreen->show();
242 // 退出全屏
243 ui->frmVideo->setWindowFlags(Qt::SubWindow);
244 ui->frmVideo->showNormal();
245
246 // 调整界面
247 ui->labFullscreen->show();
248 ui->frmControl->show();
249 ui->layoutCentral->setContentsMargins(cntMargins);
250 ui->frmScreen->setFrameStyle(frmStyle);
251 // 退出全屏
252 showNormal();
253// Q_OS_WINDOWS
254 // 恢复光标
255 ui->frmVideo->unsetCursor();
256 // 激活窗口
257 qApp->setActiveWindow(this);
258 }
259 else // 窗口->全屏
260 {
261 // 隐藏光标
262 ui->frmVideo->setCursor(Qt::BlankCursor);
263
264 // 进入全屏
265 ui->frmVideo->setWindowFlags(Qt::Window);
266 ui->frmVideo->showFullScreen();
267 // 调整界面
268 ui->frmScreen->hide();
269 minHeight = minimumHeight();
270 winSize = size();
271 setMinimumHeight(
272 ui->layoutCentral->contentsMargins().top() +
273 ui->labFullscreen->size().height() +
274 ui->layoutCentral->spacing() +
275 ui->frmControl->size().height() +
276 ui->layoutCentral->contentsMargins().bottom());
277 resize(size().width(), minimumHeight());
278
279 // 进入全屏
280 showFullScreen();
281 // 调整界面
282 ui->labFullscreen->hide();
283 ui->frmControl->hide();
284 cntMargins = ui->layoutCentral->contentsMargins();
285 ui->layoutCentral->setContentsMargins(QMargins());
286 frmStyle = ui->frmScreen->frameStyle();
287 ui->frmScreen->setFrameStyle(QFrame::NoFrame);
288// Q_OS_WINDOWS
289 }
290
291 fullscreen = !fullscreen;
292 return true;
293 }
294
295 return QMainWindow::eventFilter(obj, event);
296}
297
298// 响应进度滑块值改变信号的槽函数(拖拽滑块或点击滑轨)
299void MainWindow::on_sliderProgress_valueChanged(int value)
300{
301 // 在响应时间改变事件的处理函数中,根据媒体时间的毫秒值调整进度
302 // 滑块的位置,也会引发值改变信号,此处若不加判断势必构成死循环
303 if (libvlc_media_player_get_time(vlcMediaPlayer) != value)
304 // 定位VLC媒体
305 libvlc_media_player_set_time(vlcMediaPlayer, value);
306}
307
308// 响应播放按钮点击信号的槽函数
309void MainWindow::on_btnPlay_clicked()
310{
311 string url = ui->editURL->text().toStdString();
312
313 vector<string> protocols;
314 protocols.push_back("http");
315 protocols.push_back("https");
316 protocols.push_back("ftp");
317 protocols.push_back("rstp");
318
319 vector<string>::const_iterator it;
320 for (it = protocols.begin(); it != protocols.end(); ++it)
321 if (!url.compare(0, it->size(), *it))
322 break;
323
324 // 若网络媒体...
325 if (it != protocols.end())
326 {
327 // 创建VLC媒体
328 if (!(vlcMedia = libvlc_media_new_location(vlcInstance, url.c_str())))
329 {
330 QMessageBox(QMessageBox::Critical, windowTitle(),
331 "无法创建VLC媒体!", QMessageBox::Ok, this).exec();
332 return;
333 }
334 }
335 else // 否则,即本地媒体...
336 {
337 // 创建VLC媒体
338 if (!(vlcMedia = libvlc_media_new_path(vlcInstance, url.c_str())))
339 {
340 QMessageBox(QMessageBox::Critical, windowTitle(),
341 "无法创建VLC媒体!", QMessageBox::Ok, this).exec();
342 return;
343 }
344 }
345
346 // 将VLC媒体设置到VLC媒体播放器中
347 libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia);
348
349 // 播放VLC媒体
350 if (libvlc_media_player_play(vlcMediaPlayer) == -1)
351 {
352 QMessageBox(QMessageBox::Critical, windowTitle(),
353 "无法播放VLC媒体!", QMessageBox::Ok, this).exec();
354 return;
355 }
356
357 // 若内嵌视频...
358 if (embed)
359 // 禁止视频框控件更新显示,避免闪烁
360 ui->frmVideo->setUpdatesEnabled(false);
361
362 // 调整界面
363 ui->sliderProgress->setEnabled(true);
364 ui->btnPlay->setEnabled(false);
365 ui->btnPause->setEnabled(true);
366 ui->btnStop->setEnabled(true);
367 ui->btnFastForward->setEnabled(true);
368 ui->btnFastBackward->setEnabled(true);
369}
370
371// 响应暂停按钮点击信号的槽函数
372void MainWindow::on_btnPause_clicked()
373{
374 if (libvlc_media_player_is_playing(vlcMediaPlayer))
375 {
376 // 暂停VLC媒体
377 libvlc_media_player_pause(vlcMediaPlayer);
378 ui->btnPause->setText("继续");
379 }
380 else
381 {
382 // 播放VLC媒体
383 libvlc_media_player_play(vlcMediaPlayer);
384 ui->btnPause->setText("暂停");
385 }
386}
387
388// 响应停止按钮点击信号的槽函数
389void MainWindow::on_btnStop_clicked()
390{
391 // 停止VLC媒体
392 libvlc_media_player_stop(vlcMediaPlayer);
393
394 // 若内嵌视频...
395 if (embed)
396 // 激活视频框控件更新显示
397 ui->frmVideo->setUpdatesEnabled(true);
398
399 // 调整界面
400 ui->sliderProgress->setValue(0);
401 ui->sliderProgress->setEnabled(false);
402 ui->labProgress->setText("00:00:00.000/00:00:00.000");
403 ui->btnPlay->setEnabled(true);
404 ui->btnPause->setEnabled(false);
405 ui->btnPause->setText("暂停");
406 ui->btnStop->setEnabled(false);
407 ui->btnFastForward->setEnabled(false);
408 ui->btnFastBackward->setEnabled(false);
409}
410
411// 响应快进按钮点击信号的槽函数
412void MainWindow::on_btnFastForward_clicked()
413{
414 // 向前步进媒体长度的百分之一
415 libvlc_time_t time = libvlc_media_player_get_time(vlcMediaPlayer) +
416 vlcMediaLength / 100;
417
418 // 定位VLC媒体
419 libvlc_media_player_set_time(vlcMediaPlayer,
420 time < vlcMediaLength ? time : vlcMediaLength);
421}
422
423// 响应快退按钮点击信号的槽函数
424void MainWindow::on_btnFastBackward_clicked()
425{
426 // 向后步进媒体长度的百分之一
427 libvlc_time_t time = libvlc_media_player_get_time(vlcMediaPlayer) -
428 vlcMediaLength / 100;
429
430 // 定位VLC媒体
431 libvlc_media_player_set_time(vlcMediaPlayer,
432 time > 0 ? time : 0);
433}
434
435// 响应音量滑块移动信号的槽函数(拖拽滑块)
436void MainWindow::on_sliderVolume_sliderMoved(int position)
437{
438 // 调整音量
439 libvlc_audio_set_volume(vlcMediaPlayer, position);
440 // 设置静音
441 libvlc_audio_set_mute(vlcMediaPlayer, !position);
442}
443
444// 响应音量滑块值改变信号的槽函数(点击滑轨)
445void MainWindow::on_sliderVolume_valueChanged(int value)
446{
447 if (libvlc_audio_get_volume(vlcMediaPlayer) != value)
448 {
449 // 调整音量
450 libvlc_audio_set_volume(vlcMediaPlayer, value);
451 // 设置静音
452 libvlc_audio_set_mute(vlcMediaPlayer, !value);
453 }
454}
455
456// 响应关于按钮点击信号的槽函数
457void MainWindow::on_btnAbout_clicked()
458{
459 // 显示版本
460 QMessageBox(QMessageBox::Information, windowTitle(),
461 "基于Qt和libVLC的流媒体播放器\n\n"
462 "版本:1.0\n\n"
463 "版权所有 (C) 达内科技, 2020",
464 QMessageBox::Ok, this).exec();
465}
466
467// 响应退出按钮点击信号的槽函数
468void MainWindow::on_btnQuit_clicked()
469{
470 // 关闭窗口
471 close();
472}