Qt使用libvlc简单播放视频文件
1. 下载sdk
vlc sdk下载地址为http://download.videolan.org/pub/videolan/vlc/,以3.0.20为例,下载文件为vlc-3.0.20-win32.7z。
需要注意的是,需要下载.7z文件,.zip文件中是没有sdk文件夹的。
将vlc-3.0.20-win32.7z解压缩,拷贝sdk文件夹中的include、lib文件夹到qt项目中的third_party/vlc。
将libvlc.dll、libvlccore.dll、plugins文件夹拷贝到qt项目输出目录。
2. 配置 Qt 项目文件 (.pro)
在.pro文件中添加下面的内容:
# 添加 VLC 库路径和头文件
INCLUDEPATH += $$PWD/third_party/vlc/include
LIBS += $$PWD/third_party/vlc/lib/libvlc.lib \
$$PWD/third_party/vlc/lib/libvlccore.lib
3. 基本视频播放器实现
3.1 主窗口头文件 (mainwindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QSlider>
#include <vlc/vlc.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void openFile();
void play();
void pause();
void stop();
void setVolume(int volume);
void updatePosition(float pos);
void seek(int position);
private:
void initVLC();
void createUI();
void releaseVLC();
private:
//UI组件
QWidget *m_videoWidget;
QSlider *m_positionSlider;
QSlider *m_volumeSlider;
QPushButton *m_playButton;
QPushButton *m_pauseButton;
QPushButton *m_stopButton;
QPushButton *m_openButton;
//VLC实例指针
libvlc_instance_t *m_vlcInstance = nullptr;
libvlc_media_player_t *m_mediaPlayer = nullptr;
libvlc_media_t *m_media = nullptr;
};
#endif // MAINWINDOW_H
3.2 主窗口实现 (mainwindow.cpp)
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFileDialog>
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include <QLabel>
#include <QElapsedTimer>
#include <QCoreApplication>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
initVLC();
createUI();
resize(800, 600);
setWindowTitle("Qt VLC Player");
}
MainWindow::~MainWindow()
{
releaseVLC();
}
void MainWindow::initVLC()
{
const char *vlc_args[] =
{
"--ignore-config", //忽略默认配置
"--no-osd", //禁用屏幕显示
"--no-snapshot-preview" //禁用快照预览
};
//初始化VLC实例
m_vlcInstance = libvlc_new(sizeof(vlc_args)/sizeof(vlc_args[0]), vlc_args);
if (!m_vlcInstance)
{
QString message = QString("Failed to initialize libVLC: %1").arg(QString(libvlc_errmsg()));
QMessageBox::critical(this, "Error", message);
qDebug() << message;
}
}
void MainWindow::releaseVLC()
{
//停止播放
stop();
if (m_media)
{
libvlc_media_release(m_media);
m_media = nullptr;
}
if (m_mediaPlayer)
{
libvlc_media_player_release(m_mediaPlayer);
m_mediaPlayer = nullptr;
}
if (m_vlcInstance)
{
libvlc_release(m_vlcInstance);
m_vlcInstance = nullptr;
}
}
void MainWindow::createUI()
{
//创建视频显示区域
m_videoWidget = new QWidget(this);
m_videoWidget->setStyleSheet("background-color: black;");
//创建控制按钮
m_openButton = new QPushButton("Open", this);
m_playButton = new QPushButton("Play", this);
m_pauseButton = new QPushButton("Pause", this);
m_stopButton = new QPushButton("Stop", this);
//创建滑块
m_positionSlider = new QSlider(Qt::Horizontal, this);
m_positionSlider->setRange(0, 1000);
m_positionSlider->setEnabled(false);
m_volumeSlider = new QSlider(Qt::Horizontal, this);
m_volumeSlider->setRange(0, 100);
m_volumeSlider->setValue(80);
//布局
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_videoWidget, 1);
mainLayout->addWidget(m_positionSlider);
QHBoxLayout *controlLayout = new QHBoxLayout;
controlLayout->addWidget(m_openButton);
controlLayout->addWidget(m_playButton);
controlLayout->addWidget(m_pauseButton);
controlLayout->addWidget(m_stopButton);
controlLayout->addWidget(new QLabel("Volume:", this));
controlLayout->addWidget(m_volumeSlider);
mainLayout->addLayout(controlLayout);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
//连接信号槽
connect(m_openButton, &QPushButton::clicked, this, &MainWindow::openFile);
connect(m_playButton, &QPushButton::clicked, this, &MainWindow::play);
connect(m_pauseButton, &QPushButton::clicked, this, &MainWindow::pause);
connect(m_stopButton, &QPushButton::clicked, this, &MainWindow::stop);
connect(m_volumeSlider, &QSlider::valueChanged, this, &MainWindow::setVolume);
connect(m_positionSlider, &QSlider::sliderMoved, this, &MainWindow::seek);
//创建位置更新定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]()
{
if (m_mediaPlayer && libvlc_media_player_is_playing(m_mediaPlayer))
{
float pos = libvlc_media_player_get_position(m_mediaPlayer);
updatePosition(pos);
}
});
timer->start(200); //每200ms更新一次位置
}
void MainWindow::openFile()
{
QString filePath = QFileDialog::getOpenFileName(this, "Open Media File",
QDir::homePath(),
"Media Files (*.mp4 *.avi *.mkv *.mov *.mp3 *.wav)");
if (filePath.isNull() || filePath.isEmpty())
{
return;
}
//停止当前播放
stop();
//创建媒体
if (m_media)
{
libvlc_media_release(m_media);
}
m_media = libvlc_media_new_path(m_vlcInstance, QDir::toNativeSeparators(filePath).toStdString().c_str());
if (!m_media)
{
QMessageBox::critical(this, "Error", "Failed to create media");
return;
}
//创建媒体播放器
if (m_mediaPlayer)
{
libvlc_media_player_release(m_mediaPlayer);
}
m_mediaPlayer = libvlc_media_player_new_from_media(m_media);
if (!m_mediaPlayer)
{
QMessageBox::critical(this, "Error", "Failed to create media player");
libvlc_media_release(m_media);
m_media = nullptr;
return;
}
libvlc_media_release(m_media); // 立即释放媒体引用
m_media = nullptr;
//设置视频输出窗口
#if defined(Q_OS_WIN)
libvlc_media_player_set_hwnd(m_mediaPlayer, (void*)m_videoWidget->winId());
#elif defined(Q_OS_MAC)
libvlc_media_player_set_nsobject(m_mediaPlayer, (void*)m_videoWidget->winId());
#elif defined(Q_OS_LINUX)
libvlc_media_player_set_xwindow(m_mediaPlayer, m_videoWidget->winId());
#endif
//设置初始音量
libvlc_audio_set_volume(m_mediaPlayer, m_volumeSlider->value());
//启用位置滑块
m_positionSlider->setEnabled(true);
//自动播放
play();
}
void MainWindow::play()
{
if (m_mediaPlayer)
{
libvlc_media_player_play(m_mediaPlayer);
}
}
void MainWindow::pause()
{
if (m_mediaPlayer && libvlc_media_player_can_pause(m_mediaPlayer))
{
libvlc_media_player_set_pause(m_mediaPlayer, 1);
}
}
void MainWindow::stop()
{
if (m_mediaPlayer)
{
libvlc_media_player_stop(m_mediaPlayer);
libvlc_media_player_release(m_mediaPlayer);
m_mediaPlayer = nullptr;
updatePosition(0.0f);
}
if (m_media)
{
libvlc_media_release(m_media);
m_media = nullptr;
}
}
void MainWindow::setVolume(int volume)
{
if (m_mediaPlayer)
{
libvlc_audio_set_volume(m_mediaPlayer, volume);
}
}
void MainWindow::updatePosition(float pos)
{
//防止位置更新时滑块拖动冲突
if (!m_positionSlider->isSliderDown())
{
m_positionSlider->setValue(static_cast<int>(pos * 1000));
}
}
void MainWindow::seek(int position)
{
if (m_mediaPlayer)
{
float pos = static_cast<float>(position) / 1000.0f;
libvlc_media_player_set_position(m_mediaPlayer, pos);
}
}
4. 解决 libvlc_media_player_stop 死锁
在调用 libvlc_media_player_stop() 方法时有时会卡死,大概率是因为libvlc的回调事件阻塞了。参考资料:解决libvlc_media_player_stop时死锁的方法。
4.1 解决方法1:在新线程中停止播放
在新线程中调用libvlc_media_player_stop()方法,这种方法可以解决vlc停止播放死锁的问题,但是对于视频播放控制流程不太友好。
4.2 解决方法2:停止播放前销毁播放窗口
在libvlc_media_player_stop()之前,先把VLC视频窗口销毁,后面如果需要再重建。
- 在主窗口头文件定义QLabel
private:
//UI组件
QVBoxLayout *m_videoLayout; //新添加QVBoxLayout组件
QLabel *m_videoLabel; //新添加QLabel组件
QWidget *m_videoWidget;
- 修改UI创建代码
void MainWindowX::createUI()
{
//创建视频显示区域
m_videoWidget = new QWidget(this);
m_videoWidget->setStyleSheet("background-color: black;");
m_videoLayout = new QVBoxLayout; //创建视频控件布局
m_videoWidget->setLayout(m_videoLayout); //应用视频控件布局
//其他代码
}
- 视频播放时创建m_videoLabel
void MainWindowX::openFile()
{
//其他代码
libvlc_media_release(m_media); // 立即释放媒体引用
m_media = nullptr;
//创建m_videoLabel
if (!m_videoLabel)
{
m_videoLabel = new QLabel;
m_videoLabel->setStyleSheet("background-color: black;");
m_videoLayout->addWidget(m_videoLabel);
}
//设置视频输出窗口
}
- 停止播放时销毁m_videoLabel
void MainWindowX::stop()
{
if (m_mediaPlayer)
{
if (m_videoLabel)
{
m_videoLayout->removeWidget(m_videoLabel);
delete m_videoLabel;
m_videoLabel = nullptr;
}
libvlc_media_player_stop(m_mediaPlayer);
libvlc_media_player_release(m_mediaPlayer);
m_mediaPlayer = nullptr;
updatePosition(0.0f);
}
if (m_media)
{
libvlc_media_release(m_media);
m_media = nullptr;
}
}
5. 完善后的视频播放器实现
5.1 主窗口头文件 (mainwindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>
#include <QLabel>
#include <vlc/vlc.h>
class MainWindowX : public QMainWindow
{
Q_OBJECT
public:
MainWindowX(QWidget *parent = nullptr);
~MainWindowX();
private slots:
void openFile();
void play();
void pause();
void stop();
void setVolume(int volume);
void updatePosition(float pos);
void seek(int position);
private:
void initVLC();
void createUI();
void releaseVLC();
private:
//UI组件
QVBoxLayout *m_videoLayout;
QLabel *m_videoLabel;
QWidget *m_videoWidget;
QSlider *m_positionSlider;
QSlider *m_volumeSlider;
QPushButton *m_playButton;
QPushButton *m_pauseButton;
QPushButton *m_stopButton;
QPushButton *m_openButton;
//VLC实例指针
libvlc_instance_t *m_vlcInstance = nullptr;
libvlc_media_player_t *m_mediaPlayer = nullptr;
libvlc_media_t *m_media = nullptr;
};
#endif // MAINWINDOW_H
5.2 主窗口实现 (mainwindow.cpp)
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFileDialog>
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include <QLabel>
#include <QElapsedTimer>
#include <QCoreApplication>
#include "mainwindow_improve.h"
MainWindowX::MainWindowX(QWidget *parent)
: QMainWindow(parent)
{
initVLC();
createUI();
resize(800, 600);
setWindowTitle("Qt VLC Player");
}
MainWindowX::~MainWindowX()
{
releaseVLC();
}
void MainWindowX::initVLC()
{
const char *vlc_args[] =
{
"--ignore-config", //忽略默认配置
"--no-osd", //禁用屏幕显示
"--no-snapshot-preview" //禁用快照预览
};
//初始化VLC实例
m_vlcInstance = libvlc_new(sizeof(vlc_args)/sizeof(vlc_args[0]), vlc_args);
if (!m_vlcInstance)
{
QString message = QString("Failed to initialize libVLC: %1").arg(QString(libvlc_errmsg()));
QMessageBox::critical(this, "Error", message);
qDebug() << message;
}
}
void MainWindowX::releaseVLC()
{
//停止播放
stop();
if (m_media)
{
libvlc_media_release(m_media);
m_media = nullptr;
}
if (m_mediaPlayer)
{
libvlc_media_player_release(m_mediaPlayer);
m_mediaPlayer = nullptr;
}
if (m_vlcInstance)
{
libvlc_release(m_vlcInstance);
m_vlcInstance = nullptr;
}
}
void MainWindowX::createUI()
{
//创建视频显示区域
m_videoWidget = new QWidget(this);
m_videoWidget->setStyleSheet("background-color: black;");
m_videoLayout = new QVBoxLayout;
m_videoWidget->setLayout(m_videoLayout);
//创建控制按钮
m_openButton = new QPushButton("Open", this);
m_playButton = new QPushButton("Play", this);
m_pauseButton = new QPushButton("Pause", this);
m_stopButton = new QPushButton("Stop", this);
//创建滑块
m_positionSlider = new QSlider(Qt::Horizontal, this);
m_positionSlider->setRange(0, 1000);
m_positionSlider->setEnabled(false);
m_volumeSlider = new QSlider(Qt::Horizontal, this);
m_volumeSlider->setRange(0, 100);
m_volumeSlider->setValue(80);
//布局
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_videoWidget, 1);
mainLayout->addWidget(m_positionSlider);
QHBoxLayout *controlLayout = new QHBoxLayout;
controlLayout->addWidget(m_openButton);
controlLayout->addWidget(m_playButton);
controlLayout->addWidget(m_pauseButton);
controlLayout->addWidget(m_stopButton);
controlLayout->addWidget(new QLabel("Volume:", this));
controlLayout->addWidget(m_volumeSlider);
mainLayout->addLayout(controlLayout);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
//连接信号槽
connect(m_openButton, &QPushButton::clicked, this, &MainWindowX::openFile);
connect(m_playButton, &QPushButton::clicked, this, &MainWindowX::play);
connect(m_pauseButton, &QPushButton::clicked, this, &MainWindowX::pause);
connect(m_stopButton, &QPushButton::clicked, this, &MainWindowX::stop);
connect(m_volumeSlider, &QSlider::valueChanged, this, &MainWindowX::setVolume);
connect(m_positionSlider, &QSlider::sliderMoved, this, &MainWindowX::seek);
//创建位置更新定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]()
{
if (m_mediaPlayer && libvlc_media_player_is_playing(m_mediaPlayer))
{
float pos = libvlc_media_player_get_position(m_mediaPlayer);
updatePosition(pos);
}
});
timer->start(200); //每200ms更新一次位置
}
void MainWindowX::openFile()
{
QString filePath = QFileDialog::getOpenFileName(this, "Open Media File",
QDir::homePath(),
"Media Files (*.mp4 *.avi *.mkv *.mov *.mp3 *.wav)");
if (filePath.isNull() || filePath.isEmpty())
{
return;
}
//停止当前播放
stop();
//创建媒体
if (m_media)
{
libvlc_media_release(m_media);
}
m_media = libvlc_media_new_path(m_vlcInstance, QDir::toNativeSeparators(filePath).toStdString().c_str());
if (!m_media)
{
QMessageBox::critical(this, "Error", "Failed to create media");
return;
}
//创建媒体播放器
if (m_mediaPlayer)
{
libvlc_media_player_release(m_mediaPlayer);
}
m_mediaPlayer = libvlc_media_player_new_from_media(m_media);
if (!m_mediaPlayer)
{
QMessageBox::critical(this, "Error", "Failed to create media player");
libvlc_media_release(m_media);
m_media = nullptr;
return;
}
libvlc_media_release(m_media); // 立即释放媒体引用
m_media = nullptr;
if (!m_videoLabel)
{
m_videoLabel = new QLabel;
m_videoLabel->setStyleSheet("background-color: black;");
m_videoLayout->addWidget(m_videoLabel);
}
//设置视频输出窗口
#if defined(Q_OS_WIN)
libvlc_media_player_set_hwnd(m_mediaPlayer, (void*)m_videoLabel->winId());
#elif defined(Q_OS_MAC)
libvlc_media_player_set_nsobject(m_mediaPlayer, (void*)m_videoLabel->winId());
#elif defined(Q_OS_LINUX)
libvlc_media_player_set_xwindow(m_mediaPlayer, m_videoLabel->winId());
#endif
//设置初始音量
libvlc_audio_set_volume(m_mediaPlayer, m_volumeSlider->value());
//启用位置滑块
m_positionSlider->setEnabled(true);
//自动播放
play();
}
void MainWindowX::play()
{
if (m_mediaPlayer)
{
libvlc_media_player_play(m_mediaPlayer);
}
}
void MainWindowX::pause()
{
if (m_mediaPlayer && libvlc_media_player_can_pause(m_mediaPlayer))
{
libvlc_media_player_set_pause(m_mediaPlayer, 1);
}
}
void MainWindowX::stop()
{
if (m_mediaPlayer)
{
if (m_videoLabel)
{
m_videoLayout->removeWidget(m_videoLabel);
delete m_videoLabel;
m_videoLabel = nullptr;
}
libvlc_media_player_stop(m_mediaPlayer);
libvlc_media_player_release(m_mediaPlayer);
m_mediaPlayer = nullptr;
updatePosition(0.0f);
}
if (m_media)
{
libvlc_media_release(m_media);
m_media = nullptr;
}
}
void MainWindowX::setVolume(int volume)
{
if (m_mediaPlayer)
{
libvlc_audio_set_volume(m_mediaPlayer, volume);
}
}
void MainWindowX::updatePosition(float pos)
{
//防止位置更新时滑块拖动冲突
if (!m_positionSlider->isSliderDown())
{
m_positionSlider->setValue(static_cast<int>(pos * 1000));
}
}
void MainWindowX::seek(int position)
{
if (m_mediaPlayer)
{
float pos = static_cast<float>(position) / 1000.0f;
libvlc_media_player_set_position(m_mediaPlayer, pos);
}
}

浙公网安备 33010602011771号