mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 18:54:14 +01:00 
			
		
		
		
	service: caps: Implement SaveScreenShotEx0 and variants
This commit is contained in:
		
							parent
							
								
									94836ba3b1
								
							
						
					
					
						commit
						897b411ae7
					
				| @ -25,11 +25,12 @@ void LoopProcess(Core::System& system) { | ||||
|     server_manager->RegisterNamedService( | ||||
|         "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager)); | ||||
| 
 | ||||
|     server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system)); | ||||
|     server_manager->RegisterNamedService( | ||||
|         "caps:ss", std::make_shared<IScreenShotService>(system, album_manager)); | ||||
|     server_manager->RegisterNamedService("caps:sc", | ||||
|                                          std::make_shared<IScreenShotControlService>(system)); | ||||
|     server_manager->RegisterNamedService("caps:su", | ||||
|                                          std::make_shared<IScreenShotApplicationService>(system)); | ||||
|     server_manager->RegisterNamedService( | ||||
|         "caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager)); | ||||
| 
 | ||||
|     ServerManager::RunServer(std::move(server_manager)); | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #include <sstream> | ||||
| #include <stb_image.h> | ||||
| #include <stb_image_resize.h> | ||||
| #include <stb_image_write.h> | ||||
| 
 | ||||
| #include "common/fs/file.h" | ||||
| #include "common/fs/path_util.h" | ||||
| @ -227,6 +228,49 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( | ||||
|                      +static_cast<int>(out_image_output.height), decoder_options.flags); | ||||
| } | ||||
| 
 | ||||
| Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, | ||||
|                                     const ScreenShotAttribute& attribute, | ||||
|                                     std::span<const u8> image_data, u64 aruid) { | ||||
|     return SaveScreenShot(out_entry, attribute, {}, image_data, aruid); | ||||
| } | ||||
| 
 | ||||
| Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, | ||||
|                                     const ScreenShotAttribute& attribute, | ||||
|                                     const ApplicationData& app_data, std::span<const u8> image_data, | ||||
|                                     u64 aruid) { | ||||
|     const u64 title_id = system.GetApplicationProcessProgramID(); | ||||
|     const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); | ||||
| 
 | ||||
|     s64 posix_time{}; | ||||
|     Result result = user_clock.GetCurrentTime(system, posix_time); | ||||
| 
 | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     const auto date = ConvertToAlbumDateTime(posix_time); | ||||
| 
 | ||||
|     return SaveImage(out_entry, image_data, title_id, date); | ||||
| } | ||||
| 
 | ||||
| Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, | ||||
|                                           const ScreenShotAttribute& attribute, | ||||
|                                           const AlbumFileId& file_id, | ||||
|                                           std::span<const u8> image_data) { | ||||
|     const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); | ||||
| 
 | ||||
|     s64 posix_time{}; | ||||
|     Result result = user_clock.GetCurrentTime(system, posix_time); | ||||
| 
 | ||||
|     if (result.IsError()) { | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     const auto date = ConvertToAlbumDateTime(posix_time); | ||||
| 
 | ||||
|     return SaveImage(out_entry, image_data, file_id.application_id, date); | ||||
| } | ||||
| 
 | ||||
| Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { | ||||
|     const auto file = album_files.find(file_id); | ||||
| 
 | ||||
| @ -365,6 +409,45 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, | ||||
|                                u64 title_id, const AlbumFileDateTime& date) const { | ||||
|     const auto screenshot_path = | ||||
|         Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir); | ||||
|     const std::string formatted_date = | ||||
|         fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day, | ||||
|                     date.hour, date.minute, date.second, 0); | ||||
|     const std::string file_path = | ||||
|         fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date); | ||||
| 
 | ||||
|     const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write, | ||||
|                                      Common::FS::FileType::BinaryFile}; | ||||
| 
 | ||||
|     s32 len; | ||||
|     const u8* png = stbi_write_png_to_mem(image.data(), 0, 1280, 720, STBI_rgb_alpha, &len); | ||||
| 
 | ||||
|     if (!png) { | ||||
|         return ResultFileCountLimit; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> png_image(len); | ||||
|     std::memcpy(png_image.data(), png, len); | ||||
| 
 | ||||
|     if (db_file.Write(png_image) != png_image.size()) { | ||||
|         return ResultFileCountLimit; | ||||
|     } | ||||
| 
 | ||||
|     out_entry = { | ||||
|         .size = png_image.size(), | ||||
|         .hash = {}, | ||||
|         .datetime = date, | ||||
|         .storage = AlbumStorage::Sd, | ||||
|         .content = ContentType::Screenshot, | ||||
|         .unknown = 1, | ||||
|     }; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { | ||||
|     Time::TimeZone::CalendarInfo calendar_date{}; | ||||
|     const auto& time_zone_manager = | ||||
|  | ||||
| @ -58,6 +58,15 @@ public: | ||||
|                                         std::vector<u8>& out_image, const AlbumFileId& file_id, | ||||
|                                         const ScreenShotDecodeOption& decoder_options) const; | ||||
| 
 | ||||
|     Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, | ||||
|                           std::span<const u8> image_data, u64 aruid); | ||||
|     Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, | ||||
|                           const ApplicationData& app_data, std::span<const u8> image_data, | ||||
|                           u64 aruid); | ||||
|     Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, | ||||
|                                 const ScreenShotAttribute& attribute, const AlbumFileId& file_id, | ||||
|                                 std::span<const u8> image_data); | ||||
| 
 | ||||
