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视频窗口销毁,后面如果需要再重建。

  1. 在主窗口头文件定义QLabel
private:
    //UI组件
    QVBoxLayout *m_videoLayout; //新添加QVBoxLayout组件
    QLabel *m_videoLabel; //新添加QLabel组件
    QWidget *m_videoWidget;
  1. 修改UI创建代码
void MainWindowX::createUI()
{
    //创建视频显示区域
    m_videoWidget = new QWidget(this);
    m_videoWidget->setStyleSheet("background-color: black;");

    m_videoLayout = new QVBoxLayout; //创建视频控件布局
    m_videoWidget->setLayout(m_videoLayout); //应用视频控件布局

    //其他代码
}
  1. 视频播放时创建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);
    }

    //设置视频输出窗口
}
  1. 停止播放时销毁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);
    }
}
posted @ 2025-07-04 09:46  xhubobo  阅读(275)  评论(0)    收藏  举报