QTAV踩过的坑和MDK-SDK的一些小东西

最近需要在qt界面内放一个widget用以播放视频,被推荐了qtav,踩了很多坑

  • qtav
  1. 首先说明,我是需要内网编译,内网开发,然后打包程序,所以直接注入到qt根目录的方式我是不考虑的,以下问题大多建立在这个基础之上
  2. 网上给的编译教程基本翻烂了,感觉都是一样的,这边推荐是可以试一下官网给的现成的lib库,mscv2015的,如果可用那么恭喜你,逃过一劫,地址我放到下面了
    QtAV1.12.0-VS2015x86.7z/download
    如果你很不幸和我一样需要自己动手编译,windows平台上我可以提供给诸位的教训如下:
    1. 下请务必确定自己可以使用mscv去按照教程编译而不是mingw,mingw编译出的.a非常难用,我甚至一度想过把他强转成lib
    2. 你可能会遇到mingw编译通过(可能会提示缺一个Q什么的,自己去补个头文件就好)但是mscv提示lnk2019这种无法理解的问题,请你全局搜索qlistlink,这个库因为时间的问题在一个地方使用了几次这个类型的变量,而如果你的qt版本稍稍新一些,他会导致你出现lnk2019的问题,自己去全部替换成qlist就行,不会影响你的正常使用的
    3. 这里不是编译的bug而是qtav的bug,我不知道为什么网上讨论的这么少,但是我这边播放视频有近乎一半的概率会出现前几秒视频在黑屏,然后这几秒的视频就丢失了,这个问题如果也困扰到了你,我这边的建议是放弃这个问题,我在github的issue中找到了有同样困惑的大家,但是这个库已经不维护了,如果你看到了github里面的rendme,你就会发现这个新的库,mkd-sdk,他几乎完美的避免了qtav的上述问题
  • MDK-SDK
    作者直接提供了lib文件和dll文件,以及在github中的使用例子
    https://github.com/wang-bin/mdk-examples/blob/master/Qt/README.md
    不过要注意,现在使用它去在qt中播放视频必须需要qopenglwidget的支持,请确保你的项目可以这么做
  • mdk-sdk的一点小代码
    因为我需要绑定一个qslider,我在搞进去example中的QMDKWidget之后无法很好的实现这个功能,结合理解取了下巧分享给大家
    我这边是对QMDKWidget类加了一个信号,使得视频在渲染新的一帧的时候触发,这样我就能得到现在播放到了什么位置,请注意 void positionChange(int p);,除和他相关之外所有代码和作者的例子中的内容相同
  • QMDKWidget.h
/** Copyright (c) 2020-2021 WangBin <wbsecg1 at gmail.com>* MDK SDK with QOpenGLWindow example*/
#pragma once
#include <QOpenGLWidget>
#include <memory>namespace mdk {
class Player;
}
class QMDKWidget : public QOpenGLWidget
{Q_OBJECT
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, bool accurate = false);qint64 position() const;void snapshot();qint64 duration() const;void prepreForPreview(); // load the media, and set parameters
signals:void mouseMoved(int x, int y);void doubleClicked();void positionChange(int p);
protected:void initializeGL() override;void resizeGL(int w, int h) override;void paintGL() override;void keyPressEvent(QKeyEvent *) override;void mouseMoveEvent(QMouseEvent* ev) override;void mouseDoubleClickEvent(QMouseEvent*) override;
private:std::shared_ptr<mdk::Player> player_;
};
  • QMDKWidget.cpp