| private: | ||||
|     static constexpr std::size_t NandAlbumFileLimit = 1000; | ||||
|     static constexpr std::size_t SdAlbumFileLimit = 10000; | ||||
| @ -67,6 +76,8 @@ private: | ||||
|     Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; | ||||
|     Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, | ||||
|                      int height, ScreenShotDecoderFlag flag) const; | ||||
|     Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id, | ||||
|                      const AlbumFileDateTime& date) const; | ||||
| 
 | ||||
|     AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const; | ||||
| 
 | ||||
|  | ||||
| @ -1,19 +1,25 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/service/caps/caps_manager.h" | ||||
| #include "core/hle/service/caps/caps_types.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| 
 | ||||
| #include "core/hle/service/caps/caps_ss.h" | ||||
| 
 | ||||
| namespace Service::Capture { | ||||
| 
 | ||||
| IScreenShotService::IScreenShotService(Core::System& system_) | ||||
|     : ServiceFramework{system_, "caps:ss"} { | ||||
| IScreenShotService::IScreenShotService(Core::System& system_, | ||||
|                                        std::shared_ptr<AlbumManager> album_manager) | ||||
|     : ServiceFramework{system_, "caps:ss"}, manager{album_manager} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {201, nullptr, "SaveScreenShot"}, | ||||
|         {202, nullptr, "SaveEditedScreenShot"}, | ||||
|         {203, nullptr, "SaveScreenShotEx0"}, | ||||
|         {203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"}, | ||||
|         {204, nullptr, "SaveEditedScreenShotEx0"}, | ||||
|         {206, nullptr, "Unknown206"}, | ||||
|         {206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"}, | ||||
|         {208, nullptr, "SaveScreenShotOfMovieEx1"}, | ||||
|         {1000, nullptr, "Unknown1000"}, | ||||
|     }; | ||||
| @ -24,4 +30,65 @@ IScreenShotService::IScreenShotService(Core::System& system_) | ||||
| 
 | ||||
| IScreenShotService::~IScreenShotService() = default; | ||||
| 
 | ||||
| void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     struct Parameters { | ||||
|         ScreenShotAttribute attribute{}; | ||||
|         u32 report_option{}; | ||||
|         INSERT_PADDING_BYTES(0x4); | ||||
|         u64 applet_resource_user_id{}; | ||||
|     }; | ||||
|     static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); | ||||
| 
 | ||||
|     const auto parameters{rp.PopRaw<Parameters>()}; | ||||
|     const auto image_data_buffer = ctx.ReadBuffer(); | ||||
| 
 | ||||
|     LOG_INFO(Service_Capture, | ||||
|              "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", | ||||
|              parameters.report_option, image_data_buffer.size(), | ||||
|              parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     ApplicationAlbumEntry entry{}; | ||||
|     const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, | ||||
|                                                 parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 10}; | ||||
|     rb.Push(result); | ||||
|     rb.PushRaw(entry); | ||||
| } | ||||
| void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     struct Parameters { | ||||
|         ScreenShotAttribute attribute; | ||||
|         u64 width; | ||||
|         u64 height; | ||||
|         u64 thumbnail_width; | ||||
|         u64 thumbnail_height; | ||||
|         AlbumFileId file_id; | ||||
|     }; | ||||
|     static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size."); | ||||
| 
 | ||||
|     const auto parameters{rp.PopRaw<Parameters>()}; | ||||
|     const auto application_data_buffer = ctx.ReadBuffer(0); | ||||
|     const auto image_data_buffer = ctx.ReadBuffer(1); | ||||
|     const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2); | ||||
| 
 | ||||
|     LOG_INFO(Service_Capture, | ||||
|              "called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, " | ||||
|              "application_id={:016x},  storage={},  type={}, app_data_buffer_size={}, " | ||||
|              "image_data_buffer_size={}, thumbnail_image_buffer_size={}", | ||||
|              parameters.width, parameters.height, parameters.thumbnail_width, | ||||
|              parameters.thumbnail_height, parameters.file_id.application_id, | ||||
|              parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(), | ||||
|              image_data_buffer.size(), thumbnail_image_data_buffer.size()); | ||||
| 
 | ||||
|     ApplicationAlbumEntry entry{}; | ||||
|     const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, | ||||
|                                                       parameters.file_id, image_data_buffer); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 10}; | ||||
|     rb.Push(result); | ||||
|     rb.PushRaw(entry); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Capture
 | ||||
