From 83a8347161a44be945d2073ea8b2dae707c7680c Mon Sep 17 00:00:00 2001 From: xfangfang <2553041586@qq.com> Date: Sat, 14 Sep 2024 06:43:52 +0800 Subject: [PATCH] Shaders support additional mpv settings eg: { "name": "fsrcnnx-high", "shaders": [ "FSRCNNX_x2_16-0-4-1.glsl", "SSimDownscaler.glsl", "KrigBilateral.glsl" ], "settings": [ ["scale", "ewa_lanczos"], ["dscale", "mitchell"], ["linear_downscaling", "no"], ["cscale", "mitchell"] ] }, --- wiliwili/include/activity/player_activity.hpp | 3 + wiliwili/include/utils/event_helper.hpp | 31 +++++++ wiliwili/include/utils/shader_helper.hpp | 33 +++++++- wiliwili/include/view/mpv_core.hpp | 27 ++++--- .../source/activity/player_base_activity.cpp | 53 +++++++----- wiliwili/source/fragment/player_setting.cpp | 3 +- wiliwili/source/utils/shader_helper.cpp | 20 +++-- wiliwili/source/view/mpv_core.cpp | 80 +++++++++++++++---- 8 files changed, 190 insertions(+), 60 deletions(-) diff --git a/wiliwili/include/activity/player_activity.hpp b/wiliwili/include/activity/player_activity.hpp index 5ef10d30..acbccd38 100644 --- a/wiliwili/include/activity/player_activity.hpp +++ b/wiliwili/include/activity/player_activity.hpp @@ -137,6 +137,9 @@ class BasePlayerActivity : public brls::Activity, public VideoDetail { private: bool activityShown = false; std::chrono::system_clock::time_point videoDeadline{}; + + // 重新选择当前清晰度的播放链接播放 + void updateVideoLink(); }; class PlayerActivity : public BasePlayerActivity { diff --git a/wiliwili/include/utils/event_helper.hpp b/wiliwili/include/utils/event_helper.hpp index 6851c5d8..57176952 100644 --- a/wiliwili/include/utils/event_helper.hpp +++ b/wiliwili/include/utils/event_helper.hpp @@ -8,6 +8,10 @@ #include typedef enum MpvEventEnum { + /** + * 视频播放的一系列状态 + * 播放器组件会订阅这些事件处理不同的逻辑 + */ MPV_LOADED, MPV_PAUSE, MPV_RESUME, @@ -20,12 +24,39 @@ typedef enum MpvEventEnum { UPDATE_PROGRESS, START_FILE, END_OF_FILE, + + /** + * 视频缓存速度更新时触发此事件 + * 播放器组件会订阅此事件,用于在网络加载卡顿时显示缓冲速度 + */ CACHE_SPEED_CHANGE, + + /** + * 视频播放速度调整时触发此事件 + * 弹幕组件和播放器组件的相关功能会订阅此事件 + */ VIDEO_SPEED_CHANGE, + + /** + * mpv内部音量调整时触发以下事件 + * DLNA 播放页面会订阅相关事件,并将音量状态同步到手机投屏端 + */ VIDEO_VOLUME_CHANGE, VIDEO_MUTE, VIDEO_UNMUTE, + + /** + * 每次播放视频前,触发此事件 + * 重置视频进度、视频比例、视频时长等信息 + * 弹幕组件、字幕组件和播放器组件的相关功能会订阅此事件 + */ RESET, + + /** + * 需要重置到播放器初识参数时,触发此事件(比如清空着色器设置) + * 视频播放页会订阅此事件,用来在播放器重置后重新设置播放链接 + */ + RESTART, } MpvEventEnum; typedef brls::Event MPVEvent; diff --git a/wiliwili/include/utils/shader_helper.hpp b/wiliwili/include/utils/shader_helper.hpp index 2210189b..b63544b9 100644 --- a/wiliwili/include/utils/shader_helper.hpp +++ b/wiliwili/include/utils/shader_helper.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -13,12 +14,13 @@ class ShaderProfile { public: std::string name; std::vector shaders; + std::vector> settings; std::string getShaderString(); }; inline void to_json(nlohmann::json& nlohmann_json_j, const ShaderProfile& nlohmann_json_t) { - NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, name, shaders)); + NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, name, shaders, settings)); } inline void from_json(const nlohmann::json& nlohmann_json_j, ShaderProfile& nlohmann_json_t) { @@ -30,6 +32,24 @@ inline void from_json(const nlohmann::json& nlohmann_json_j, ShaderProfile& nloh auto& shaders = nlohmann_json_j.at("shaders"); if (shaders.is_array()) shaders.get_to(nlohmann_json_t.shaders); } + if (nlohmann_json_j.contains("settings")) { + auto& settings = nlohmann_json_j.at("settings"); + if (settings.is_array()) settings.get_to(nlohmann_json_t.settings); + for (auto& setting : nlohmann_json_t.settings) { + if (setting.empty()) continue; + // 检查是否包含操作指令 + const std::vector mainOptions = {"set", "run", "change-list"}; + bool hasMainOption = false; + for (auto& option : mainOptions) { + if (pystring::endswith(setting[0], option)) { + hasMainOption = true; + break; + } + } + // 如果没有指明操作方式,则默认为 set + if (!hasMainOption) setting.insert(setting.begin(), "set"); + } + } } typedef std::vector ShaderProfileList; @@ -133,11 +153,18 @@ class ShaderHelper : public brls::Singleton { std::string getProfileNameByIndex(size_t index); /** - * 通过配置索引获取 profile 字符串 + * 通过配置索引获取 profile shader + * @param index + * @return + */ + std::string getProfileShaderByIndex(size_t index); + + /** + * 通过配置索引获取 profile settings * @param index * @return */ - std::string getProfileByIndex(size_t index); + std::vector> getByProfileSettingByIndex(size_t index); /** * 通过剧集 id 获取配置索引 diff --git a/wiliwili/include/view/mpv_core.hpp b/wiliwili/include/view/mpv_core.hpp index bbfae34c..569cfa78 100644 --- a/wiliwili/include/view/mpv_core.hpp +++ b/wiliwili/include/view/mpv_core.hpp @@ -224,6 +224,8 @@ class MPVCore : public brls::Singleton { */ void setAspect(const std::string &value); + void setMirror(bool value); + /** * 设置视频亮度 * @param value [-100, 100] @@ -288,7 +290,15 @@ class MPVCore : public brls::Singleton { void reset(); - void setShader(const std::string &profile, const std::string &shaders, bool showHint = true); + /** + * 设置着色器配置 + * @param profile 配置名 + * @param shaders 着色器文件 + * @param settings mpv 配置 + * @param reset 在设置前是否需要重置 + */ + void setShader(const std::string &profile, const std::string &shaders, + const std::vector> &settings, bool reset = true); void clearShader(bool showHint = true); @@ -300,17 +310,11 @@ class MPVCore : public brls::Singleton { return; } std::vector commands = {fmt::format("{}", std::forward(args))...}; - - std::vector res; - res.reserve(commands.size() + 1); - for (auto &i : commands) { - res.emplace_back(i.c_str()); - } - res.emplace_back(nullptr); - - mpvCommandAsync(mpv, 0, res.data()); + _command_async(commands); } + void _command_async(const std::vector& commands); + // core states int64_t duration = 0; // second int64_t cache_speed = 0; // Bps @@ -330,6 +334,7 @@ class MPVCore : public brls::Singleton { std::string filepath; std::string currentShaderProfile; // 当前着色器脚本名 std::string currentShader; // 当前着色器脚本 + std::vector> currentSetting; // 当前着色器脚本附加的mpv配置 double video_brightness = 0; double video_contrast = 0; @@ -347,7 +352,7 @@ class MPVCore : public brls::Singleton { inline static bool TERMINAL = false; // 硬件解码 - inline static bool HARDWARE_DEC = false; + inline static bool HARDWARE_DEC = false; // 硬解方式 #ifdef __SWITCH__ diff --git a/wiliwili/source/activity/player_base_activity.cpp b/wiliwili/source/activity/player_base_activity.cpp index fc895304..6794ed11 100644 --- a/wiliwili/source/activity/player_base_activity.cpp +++ b/wiliwili/source/activity/player_base_activity.cpp @@ -253,10 +253,13 @@ void BasePlayerActivity::setCommonData() { }); // 暂停 - this->registerAction("toggle", brls::ControllerButton::BUTTON_SPACE, [this](...) -> bool { - this->video->togglePlay(); - return true; - }, true); + this->registerAction( + "toggle", brls::ControllerButton::BUTTON_SPACE, + [this](...) -> bool { + this->video->togglePlay(); + return true; + }, + true); this->btnQR->getParent()->addGestureRecognizer(new brls::TapGestureRecognizer(this->btnQR->getParent())); @@ -345,6 +348,9 @@ void BasePlayerActivity::setCommonData() { } } break; + case MpvEventEnum::RESTART: + this->updateVideoLink(); + break; default: break; } @@ -405,6 +411,26 @@ void BasePlayerActivity::showCoinDialog(uint64_t aid) { dialog->open(); } +void BasePlayerActivity::updateVideoLink() { + // 设置视频加载后跳转的时间 + setProgress(MPVCore::instance().video_progress); + + // dash + if (!this->videoUrlResult.dash.video.empty()) { + // dash格式的视频无需重复请求视频链接,这里简单的设置清晰度即可 + videoUrlResult.quality = BasePlayerActivity::defaultQuality; + this->onVideoPlayUrl(videoUrlResult); + return; + } + + // flv + if (dynamic_cast(this)) { + this->requestSeasonVideoUrl(episodeResult.bvid, episodeResult.cid); + } else { + this->requestVideoUrl(videoDetailResult.bvid, videoDetailPage.cid); + } +} + void BasePlayerActivity::setVideoQuality() { if (this->videoUrlResult.accept_description.empty()) return; @@ -421,24 +447,7 @@ void BasePlayerActivity::setVideoQuality() { return; } - // 设置视频加载后跳转的时间 - setProgress(MPVCore::instance().video_progress); - - // dash - if (!this->videoUrlResult.dash.video.empty()) { - // dash格式的视频无需重复请求视频链接,这里简单的设置清晰度即可 - videoUrlResult.quality = BasePlayerActivity::defaultQuality; - this->onVideoPlayUrl(videoUrlResult); - return; - } - - // flv - auto self = dynamic_cast(this); - if (self) { - this->requestSeasonVideoUrl(episodeResult.bvid, episodeResult.cid); - } else { - this->requestVideoUrl(videoDetailResult.bvid, videoDetailPage.cid); - } + this->updateVideoLink(); }, getQualityIndex()); auto* recycler = dropdown->getRecyclingList(); diff --git a/wiliwili/source/fragment/player_setting.cpp b/wiliwili/source/fragment/player_setting.cpp index 3db85c39..f6549702 100644 --- a/wiliwili/source/fragment/player_setting.cpp +++ b/wiliwili/source/fragment/player_setting.cpp @@ -192,8 +192,7 @@ void PlayerSetting::setupCommonSetting() { /// Player mirror btnMirror->init("wiliwili/player/setting/common/mirror"_i18n, MPVCore::VIDEO_MIRROR, [](bool value) { - MPVCore::VIDEO_MIRROR = !MPVCore::VIDEO_MIRROR; - MPVCore::instance().command_async("set", "vf", MPVCore::VIDEO_MIRROR ? "hflip" : ""); + MPVCore::instance().setMirror(!MPVCore::VIDEO_MIRROR); GA("player_setting", {{"mirror", value ? "true" : "false"}}); // 如果正在使用硬解,那么将硬解更新为 auto-copy,避免直接硬解因为不经过 cpu 处理导致镜像翻转无效 diff --git a/wiliwili/source/utils/shader_helper.cpp b/wiliwili/source/utils/shader_helper.cpp index 805c3081..a9ea7cca 100644 --- a/wiliwili/source/utils/shader_helper.cpp +++ b/wiliwili/source/utils/shader_helper.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ std::string ShaderProfile::getShaderString() { std::string separator = ":"; #endif std::vector res; + res.reserve(shaders.size()); for (auto& s : shaders) { res.emplace_back("~~/shaders/" + s); } @@ -33,14 +35,15 @@ void ShaderHelper::setShaderPack(const ShaderPack& data) { this->pack = data; } ShaderPack ShaderHelper::getShaderPack() { return this->pack; } void ShaderHelper::setShader(size_t index, bool showHint) { - MPVCore::instance().setShader(getProfileNameByIndex(index), getProfileByIndex(index), showHint); + MPVCore::instance().setShader(getProfileNameByIndex(index), getProfileShaderByIndex(index), + getByProfileSettingByIndex(index), showHint); } void ShaderHelper::clearShader(bool showHint) { MPVCore::instance().clearShader(showHint); } void ShaderHelper::setProfile(size_t sid, size_t profileIndex) { if (!isAvailable()) return; - if (profileIndex < 0 || profileIndex >= pack.profiles.size()) return; + if (profileIndex >= pack.profiles.size()) return; for (auto& anime : pack.animeList) { if (anime.anime == sid) { // 修改已有配置 @@ -92,16 +95,22 @@ std::string ShaderHelper::getProfileByName(const std::string& name) { std::string ShaderHelper::getProfileNameByIndex(size_t index) { if (!isAvailable()) return ""; - if (index < 0 || index >= pack.profiles.size()) return ""; + if (index >= pack.profiles.size()) return ""; return pack.profiles[index].name; } -std::string ShaderHelper::getProfileByIndex(size_t index) { +std::string ShaderHelper::getProfileShaderByIndex(size_t index) { if (!isAvailable()) return ""; - if (index < 0 || index >= pack.profiles.size()) return ""; + if (index >= pack.profiles.size()) return ""; return pack.profiles[index].getShaderString(); } +std::vector> ShaderHelper::getByProfileSettingByIndex(size_t index) { + if (!isAvailable()) return {}; + if (index >= pack.profiles.size()) return {}; + return pack.profiles[index].settings; +} + size_t ShaderHelper::getProfileIndexBySeason(size_t sid) { if (!isAvailable()) return -1; for (auto& anime : pack.animeList) { @@ -146,6 +155,7 @@ void ShaderHelper::load() { this->setShaderPack(content.get()); } catch (const std::exception& e) { brls::Logger::error("ShaderHelper::load: {}", e.what()); + brls::Application::notify("Load custom shader pack failed\n" + std::string(e.what())); } brls::Logger::info("Load custom shader pack from: {}", path); } else { diff --git a/wiliwili/source/view/mpv_core.cpp b/wiliwili/source/view/mpv_core.cpp index 95b207f7..def4908b 100644 --- a/wiliwili/source/view/mpv_core.cpp +++ b/wiliwili/source/view/mpv_core.cpp @@ -221,8 +221,7 @@ void MPVCore::on_wakeup(void *self) { #if defined(MPV_BUNDLE_DLL) template -void initMpvProc(Module dll, fnGetProcAddress pGetProcAddress) -{ +void initMpvProc(Module dll, fnGetProcAddress pGetProcAddress) { mpvSetOptionString = (mpvSetOptionStringFunc)pGetProcAddress(dll, "mpv_set_option_string"); mpvObserveProperty = (mpvObservePropertyFunc)pGetProcAddress(dll, "mpv_observe_property"); mpvCreate = (mpvCreateFunc)pGetProcAddress(dll, "mpv_create"); @@ -242,9 +241,10 @@ void initMpvProc(Module dll, fnGetProcAddress pGetProcAddress) mpvRenderContextUpdate = (mpvRenderContextUpdateFunc)pGetProcAddress(dll, "mpv_render_context_update"); mpvRenderContextFree = (mpvRenderContextFreeFunc)pGetProcAddress(dll, "mpv_render_context_free"); mpvRenderContextRender = (mpvRenderContextRenderFunc)pGetProcAddress(dll, "mpv_render_context_render"); - mpvRenderContextSetUpdateCallback = (mpvRenderContextSetUpdateCallbackFunc)pGetProcAddress(dll, "mpv_render_context_set_update_callback"); + mpvRenderContextSetUpdateCallback = + (mpvRenderContextSetUpdateCallbackFunc)pGetProcAddress(dll, "mpv_render_context_set_update_callback"); mpvRenderContextReportSwap = (mpvRenderContextReportSwapFunc)pGetProcAddress(dll, "mpv_render_context_report_swap"); - mpvClientApiVersion = (mpvClientApiVersionFunc)pGetProcAddress(dll, "mpv_client_api_version"); + mpvClientApiVersion = (mpvClientApiVersionFunc)pGetProcAddress(dll, "mpv_client_api_version"); } #endif @@ -252,12 +252,12 @@ MPVCore::MPVCore() { #if defined(MPV_BUNDLE_DLL) HMODULE hMpv = ::LoadLibraryW(L"libmpv-2.dll"); if (!hMpv) { - HRSRC hSrc = ::FindResource(nullptr, "MPV", RT_RCDATA); + HRSRC hSrc = ::FindResource(nullptr, "MPV", RT_RCDATA); HGLOBAL hRes = ::LoadResource(nullptr, hSrc); DWORD dwSize = ::SizeofResource(nullptr, hSrc); - dll = MemoryLoadLibrary(::LockResource(hRes), dwSize); + dll = MemoryLoadLibrary(::LockResource(hRes), dwSize); ::FreeResource(hRes); - + brls::Logger::info("Load bundled libmpv-2.dll, size: {}", dwSize); initMpvProc(dll, MemoryGetProcAddress); } else { @@ -417,7 +417,7 @@ void MPVCore::init() { {MPV_RENDER_PARAM_INVALID, nullptr}}; #elif defined(BOREALIS_USE_D3D11) mpv_dxgi_init_params init_params{D3D11_CONTEXT->getDevice(), D3D11_CONTEXT->getSwapChain()}; - mpv_render_param params[] { + mpv_render_param params[]{ {MPV_RENDER_PARAM_API_TYPE, const_cast(MPV_RENDER_API_TYPE_DXGI)}, {MPV_RENDER_PARAM_DXGI_INIT_PARAMS, &init_params}, {MPV_RENDER_PARAM_INVALID, nullptr}, @@ -506,8 +506,13 @@ void MPVCore::clean() { void MPVCore::restart() { this->clean(); this->init(); - command_async("set", "vf", MPVCore::VIDEO_MIRROR ? "hflip" : ""); - setShader(currentShaderProfile, currentShader, false); + setMirror(MPVCore::VIDEO_MIRROR); + setShader(currentShaderProfile, currentShader, currentSetting, false); + mpvCoreEvent.fire(MpvEventEnum::RESTART); + + // 如果正在播放视频时重启mpv,重启前后存在软硬解切,那么视频尺寸会不正确 + // 手动设置一次尺寸可以解决这个问题 (同 MPVCore::reset()) + setFrameSize(rect); } void MPVCore::uninitializeVideo() { @@ -657,7 +662,7 @@ void MPVCore::setFrameSize(brls::Rect r) { mpvRenderContextRender(mpv_context, mpv_params); mpvRenderContextReportSwap(mpv_context); #elif !defined(MPV_USE_FB) - // Using default framebuffer + // Using default framebuffer #ifndef BOREALIS_USE_D3D11 this->mpv_fbo.w = brls::Application::windowWidth; this->mpv_fbo.h = brls::Application::windowHeight; @@ -1147,6 +1152,11 @@ void MPVCore::setAspect(const std::string &value) { } } +void MPVCore::setMirror(bool value) { + MPVCore::VIDEO_MIRROR = value; + command_async("set", "vf", value ? "hflip": ""); +} + void MPVCore::setBrightness(int value) { if (value < -100) value = -100; if (value > 100) value = 100; @@ -1240,21 +1250,57 @@ void MPVCore::disableDimming(bool disable) { } } -void MPVCore::setShader(const std::string &profile, const std::string &shaders, bool showHint) { +void MPVCore::setShader(const std::string &profile, const std::string &shaders, + const std::vector> &settings, bool reset) { brls::Logger::info("Set shader [{}]: {}", profile, shaders); + + // 如果之前设置的shader包含mpv配置,就需要重置一下 + if (!currentSetting.empty() && reset) clearShader(false); + currentShaderProfile = profile; currentShader = shaders; - if (shaders.empty()) return; - command_async("no-osd", "change-list", "glsl-shaders", "set", shaders); - if (showHint) showOsdText(profile); + currentSetting = settings; + + // 设置着色器 + if (!shaders.empty()) command_async("no-osd", "change-list", "glsl-shaders", "set", shaders); + + // 设置mpv配置 + for (auto &setting : settings) { + _command_async(setting); + } + + // 显示通知 + if (reset) brls::Application::notify(profile); } void MPVCore::clearShader(bool showHint) { brls::Logger::info("Clear shader"); + + // 如果当前不涉及mpv配置修改,就无需重置 + bool reset = !currentSetting.empty(); + currentShader.clear(); currentShaderProfile.clear(); + currentSetting.clear(); + + // 清空着色器 command_async("no-osd", "change-list", "glsl-shaders", "clr", ""); - if (showHint) showOsdText("Clear shader"); + + // 重置mpv配置 + if (reset) MPVCore::instance().restart(); + + // 显示通知 + if (showHint) brls::Application::notify("Clear profile"); } -void MPVCore::showOsdText(const std::string &value, int d) { command_async("show-text", value, d); } \ No newline at end of file +void MPVCore::showOsdText(const std::string &value, int d) { command_async("show-text", value, d); } + +void MPVCore::_command_async(const std::vector &commands) { + std::vector res; + res.reserve(commands.size() + 1); + for (auto &i : commands) { + res.emplace_back(i.c_str()); + } + res.emplace_back(nullptr); + mpvCommandAsync(mpv, 0, res.data()); +} \ No newline at end of file