效果展示
vlcplayer_test视频播放器
MainWidget.ui
- 注意控件的布局和命名,控件的命名和信号与槽函数的绑定有关,所以这点很重要。
下载VLC组件和环境配置
- videolan下载地址
- 我下载的是vlc-3.0.8-win64版本.
- 将下载的文件复制粘贴到项目文件中.
- 复制粘贴这三个文件到项目的debug文件夹里面.
- 然后我们在主文件里面添加
#include <vlc/vlc.h>
头文件.
MainWidget.h
#pragma once
#include <QtWidgets>
#include "ui_MainWidget.h"
#include <vlc/vlc.h>
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = nullptr);
~MainWidget();
libvlc_media_player_t* getMediaPlayer();
//获取media player对象
qint64 getDuration();
//获取总时长,单位是秒
void setTimeSliderPos(int value);
//设置时间滑动条的值
void setVolumeSliderPos(int value);
//设置音量滑动条的值
void setTimeText(QString str);
//设置时间标签文本
private slots:
void on_btnOpen_clicked();
//打开按钮槽函数
void on_btnPlay_clicked();
//播放按钮槽函数
void on_btnPause_clicked();
//暂停按钮槽函数
void on_btnStop_clicked();
//停止按钮槽函数
void onTimeSliderMoved(int value);
//时间滑动条移动槽函数
void onVolumeSliderMoved(int value);
//音量滑动条移动槽函数
private:
Ui::MainWidgetClass ui;
libvlc_instance_t* m_pInstance = nullptr;
//视频示例,负责管理全局配置和资源
libvlc_media_player_t* m_pMediaPlayer = nullptr;
//VLC 媒体播放器的指针,用于控制媒体的播放、暂停、停止等操作
libvlc_media_t* m_pMedia = nullptr;
// VLC 媒体的指针,用于加载和管理特定的媒体内容(如音频或视频文件)
libvlc_event_manager_t* m_pEvent_manager = nullptr;
//事件管理器的指针,负责处理 VLC 播放器的各种事件(例如媒体播放完毕、音量变化等)
qint64 m_totalSecs = -1;
//总时长,单位是秒
};
- 我们利用vlc库去实现视频播放器,那么我们就需要按照他人的要求去编写代码,因为vlc库是别人写出来的东西,而他人的要求就是需要我们去定义示例,媒体播放器,媒体,事件等对象,并按照要求去使用.
MainWidget.cpp
#include "MainWidget.h"
void vlc_callback(const struct libvlc_event_t* p_event, void* p_data) {
MainWidget* pMain = static_cast<MainWidget*>(p_data);
if (pMain) {
switch (p_event->type) {
case libvlc_MediaPlayerPositionChanged:
{
float pos = libvlc_media_player_get_position(pMain->getMediaPlayer());
pMain->setTimeSliderPos(pos * 100);
qint64 curSecs = libvlc_media_player_get_time(pMain->getMediaPlayer()) / 1000;
int curH = curSecs / 3600;
int curMinute = (curSecs - curH * 3600) / 60;
int curSec = curSecs - curH * 3600 - curMinute * 60;
QString str1 = QString("%1:%2:%3")
.arg(curH, 2, 10, QChar('0'))
.arg(curMinute, 2, 10, QChar('0'))
.arg(curSec, 2, 10, QChar('0'));
qint64 totalSecs = pMain->getDuration();
int totalH = totalSecs / 3600;
int totalMinute = (totalSecs - totalH * 3600) / 60;
int totalSec = totalSecs - totalH * 3600 - totalMinute * 60;
QString str2 = QString("%1:%2:%3")
.arg(totalH, 2, 10, QChar('0'))
.arg(totalMinute, 2, 10, QChar('0'))
.arg(totalSec, 2, 10, QChar('0'));
QString text = str1 + "/" + str2;
pMain->setTimeText(text);
break;
}
case libvlc_MediaPlayerAudioVolume:
{
int volume = libvlc_audio_get_volume(pMain->getMediaPlayer());
pMain->setVolumeSliderPos(volume);
break;
}
}
}
}
MainWidget::MainWidget(QWidget* parent)
: QWidget(parent) {
ui.setupUi(this);
m_pInstance = libvlc_new(0, nullptr);
if (m_pInstance) {
m_pMediaPlayer = libvlc_media_player_new(m_pInstance);
if (m_pMediaPlayer) {
m_pEvent_manager = libvlc_media_player_event_manager(m_pMediaPlayer);
libvlc_event_attach(m_pEvent_manager, libvlc_MediaPlayerPositionChanged, vlc_callback, this);
libvlc_event_attach(m_pEvent_manager, libvlc_MediaPlayerAudioVolume, vlc_callback, this);
} else {
libvlc_release(m_pInstance);
QMessageBox::information(this, "提示", "libvlc_media_player_new failed");
exit(EXIT_FAILURE);
}
} else {
QMessageBox::information(this, "提示", "libvlc_new failed");
exit(EXIT_FAILURE);
}
ui.label_time->setText("");
connect(ui.timeSlider, &QSlider::sliderMoved, this, &MainWidget::onTimeSliderMoved);
connect(ui.volumeSlider, &QSlider::sliderMoved, this, &MainWidget::onVolumeSliderMoved);
}
MainWidget::~MainWidget() {
if (m_pMediaPlayer) {
libvlc_media_player_release(m_pMediaPlayer);
m_pMediaPlayer = nullptr;
}
if (m_pInstance) {
libvlc_release(m_pInstance);
m_pInstance = nullptr;
}
}
libvlc_media_player_t* MainWidget::getMediaPlayer() {
return m_pMediaPlayer;
}
qint64 MainWidget::getDuration() {
return m_totalSecs;
}
void MainWidget::setTimeSliderPos(int value) {
ui.timeSlider->setValue(value);
}
void MainWidget::setVolumeSliderPos(int value) {
ui.volumeSlider->setValue(value);
}
void MainWidget::setTimeText(QString str) {
ui.label_time->setText(str);
}
void MainWidget::on_btnOpen_clicked() {
QString filename = QFileDialog::getOpenFileName(this, "请选择视频文件", "D:",
"视频文件(*.mp4 *.flv);;所有文件(*.*);;");
if (filename.isEmpty()) return;
filename = QDir::toNativeSeparators(filename);
m_pMedia = libvlc_media_new_path(m_pInstance, filename.toStdString().c_str());
if (m_pMedia) {
libvlc_media_parse(m_pMedia);
libvlc_media_player_set_media(m_pMediaPlayer, m_pMedia);
libvlc_media_player_set_hwnd(m_pMediaPlayer, (void*)(ui.video_widget->winId()));
libvlc_media_release(m_pMedia);
m_totalSecs = libvlc_media_get_duration(m_pMedia) / 1000;
m_pMedia = nullptr;
libvlc_media_player_play(m_pMediaPlayer);
} else {
if (m_pMediaPlayer) {
libvlc_media_player_release(m_pMediaPlayer);
m_pMediaPlayer = nullptr;
}
if (m_pInstance) {
libvlc_release(m_pInstance);
m_pInstance = nullptr;
}
QMessageBox::information(this, "提示", "libvlc_media_new_path failed");
exit(EXIT_FAILURE);
}
}
void MainWidget::on_btnPlay_clicked() {
if (libvlc_media_player_get_state(m_pMediaPlayer) == libvlc_state_t::libvlc_Paused
|| libvlc_media_player_get_state(m_pMediaPlayer) == libvlc_state_t::libvlc_Stopped) {
libvlc_media_player_play(m_pMediaPlayer);
}
}
void MainWidget::on_btnPause_clicked() {
if (libvlc_media_player_get_state(m_pMediaPlayer) == libvlc_state_t::libvlc_Playing
) {
libvlc_media_player_pause(m_pMediaPlayer);
}
}
void MainWidget::on_btnStop_clicked() {
if (libvlc_media_player_get_state(m_pMediaPlayer) == libvlc_state_t::libvlc_Playing
|| libvlc_media_player_get_state(m_pMediaPlayer) == libvlc_state_t::libvlc_Paused) {
libvlc_media_player_stop(m_pMediaPlayer);
}
}
void MainWidget::onTimeSliderMoved(int value) {
libvlc_media_player_set_position(m_pMediaPlayer, value / 100.0);
}
void MainWidget::onVolumeSliderMoved(int value) {
libvlc_audio_set_volume(m_pMediaPlayer, value);
}
MainWidget
m_pInstance = libvlc_new(0, nullptr);
利用libvlc_new函数去创建示例对象.m_pMediaPlayer = libvlc_media_player_new(m_pInstance);
如果实例创建成功,就创建视频媒体对象,利用libvlc_media_player_new()函数创建对象.m_pEvent_manager = libvlc_media_player_event_manager(m_pMediaPlayer);
如果视频媒体对象创建成功,就创建事件管理器的对象,利用libvlc_media_player_event_manager()函数创建对象.libvlc_event_attach(m_pEvent_manager, libvlc_MediaPlayerPositionChanged, vlc_callback, this);
视频媒体位置改变了就会发送信号到回调函数vlc_callback也就是说只要视频在播放,那么就会持续不断的发送信号到回调函数`vlc_callback中.libvlc_event_attach(m_pEvent_manager, libvlc_MediaPlayerAudioVolume, vlc_callback, this);
视频声音发生改变的时候触发的事件,发送信号到回调函数vlc_callback,这段代码的意义是保证程序一进去的时候音量和滑动条是对应的.connect(ui.timeSlider, &QSlider::sliderMoved, this, &MainWidget::onTimeSliderMoved);
时间滑动条被拖动的时候发送信号触发槽函数.connect(ui.volumeSlider, &QSlider::sliderMoved, this, &MainWidget::onVolumeSliderMoved);
音量滑动条被拖动的时候发送信号触发槽函数.
vlc_callback
void vlc_callback(const struct libvlc_event_t* p_event, void* p_data)
这是回调函数的固定写法.p_event 是指向 libvlc_event_t 类型的常量指针,表示发生的具体事件.在回调函数中,通常将 p_data 转换为具体类型(例如指向 MainWidget 的指针),以便在回调中访问类成员或调用类方法。MainWidget* pMain = static_cast<MainWidget*>(p_data);
将p_date进行安全的类型转换,转换成MainWidget类型,这样我们就可以通过pMain直接访问主窗口类里面的对象成员.- 利用switch语句对传递进来的不同事件进行不同的代码处理,我们只编辑了两个具体的事件,一个是libvlc_MediaPlayerPositionChanged事件,视频只要在播放就会一直发送信号,一个是libvlc_MediaPlayerAudioVolume,视频的音量改变了就会发送信号,用于进入程序时将音量的滑动条和音量进行绑定.
libvlc_MediaPlayerAudioVolume
内部代码,
int volume = libvlc_audio_get_volume(pMain->getMediaPlayer());
获取VLC播放器的音量,volume 的值通常在 0 到 100 之间,表示音量的百分比.然后
pMain->setVolumeSliderPos(volume);
设置这个音量到音量滑动条中.也就是说我们一进入程序获取音量然后设置音量滑动条的值.之后我们手动改变音量滑动条视频音量和滑动条通过槽函数一直都是绑定在一起的.libvlc_MediaPlayerPositionChanged
内部代码,
float pos = libvlc_media_player_get_position(pMain->getMediaPlayer());
获取视频当前进度占总进度的百分比值,返回值时一个0~1的float类型的值,
pMain->setTimeSliderPos(pos * 100);
将返回值乘以100得到的是具体的值,因为事件滑动条默认是0~100,这样我们直接设置乘以100的值为此时滑动条的值就按照百分比绑定了当前视频进度和滑动条位置.qint64 curSecs = libvlc_media_player_get_time(pMain->getMediaPlayer()) / 1000;
获取当前视频的时间,单位是毫秒,转化为秒需要除以1000.然后按照计算得到此时对应的时分秒.将时分秒转化为对应的字符串,然后计算总时间的时分秒转化为字符串拼接在一起,设置为Label的text值.
on_btnOpen_clicked
- 打开按钮需要实现的效果是,点击之后需要有一个弹窗,选择我们需要播放的视频文件,然后播放.
getOpenFileName
函数实现弹窗选择视频文件的功能,toNativeSeparators
函数将得到的路径转换为正确的格式路径,因为得到的路径 \和/可能不符合当前程序QT里面的规则,用这个函数可以进行转化统一.m_pMedia = libvlc_media_new_path(m_pInstance, filename.toStdString().c_str());
得到视频的路径之后创建媒体的对象.libvlc_media_parse(m_pMedia);
解析媒体文件,以便从文件中提取元数据信息(如时长、标题、格式等)。
libvlc_media_player_set_media(m_pMediaPlayer, m_pMedia);
将媒体 m_pMedia 设置到媒体播放器 m_pMediaPlayer 中。此操作指示播放器应使用该媒体文件作为播放内容。此时 m_pMedia 已经和播放器绑定,不再需要手动管理其生命周期。
libvlc_media_player_set_hwnd(m_pMediaPlayer, (void*)(ui.video_widget->winId()));
设置视频输出窗口的句柄,使播放器的视频内容渲染在指定的窗口控件上。此处 ui.video_widget->winId() 获取了窗口句柄,将其转换为 void* 类型。m_totalSecs = libvlc_media_get_duration(m_pMedia) / 1000;
在媒体进行销毁之前计算出视频总时长,得到的时间是毫秒单位需要除以1000转化为秒.
on_btnPlay_clicked等其他按钮
ibvlc_media_player_get_state(m_pMediaPlayer)
得到当前的状态,libvlc_state_t::libvlc_Paused
暂停状态,libvlc_state_t::libvlc_Stopped
停止状态,libvlc_state_t::libvlc_Playing
播放状态,libvlc_media_player_play(m_pMediaPlayer);
播放视频媒体,libvlc_media_player_pause(m_pMediaPlayer);
暂停视频媒体,libvlc_media_player_stop(m_pMediaPlayer);
停止视频媒体
杂项
libvlc_media_player_set_position
设置视频媒体时长位置,
value / 100.0
:value 通常是从进度滑块控件中获取的整数值,范围通常是 0 到 100。通过除以 100.0,将其转换为 0.0 到 1.0 之间的小数(即百分比),符合 libvlc 所需的参数范围。0.0 表示播放开始位置,1.0 表示播放结束位置。libvlc_audio_set_volume(m_pMediaPlayer, value);
value:要设置的音量值,通常范围是 0 到 100,0 表示静音;100 表示最大音量(也可以设置大于 100,视 VLC 配置可能允许更高的音量,但通常建议限制在 0-100 范围内)。
结尾
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!