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

news/2024/11/8 18:43:20/

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可执行程序下载


http://www.ppmy.cn/news/637750.html

相关文章

动态壁纸-软件制作-教程

0、开始&#xff1a; 演示视频&#xff1a;请移至&#xff08;bilibili&#xff09; 源代码&#xff1a;请移至&#xff08;码云&#xff09; 下面是关键实现&#xff0c;具体请看仓库源码。 1、创建工程 打开vs2017&#xff0c;选择 文件 > 新建 > 项目 > Windows 窗…

自己动手制作安卓动态壁纸教程

准备工作&#xff1a; 1、动画分解软件(将一个视频或动画分解成一张一张的png图片&#xff0c;很多软件都可以的&#xff0c;大家看自己喜好吧&#xff0c;比如photo shop,光影魔术手&#xff0c;KMP播放器截图等)但是我用的是Ulead GIF Animator (GIF动画制作软件)可以百度搜索…

win10将HTML动态做桌面壁纸,Win10 怎么制作动态界面壁纸

随着科技的发展&#xff0c;很多人已经不再满足于静态的图片&#xff0c;不管是在平时的聊天还是关于手机的壁纸都是如此&#xff0c;在聊天的时候会使用到GIF动态图&#xff0c;手机中的壁纸也会设置成小视频&#xff0c;那既然使用动态图这么频繁&#xff0c;怎么制作这些动态…

手把手带你从零基础抓取A站短视频,并且制作从动态壁纸,这些小姐姐我全都要!

大家好&#xff0c;我是辣条。 我知道大家都是冲着学技术来的&#xff0c;肯定不是为了那些好看的小姐姐进来的&#xff0c;所以直接进入主题吧。 A站视频数据采集 采集数据目标效果展示工具使用重点学习内容项目思路解析简易源码分析 采集数据目标 网址&#xff1a;A站 效…

Java调用scala中map转换问题处理

网上代码 把Javamap转为scala的map代码 scala.collection.mutable.Map<String, String> scalaMap JavaConverters.mapAsScalaMapConverter(map).asScala();Object objMap Map$.MODULE$.<String, String>newBuilder().$plus$plus$eq(scalaMap.toSeq());Object Bui…

Win11转移conda环境——从C盘转移到D盘

原本就是将Anaconda安装到了C盘&#xff0c;结果发现环境他还是默认安装到了C盘&#xff0c;就打算再转移一下 conda版本为 首先找到Win11下面的环境位置 C:\Users\用户名\.conda\envs比如我的就是 C:\Users\Arona\.conda\envs找到D盘安装Anaconda的位置 D:\ProgramData\an…

【前端面试必读】w3c标准是什么?

web标准简单来说可以分为结构、表现和行为 结构 主要是有HTML标签组成 表现 即指css样式表 行为 主要是有js、dom组成 web标准一般是将该三部分独立分开&#xff0c;使其更具有模块化。但一般产生行为时&#xff0c;就会有结构或者表现的变化&#xff0c;也使这三者的界限并不那…

两个实用型教学网站:菜鸟教程与W3School,估计是国内做得做好的了

1、菜鸟教程 这是个非常的基础的在线教育网站&#xff0c;很经典的教程&#xff0c;分类明确&#xff0c;强烈推荐收藏。 2、W3School 学WEB开发&#xff0c;结合w3school学习前端&#xff0c;开发时&#xff0c;核心是语法方向的。很赞。