/** Copyright (c) 2020-2023 WangBin <wbsecg1 at gmail.com>* MDK SDK with QOpenGLWidget example*/
#include "QMDKWidget.h"
#include "mdk/Player.h"
#include <QDebug>
#include <QDir>
#include <QKeyEvent>
#include <QOpenGLContext>
#include <QStringList>
#include <QScreen>
#include <QGuiApplication>
#if __has_include(<QX11Info>)
#include <QX11Info>
#endif
#if defined(Q_OS_ANDROID)
# if __has_include(<QAndroidJniEnvironment>)
#   include <QAndroidJniEnvironment>
# endif
# if __has_include(<QtCore/QJniEnvironment>)
#   include <QtCore/QJniEnvironment>
# endif
#endif
#include <mutex>using namespace MDK_NS;static void InitEnv()
{
#ifdef QX11INFO_X11_HSetGlobalOption("X11Display", QX11Info::display());qDebug("X11 display: %p", QX11Info::display());
#elif (QT_FEATURE_xcb + 0 == 1) && (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0))const auto x = qGuiApp->nativeInterface<QNativeInterface::QX11Application>();if (x) {const auto xdisp = x->display();SetGlobalOption("X11Display", xdisp);qDebug("X11 display: %p", xdisp);}
#endif
#ifdef QJNI_ENVIRONMENT_HSetGlobalOption("JavaVM", QJniEnvironment::javaVM());
#endif
#ifdef QANDROIDJNIENVIRONMENT_HSetGlobalOption("JavaVM", QAndroidJniEnvironment::javaVM());
#endif
}QMDKWidget::QMDKWidget(QWidget *parent, Qt::WindowFlags f): QOpenGLWidget(parent, f), player_(std::make_shared<Player>())
{static std::once_flag initFlag;std::call_once(initFlag, InitEnv);player_->setDecoders(MediaType::Video, {
#if (__APPLE__+0)"VT","hap",
#elif (__ANDROID__+0)"AMediaCodec:java=0:copy=0:surface=1:async=0",
#elif (_WIN32+0)"MFT:d3d=11","CUDA","hap", // before any ffmpeg based decoders"D3D11","DXVA",
#elif (__linux__+0)"hap","VAAPI","VDPAU","CUDA",
#endif"FFmpeg"});player_->setRenderCallback([this](void*){QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);emit positionChange(player_.position());});
}QMDKWidget::~QMDKWidget()
{makeCurrent();player_->setVideoSurfaceSize(-1, -1); // cleanup gl renderer resources
}void QMDKWidget::setDecoders(const QStringList &dec)
{std::vector<std::string> v;for (const auto& d : dec) {v.push_back(d.toStdString());}player_->setDecoders(MediaType::Video, v);
}void QMDKWidget::setMedia(const QString &url)
{player_->setMedia(url.toUtf8().constData());
}void QMDKWidget::play()
{player_->set(State::Playing);
}void QMDKWidget::pause()
{player_->set(State::Paused);
}void QMDKWidget::stop()
{player_->set(State::Stopped);
}bool QMDKWidget::isPaused() const
{return player_->state() == State::Paused;
}void QMDKWidget::seek(qint64 ms, bool accurate)
{auto flags = SeekFlag::FromStart;if (!accurate)flags |= SeekFlag::KeyFrame;player_->seek(ms, flags);
}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.jpg").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 std::string();*/});
}qint64 QMDKWidget::duration() const
{return player_->mediaInfo().duration;
}void QMDKWidget::prepreForPreview()
{player_->setActiveTracks(MediaType::Audio, {});player_->setActiveTracks(MediaType::Subtitle, {});player_->setProperty("continue_at_end", "1"); // not required by the latest sdkplayer_->setBufferRange(0);player_->prepare();
}void QMDKWidget::initializeGL()
{GLRenderAPI ra;ra.getProcAddress = +[](const char* name, void* opaque) {Q_UNUSED(opaque); // ((QOpenGLContext*)opaque)->getProcAddress(name));return (void*)QOpenGLContext::currentContext()->getProcAddress(name);};ra.opaque = context();player_->setRenderAPI(&ra/*, this*/);// context() may change(destroy old and create new) via setParent()std::weak_ptr<mdk::Player> wp = player_;connect(context(), &QOpenGLContext::aboutToBeDestroyed, [=]{makeCurrent();auto sp = wp.lock();if (sp) // release and remove old gl resources with the same vo_opaque(nullptr), then new resource will be created in resizeGL/paintGLsp->setVideoSurfaceSize(-1, -1/*, context()*/); // it's better to cleanup gl renderer resources as early as possibleelsePlayer::foreignGLContextDestroyed();doneCurrent();});
}void QMDKWidget::resizeGL(int w, int h)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)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()/*, this*/);
#elseplayer_->setVideoSurfaceSize(w, h/*, this*/);
#endif
}void QMDKWidget::paintGL()
{player_->renderVideo(/*this*/);
}void QMDKWidget::keyPressEvent(QKeyEvent *e)
{switch (e->key()) {case Qt::Key_Space: {if (player_->state() != State::Playing)play();elsepause();}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;case Qt::Key_F: {if (isFullScreen())showNormal();elseshowFullScreen();}break;default:break;}
}void QMDKWidget::mouseMoveEvent(QMouseEvent *ev)
{Q_EMIT mouseMoved(ev->pos().x(), ev->pos().y());ev->accept();
}void QMDKWidget::mouseDoubleClickEvent(QMouseEvent *ev)
{Q_EMIT doubleClicked();ev->accept();
}

