简单的多屏播放器示例(vlc+qt)

时间:2024-03-11 12:33:02

简单的多屏播放器示例(vlc+qt)

介绍

  • 简单的多屏播放器
  • 最多同时播放16个视频
  • 支持本地文件和rtsp、rtmp等流媒体播放
  • VS2015工程,依赖Qt+VLC
  • 练手作品

截图

测试截图


下载

程序:download.csdn.net/detail/u014755412/9908787

源码:github.com/FutaAlice/QtPlayer


代码分析

IMediaPlayer是为规定接口的基类
提供了播放和控制的几个常用函数
其中打开媒体部分拆分为了OpenURL和OpenFile,并在cpp中实现
若为Windows环境,则对QFileDialog获取的路径进行替换

/*******************************************************************
IMediaPlayer.h(接口类)
构造时传入QWidget*
调用OpenFile或OpenURL或Open打开文件并渲染窗体
*******************************************************************/

#ifndef IMEDIAPLAYER_H
#define IMEDIAPLAYER_H

class QWidget;
class IMediaPlayer
{
public:
    IMediaPlayer(QWidget* pWidget);
    virtual ~IMediaPlayer();

    virtual bool OpenFile();
    virtual bool OpenURL(const char* url);

    virtual bool Open(const char* url) = 0;
    virtual bool Play() = 0;
    virtual void Pause() = 0;
    virtual void Stop() = 0;
    virtual void ChangeVolume(int vol) = 0;

protected:
    QWidget* m_pWidget;
};

#endif // IMEDIAPLAYER_H
/*******************************************************************
IMediaPlayer.cpp(接口类)
*******************************************************************/
#include "IMediaPlayer.h"
#include <QtWidgets/QWidget>
#include <QtWidgets/qfiledialog.h>

// Windows环境下进行字符替换
static void StrReplace(QString& str)
{
#if defined(Q_OS_MAC)       // Mac
#elif defined(Q_OS_UNIX)    // Linux
#elif defined(Q_OS_WIN)     // Windows
    str = str.replace(QRegExp("/"), "\\");
#endif
}

IMediaPlayer::IMediaPlayer(QWidget* pWidget)
    : m_pWidget(pWidget)
{
}

IMediaPlayer::~IMediaPlayer()
{
}

bool IMediaPlayer::OpenFile()
{
    QString fileOpen = QFileDialog::getOpenFileName(NULL, "Load a file", "~");
    if (!fileOpen.isEmpty())
    {
        StrReplace(fileOpen);
        return Open(fileOpen.toUtf8().constData());
    }
    else
        return false;
}

bool IMediaPlayer::OpenURL(const char * url)
{
    return Open(url);
}

之后新建一个派生自IMediaPlayer的类:VlcMediaPlayer,
并使用libvlc实现其基类中的纯虚函数实现视频的播放

/*******************************************************************
VlcMediaPlayer.h
使用libvlc实现的IMediaPlayer
构造时传入QWidget*
调用OpenFile或OpenURL或Open打开文件并渲染窗体
例如:
    QWidget* pWidget = new QOpenGLWidget();
    pWidget->show();
    auto player = new VlcMediaPlayer(pWidget);
    player->Open("test.hevc");
*******************************************************************/

#ifndef VLCMEDIAPLAYER_H
#define VLCMEDIAPLAYER_H

#include "IMediaPlayer.h"

struct libvlc_media_player_t;
struct libvlc_instance_t;
class VlcMediaPlayer :
    public IMediaPlayer
{
public:
    VlcMediaPlayer(QWidget* pWidget);
    ~VlcMediaPlayer();

    // 禁用拷贝构造和赋值
    VlcMediaPlayer(const VlcMediaPlayer&) = delete;
    VlcMediaPlayer& operator=(VlcMediaPlayer&) = delete;

    // Control
    virtual bool Open(const char* url);
    virtual bool Play();
    virtual void Pause();
    virtual void Stop();
    virtual void ChangeVolume(int vol) ;

private:
    // 播放器对象
    libvlc_media_player_t *m_pVlcPlayer;

private:
    // libvlc实例,所有窗体的渲染共用一个
    static libvlc_instance_t *s_pVlcInstance;
    static unsigned int s_ref;
};

#endif // VLCMEDIAPLAYER_H
/*******************************************************************
VlcMediaPlayer.cpp
libvlc播放视频的实现
*******************************************************************/
#include "VlcMediaPlayer.h"
#include <assert.h>
#include <QtWidgets/QWidget>

# ifdef __cplusplus
extern "C" {
# endif
#include <vlc/vlc.h>
# ifdef __cplusplus
}
# endif

#if defined(Q_OS_MAC)       // Mac
// TODO
#elif defined(Q_OS_UNIX)    // Linux
#pragma comment(lib, "libvlc.a")
#elif defined(Q_OS_WIN)     // Windows
#pragma comment(lib, "libvlc.lib")
#endif

unsigned int VlcMediaPlayer::s_ref = 0;
libvlc_instance_t *VlcMediaPlayer::s_pVlcInstance = NULL;

VlcMediaPlayer::VlcMediaPlayer(QWidget* pWidget)
    : IMediaPlayer(pWidget)
    , m_pVlcPlayer(NULL)
{
    /* Initialize libVLC */
    if (0 == s_ref++)
    {
        s_pVlcInstance = libvlc_new(0, NULL);
        if (NULL == s_pVlcInstance)
        {
            assert(false);
        }
    }
}


VlcMediaPlayer::~VlcMediaPlayer()
{
    if (0 == --s_ref)
    {
        libvlc_release(s_pVlcInstance);
    }
}

