Skip to content

Commit

Permalink
[功能更新与优化] 统一跨平台播放器控件实现,并新增基于 Qt 的 QPlayer 示例。
Browse files Browse the repository at this point in the history
- 控件实现统一:在 Windows 和 Unix 系统下统一了 `ControlWidget` 和 `TitleWidget` 的行为,提升了视频窗口与控件的交互体验。
- 新增 QPlayer 示例:引入了基于 Qt Multimedia Widgets 的新播放器示例 `QPlayer`,提供了一个简洁的播放解决方案。
- 项目文件更新:更新了 CMakeLists.txt 和 .pro 文件,整合了新的 `qplayer` 示例目录,并优化了库的链接。
  • Loading branch information
RealChuan committed Nov 12, 2024
1 parent e1db61b commit 231ebe2
Show file tree
Hide file tree
Showing 36 changed files with 1,089 additions and 217 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,6 @@ transcodeCtx->audioPts += frame->nb_samples;
qt.dbus.integration: Could not connect "org.freedesktop.IBus" to globalEngineChanged(QString)
```

- 在Windows和Unix下,ControlWidget和TitleWidget的控制方式不同

1. Windows下使用 `mpv_set_property(d_ptr->mpv, "wid", MPV_FORMAT_INT64, &wid);`,使用layout布局,会使得视频窗口在最前面,遮挡ControlWidget和TitleWidget,所以将ControlWidget和TitleWidget悬浮在视频窗口上方,使用 `eventFilter`去处理大部分情况下ControlWidget和TitleWidget的显示,写的非常啰嗦,但是为了能够使用D3D11渲染,更棒的性能,只能这样处理,也是值得的;
2. Unix下使用QOpenGLWidget,使用layout布局更加方便;

- MacOS打包需要[install_name_tool](/mac/change_lib_dependencies.rb),依赖拷贝脚本文件来自[iina](https://github.com/iina/iina/blob/develop/other/change_lib_dependencies.rb);

**当前 `brew`安装的 `mpv`中,`libmpv.dylib`的依赖是 `@loader_path/`,所以对脚本进行了一些修改;**
Expand All @@ -125,6 +120,10 @@ transcodeCtx->audioPts += frame->nb_samples;

依赖会拷贝到 `packet/Qt-Mpv.app/Contents/Frameworks/`

# QPlayer

- 参考 [Media Player Example](https://doc.qt.io/qt-6/qtmultimedia-player-example.html)

## QT-BUG

- 动态切换Video Render,从opengl切换到widget,还是有GPU 0-3D占用,而且使用量是opengl的2倍!!!QT-BUG?
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_subdirectory(ffmpegplayer)
add_subdirectory(ffmpegtranscoder)
add_subdirectory(qplayer)

if(BUILD_MPV)
add_subdirectory(mpvplayer)
Expand Down
12 changes: 12 additions & 0 deletions examples/common/commonstr.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <QCoreApplication>

namespace Common {

struct Tr
{
Q_DECLARE_TR_FUNCTIONS(Common)
};

} // namespace Common
7 changes: 2 additions & 5 deletions examples/common/controlwidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,6 @@ ControlWidget::ControlWidget(QWidget *parent)
: QWidget{parent}
, d_ptr(new ControlWidgetPrivate(this))
{
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::Tool);
setAttribute(Qt::WA_TranslucentBackground); //设置窗口背景透明

d_ptr->setupUI();
buildConnect();
d_ptr->initModelButton();
Expand Down Expand Up @@ -213,7 +210,7 @@ void ControlWidget::setDuration(int value)
setPosition(0);
}

#ifdef MPV_ON
#if defined(MPV_ON)
void ControlWidget::setChapters(const Mpv::Chapters &chapters)
{
QVector<qint64> nodes;
Expand All @@ -222,7 +219,7 @@ void ControlWidget::setChapters(const Mpv::Chapters &chapters)
}
d_ptr->slider->setNodes(nodes);
}
#else
#elif defined(FFMPEG_ON)
void ControlWidget::setChapters(const Ffmpeg::Chapters &chapters)
{
QVector<qint64> nodes;
Expand Down
8 changes: 4 additions & 4 deletions examples/common/controlwidget.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef CONTROLWIDGET_HPP
#define CONTROLWIDGET_HPP

#ifdef MPV_ON
#if defined(MPV_ON)
#include <mpv/mediainfo.hpp>
#else
#elif defined(FFMPEG_ON)
#include <ffmpeg/mediainfo.hpp>
#endif

Expand All @@ -21,9 +21,9 @@ class ControlWidget : public QWidget

void setDuration(int value);
[[nodiscard]] auto duration() const -> int;
#ifdef MPV_ON
#if defined(MPV_ON)
void setChapters(const Mpv::Chapters &chapters);
#else
#elif defined(FFMPEG_ON)
void setChapters(const Ffmpeg::Chapters &chapters);
#endif
[[nodiscard]] auto sliderGlobalPos() const -> QPoint;
Expand Down
2 changes: 0 additions & 2 deletions examples/common/titlewidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ TitleWidget::TitleWidget(QWidget *parent)
: QWidget{parent}
, d_ptr(new TitleWidgetPrivate(this))
{
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::Tool);
setAttribute(Qt::WA_TranslucentBackground);

setupUI();
buildConnect();
Expand Down
3 changes: 2 additions & 1 deletion examples/examples.pro
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ CONFIG += ordered

SUBDIRS += \
ffmpegplayer \
ffmpegtranscoder
ffmpegtranscoder \
qplayer

win32 {
exists("C:/3rd/x64/mpv/include"){
Expand Down
8 changes: 5 additions & 3 deletions examples/ffmpegplayer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(PROJECT_SOURCES
../common/commonstr.hpp
../common/controlwidget.cc
../common/controlwidget.hpp
../common/equalizerdialog.cpp
Expand All @@ -24,16 +25,17 @@ set(PROJECT_SOURCES
mainwindow.h)

qt_add_executable(FfmpegPlayer MANUAL_FINALIZATION ${PROJECT_SOURCES})
target_compile_definitions(FfmpegPlayer PRIVATE "FFMPEG_ON")
target_link_libraries(
FfmpegPlayer
PRIVATE ffmpeg
mediaconfig
thirdparty
dump
utils
Qt6::Widgets
Qt6::Multimedia
Qt6::OpenGLWidgets)
Qt::Widgets
Qt::Multimedia
Qt::OpenGLWidgets)
target_link_libraries(FfmpegPlayer PRIVATE PkgConfig::ffmpeg)
if(CMAKE_HOST_APPLE)
target_link_libraries(
Expand Down
3 changes: 3 additions & 0 deletions examples/ffmpegplayer/ffmpegplayer.pro
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ TEMPLATE = app

TARGET = FfmpegPlayer

DEFINES += FFMPEG_ON

LIBS += \
-l$$replaceLibName(ffmpeg) \
-l$$replaceLibName(mediaconfig) \
Expand All @@ -30,6 +32,7 @@ SOURCES += \
mainwindow.cpp

HEADERS += \
../common/commonstr.hpp \
../common/controlwidget.hpp \
../common/equalizerdialog.h \
../common/openwebmediadialog.hpp \
Expand Down
108 changes: 54 additions & 54 deletions examples/ffmpegplayer/mainwindow.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "mainwindow.h"

#include <examples/common/commonstr.hpp>
#include <examples/common/controlwidget.hpp>
#include <examples/common/equalizerdialog.h>
#include <examples/common/openwebmediadialog.hpp>
Expand All @@ -18,6 +19,7 @@
#include <ffmpeg/videorender/videorendercreate.hpp>
#include <ffmpeg/widgets/mediainfodialog.hpp>

#include <QMediaDevices>
#include <QtWidgets>

class MainWindow::MainWindowPrivate
Expand All @@ -32,27 +34,19 @@ class MainWindow::MainWindowPrivate
titleWidget = new TitleWidget(q_ptr);
titleWidget->setMinimumHeight(80);
titleWidget->setVisible(false);
auto *bottomLayout = new QHBoxLayout;
bottomLayout->addStretch();
bottomLayout->addWidget(controlWidget);
bottomLayout->addStretch();
controlLayout = new QVBoxLayout;
controlLayout->addWidget(titleWidget);
controlLayout->addStretch();
controlLayout->addLayout(bottomLayout);

playlistModel = new PlaylistModel(q_ptr);
playlistView = new PlayListView(q_ptr);
playlistView->setModel(playlistModel);
playlistView->setCurrentIndex(
playlistModel->index(playlistModel->playlist()->currentIndex(), 0));
//playlistView->setMaximumWidth(250);
playListMenu = new QMenu(q_ptr);

menu = new QMenu(q_ptr);

videoMenu = new QMenu(QCoreApplication::translate("MainWindowPrivate", "Video"), q_ptr);
audioMenu = new QMenu(QCoreApplication::translate("MainWindowPrivate", "Audio"), q_ptr);
subMenu = new QMenu(QCoreApplication::translate("MainWindowPrivate", "Subtitles"), q_ptr);
videoMenu = new QMenu(Common::Tr::tr("Video"), q_ptr);
audioMenu = new QMenu(Common::Tr::tr("Audio"), q_ptr);
subMenu = new QMenu(Common::Tr::tr("Subtitles"), q_ptr);

videoTracksGroup = new QActionGroup(q_ptr);
videoTracksGroup->setExclusive(true);
Expand All @@ -61,27 +55,36 @@ class MainWindow::MainWindowPrivate
subTracksGroup = new QActionGroup(q_ptr);
subTracksGroup->setExclusive(true);

mediaInfoAction = new QAction(QCoreApplication::translate("MainWindowPrivate", "Media Info"),
q_ptr);

playListMenu = new QMenu(q_ptr);
mediaInfoAction = new QAction(Common::Tr::tr("Media Info"), q_ptr);

fpsTimer = new QTimer(q_ptr);

splitter = new QSplitter(q_ptr);
splitter->addWidget(playlistView);

initShortcut();
}

~MainWindowPrivate() = default;

void setupUI()
{
auto *bottomLayout = new QHBoxLayout;
bottomLayout->addStretch();
bottomLayout->addWidget(controlWidget);
bottomLayout->addStretch();
controlLayout = new QVBoxLayout;
controlLayout->addWidget(titleWidget);
controlLayout->addStretch();
controlLayout->addLayout(bottomLayout);

splitter = new QSplitter(q_ptr);
splitter->addWidget(playlistView);
q_ptr->setCentralWidget(splitter);
}

auto createToneMappingMenu() -> QMenu *
{
auto *group = new QActionGroup(q_ptr);
group->setExclusive(true);
auto *menu = new QMenu(QCoreApplication::translate("MainWindowPrivate", "Tone-Mapping"),
q_ptr);
auto *menu = new QMenu(Common::Tr::tr("Tone-Mapping"), q_ptr);
auto toneMappings = QMetaEnum::fromType<Ffmpeg::ToneMapping::Type>();
for (int i = 0; i < toneMappings.keyCount(); ++i) {
auto value = toneMappings.value(i);
Expand Down Expand Up @@ -110,8 +113,7 @@ class MainWindow::MainWindowPrivate
{
auto *group = new QActionGroup(q_ptr);
group->setExclusive(true);
auto *menu = new QMenu(QCoreApplication::translate("MainWindowPrivate", "Target Primaries"),
q_ptr);
auto *menu = new QMenu(Common::Tr::tr("Target Primaries"), q_ptr);
auto primaris = QMetaEnum::fromType<Ffmpeg::ColorUtils::Primaries::Type>();
for (int i = 0; i < primaris.keyCount(); ++i) {
auto value = primaris.value(i);
Expand Down Expand Up @@ -242,6 +244,24 @@ class MainWindow::MainWindowPrivate
controlWidget->setPosition(0);
}

void addToPlaylist(const QList<QUrl> &urls)
{
auto *playlist = playlistModel->playlist();
const int previousMediaCount = playlist->mediaCount();
for (const auto &url : urls) {
if (isPlaylist(url)) {
playlist->load(url);
} else {
playlist->addMedia(url);
}
}
if (playlist->mediaCount() > previousMediaCount) {
auto index = playlistModel->index(previousMediaCount, 0);
playlistView->setCurrentIndex(index);
q_ptr->jump(index);
}
}

MainWindow *q_ptr;

QScopedPointer<Ffmpeg::Player> playerPtr;
Expand All @@ -254,6 +274,8 @@ class MainWindow::MainWindowPrivate

PlayListView *playlistView;
PlaylistModel *playlistModel;
QMenu *playListMenu;
QSplitter *splitter;

QMenu *menu;

Expand All @@ -271,12 +293,8 @@ class MainWindow::MainWindowPrivate

QAction *mediaInfoAction;

QMenu *playListMenu;

QTimer *fpsTimer;

QSplitter *splitter;

Ffmpeg::ToneMapping::Type toneMappingType = Ffmpeg::ToneMapping::Type::AUTO;
Ffmpeg::ColorUtils::Primaries::Type primarisType = Ffmpeg::ColorUtils::Primaries::Type::AUTO;
};
Expand All @@ -287,7 +305,12 @@ MainWindow::MainWindow(QWidget *parent)
{
Ffmpeg::printFfmpegInfo();

setupUI();
// QPlatformMediaDevices中有一个static std::unique_ptr<QPlatformMediaDevices> create();
// 这个QPlatformMediaDevices最终会在主线程释放,需要在主线程创建
// 如果在主线程创建,会导致退出程序崩溃,ASSERT: "m_threadId == GetCurrentThreadId()"
QMediaDevices mediaDevices;

d_ptr->setupUI();
buildConnect();
initMenu();
initPlayListMenu();
Expand Down Expand Up @@ -369,7 +392,7 @@ void MainWindow::onOpenLocalMedia()
if (urls.isEmpty()) {
return;
}
addToPlaylist(urls);
d_ptr->addToPlaylist(urls);
}

void MainWindow::onOpenWebMedia()
Expand All @@ -379,7 +402,7 @@ void MainWindow::onOpenWebMedia()
if (dialog.exec() != QDialog::Accepted) {
return;
}
addToPlaylist({QUrl(dialog.url())});
d_ptr->addToPlaylist({QUrl(dialog.url())});
}

void MainWindow::onRenderChanged(QAction *action)
Expand Down Expand Up @@ -552,7 +575,7 @@ auto MainWindow::eventFilter(QObject *watched, QEvent *event) -> bool
auto *ev = dynamic_cast<QDropEvent *>(event);
auto urls = ev->mimeData()->urls();
if (!urls.isEmpty()) {
addToPlaylist(urls);
d_ptr->addToPlaylist(urls);
}
} break;
case QEvent::ContextMenu: {
Expand Down Expand Up @@ -619,11 +642,6 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
}
}

void MainWindow::setupUI()
{
setCentralWidget(d_ptr->splitter);
}

void MainWindow::buildConnect()
{
connect(d_ptr->playerPtr.data(),
Expand Down Expand Up @@ -776,21 +794,3 @@ void MainWindow::initPlayListMenu()
d_ptr->playlistModel->playlist()->clear();
});
}

void MainWindow::addToPlaylist(const QList<QUrl> &urls)
{
auto *playlist = d_ptr->playlistModel->playlist();
const int previousMediaCount = playlist->mediaCount();
for (const auto &url : urls) {
if (isPlaylist(url)) {
playlist->load(url);
} else {
playlist->addMedia(url);
}
}
if (playlist->mediaCount() > previousMediaCount) {
auto index = d_ptr->playlistModel->index(previousMediaCount, 0);
d_ptr->playlistView->setCurrentIndex(index);
jump(index);
}
}
2 changes: 0 additions & 2 deletions examples/ffmpegplayer/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ private slots:
void keyPressEvent(QKeyEvent *event) override;

private:
void setupUI();
void buildConnect();
void initMenu();
void renderMenu();
void initPlayListMenu();
void addToPlaylist(const QList<QUrl> &urls);

class MainWindowPrivate;
QScopedPointer<MainWindowPrivate> d_ptr;
Expand Down
Loading

0 comments on commit 231ebe2

Please sign in to comment.