好的,现在你有了信号,每次他触发都代表视频播放到了新的位置,之后的事情就交给大家了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/634140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python GUI 新手入门教程:轻松构建图形用户界面

Python 凭借其简单性和多功能性&#xff0c;已经成为最流行的编程语言之一。被广泛应用于从 web 开发到数据科学的各个领域。 在本教程中&#xff0c;我们将探索用于创建图形用户界面&#xff08;GUIs&#xff09;的 Python 内置库&#xff1a; Tkinter&#xff1a;无论你是初…

golang 中使用 statik 将静态资源编译进二进制文件中

现在的很多程序都会提供一个 Dashboard 类似的页面用于查看程序状态并进行一些管理的功能&#xff0c;通常都不会很复杂&#xff0c;但是其中用到的图片和网页的一些静态资源&#xff0c;如果需要用户额外存放在一个目录&#xff0c;也不是很方便&#xff0c;如果能打包进程序发…

Byrdhouse AI实时语音翻译工具,可以在视频通话中翻译100多种语言

你是否曾经在跨国会议或与外国友人聊天时&#xff0c;因为语言不通而感到尴尬或困扰&#xff1f;是不是还在找可以实时翻译的软件或者APP&#xff1f;现在&#xff0c;有了这款语音翻译神器&#xff0c;一切都将变得简单&#xff01; 免费使用链接&#xff1a;https://byrdhous…

常用的JavaScript数组内置方法

目录 1、修改数组 push()&#xff1a;添加 pop()&#xff1a;删除 unshift()&#xff1a;添加 shift()&#xff1a;删除 splice()&#xff1a;修改&#xff0c;删除&#xff0c;添加 2、访问数组 concat()&#xff1a;连接数组 join()&#xff1a;连接 slice()&#xff1a…

【工作记录】基于springboot3+springsecurity实现多种方式登录及鉴权(二)

前言 上篇文章介绍了基于springboot3+springsecurity实现的基于模拟数据的用户多种方式登录及鉴权的流程和代码实现,本文我们继续完善。 主要完善的点 主要通过如下几个点来完成优化和完善: 用户信息获取通过查询mysql数据库实现token生成方式使用jwt用户信息存储及读取使用…

Text:焦点切换文字颜色随之改变

按Tab键切换2段文字的焦点&#xff0c;哪段文字的焦点为true&#xff0c;则字体颜色变为红色。 import QtQuickWindow {width: 640height: 480visible: truetitle: qsTr("2.2 属性")Rectangle {Text {id: thislabeltext: qsTr("hello world")font.pixelSiz…

JAVA ORM Bee的设计模式分析

创建型 工厂模式&#xff08;Factory Pattern&#xff09; 日志工厂 LoggerFactory 静态工厂模式 *&#xff08;Static Factory&#xff09; BeeFactoryHelper 单例模式&#xff08;Singleton Pattern&#xff09; 使用单例模式管理系统的配置信息 HoneyConfig 建…

龙芯3A5000上使用腾讯会议

原文链接&#xff1a;龙芯3A5000上使用腾讯会议 hello&#xff0c;大家好啊&#xff01;今天我要给大家介绍的是在龙芯3A5000处理器上安装使用腾讯会议的经验分享。随着远程工作和在线会议的普及&#xff0c;腾讯会议成为了许多人日常工作不可或缺的工具。而对于使用龙芯3A5000…

极客时间-《罗剑锋的 C++ 实战笔记》文章笔记 + 个人思考