|  | ||||
| @ -13,8 +13,14 @@ namespace Service::Capture { | ||||
| 
 | ||||
| class IScreenShotService final : public ServiceFramework<IScreenShotService> { | ||||
| public: | ||||
|     explicit IScreenShotService(Core::System& system_); | ||||
|     explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager); | ||||
|     ~IScreenShotService() override; | ||||
| 
 | ||||
| private: | ||||
|     void SaveScreenShotEx0(HLERequestContext& ctx); | ||||
|     void SaveEditedScreenShotEx1(HLERequestContext& ctx); | ||||
| 
 | ||||
|     std::shared_ptr<AlbumManager> manager; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Capture
 | ||||
|  | ||||
| @ -2,19 +2,22 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/service/caps/caps_manager.h" | ||||
| #include "core/hle/service/caps/caps_su.h" | ||||
| #include "core/hle/service/caps/caps_types.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| 
 | ||||
| namespace Service::Capture { | ||||
| 
 | ||||
| IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) | ||||
|     : ServiceFramework{system_, "caps:su"} { | ||||
| IScreenShotApplicationService::IScreenShotApplicationService( | ||||
|     Core::System& system_, std::shared_ptr<AlbumManager> album_manager) | ||||
|     : ServiceFramework{system_, "caps:su"}, manager{album_manager} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, | ||||
|         {201, nullptr, "SaveScreenShot"}, | ||||
|         {203, nullptr, "SaveScreenShotEx0"}, | ||||
|         {205, nullptr, "SaveScreenShotEx1"}, | ||||
|         {203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"}, | ||||
|         {205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"}, | ||||
|         {210, nullptr, "SaveScreenShotEx2"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| @ -36,4 +39,62 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     struct Parameters { | ||||
|         ScreenShotAttribute attribute{}; | ||||
|         AlbumReportOption report_option{}; | ||||
|         INSERT_PADDING_BYTES(0x4); | ||||
|         u64 applet_resource_user_id{}; | ||||
|     }; | ||||
|     static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); | ||||
| 
 | ||||
|     const auto parameters{rp.PopRaw<Parameters>()}; | ||||
|     const auto image_data_buffer = ctx.ReadBuffer(); | ||||
| 
 | ||||
|     LOG_INFO(Service_Capture, | ||||
|              "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", | ||||
|              parameters.report_option, image_data_buffer.size(), | ||||
|              parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     ApplicationAlbumEntry entry{}; | ||||
|     const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, | ||||
|                                                 parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 10}; | ||||
|     rb.Push(result); | ||||
|     rb.PushRaw(entry); | ||||
| } | ||||
| 
 | ||||
| void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     struct Parameters { | ||||
|         ScreenShotAttribute attribute{}; | ||||
|         AlbumReportOption report_option{}; | ||||
|         INSERT_PADDING_BYTES(0x4); | ||||
|         u64 applet_resource_user_id{}; | ||||
|     }; | ||||
|     static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); | ||||
| 
 | ||||
|     const auto parameters{rp.PopRaw<Parameters>()}; | ||||
|     const auto app_data_buffer = ctx.ReadBuffer(0); | ||||
|     const auto image_data_buffer = ctx.ReadBuffer(1); | ||||
| 
 | ||||
|     LOG_INFO(Service_Capture, | ||||
|              "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", | ||||
|              parameters.report_option, image_data_buffer.size(), | ||||
|              parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     ApplicationAlbumEntry entry{}; | ||||
|     ApplicationData app_data{}; | ||||
|     std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); | ||||
|     const auto result = | ||||
|         manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer, | ||||
|                                 parameters.applet_resource_user_id); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 10}; | ||||
|     rb.Push(result); | ||||
|     rb.PushRaw(entry); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Capture
 | ||||
|  | ||||
| @ -10,14 +10,20 @@ class System; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Capture { | ||||
| class AlbumManager; | ||||
| 
 | ||||
| class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { | ||||
| public: | ||||
|     explicit IScreenShotApplicationService(Core::System& system_); | ||||
|     explicit IScreenShotApplicationService(Core::System& system_, | ||||
|                                            std::shared_ptr<AlbumManager> album_manager); | ||||
|     ~IScreenShotApplicationService() override; | ||||
| 
 | ||||
| private: | ||||
|     void SetShimLibraryVersion(HLERequestContext& ctx); | ||||
|     void SaveScreenShotEx0(HLERequestContext& ctx); | ||||
|     void SaveScreenShotEx1(HLERequestContext& ctx); | ||||
| 
 | ||||
|     std::shared_ptr<AlbumManager> manager; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Capture
 | ||||
|  | ||||
| @ -20,6 +20,8 @@ enum class AlbumImageOrientation { | ||||
| enum class AlbumReportOption : s32 { | ||||
|     Disable, | ||||
|     Enable, | ||||
|     Unknown2, | ||||
|     Unknown3, | ||||
| }; | ||||
| 
 | ||||
| enum class ContentType : u8 { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user