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

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

一、环境介绍

操作系统: 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://xiaolong.blog.csdn.net/article/details/117557963


3.1 运行效果

image.png

image.png

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

1./*
 * 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

/*
 * 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

#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代码

#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文件

image.png

image.png

   image.png

image.png

目录
相关文章
|
3月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
|
3月前
|
4月前
|
数据采集 开发工具 Python
海康威视工业相机SDK+Python+PyQt开发数据采集系统(支持软件触发、编码器触发)
该系统基于海康威视工业相机SDK,使用Python与PyQt开发,支持Gige与USB相机设备的搜索及双相机同时显示。系统提供软件触发与编码器触发模式,并可在数据采集过程中实时保存图像。此外,用户可以调节曝光时间和增益,并进行信息输入,这些信息将被保存至配置文件以便下次自动加载。参数调节与实时预览等功能进一步增强了系统的实用性。
320 1
|
4月前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
211 2
|
4月前
|
网络协议 容器
Qt开发网络嗅探器03
Qt开发网络嗅探器03
|
4月前
|
存储 监控 开发工具
Django 后端架构开发:手机与邮箱验证码接入、腾讯云短信SDK和网易邮箱
Django 后端架构开发:手机与邮箱验证码接入、腾讯云短信SDK和网易邮箱
79 0
|
4月前
|
API 开发工具 C语言
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
248 0
|
4月前
|
JavaScript 前端开发 Java
[Android][Framework]系统jar包,sdk的制作及引用
[Android][Framework]系统jar包,sdk的制作及引用
122 0
|
1月前
|
Java Linux API
Android SDK
【10月更文挑战第21天】
86 1
|
2月前
|
程序员 开发工具 Android开发
Android|使用阿里云推流 SDK 实现双路推流不同画面
本文记录了一种使用没有原生支持多路推流的阿里云推流 Android SDK,实现同时推送两路不同画面的流的方法。
68 7