极客时间-《罗剑锋的 C 实战笔记》文章笔记 个人思考 语言特性06 | auto/decltype&#xff1a;为什么要有自动类型推导&#xff1f; 语言特性 06 | auto/decltype&#xff1a;为什么要有自动类型推导&#xff1f; auto 在C 11 引入。 为什么说C是静态强类型语言&#xff1f…

Open3D 点云转深度图像

目录 一、算法原理1、算法过程2、主要函数二、代码实现三、结果展示1、点云2、深度图像四、测试数据Open3D 点云转深度图像由CSDN点云侠原创。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。<

【JavaScript】 失去了eval时怎么办(表达式解析与求值深入解析)

JavaScript 表达式解析与求值深入解析 有的时候我们不得不面临不可使用eval函数或者new function&#xff0c;但是又需要将一个字符串作为代码运行的尴尬场景&#xff0c;比如小程序考虑到其安全性问题&#xff0c;就禁止使用&#xff1b;这种情况下我们就需要一个表达式解析器…

全网最详细!!Python 爬虫快速入门

1. 背景 最近在工作中有需要使用到爬虫的地方&#xff0c;需要根据 Gitlab Python 实现一套定时爬取数据的工具&#xff0c;所以借此机会&#xff0c;针对 Python 爬虫方面的知识进行了学习&#xff0c;也算 Python 爬虫入门了。 需要了解的知识点&#xff1a; Python 基础语…

Spring Cloud核心组件介绍

三大门派 有Spring Cloud的地方就有江湖&#xff0c;我们就来看一看在这个江湖中都有哪些独霸一方的门派! Netflix 是先有SpringCloud还是先有Netflix?这是一个好问题。Netflix是一家大名鼎鼎的互联网传媒公司&#xff0c;但为什么它在开源软件领域有这么大的名声呢?这就…

标题:智能对话新纪元:ChatGPT与文心一言的全面比较

标题&#xff1a;智能对话新纪元&#xff1a;ChatGPT与文心一言的全面比较 引言&#xff1a; 在这个由数据驱动的时代&#xff0c;人工智能语言模型已成为技术创新的前沿。特别是OpenAI的ChatGPT和百度的文心一言&#xff08;ERNIE Bot&#xff09;&#xff0c;它们不仅代表了…

如何在 Element Plus 中使用自定义 icon 组件 (非组件库内置icon)

先说原理就是将 svg 文件以 vue 组件文件的方式使用 需求&#xff1a;我想要在 Element Plus 得评分组件中使用自定义得图标。 el-rate v-model"value1" /> 组件本身是支持自定义图标的&#xff0c;但是教程中只说明了如何使用 element-plus/icons-vue 图标库内置…

常用的gpt-4 prompt words收集2

1. attended an English speaking class about traffic. 学习了关于…的英语口语课 2. I am a newbie at English. 我英语很菜 3. Please respond in Markdown format text. 请返回markdown格式的回答 4. That’s brilliant! / That’s the best idea I’ve heard all da…

vue3移动端调用手机摄像头实现扫描二维码功能

vue3移动端调用手机摄像头实现扫描二维码功能 需求&#xff1a; vue3vant4 实现移动端网页调用手机摄像头实现扫描二维码&#xff0c;并返回二维码附带信息功能 效果图&#xff1a; 实现方法 采用vue3-qr-reader插件实现 项目安装依赖&#xff1a; npm install --save vue3-…

慢查询定位

慢查询 使用工具 mysql自带慢日志 默认没有开启需要手动开启 查看慢日志中的文件 总结

第三讲_ArkTS的初识

ArkTS的初识 1. ArkTS的基本组成2. ArkTS自定义组件 1. ArkTS的基本组成 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。自定义组件&#xff1a;可复用的UI单元&#xff0c;可组合其他组件&#xff0c;图示中Component装饰的struct Hello…

路由综合实验-nat

一.要求 R2为ISP路由器&#xff0c;其上只能配置ip地址&#xff0c;不得再进行其他的任何配置 PC1-PC2可以ping通客户平板和DNS服务器; 客户端可以通过域名访问http1&#xff0c;通过地址访问HTTP2 R1为边界路由器&#xff0c;!其上只有一个公有ip地址 拓扑图&#xff1a; 子…