操作系统: win10 64位
QT版本: QT5.12.6
编译器: MinGW 32
github 首页地址: https://github.com/wang-bin/mdk-sdk
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
工程源码地址: https://download.csdn.net/download/xiaolong1126626497/16548885
下面播放器例子比较简单,但是完成了播放器基本功能,支持的功能如下:
完整的播放器实现看这里:https://cloud.tencent.com/developer/article/1932745
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
/*
* 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>
bool av_MediaStatusChanged(mdk::MediaStatus m)
{
qDebug()<<"av_MediaStatusChanged.";
return true;
}
bool av_MediaEvent(const mdk::MediaEvent&m)
{
qDebug()<<"av_MediaEvent.";
return true;
}
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);
});
//设置回调: 事件
player_->onEvent(av_MediaEvent);
//获取状态
// MediaStatus a=player_->mediaStatus();
//设置回调: 状态改变
player_->onMediaStatusChanged(av_MediaStatusChanged);
}
QMDKWidget::~QMDKWidget()
{
makeCurrent();
player_->setVideoSurfaceSize(-1, -1); // cleanup gl renderer resources
}
//设置音量 值:> = 0。1.0是原始音量
void QMDKWidget::setVolume(float value)
{
player_->setVolume(value);
}
//当前进度 当前播放时间(以毫秒为单位)。相对于媒体的第一个时间戳。即mediaInfo().start_time,通常为0。
int64_t QMDKWidget::position()
{
return player_->position();
}
//总时间
int64_t QMDKWidget::duration()
{
return player_->mediaInfo().duration;
}
//设置静音
void QMDKWidget::setMute(bool value)
{
player_->setMute(value);
}
void QMDKWidget::setPlaybackRate(float value)
{
//设置播放器播放速度 正常速度是1.0
player_->setPlaybackRate(value);
}
//旋转视频 逆时针0、90、180、270
//player_->rotate(int degree, void* vo_opaque = nullptr);
void QMDKWidget::setrotate(int degree) //设置旋转
{
player_->rotate(degree);
}
/*
工程: QMDK_Player
日期: 2021-04-08
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 设置解码器
*/
void QMDKWidget::setDecoders(const QStringList &dec)
{
std::vector<std::string> v;
foreach (QString d, dec) {
v.push_back(d.toStdString());
}
player_->setVideoDecoders(v);
}
/*
工程: QMDK_Player
日期: 2021-04-08
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 设置媒体文件
*/
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);
}
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();
}
/*
* 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);
void snapshot();
void setPlaybackRate(float value); //播放速度
void setrotate(int degree); //设置旋转
void setMute(bool value); //设置静音
void setVolume(float value); //设置音量
int64_t duration(); //视频总时间
int64_t position(); //当前进度
protected:
void resizeGL(int w, int h) override;
void paintGL() override;
private:
std::shared_ptr<mdk::Player> player_;
};
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timeout_update()));
}
Widget::~Widget()
{
delete ui;
}
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
if(obj==ui->horizontalSlider)
{
if (event->type()==QEvent::MouseButtonPress) //判断类型
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton) //判断左键
{
int value = QStyle::sliderValueFromPosition(ui->horizontalSlider->minimum(), ui->horizontalSlider->maximum(), mouseEvent->pos().x(), ui->horizontalSlider->width());
ui->horizontalSlider->setValue(value);
//跳转播放器
ui->AV_player->seek(value);
}
}
}
return QObject::eventFilter(obj,event);
}
//定时器超时
void Widget::timeout_update()
{
int64_t pos=ui->AV_player->position();
ui->horizontalSlider->setValue(pos);
// 设置时间
ui->label_t2->setText(QString("%1").arg(pos));
}
/*
工程: 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();
QThread::msleep(100);
//设置总时间
ui->label_t1->setText(QString("%1").arg(ui->AV_player->duration()));
//设置进度条滑块范围
ui->horizontalSlider->setMinimum(0);
ui->horizontalSlider->setMaximum(ui->AV_player->duration());
//事件监听
ui->horizontalSlider->installEventFilter(this);
//开启定时器
timer->start(100);
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 暂停/继续
*/
void Widget::on_pushButton_pause_clicked()
{
timer->stop();
ui->AV_player->pause();
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 重新播放
*/
void Widget::on_pushButton_reset_clicked()
{
ui->AV_player->seek(0);
ui->AV_player->play();
timer->start(100);
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 播放
*/
void Widget::on_pushButton_play_clicked()
{
ui->AV_player->play();
timer->start(100);
}
/*
工程: QMDK_Player
日期: 2021-03-31
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 停止播放
*/
void Widget::on_pushButton_stop_clicked()
{
ui->AV_player->stop();
}
//静音设置
void Widget::on_pushButton_Volume_clicked()
{
static bool value=false;
value=!value;
ui->AV_player->setMute(value);
}
//音量设置
void Widget::on_horizontalSlider_Volume_valueChanged(int value)
{
ui->AV_player->setVolume(float(value/10.0));
}
//拍照. 保存到本地目录下png
void Widget::on_pushButton_snapshot_clicked()
{
ui->AV_player->snapshot();
}
//设置速度
void Widget::on_comboBox_speed_currentTextChanged(const QString &arg1)
{
qDebug()<<"速度:"<<arg1;
ui->AV_player->setPlaybackRate(arg1.toDouble());
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QOpenGLWidget>
#include <memory>
#include "QMDKWidget.h"
#include <QFileDialog>
#include "QDebug"
#include <QThread>
#include <QMouseEvent>
#include <QStyle>
#include <QTimer>
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 timeout_update();
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();
void on_pushButton_Volume_clicked();
void on_horizontalSlider_Volume_valueChanged(int value);
void on_pushButton_snapshot_clicked();
void on_comboBox_speed_currentTextChanged(const QString &arg1);
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::Widget *ui;
QTimer *timer;
};
#endif // WIDGET_H