介绍
- 简单的多屏播放器
- 最多同时播放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; } } }