bool VlcMediaPlayer::Open(const char *url)
{
    /* Stop if something is playing */
    Stop();

    auto funcOpen = libvlc_media_new_path;
    if (QString(url).startsWith("rtsp://") ||
        QString(url).startsWith("rtmp://") ||
        QString(url).startsWith("rtp://") ||
        QString(url).startsWith("tcp://") ||
        QString(url).startsWith("udp://") ||
        QString(url).startsWith("ftp://") ||
        QString(url).startsWith("http://") ||
        QString(url).startsWith("https://"))
    {
        funcOpen = libvlc_media_new_location;
    }

    /* Create a new Media */
    libvlc_media_t *vlcMedia = funcOpen(s_pVlcInstance, url);
    /* Fail to open url*/
    if (!vlcMedia)
    {
        return false;
    }

    if (QString(url).endsWith(".hevc"))
        libvlc_media_add_option(vlcMedia, ":demux=hevc");
    else if (QString(url).endsWith("rtsp"))
        libvlc_media_add_option(vlcMedia, ":rtsp-tcp");
    
    /* Create a new libvlc player */
    m_pVlcPlayer = libvlc_media_player_new_from_media(vlcMedia);

    /* Release the media */
    libvlc_media_release(vlcMedia);

    return Play();
}

bool VlcMediaPlayer::Play()
{
    /* Integrate the video in the interface */
#if defined(Q_OS_MAC)
    libvlc_media_player_set_nsobject(m_pVlcPlayer, (void*)m_pWidget->winId());
#elif defined(Q_OS_UNIX)
    libvlc_media_player_set_xwindow(m_pVlcPlayer, m_pWidget->winId());
#elif defined(Q_OS_WIN)
    libvlc_media_player_set_hwnd(m_pVlcPlayer, (void*)m_pWidget->winId());
#endif

    /* And start playback */
    int vlc_ret = libvlc_media_player_play(m_pVlcPlayer);
    if (0 == vlc_ret)
        return true;
    else
        return false;
}

void VlcMediaPlayer::Pause()
{
    if (m_pVlcPlayer && libvlc_media_player_is_playing(m_pVlcPlayer))
    {
        libvlc_media_player_pause(m_pVlcPlayer);
    }
}

void VlcMediaPlayer::Stop()
{
    if (m_pVlcPlayer)
    {
        /* stop the media player */
        libvlc_media_player_stop(m_pVlcPlayer);

        /* release the media player */
        libvlc_media_player_release(m_pVlcPlayer);

        /* Reset application values */
        m_pVlcPlayer = NULL;
    }
}

void VlcMediaPlayer::ChangeVolume(int vol)
{
    if (m_pVlcPlayer)
    {
        libvlc_audio_set_volume(m_pVlcPlayer, vol);
    }
}

界面部分,
响应界面按钮点击的消息和调整窗体大小的消息,
并且调用VlcMediaPlayer添加播放视频的小窗口

/*******************************************************************
QtPlayer.h
*******************************************************************/
#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtPlayer.h"

struct libvlc_media_player_t;
class QtPlayer : public QWidget
{
    Q_OBJECT
public:
    QtPlayer(QWidget *parent = Q_NULLPTR);
    void resizeEvent(QResizeEvent* e);

private slots:
    void openFile();
    void openURL();

private:
    Ui::QtPlayerClass ui;
    QWidget* m_pSubWidgets[16];
};
/*******************************************************************
QtPlayer.cpp
*******************************************************************/
#include "QtPlayer.h"
#include "VlcMediaPlayer.h"


QtPlayer::QtPlayer(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    memset(m_pSubWidgets, NULL, sizeof(m_pSubWidgets));
}

void QtPlayer::openFile()
{
    int w = width() / 4, h = (height() - 24) / 4;
    for (int i = 0; i < 16; ++i)
    {
        if (m_pSubWidgets[i] == NULL)
        {
            m_pSubWidgets[i] = new QWidget(this);
            auto player = new VlcMediaPlayer(m_pSubWidgets[i]);

            // 打开成功
            if (player->OpenFile())
            {
                resizeEvent(NULL);
                m_pSubWidgets[i]->show();
            }
            else
            {
                delete player;
                delete m_pSubWidgets[i];
                m_pSubWidgets[i] = NULL;
            }
            break;
        }
    }
}

void QtPlayer::resizeEvent(QResizeEvent *e)
{
    int w = width() / 4, h = (height() - 24) / 4;
    for (int i = 0; i < 16; ++i)
    {
        if (NULL == m_pSubWidgets[i])
            continue;
        m_pSubWidgets[i]->resize(QSize(w, h));
        m_pSubWidgets[i]->move(QPoint((i % 4) * w, (i / 4) * h));
    }
    QPoint pos = ui.btnOpenFile->pos();
    pos.setY(height() - 24);
    ui.btnOpenFile->move(pos);

    pos = ui.btnOpenURL->pos();
    pos.setY(height() - 24);
    ui.btnOpenURL->move(pos);

    pos = ui.lineEdit->pos();
    pos.setY(height() - 24);
    ui.lineEdit->move(pos);
}

void QtPlayer::openURL()
{
    int w = width() / 4, h = height() / 4;
    for (int i = 0; i < 16; ++i)
    {
        if (m_pSubWidgets[i] == NULL)
        {
            m_pSubWidgets[i] = new QWidget(this);
            auto player = new VlcMediaPlayer(m_pSubWidgets[i]);
            // 打开成功
            if (player->OpenURL(ui.lineEdit->text().toUtf8().constData()))
            {
                resizeEvent(NULL);
                m_pSubWidgets[i]->show();
            }
            else
            {
                delete player;
                delete m_pSubWidgets[i];
                m_pSubWidgets[i] = NULL;
            }
            break;
        }
    }
}