mpv是啥?

mpv之前是mediaplayer,windwos之前好像都有预装这个,都来经过发展,现在是一个对跨平台开发很友好的播放器工具。

Qt是啥?

制作桌面应用程序的开发语言及工具,基于C++,跨平台。

基础开发步骤

1.动态壁纸需要一个播放视频的软件,那么可以借鉴mpv的官方demo
https://github.com/mpv-player/mpv-examples/tree/master/libmpv
可以使用里面的qt文件夹里面的demo或者qt_opengl里面的demo
(我是使用的opengl那个demo)
demo编译就会发现,可以播放视频了,那么就以这个demo作为我们的播放模块的代码

2.动态壁纸需要放到图标层以下(windows)
程序需要msvc编译,不能用mingw编译,怀疑是mingw用不了部分win32的部分api

需要在qt pro文件中增加api所需要的库文件

LIBS+=-luser32    //所需要的win32 api库
win32: LIBS += $$PWD/3rd/libmpv.dll.a    //mpv的库文件INCLUDEPATH += $$PWD/3rd/mpv //mpv头文件地址增加

3.关键代码:设置窗口放到图标下面(windows)

#ifdef Q_OS_WINDOWS
#include <windows.h>WId viewId;
HHOOK hook;
HWND workerW;LRESULT CALLBACK HookShoot(_In_ int nCode, _In_ WPARAM wParam,LPARAM lParam){if(wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE){MOUSEHOOKSTRUCT * mshook = (MOUSEHOOKSTRUCT *)lParam;PostMessage((HWND)viewId,WM_MOUSEMOVE,0,MAKELPARAM(mshook->pt.x,mshook->pt.y));};return CallNextHookEx(NULL, nCode, wParam, lParam);
}HWND _WORKERW = nullptr;inline BOOL CALLBACK EnumWindowsProc(_In_ HWND tophandle, _In_ LPARAM topparamhandle)
{HWND defview = FindWindowEx(tophandle, 0, L"SHELLDLL_DefView", nullptr);if (defview != nullptr){_WORKERW = FindWindowEx(0, tophandle, L"WorkerW", 0);}return true;
}HWND GetWorkerDesktop(){int result;HWND windowHandle = FindWindow(L"Progman", nullptr);//使用 0x3e8 命令分割出两个 WorkerWSendMessageTimeout(windowHandle, 0x052c, 0 ,0, SMTO_NORMAL, 0x3e8,(PDWORD_PTR)&result);//遍历窗体获得窗口句柄EnumWindows(EnumWindowsProc,(LPARAM)nullptr);// 显示WorkerWShowWindow(_WORKERW,SW_HIDE);return windowHandle;
}void Wallpaper::registerDesktop()
{//windwos设置workerW =  GetWorkerDesktop();if(this){viewId = this->winId();// 返回workerW窗口句柄//设置窗口样式GetWindowLongA((HWND)viewId, GWL_STYLE);//设置壁纸窗体的父窗体SetParent((HWND)viewId,workerW);SetWindowPos((HWND)viewId,HWND_TOP,0,0,0,0,WS_EX_LEFT|WS_EX_LTRREADING|WS_EX_RIGHTSCROLLBAR|WS_EX_NOACTIVATE);// 设置全局鼠标事件钩子(会很卡)
//        hook = SetWindowsHookEx(WH_MOUSE_LL,HookShoot,GetModuleHandle(NULL),0);QDesktopWidget *desktop = QApplication::desktop();this->move(QPoint(0,0));int height = desktop->height();int width = desktop->width();this->resize(QSize(width,height));this->showFullScreen();}

4关键代码 linux,设置桌面属性

#include <QtX11Extras/QX11Info>
#include <xcb/xcb.h>
#include <xcb/xcb_ewmh.h>
#include <QtPlatformHeaders/QXcbWindowFunctions>
void Wallpaper::registerDesktop()
{this->winId();QWindow *window = this->windowHandle();window->setOpacity(0.99);if (QApplication::platformName() == "wayland") {qDebug() << "wayland set desktop"; //wayland环境下没有做} else {//x11环境下直接设置这个即可QXcbWindowFunctions::setWmWindowType(window, QXcbWindowFunctions::Desktop);}//随意激活下窗口,可能不需要QTimer::singleShot(1, this, [=] {show();lower();});
}

5 mpv播放器使用关键代码 (可以换用其他播放器)

头文件:

#ifndef PLAYERWINDOW_H
#define PLAYERWINDOW_H#include <QtWidgets/QOpenGLWidget>
#include "mpv/client.h"
#include "mpv/render_gl.h"
#include "mpv/qthelper.hpp"
#include <QSize>class MpvWidget Q_DECL_FINAL: public QOpenGLWidget
{Q_OBJECT
public:MpvWidget(QWidget *parent = 0, Qt::WindowFlags f = nullptr);~MpvWidget();void command(const QVariant &params);void setProperty(const QString &name, const QVariant &value);QVariant getProperty(const QString &name) const;QSize sizeHint() const Q_DECL_OVERRIDE { return QSize(480, 270);}Q_SIGNALS:void durationChanged(int value);void positionChanged(int value);
protected:void initializeGL() Q_DECL_OVERRIDE;void paintGL() Q_DECL_OVERRIDE;
private Q_SLOTS:void on_mpv_events();void maybeUpdate();
private:void handle_mpv_event(mpv_event *event);static void on_update(void *ctx);mpv_handle *mpv;mpv_render_context *mpv_gl;bool m_bScrrenShot{false};};#endif // PLAYERWINDOW_H

cpp:

#include "mpvwidget.h"
#include <stdexcept>
#include <QtGui/QOpenGLContext>
#include <QtCore/QMetaObject>
#include "application.h"#include <QDateTime>
#include <QStandardPaths>static void wakeup(void *ctx)
{QMetaObject::invokeMethod((MpvWidget *)ctx, "on_mpv_events", Qt::QueuedConnection);
}static void *get_proc_address(void *ctx, const char *name)
{Q_UNUSED(ctx);QOpenGLContext *glctx = QOpenGLContext::currentContext();if (!glctx)return nullptr;return reinterpret_cast<void *>(glctx->getProcAddress(QByteArray(name)));
}MpvWidget::MpvWidget(QWidget *parent, Qt::WindowFlags f): QOpenGLWidget(parent, f)
{setAttribute(Qt::WA_TranslucentBackground);mpv = mpv_create();if (!mpv)throw std::runtime_error("could not create mpv context");//    mpv_set_option_string(mpv, "terminal", "yes");mpv_set_option_string(mpv, "msg-level", "all=v");if (mpv_initialize(mpv) < 0)throw std::runtime_error("could not initialize mpv context");// Request hw decoding, just for testing.
//    mpv::qt::set_option_variant(mpv, "hwdec", "auto");mpv::qt::set_option_variant(mpv, "hwdec", "gpu");mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);mpv_set_wakeup_callback(mpv, wakeup, this);QList<QVariant> list;list << "no-correct-pts";
//    mpv::qt::command_variant(mpv, list);mpv::qt::set_property_variant(mpv, "correct-pts", "no");mpv::qt::set_property_variant(mpv, "fps", "0");}MpvWidget::~MpvWidget()
{makeCurrent();if (mpv_gl)mpv_render_context_free(mpv_gl);mpv_terminate_destroy(mpv);
}void MpvWidget::command(const QVariant &params)
{mpv::qt::command_variant(mpv, params);
}void MpvWidget::setProperty(const QString &name, const QVariant &value)
{mpv::qt::set_property_variant(mpv, name, value);
}QVariant MpvWidget::getProperty(const QString &name) const
{return mpv::qt::get_property_variant(mpv, name);
}void MpvWidget::initializeGL()
{mpv_opengl_init_params gl_init_params{get_proc_address, nullptr, nullptr};mpv_render_param params[] {{MPV_RENDER_PARAM_API_TYPE, const_cast<char *>(MPV_RENDER_API_TYPE_OPENGL)},{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},{MPV_RENDER_PARAM_INVALID, nullptr}};if (mpv_render_context_create(&mpv_gl, mpv, params) < 0)throw std::runtime_error("failed to initialize mpv GL context");mpv_render_context_set_update_callback(mpv_gl, MpvWidget::on_update, reinterpret_cast<void *>(this));
}void MpvWidget::paintGL()
{int iwidth = width();double dwidth = iwidth * devicePixelRatioF();int iheight = height();double dheight = iheight * devicePixelRatioF();int deviceiwidth = dwidth;int deviceiheight = dheight;mpv_opengl_fbo mpfbo{static_cast<int>(defaultFramebufferObject()), deviceiwidth, deviceiheight, 0};int flip_y{1};mpv_render_param params[] = {{MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo},{MPV_RENDER_PARAM_FLIP_Y, &flip_y},{MPV_RENDER_PARAM_INVALID, nullptr}};// See render_gl.h on what OpenGL environment mpv expects, and// other API details.mpv_render_context_render(mpv_gl, params);if (m_bScrrenShot) {m_bScrrenShot = false;QPixmap pix = QPixmap::fromImage(grabFramebuffer());QDateTime::currentMSecsSinceEpoch();QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" + QString::number(QDateTime::currentMSecsSinceEpoch()) + ".png";pix.save(path);}
}void MpvWidget::on_mpv_events()
{// Process all events, until the event queue is empty.while (mpv) {mpv_event *event = mpv_wait_event(mpv, 0);if (event->event_id == MPV_EVENT_NONE) {break;}handle_mpv_event(event);}
}void MpvWidget::handle_mpv_event(mpv_event *event)
{switch (event->event_id) {case MPV_EVENT_PROPERTY_CHANGE: {mpv_event_property *prop = (mpv_event_property *)event->data;if (strcmp(prop->name, "time-pos") == 0) {if (prop->format == MPV_FORMAT_DOUBLE) {double time = *(double *)prop->data;Q_EMIT positionChanged(time);}} else if (strcmp(prop->name, "duration") == 0) {if (prop->format == MPV_FORMAT_DOUBLE) {double time = *(double *)prop->data;Q_EMIT durationChanged(time);}}break;}default: ;// Ignore uninteresting or unknown events.}
}// Make Qt invoke mpv_render_context_render() to draw a new/updated video frame.
void MpvWidget::maybeUpdate()
{// If the Qt window is not visible, Qt's update() will just skip rendering.// This confuses mpv's render API, and may lead to small occasional// freezes due to video rendering timing out.// Handle this by manually redrawing.// Note: Qt doesn't seem to provide a way to query whether update() will//       be skipped, and the following code still fails when e.g. switching//       to a different workspace with a reparenting window manager.if (window()->isMinimized()) {makeCurrent();paintGL();context()->swapBuffers(context()->surface());doneCurrent();} else {update();}
}void MpvWidget::on_update(void *ctx)
{QMetaObject::invokeMethod((MpvWidget *)ctx, "maybeUpdate");
}

只要将激活窗口包含播放器,对应linux和windows设置就可以使用。

在windows下几乎完美,图标可点击,linux下只能显示视频(ubuntu18.04可以,其他似乎都不行)。

demo git地址(windows/linux)

windwos:
windwos源码
或者
https://download.csdn.net/download/qq_43081702/86741121

linux:
linux源码

windows /linux下demo可执行程序地址

linux可执行程序下载

windows可执行程序下载

Qt+mpv制作windows/linux 下的动态壁纸软件(含源码)相关推荐

  1. Linux下存储多路径软件MultiPath源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 全局概览 测试环境为CentOS 7 X64 从RPM获取源码 $ cd ~/rpmbuild/ $ yumdownloade ...

  2. 壁纸背景墙/头像/动态壁纸小程序源码-支持用户投稿-带部分采集功能+搭建教程

    介绍: 今天自己搭建测试了一下这款背景墙/头像/动态壁纸小程序源码,源码使用dcloud云开发 (云开发优势:无需服务器域名直接搭建部署即可,成本低方便维护.)支持微信QQ双端小程序也就是说可以打包成 ...

  3. 柚子壁纸为什么自动安装_Wallpaper Engine,Windows最好用的动态壁纸软件,附教程!...

    Wallpaper Engine相信不少小伙伴都听说过,是一款非常专业的动态壁纸软件,目前在Steam售价19元,其实也不算贵,但是个人总觉得花这钱整一个动态壁纸软件,不是很划算,毕竟不是必需品啊! ...

  4. 使用C++实现的仿Wallpaper动态壁纸软件(含源文件)

    在上一篇博客中,已经介绍了wallpaper的实现原理,并用C#实现,本文将使用C++和Qt框架实现,由于之前已经介绍过具体思路,本文将跳过分析过程,直接上代码. 新建Qt项目,系统自动生成widge ...

  5. linux下使用动态壁纸

    让你的linux桌面动起来(幻梦动态壁纸) 我也是突发奇想,做了这么一个程序,目前在多个linux下可以运行,支持双屏 理论上说支持mpv >=29.0 qt>=5.8.0的系统版本 ub ...

  6. Windows 10 下安装Ubuntu子系统 编译Android源码问题记录

    一.Ubuntu子系统安装 1.启用WSL Windows Subsystem for Linux(简称WSL)是一个在Windows 10\11上能够运行原生Linux二进制可执行文件(ELF格式) ...

  7. 似物性检测——linux下运行objectness-v2.2并分析源码(pami2012论文)

    需要做一个似物性检测,首先去找了前段时间很火的程老师的论文BING看,大概了解objectness的含义,也跑了程老师的代码,因为自己不严谨,所以发短信问程老师还被说了,没好好看论文,不过后面自己还是 ...

  8. Linux下软中断过程(详细)源码总结

    一.简介 由于中断会打断内核中进程的正常调度运行,所以要求中断服务程序尽可能的短小精悍:但是在实际系统中,当中断到来时,要完成工作往往进行大量的耗时处理.因此期望让中断处理程序运行得快,并想让它完成的 ...

  9. 第20节:cesium 流动纹理示例-动态输油管道(含源码+视频)

    流动纹理示例-动态输油管道综合示例 结果示例: 完整源码: <template><div class="viewer"><vc-viewer @rea ...

最新文章

  1. 推荐一款学习R的APP
  2. 请教visio-uml-活动图中动作状态和状态的区别谢谢 - 软件工程-管理 - 软件规划版...
  3. C/C++中的拷贝构造函数和赋值构造函数
  4. 如果硬盘不显示可以这么处理
  5. 3大原则让你的编程之路越走越顺
  6. python 查看excel 多少行_13行代码实现对Excel自动分表(python)
  7. 如果关闭一个窗体后激活另一个窗体的事件或方法
  8. 算法题库 java实现_LeetCode算法题-Most Common Word(Java实现)
  9. mvc框架java包怎么划分_java – 在MVC模式中将模型和动作划分为类...
  10. 三星Galaxy Note 10渲染图曝光:前置打孔双摄+后置横排四摄
  11. LINQ TO OBJECT
  12. zabbix自定义监控nginx
  13. spoonwep破解方式使用心得
  14. minic 动作句型处理
  15. 如何演示扇形面积公式推导过程
  16. 泰凌微 Telink TLSR825X Uart 串口无法接收数据 关闭休眠和深度休眠解决 问题
  17. 寒武纪笔试——嵌入式
  18. SVAC的重要Feature
  19. 利用python分析电商_基于Word2Vec+SVM对电商的评论数据进行情感分析
  20. CentOS虚拟机连接外网

热门文章

  1. 微信小程序解码emoji表情
  2. 阿里企业云邮箱怎么申请?企业云邮箱登录界面在哪?
  3. 2012 CSP-S 初赛 答案解析
  4. linux c++ 线程支持 多核应用,linux C++多线程服务端开发
  5. 应届生如何做好一份简历?
  6. PyScripter显示行号
  7. 解读广告SDK工作机制,保护App自身安全
  8. MVC5-Scaffolder
  9. QQ相关(一)【导出所有QQ好友】
  10. 2020-10-16