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

目录
相关文章
|
2月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
490 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
9月前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
593 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
6月前
|
人工智能 自然语言处理 开发工具
HarmonyOS NEXT~鸿蒙开发能力:HarmonyOS SDK AI 全解析
本文深入解析HarmonyOS SDK中的AI功能集,涵盖分布式AI引擎、核心组件(NLP、计算机视觉等)及智能决策能力。通过代码示例与开发实践指南,帮助开发者掌握环境配置、性能调优及多场景应用(智能家居、移动办公等)。同时探讨性能优化策略与未来演进方向,助力构建高效分布式智能应用。
702 9
|
8月前
|
存储 开发工具 开发者
揭秘 Microsoft.Docker.SDK:让容器开发更轻松的强大工具揭秘
随着云计算和容器技术的快速发展,`Docker` 已经成为容器化技术的事实标准。`Microsoft` 作为 `Docker` 的主要支持者和参与者,推出了 `Microsoft.Docker.SDK`,旨在帮助开发者更轻松地进行容器开发。本文将深入揭秘 Microsoft.Docker.SDK 的功能、使用方法以及它在容器开发中的应用。
237 14
|
9月前
|
前端开发 JavaScript 开发工具
【04】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-正确安装鸿蒙SDK-结构目录介绍-路由介绍-帧动画(ohos.animator)书写介绍-能够正常使用依赖库等-ArkUI基础组件介绍-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
【04】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-正确安装鸿蒙SDK-结构目录介绍-路由介绍-帧动画(ohos.animator)书写介绍-能够正常使用依赖库等-ArkUI基础组件介绍-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
587 5
【04】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-正确安装鸿蒙SDK-结构目录介绍-路由介绍-帧动画(ohos.animator)书写介绍-能够正常使用依赖库等-ArkUI基础组件介绍-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
|
9月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
629 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
10月前
|
API 开发工具 Android开发
【01】完整开发即构美颜sdk的uni官方uts插件—让所有开发者可以直接使用即构美颜sdk的能力-优雅草卓伊凡
【01】完整开发即构美颜sdk的uni官方uts插件—让所有开发者可以直接使用即构美颜sdk的能力-优雅草卓伊凡
385 23
【01】完整开发即构美颜sdk的uni官方uts插件—让所有开发者可以直接使用即构美颜sdk的能力-优雅草卓伊凡
|
9月前
|
JavaScript 编译器 开发工具
【02】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-准备工具安装-编译器DevEco Studio安装-arkts编程语言认识-编译器devco-鸿蒙SDK安装-模拟器环境调试-hyper虚拟化开启-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
【02】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-准备工具安装-编译器DevEco Studio安装-arkts编程语言认识-编译器devco-鸿蒙SDK安装-模拟器环境调试-hyper虚拟化开启-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
502 2
【02】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-项目开发实战-准备工具安装-编译器DevEco Studio安装-arkts编程语言认识-编译器devco-鸿蒙SDK安装-模拟器环境调试-hyper虚拟化开启-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
|
数据采集 开发工具 Python
海康威视工业相机SDK+Python+PyQt开发数据采集系统(支持软件触发、编码器触发)
该系统基于海康威视工业相机SDK,使用Python与PyQt开发,支持Gige与USB相机设备的搜索及双相机同时显示。系统提供软件触发与编码器触发模式,并可在数据采集过程中实时保存图像。此外,用户可以调节曝光时间和增益,并进行信息输入,这些信息将被保存至配置文件以便下次自动加载。参数调节与实时预览等功能进一步增强了系统的实用性。
1416 1