一、环境介绍
操作系统: win10 64位
QT版本: QT5.12.6
编译器: MinGW 32
二、mdk-sdk 介绍
github 首页地址: https://github.com/wang-bin/mdk-sdk
Features
- Simple and powerful API set
- Cross platform: Windows, UWP, Linux, macOS, Android, iOS, Raspberry Pi
- Hardware accelerated decoding and 0-copy GPU rendering for all platforms
- OpenGL, D3D11, Vulkan and Metal rendering w/ or w/o user provided context
- Integrated with any gui toolkits or apps via OpenGL, D3D11, Vulkan and Metal (OBS, Qt, SDL, glfw, SFML etc.) easily
- Seamless/Gapless media and bitrate switch for any media
- HDR rendering in GPU
- Optimized Continuous seeking. As fast as mpv, but much lower cpu, memory and gpu load. Suitable for timeline preview
- Smart FFmpeg runtime. See https://github.com/wang-bin/mdk-sdk/wiki/FFmpeg-Runtime
mdk-sdk的API使用介绍: https://github.com/wang-bin/mdk-sdk/wiki/Player-APIs
mdk-sdk的使用例子(CSDN): https://download.csdn.net/download/xiaolong1126626497/16273881
mdk-sdk的SDK包(CSDN)--截止当前是最新版本: https://download.csdn.net/download/xiaolong1126626497/16273875
mdk-sdk的使用例子(GitHub):https://github.com/wang-bin/mdk-examples
三、工程源码
3.1 运行效果
这个Demo只是简单的测试播放器,很多功能没去写,简单测试下性能;所以界面没有怎么去弄。
3.2 pro工程文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets opengl
CONFIG += c++17 utf8_source
MDK_SDK = $$PWD/mdk-sdk
INCLUDEPATH += $$MDK_SDK/include
MDK_ARCH = x86
LIBS += -L$$MDK_SDK/lib/$$MDK_ARCH -lmdk
LIBS += -L$$MDK_SDK/bin/$$MDK_ARCH
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
QMDKWidget.cpp \
main.cpp \
widget.cpp
HEADERS += \
QMDKWidget.h \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
3.3 QMDKWidget.cpp
/*
* Copyright (c) 2020 WangBin <wbsecg1 at gmail.com>
* MDK SDK with QOpenGLWidget example
*/
#include "QMDKWidget.h"
#include "mdk/Player.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QKeyEvent>
#include <QOpenGLContext>
#include <QStringList>
#include <QScreen>
using namespace MDK_NS;
QMDKWidget::QMDKWidget(QWidget *parent, Qt::WindowFlags f)
: QOpenGLWidget(parent, f)
, player_(std::make_shared<Player>())
{
player_->setVideoDecoders({"VT", "VAAPI", "MFT:d3d=11", "DXVA", "MMAL", "AMediaCodec:java=1:copy=0:surface=1:async=0", "FFmpeg"});
player_->setRenderCallback([this](void*){
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
});
}
QMDKWidget::~QMDKWidget()
{
makeCurrent();
player_->setVideoSurfaceSize(-1, -1); // cleanup gl renderer resources
}
void QMDKWidget::setDecoders(const QStringList &dec)
{
std::vector<std::string> v;
foreach (QString d, dec) {
v.push_back(d.toStdString());
}
player_->setVideoDecoders(v);
}
void QMDKWidget::setMedia(const QString &url)
{
player_->setMedia(url.toUtf8().constData());
}
void QMDKWidget::play()
{
player_->setState(State::Playing);
}
void QMDKWidget::pause()
{
player_->setState(State::Paused);
}
void QMDKWidget::stop()
{
player_->setState(State::Stopped);
}
bool QMDKWidget::isPaused() const
{
return player_->state() == State::Paused;
}
void QMDKWidget::seek(qint64 ms)
{
player_->seek(ms);
}
qint64 QMDKWidget::position() const
{
return player_->position();
}
void QMDKWidget::snapshot() {
Player::SnapshotRequest sr{};
player_->snapshot(&sr, [](Player::SnapshotRequest *_sr, double frameTime) {
const QString path = QDir::toNativeSeparators(
QString("%1/%2.png")
.arg(QCoreApplication::applicationDirPath())
.arg(frameTime));
return path.toStdString();
// Here's how to convert SnapshotRequest to QImage and save it to disk.
/*if (_sr) {
const QImage img = QImage(_sr->data, _sr->width, _sr->height,
QImage::Format_RGBA8888);
if (img.save(path)) {
qDebug() << "Snapshot saved:" << path;
} else {
qDebug() << "Failed to save:" << path;
}
} else {
qDebug() << "Snapshot failed.";
}
return "";*/
});
}
void QMDKWidget::resizeGL(int w, int h)
{
//auto s = screen();
//qDebug("resizeGL>>>>>dpr: %f, logical dpi: (%f,%f), phy dpi: (%f,%f)", s->devicePixelRatio(), s->logicalDotsPerInchX(), s->logicalDotsPerInchY(), s->physicalDotsPerInchX(), s->physicalDotsPerInchY());
player_->setVideoSurfaceSize(w*devicePixelRatio(), h*devicePixelRatio());
}
void QMDKWidget::paintGL()
{
player_->renderVideo();
}
void QMDKWidget::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_Space: {
if (isPaused())
play();
else
pause();
}
break;
case Qt::Key_Right:
seek(position() + 10000);
break;
case Qt::Key_Left:
seek(position() - 10000);
break;
case Qt::Key_Q:
qApp->quit();
break;
case Qt::Key_C:
//if (QKeySequence(e->modifiers() | e->key()) == QKeySequence::Copy) {
snapshot();
//}
break;
default:
break;
}
}
3.4 QMDKWidget.h
/*
* Copyright (c) 2020 WangBin <wbsecg1 at gmail.com>
* MDK SDK with QOpenGLWindow example
*/
#pragma once
#include <QOpenGLWidget>
#include <memory>
namespace mdk {
class Player;
}
class QMDKWidget : public QOpenGLWidget
{
public:
QMDKWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
~QMDKWidget();
void setDecoders(const QStringList& dec);
void setMedia(const QString& url);
void play();
void pause();
void stop();
bool isPaused() const;
void seek(qint64 ms);
qint64 position() const;
void snapshot();
protected:
void resizeGL(int w, int h) override;
void paintGL() override;
void keyPressEvent(QKeyEvent *) override;
private:
std::shared_ptr<mdk::Player> player_;
};
3.5 widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 加载视频文件
*/
void Widget::on_pushButton_load_clicked()
{
QString filename=QFileDialog::getOpenFileName(this,"选择打开的文件","C:/",tr("*.*"));
ui->AV_player->setMedia(filename);
ui->AV_player->play();
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 暂停/继续
*/
void Widget::on_pushButton_pause_clicked()
{
ui->AV_player->pause();
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 重新播放
*/
void Widget::on_pushButton_reset_clicked()
{
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 播放
*/
void Widget::on_pushButton_play_clicked()
{
ui->AV_player->play();
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 停止播放
*/
void Widget::on_pushButton_stop_clicked()
{
ui->AV_player->stop();
}
3.6 widget.h代码
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QOpenGLWidget>
#include <memory>
#include "QMDKWidget.h"
#include <QFileDialog>
namespace mdk {
class Player;
}
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_load_clicked();
void on_pushButton_pause_clicked();
void on_pushButton_reset_clicked();
void on_pushButton_play_clicked();
void on_pushButton_stop_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H