zoukankan      html  css  js  c++  java
  • 简单的多屏播放器示例(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;
            }
        }
    }
  • 相关阅读:
    HTML CSS 特殊字符表
    vscode代码统计——Vscode counter
    js数组方法整理
    CSS-界面滚动时不显示滚动条
    Vue Loader 作用域CSS(scoped)——/deep/ 深入组件选择器
    PHP模板引擎,Smarty定义
    mysql触发器trigger 实例详解
    mysql关于数据库表的水平拆分和垂直拆分
    关于数据库表的水平拆分和垂直拆分
    使用Merge存储引擎实现MySQL分表
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/9816962.html
Copyright © 2011-2022 走看看