前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >QT应用编程: 基于mdk-sdk开发视频播放器

QT应用编程: 基于mdk-sdk开发视频播放器

作者头像
DS小龙哥
发布2022-01-07 14:37:07
2.2K0
发布2022-01-07 14:37:07
举报
文章被收录于专栏:嵌入式项目开发

一、环境介绍

操作系统: 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

三、工程源码

工程源码地址: https://download.csdn.net/download/xiaolong1126626497/16548885

下面播放器例子比较简单,但是完成了播放器基本功能,支持的功能如下:

  1. 音量设置
  2. 静音切换
  3. 拍照(保存在程序运行目录下 png图片)
  4. 跳转 (鼠标可以点击播放进度条进行跳转导致指定位置)
  5. 播放进度时间
  6. 暂停、加载、播放、重新播放
  7. 播放的速率设置

完整的播放器实现看这里:https://cloud.tencent.com/developer/article/1932745

3.1 运行效果

3.2 pro工程文件

代码语言:javascript
复制
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

代码语言:javascript
复制
/*
 * 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();
}

3.4 QMDKWidget.h

代码语言:javascript
复制
/*
 * 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_;
};

3.5 widget.cpp

代码语言:javascript
复制
#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());
}

3.6 widget.h代码

代码语言:javascript
复制
#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

3.7 ui文件

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/03/31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、环境介绍
  • 二、mdk-sdk 介绍
    • Features
    • 三、工程源码
      • 3.1 运行效果
        • 3.2 pro工程文件
          • 3.3 QMDKWidget.cpp
            • 3.4 QMDKWidget.h
              • 3.5 widget.cpp
                • 3.6 widget.h代码
                  • 3.7 ui文件
                  相关产品与服务
                  GPU 云服务器
                  GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于生成式AI,自动驾驶,深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档