diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 976314f90..a3b3ee8ec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -162,7 +162,7 @@ jobs: path: upload/ macos-sdl: - runs-on: macos-latest + runs-on: macos-15 needs: get-info steps: - uses: actions/checkout@v4 @@ -218,7 +218,7 @@ jobs: path: shadps4-macos-sdl.tar.gz macos-qt: - runs-on: macos-latest + runs-on: macos-15 needs: get-info steps: - uses: actions/checkout@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 036f74309..439663352 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,6 +366,10 @@ set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp src/core/libraries/videodec/videodec2.cpp src/core/libraries/videodec/videodec2.h src/core/libraries/videodec/videodec2_avc.h + src/core/libraries/videodec/videodec.cpp + src/core/libraries/videodec/videodec.h + src/core/libraries/videodec/videodec_impl.cpp + src/core/libraries/videodec/videodec_impl.h ) set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index a76c472a7..5ca594bf7 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -120,6 +120,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, SharePlay) \ SUB(Lib, Fiber) \ SUB(Lib, Vdec2) \ + SUB(Lib, Videodec) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index fd7dcfd1a..2821729d4 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -87,6 +87,7 @@ enum class Class : u8 { Lib_SharePlay, ///< The LibSceSharePlay implemenation Lib_Fiber, ///< The LibSceFiber implementation. Lib_Vdec2, ///< The LibSceVideodec2 implementation. + Lib_Videodec, ///< The LibSceVideodec implementation. Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index 66ad5f8b6..6bbdc3080 100644 --- a/src/core/libraries/error_codes.h +++ b/src/core/libraries/error_codes.h @@ -590,4 +590,29 @@ constexpr int ORBIS_VIDEODEC2_ERROR_NEW_SEQUENCE = 0x811D0300; constexpr int ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT = 0x811D0301; constexpr int ORBIS_VIDEODEC2_ERROR_OVERSIZE_DECODE = 0x811D0302; constexpr int ORBIS_VIDEODEC2_ERROR_INVALID_SEQUENCE = 0x811D0303; -constexpr int ORBIS_VIDEODEC2_ERROR_FATAL_STREAM = 0x811D0304; \ No newline at end of file +constexpr int ORBIS_VIDEODEC2_ERROR_FATAL_STREAM = 0x811D0304; + +// Videodec library + +constexpr int ORBIS_VIDEODEC_ERROR_API_FAIL = 0x80C10000; +constexpr int ORBIS_VIDEODEC_ERROR_CODEC_TYPE = 0x80C10001; +constexpr int ORBIS_VIDEODEC_ERROR_STRUCT_SIZE = 0x80C10002; +constexpr int ORBIS_VIDEODEC_ERROR_HANDLE = 0x80C10003; +constexpr int ORBIS_VIDEODEC_ERROR_CPU_MEMORY_SIZE = 0x80C10004; +constexpr int ORBIS_VIDEODEC_ERROR_CPU_MEMORY_POINTER = 0x80C10005; +constexpr int ORBIS_VIDEODEC_ERROR_CPU_GPU_MEMORY_SIZE = 0x80C10006; +constexpr int ORBIS_VIDEODEC_ERROR_CPU_GPU_MEMORY_POINTER = 0x80C10007; +constexpr int ORBIS_VIDEODEC_ERROR_SHADER_CONTEXT_POINTER = 0x80C10008; +constexpr int ORBIS_VIDEODEC_ERROR_AU_SIZE = 0x80C10009; +constexpr int ORBIS_VIDEODEC_ERROR_AU_POINTER = 0x80C1000A; +constexpr int ORBIS_VIDEODEC_ERROR_FRAME_BUFFER_SIZE = 0x80C1000B; +constexpr int ORBIS_VIDEODEC_ERROR_FRAME_BUFFER_POINTER = 0x80C1000C; +constexpr int ORBIS_VIDEODEC_ERROR_FRAME_BUFFER_ALIGNMENT = 0x80C1000D; +constexpr int ORBIS_VIDEODEC_ERROR_CONFIG_INFO = 0x80C1000E; +constexpr int ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER = 0x80C1000F; +constexpr int ORBIS_VIDEODEC_ERROR_NEW_SEQUENCE = 0x80C10010; +constexpr int ORBIS_VIDEODEC_ERROR_DECODE_AU = 0x80C10011; +constexpr int ORBIS_VIDEODEC_ERROR_MISMATCH_SPEC = 0x80C10012; +constexpr int ORBIS_VIDEODEC_ERROR_INVALID_SEQUENCE = 0x80C10013; +constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STREAM = 0x80C10014; +constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STATE = 0x80C10015; diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index b0365435b..23d751622 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -41,6 +41,7 @@ #include "core/libraries/system/systemservice.h" #include "core/libraries/system/userservice.h" #include "core/libraries/usbd/usbd.h" +#include "core/libraries/videodec/videodec.h" #include "core/libraries/videodec/videodec2.h" #include "core/libraries/videoout/video_out.h" @@ -87,6 +88,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::GameLiveStreaming::RegisterlibSceGameLiveStreaming(sym); Libraries::SharePlay::RegisterlibSceSharePlay(sym); Libraries::Remoteplay::RegisterlibSceRemoteplay(sym); + Libraries::Videodec::RegisterlibSceVideodec(sym); } } // namespace Libraries diff --git a/src/core/libraries/videodec/videodec.cpp b/src/core/libraries/videodec/videodec.cpp new file mode 100644 index 000000000..96ece3c5c --- /dev/null +++ b/src/core/libraries/videodec/videodec.cpp @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "videodec.h" + +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "videodec_impl.h" + +namespace Libraries::Videodec { + +static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying + +int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn, + const OrbisVideodecResourceInfo* pRsrcInfoIn, + OrbisVideodecCtrl* pCtrlOut) { + LOG_INFO(Lib_Videodec, "called"); + + if (!pCfgInfoIn || !pRsrcInfoIn || !pCtrlOut) { + return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; + } + if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) || + pRsrcInfoIn->thisSize != sizeof(OrbisVideodecResourceInfo)) { + return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; + } + + VdecDecoder* decoder = new VdecDecoder(*pCfgInfoIn, *pRsrcInfoIn); + pCtrlOut->thisSize = sizeof(OrbisVideodecCtrl); + pCtrlOut->handle = decoder; + pCtrlOut->version = 1; //??? + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn, + const OrbisVideodecInputData* pInputDataIn, + OrbisVideodecFrameBuffer* pFrameBufferInOut, + OrbisVideodecPictureInfo* pPictureInfoOut) { + LOG_INFO(Lib_Videodec, "called"); + if (!pCtrlIn || !pInputDataIn || !pPictureInfoOut) { + return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; + } + if (pCtrlIn->thisSize != sizeof(OrbisVideodecCtrl) || + pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer)) { + return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; + } + + VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; + if (!decoder) { + return ORBIS_VIDEODEC_ERROR_HANDLE; + } + return decoder->Decode(*pInputDataIn, *pFrameBufferInOut, *pPictureInfoOut); +} + +int PS4_SYSV_ABI sceVideodecDeleteDecoder(OrbisVideodecCtrl* pCtrlIn) { + LOG_INFO(Lib_Videodec, "(STUBBED) called"); + + VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; + if (!decoder) { + return ORBIS_VIDEODEC_ERROR_HANDLE; + } + delete decoder; + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceVideodecFlush(OrbisVideodecCtrl* pCtrlIn, + OrbisVideodecFrameBuffer* pFrameBufferInOut, + OrbisVideodecPictureInfo* pPictureInfoOut) { + LOG_INFO(Lib_Videodec, "called"); + + if (!pFrameBufferInOut || !pPictureInfoOut) { + return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; + } + if (pFrameBufferInOut->thisSize != sizeof(OrbisVideodecFrameBuffer) || + pPictureInfoOut->thisSize != sizeof(OrbisVideodecPictureInfo)) { + return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; + } + + VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; + if (!decoder) { + return ORBIS_VIDEODEC_ERROR_HANDLE; + } + return decoder->Flush(*pFrameBufferInOut, *pPictureInfoOut); +} + +int PS4_SYSV_ABI sceVideodecMapMemory() { + LOG_ERROR(Lib_Videodec, "(STUBBED) called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCfgInfoIn, + OrbisVideodecResourceInfo* pRsrcInfoOut) { + LOG_INFO(Lib_Videodec, "called"); + + if (!pCfgInfoIn || !pRsrcInfoOut) { + return ORBIS_VIDEODEC_ERROR_ARGUMENT_POINTER; + } + if (pCfgInfoIn->thisSize != sizeof(OrbisVideodecConfigInfo) || + pRsrcInfoOut->thisSize != sizeof(OrbisVideodecResourceInfo)) { + return ORBIS_VIDEODEC_ERROR_STRUCT_SIZE; + } + + pRsrcInfoOut->thisSize = sizeof(OrbisVideodecResourceInfo); + pRsrcInfoOut->pCpuMemory = nullptr; + pRsrcInfoOut->pCpuGpuMemory = nullptr; + + pRsrcInfoOut->cpuGpuMemorySize = kMinimumMemorySize; + pRsrcInfoOut->cpuMemorySize = kMinimumMemorySize; + + pRsrcInfoOut->maxFrameBufferSize = kMinimumMemorySize; + pRsrcInfoOut->frameBufferAlignment = 0x100; + + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceVideodecReset(OrbisVideodecCtrl* pCtrlIn) { + LOG_INFO(Lib_Videodec, "(STUBBED) called"); + + VdecDecoder* decoder = (VdecDecoder*)pCtrlIn->handle; + decoder->Reset(); + return ORBIS_OK; +} + +void RegisterlibSceVideodec(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("qkgRiwHyheU", "libSceVideodec", 1, "libSceVideodec", 1, 1, + sceVideodecCreateDecoder); + LIB_FUNCTION("q0W5GJMovMs", "libSceVideodec", 1, "libSceVideodec", 1, 1, sceVideodecDecode); + LIB_FUNCTION("U0kpGF1cl90", "libSceVideodec", 1, "libSceVideodec", 1, 1, + sceVideodecDeleteDecoder); + LIB_FUNCTION("jeigLlKdp5I", "libSceVideodec", 1, "libSceVideodec", 1, 1, sceVideodecFlush); + LIB_FUNCTION("kg+lH0V61hM", "libSceVideodec", 1, "libSceVideodec", 1, 1, sceVideodecMapMemory); + LIB_FUNCTION("leCAscipfFY", "libSceVideodec", 1, "libSceVideodec", 1, 1, + sceVideodecQueryResourceInfo); + LIB_FUNCTION("f8AgDv-1X8A", "libSceVideodec", 1, "libSceVideodec", 1, 1, sceVideodecReset); +}; + +} // namespace Libraries::Videodec \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec.h b/src/core/libraries/videodec/videodec.h new file mode 100644 index 000000000..45c5a6924 --- /dev/null +++ b/src/core/libraries/videodec/videodec.h @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Videodec { + +struct OrbisVideodecConfigInfo { + u64 thisSize; + u32 codecType; + u32 profile; + u32 maxLevel; + s32 maxFrameWidth; + s32 maxFrameHeight; + s32 maxDpbFrameCount; + u64 videodecFlags; +}; + +struct OrbisVideodecResourceInfo { + u64 thisSize; + u64 cpuMemorySize; + void* pCpuMemory; + u64 cpuGpuMemorySize; + void* pCpuGpuMemory; + u64 maxFrameBufferSize; + u32 frameBufferAlignment; +}; + +struct OrbisVideodecCtrl { + u64 thisSize; + void* handle; + u64 version; +}; + +struct OrbisVideodecFrameBuffer { + u64 thisSize; + void* pFrameBuffer; + u64 frameBufferSize; +}; + +struct OrbisVideodecAvcInfo { + u32 numUnitsInTick; + u32 timeScale; + u8 fixedFrameRateFlag; + u8 aspectRatioIdc; + u16 sarWidth; + u16 sarHeight; + u8 colourPrimaries; + u8 transferCharacteristics; + u8 matrixCoefficients; + u8 videoFullRangeFlag; + u32 frameCropLeftOffset; + u32 frameCropRightOffset; + u32 frameCropTopOffset; + u32 frameCropBottomOffset; +}; + +union OrbisVideodecCodecInfo { + u8 reserved[64]; + OrbisVideodecAvcInfo avc; +}; + +struct OrbisVideodecPictureInfo { + u64 thisSize; + u32 isValid; + u32 codecType; + u32 frameWidth; + u32 framePitch; + u32 frameHeight; + u32 isErrorPic; + u64 ptsData; + u64 attachedData; + OrbisVideodecCodecInfo codec; +}; + +struct OrbisVideodecInputData { + u64 thisSize; + void* pAuData; + u64 auSize; + u64 ptsData; + u64 dtsData; + u64 attachedData; +}; + +int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn, + const OrbisVideodecResourceInfo* pRsrcInfoIn, + OrbisVideodecCtrl* pCtrlOut); +int PS4_SYSV_ABI sceVideodecDecode(OrbisVideodecCtrl* pCtrlIn, + const OrbisVideodecInputData* pInputDataIn, + OrbisVideodecFrameBuffer* pFrameBufferInOut, + OrbisVideodecPictureInfo* pPictureInfoOut); +int PS4_SYSV_ABI sceVideodecDeleteDecoder(OrbisVideodecCtrl* pCtrlIn); +int PS4_SYSV_ABI sceVideodecFlush(OrbisVideodecCtrl* pCtrlIn, + OrbisVideodecFrameBuffer* pFrameBufferInOut, + OrbisVideodecPictureInfo* pPictureInfoOut); +int PS4_SYSV_ABI sceVideodecMapMemory(); +int PS4_SYSV_ABI sceVideodecQueryResourceInfo(const OrbisVideodecConfigInfo* pCfgInfoIn, + OrbisVideodecResourceInfo* pRsrcInfoOut); +int PS4_SYSV_ABI sceVideodecReset(OrbisVideodecCtrl* pCtrlIn); + +void RegisterlibSceVideodec(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Videodec \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec_impl.cpp b/src/core/libraries/videodec/videodec_impl.cpp new file mode 100644 index 000000000..a244c4a61 --- /dev/null +++ b/src/core/libraries/videodec/videodec_impl.cpp @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "videodec_impl.h" + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" + +// The av_err2str macro in libavutil/error.h does not play nice with C++ +#ifdef av_err2str +#undef av_err2str +#include +av_always_inline std::string av_err2string(int errnum) { + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + return av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, errnum); +} +#define av_err2str(err) av_err2string(err).c_str() +#endif // av_err2str + +namespace Libraries::Videodec { + +static inline void CopyNV12Data(u8* dst, const AVFrame& src) { + u32 width = Common::AlignUp((u32)src.width, 16); + u32 height = Common::AlignUp((u32)src.height, 16); + std::memcpy(dst, src.data[0], src.width * src.height); + std::memcpy(dst + src.width * height, src.data[1], (src.width * src.height) / 2); +} + +VdecDecoder::VdecDecoder(const OrbisVideodecConfigInfo& pCfgInfoIn, + const OrbisVideodecResourceInfo& pRsrcInfoIn) { + + const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); + ASSERT(codec); + + mCodecContext = avcodec_alloc_context3(codec); + ASSERT(mCodecContext); + mCodecContext->width = pCfgInfoIn.maxFrameWidth; + mCodecContext->height = pCfgInfoIn.maxFrameHeight; + + avcodec_open2(mCodecContext, codec, nullptr); +} + +VdecDecoder::~VdecDecoder() { + avcodec_free_context(&mCodecContext); + sws_freeContext(mSwsContext); +} + +s32 VdecDecoder::Decode(const OrbisVideodecInputData& pInputDataIn, + OrbisVideodecFrameBuffer& pFrameBufferInOut, + OrbisVideodecPictureInfo& pPictureInfoOut) { + pPictureInfoOut.thisSize = sizeof(OrbisVideodecPictureInfo); + pPictureInfoOut.isValid = false; + pPictureInfoOut.isErrorPic = true; + + if (!pInputDataIn.pAuData) { + return ORBIS_VIDEODEC_ERROR_AU_POINTER; + } + if (pInputDataIn.auSize == 0) { + return ORBIS_VIDEODEC_ERROR_AU_SIZE; + } + + AVPacket* packet = av_packet_alloc(); + if (!packet) { + LOG_ERROR(Lib_Videodec, "Failed to allocate packet"); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + + packet->data = (u8*)pInputDataIn.pAuData; + packet->size = pInputDataIn.auSize; + packet->pts = pInputDataIn.ptsData; + packet->dts = pInputDataIn.dtsData; + + int ret = avcodec_send_packet(mCodecContext, packet); + if (ret < 0) { + LOG_ERROR(Lib_Videodec, "Error sending packet to decoder: {}", ret); + av_packet_free(&packet); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + + AVFrame* frame = av_frame_alloc(); + if (frame == nullptr) { + LOG_ERROR(Lib_Videodec, "Failed to allocate frame"); + av_packet_free(&packet); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + int frameCount = 0; + while (true) { + ret = avcodec_receive_frame(mCodecContext, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + LOG_ERROR(Lib_Videodec, "Error receiving frame from decoder: {}", ret); + av_packet_free(&packet); + av_frame_free(&frame); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + + if (frame->format != AV_PIX_FMT_NV12) { + AVFrame* nv12_frame = ConvertNV12Frame(*frame); + ASSERT(nv12_frame); + av_frame_free(&frame); + frame = nv12_frame; + } + + CopyNV12Data((u8*)pFrameBufferInOut.pFrameBuffer, *frame); + + pPictureInfoOut.codecType = 0; + pPictureInfoOut.frameWidth = Common::AlignUp((u32)frame->width, 16); + pPictureInfoOut.frameHeight = Common::AlignUp((u32)frame->height, 16); + pPictureInfoOut.framePitch = frame->linesize[0]; + + pPictureInfoOut.isValid = true; + pPictureInfoOut.isErrorPic = false; + frameCount++; + if (frameCount > 1) { + LOG_WARNING(Lib_Videodec, "We have more than 1 frame"); + } + } + + av_packet_free(&packet); + av_frame_free(&frame); + return ORBIS_OK; +} + +s32 VdecDecoder::Flush(OrbisVideodecFrameBuffer& pFrameBufferInOut, + OrbisVideodecPictureInfo& pPictureInfoOut) { + pPictureInfoOut.thisSize = sizeof(pPictureInfoOut); + pPictureInfoOut.isValid = false; + pPictureInfoOut.isErrorPic = true; + + AVFrame* frame = av_frame_alloc(); + if (!frame) { + LOG_ERROR(Lib_Videodec, "Failed to allocate frame"); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + + int frameCount = 0; + while (true) { + int ret = avcodec_receive_frame(mCodecContext, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + LOG_ERROR(Lib_Videodec, "Error receiving frame from decoder: {}", ret); + av_frame_free(&frame); + return ORBIS_VIDEODEC_ERROR_API_FAIL; + } + + if (frame->format != AV_PIX_FMT_NV12) { + AVFrame* nv12_frame = ConvertNV12Frame(*frame); + ASSERT(nv12_frame); + av_frame_free(&frame); + frame = nv12_frame; + } + + CopyNV12Data((u8*)pFrameBufferInOut.pFrameBuffer, *frame); + + pPictureInfoOut.codecType = 0; + pPictureInfoOut.frameWidth = Common::AlignUp((u32)frame->width, 16); + pPictureInfoOut.frameHeight = Common::AlignUp((u32)frame->height, 16); + pPictureInfoOut.framePitch = frame->linesize[0]; + + pPictureInfoOut.isValid = true; + pPictureInfoOut.isErrorPic = false; + + u32 width = Common::AlignUp((u32)frame->width, 16); + u32 height = Common::AlignUp((u32)frame->height, 16); + pPictureInfoOut.codec.avc.frameCropLeftOffset = u32(frame->crop_left); + pPictureInfoOut.codec.avc.frameCropRightOffset = + u32(frame->crop_right + (width - frame->width)); + pPictureInfoOut.codec.avc.frameCropTopOffset = u32(frame->crop_top); + pPictureInfoOut.codec.avc.frameCropBottomOffset = + u32(frame->crop_bottom + (height - frame->height)); + // TODO maybe more avc? + + if (frameCount > 1) { + LOG_WARNING(Lib_Videodec, "We have more than 1 frame"); + } + } + + av_frame_free(&frame); + return ORBIS_OK; +} + +s32 VdecDecoder::Reset() { + avcodec_flush_buffers(mCodecContext); + return ORBIS_OK; +} + +AVFrame* VdecDecoder::ConvertNV12Frame(AVFrame& frame) { + AVFrame* nv12_frame = av_frame_alloc(); + nv12_frame->pts = frame.pts; + nv12_frame->pkt_dts = frame.pkt_dts < 0 ? 0 : frame.pkt_dts; + nv12_frame->format = AV_PIX_FMT_NV12; + nv12_frame->width = frame.width; + nv12_frame->height = frame.height; + nv12_frame->sample_aspect_ratio = frame.sample_aspect_ratio; + nv12_frame->crop_top = frame.crop_top; + nv12_frame->crop_bottom = frame.crop_bottom; + nv12_frame->crop_left = frame.crop_left; + nv12_frame->crop_right = frame.crop_right; + + av_frame_get_buffer(nv12_frame, 0); + + if (mSwsContext == nullptr) { + mSwsContext = sws_getContext(frame.width, frame.height, AVPixelFormat(frame.format), + nv12_frame->width, nv12_frame->height, AV_PIX_FMT_NV12, + SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); + } + + const auto res = sws_scale(mSwsContext, frame.data, frame.linesize, 0, frame.height, + nv12_frame->data, nv12_frame->linesize); + if (res < 0) { + LOG_ERROR(Lib_Videodec, "Could not convert to NV12: {}", av_err2str(res)); + return nullptr; + } + + return nv12_frame; +} + +} // namespace Libraries::Videodec diff --git a/src/core/libraries/videodec/videodec_impl.h b/src/core/libraries/videodec/videodec_impl.h new file mode 100644 index 000000000..3d48db608 --- /dev/null +++ b/src/core/libraries/videodec/videodec_impl.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "videodec.h" + +extern "C" { +#include +#include +#include +} + +namespace Libraries::Videodec { + +class VdecDecoder { +public: + VdecDecoder(const OrbisVideodecConfigInfo& pCfgInfoIn, + const OrbisVideodecResourceInfo& pRsrcInfoIn); + ~VdecDecoder(); + s32 Decode(const OrbisVideodecInputData& pInputDataIn, + OrbisVideodecFrameBuffer& pFrameBufferInOut, + OrbisVideodecPictureInfo& pPictureInfoOut); + s32 Flush(OrbisVideodecFrameBuffer& pFrameBufferInOut, + OrbisVideodecPictureInfo& pPictureInfoOut); + s32 Reset(); + +private: + AVFrame* ConvertNV12Frame(AVFrame& frame); + +private: + AVCodecContext* mCodecContext = nullptr; + SwsContext* mSwsContext = nullptr; +}; + +} // namespace Libraries::Videodec \ No newline at end of file diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 8d7018522..823ad921c 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -44,20 +44,31 @@ public: // Setup menu. QMenu menu(widget); + + // "Open Folder..." submenu + QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget); + QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget); + QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget); + QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget); + + openFolderMenu->addAction(openGameFolder); + openFolderMenu->addAction(openSaveDataFolder); + openFolderMenu->addAction(openLogFolder); + + menu.addMenu(openFolderMenu); + QAction createShortcut(tr("Create Shortcut"), widget); - QAction openFolder(tr("Open Game Folder"), widget); QAction openCheats(tr("Cheats / Patches"), widget); QAction openSfoViewer(tr("SFO Viewer"), widget); QAction openTrophyViewer(tr("Trophy Viewer"), widget); - menu.addAction(&openFolder); menu.addAction(&createShortcut); menu.addAction(&openCheats); menu.addAction(&openSfoViewer); menu.addAction(&openTrophyViewer); // "Copy" submenu. - QMenu* copyMenu = new QMenu(tr("Copy info"), widget); + QMenu* copyMenu = new QMenu(tr("Copy info..."), widget); QAction* copyName = new QAction(tr("Copy Name"), widget); QAction* copySerial = new QAction(tr("Copy Serial"), widget); QAction* copyNameAll = new QAction(tr("Copy All"), widget); @@ -86,12 +97,29 @@ public: return; } - if (selected == &openFolder) { + if (selected == openGameFolder) { QString folderPath; Common::FS::PathToQString(folderPath, m_games[itemID].path); QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath)); } + if (selected == openSaveDataFolder) { + QString userPath; + Common::FS::PathToQString(userPath, + Common::FS::GetUserPath(Common::FS::PathType::UserDir)); + QString saveDataPath = + userPath + "/savedata/1/" + QString::fromStdString(m_games[itemID].serial); + QDir(saveDataPath).mkpath(saveDataPath); + QDesktopServices::openUrl(QUrl::fromLocalFile(saveDataPath)); + } + + if (selected == openLogFolder) { + QString userPath; + Common::FS::PathToQString(userPath, + Common::FS::GetUserPath(Common::FS::PathType::UserDir)); + QDesktopServices::openUrl(QUrl::fromLocalFile(userPath + "/log")); + } + if (selected == &openSfoViewer) { PSF psf; QString game_update_path; diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index 457d84ef8..25e215183 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -100,11 +100,6 @@ Create Shortcut إنشاء اختصار - - - Open Game Folder - فتح مجلد اللعبة - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer عارض الجوائز + + + Open Folder... + فتح المجلد... + + + + Open Game Folder + فتح مجلد اللعبة + + + + Open Save Data Folder + فتح مجلد بيانات الحفظ + + + + Open Log Folder + فتح مجلد السجل + - Copy info - نسخ المعلومات + Copy info... + ...نسخ المعلومات diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index e14826725..14c42f1d9 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Åbn Mappe... + + + + Open Game Folder + Åbn Spilmappe + + + + Open Save Data Folder + Åbn Gem Data Mappe + + + + Open Log Folder + Åbn Log Mappe + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 77b6a01ac..64a6c6480 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -100,11 +100,6 @@ Create Shortcut Verknüpfung erstellen - - - Open Game Folder - Spieleordner öffnen - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophäen anzeigen + + + Open Folder... + Ordner öffnen... + + + + Open Game Folder + Spielordner öffnen + + + + Open Save Data Folder + Speicherordner öffnen + + + + Open Log Folder + Protokollordner öffnen + - Copy info - Infos kopieren + Copy info... + Infos kopieren... diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index a738bf90a..e064f8c26 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Άνοιγμα Φακέλου... + + + + Open Game Folder + Άνοιγμα Φακέλου Παιχνιδιού + + + + Open Save Data Folder + Άνοιγμα Φακέλου Αποθηκευμένων Δεδομένων + + + + Open Log Folder + Άνοιγμα Φακέλου Καταγραφής + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 9f25fc836..9bf7c7188 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Open Folder... + + + + Open Game Folder + Open Game Folder + + + + Open Save Data Folder + Open Save Data Folder + + + + Open Log Folder + Open Log Folder + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index b0a6e4335..5d637249e 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -100,11 +100,6 @@ Create Shortcut Crear acceso directo - - - Open Game Folder - Abrir carpeta del juego - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Ver trofeos + + + Open Folder... + Abrir Carpeta... + + + + Open Game Folder + Abrir Carpeta del Juego + + + + Open Save Data Folder + Abrir Carpeta de Datos Guardados + + + + Open Log Folder + Abrir Carpeta de Registros + - Copy info - Copiar información + Copy info... + Copiar información... diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 15f5d6193..55a2fdf53 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -100,11 +100,6 @@ Create Shortcut ساخت شورتکات - - - Open Game Folder - بازکردن محل نصب بازی - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer مشاهده تروفی ها + + + Open Folder... + باز کردن پوشه... + - Copy info - کپی کردن اطلاعات + Open Game Folder + باز کردن پوشه بازی + + + + Open Save Data Folder + پوشه ذخیره داده را باز کنید + + + + Open Log Folder + باز کردن پوشه لاگ + + + + Copy info... + ...کپی کردن اطلاعات diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index cb7426e01..4d160bf6b 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Avaa Kansio... + + + + Open Game Folder + Avaa Pelikansio + + + + Open Save Data Folder + Avaa Tallennustiedostokansio + + + + Open Log Folder + Avaa Lokikansio + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 4c2d5cbdd..39cd11bf6 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -100,11 +100,6 @@ Create Shortcut Créer un raccourci - - - Open Game Folder - Ouvrir le dossier du jeu - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Visionneuse de trophées + + + Open Folder... + Ouvrir le Dossier... + + + + Open Game Folder + Ouvrir le Dossier du Jeu + + + + Open Save Data Folder + Ouvrir le Dossier des Données de Sauvegarde + + + + Open Log Folder + Ouvrir le Dossier des Logs + - Copy info - Copier infos + Copy info... + Copier infos... diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 633ba9810..86279b2de 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -100,11 +100,6 @@ Create Shortcut Parancsikon Létrehozása - - - Open Game Folder - Játék Mappa Megnyitása - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trófeák Megtekintése + + + Open Folder... + Mappa megnyitása... + - Copy info - Információ Másolása + Open Game Folder + Játék Mappa Megnyitása + + + + Open Save Data Folder + Mentési adatok mappa megnyitása + + + + Open Log Folder + Napló mappa megnyitása + + + + Copy info... + Információ Másolása... diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index f841ad3a8..d616f1cf3 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Buka Folder... + + + + Open Game Folder + Buka Folder Game + + + + Open Save Data Folder + Buka Folder Data Simpanan + + + + Open Log Folder + Buka Folder Log + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index b6eb13240..c59289314 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -100,11 +100,6 @@ Create Shortcut Crea scorciatoia - - - Open Game Folder - Apri cartella del gioco - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Visualizzatore Trofei + + + Open Folder... + Apri Cartella... + + + + Open Game Folder + Apri Cartella del Gioco + + + + Open Save Data Folder + Apri Cartella dei Dati di Salvataggio + + + + Open Log Folder + Apri Cartella dei Log + - Copy info - Copia informazioni + Copy info... + Copia informazioni... diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index a79b34e2a..f4a4b15ad 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -100,11 +100,6 @@ Create Shortcut ショートカットを作成 - - - Open Game Folder - ゲームフォルダを開く - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer トロフィービューワー + + + Open Folder... + フォルダを開く... + + + + Open Game Folder + ゲームフォルダを開く + + + + Open Save Data Folder + セーブデータフォルダを開く + + + + Open Log Folder + ログフォルダを開く + - Copy info - 情報をコピー + Copy info... + 情報をコピー... diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 6ef89ea24..2fa3ee153 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Open Folder... + + + + Open Game Folder + Open Game Folder + + + + Open Save Data Folder + Open Save Data Folder + + + + Open Log Folder + Open Log Folder + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index d7fc6e844..16aaf5d86 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Apgaulės / Pleistrai @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Atidaryti Katalogą... + + + + Open Game Folder + Atidaryti Žaidimo Katalogą + + + + Open Save Data Folder + Atidaryti Išsaugotų Duomenų Katalogą + + + + Open Log Folder + Atidaryti Žurnalų Katalogą + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index cdcf4d5fb..940c6c9b6 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Åpne Mappen... + + + + Open Game Folder + Åpne Spillmappe + + + + Open Save Data Folder + Åpne Lagrede Data-mappen + + + + Open Log Folder + Åpne Loggmappen + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 380d90705..b0cfaff5e 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Map openen... + + + + Open Game Folder + Open Spelmap + + + + Open Save Data Folder + Open Map voor Opslagdata + + + + Open Log Folder + Open Logmap + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 5d211734e..4d11c13f6 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -100,11 +100,6 @@ Create Shortcut Utwórz skrót - - - Open Game Folder - Otwórz katalog gry - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Menedżer trofeów + + + Open Folder... + Otwórz Folder... + + + + Open Game Folder + Otwórz Katalog Gry + + + + Open Save Data Folder + Otwórz Folder Danych Zapisów + + + + Open Log Folder + Otwórz Folder Dziennika + - Copy info - Kopiuj informacje + Copy info... + Kopiuj informacje... diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index eb79fade4..f1d3631d8 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -100,11 +100,6 @@ Create Shortcut Criar Atalho - - - Open Game Folder - Abrir Pasta do Jogo - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Visualizador de Troféu + + + Open Folder... + Abrir Pasta... + + + + Open Game Folder + Abrir Pasta do Jogo + + + + Open Save Data Folder + Abrir Pasta de Save + + + + Open Log Folder + Abrir Pasta de Log + - Copy info - Copiar informação + Copy info... + Copiar informação... diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 603cd3a24..fff0bcddb 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Trapaças / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Deschide Folder... + + + + Open Game Folder + Deschide Folder Joc + + + + Open Save Data Folder + Deschide Folder Date Salvate + + + + Open Log Folder + Deschide Folder Jurnal + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 4c58786c4..052623235 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -100,11 +100,6 @@ Create Shortcut Создать ярлык - - - Open Game Folder - Открыть папку с игрой - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Просмотр трофеев + + + Open Folder... + Открыть Папку... + + + + Open Game Folder + Открыть папку с игрой + + + + Open Save Data Folder + Открыть Папку Сохранений + + + + Open Log Folder + Открыть Папку Логов + - Copy info - Копировать информацию + Copy info... + Копировать информацию... diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 00fd5cb48..5715371bf 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -100,11 +100,6 @@ Create Shortcut Krijo Shkurtore - - - Open Game Folder - Hap Dosjen e Lojës - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Shikuesi i Trofeve + + + Open Folder... + Hapni Dosjen... + + + + Open Game Folder + Hapni Dosjen e Lojës + + + + Open Save Data Folder + Hapni Dosjen e të Dhënave të Ruajtura + + + + Open Log Folder + Hapni Dosjen e Regjistrimeve + - Copy info - Kopjo informacionin + Copy info... + Kopjo informacionin... diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 6c4913603..335465778 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -100,11 +100,6 @@ Create Shortcut Kısayol Oluştur - - - Open Game Folder - Oyun Klasörünü Aç - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Kupa Görüntüleyici + + + Open Folder... + Klasörü Aç... + + + + Open Game Folder + Oyun Klasörünü Aç + + + + Open Save Data Folder + Kaydetme Verileri Klasörünü Aç + + + + Open Log Folder + Log Klasörünü Aç + - Copy info - Bilgiyi Kopyala + Copy info... + Bilgiyi Kopyala... diff --git a/src/qt_gui/translations/uk_UA.ts b/src/qt_gui/translations/uk_UA.ts index 61c884986..31bfe9dba 100644 --- a/src/qt_gui/translations/uk_UA.ts +++ b/src/qt_gui/translations/uk_UA.ts @@ -100,11 +100,6 @@ Create Shortcut Створити Ярлик - - - Open Game Folder - Відкрити папку з грою - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Перегляд трофеїв + + + Open Folder... + Відкрити Папку... + + + + Open Game Folder + Відкрити папку з грою + + + + Open Save Data Folder + Відкрити Папку Збережених Даних + + + + Open Log Folder + Відкрити Папку Логів + - Copy info - Копіювати інформацію + Copy info... + Копіювати інформацію... diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 5fca6b6b5..223cb9ed0 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + Mở Thư Mục... + + + + Open Game Folder + Mở Thư Mục Trò Chơi + + + + Open Save Data Folder + Mở Thư Mục Dữ Liệu Lưu + + + + Open Log Folder + Mở Thư Mục Nhật Ký + - Copy info - Copy info + Copy info... + Copy info... diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index bfcbbaa98..4fe1f7c42 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -100,11 +100,6 @@ Create Shortcut 创建快捷方式 - - - Open Game Folder - 打开游戏文件夹 - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy 查看器 + + + Open Folder... + 打开文件夹... + + + + Open Game Folder + 打开游戏文件夹 + + + + Open Save Data Folder + 打开保存数据文件夹 + + + + Open Log Folder + 打开日志文件夹 + - Copy info - 复制信息 + Copy info... + 复制信息... diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 84b32b7a5..4db00775d 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -100,11 +100,6 @@ Create Shortcut Create Shortcut - - - Open Game Folder - Open Game Folder - Cheats / Patches @@ -120,10 +115,30 @@ Trophy Viewer Trophy Viewer + + + Open Folder... + 打開資料夾... + + + + Open Game Folder + 打開遊戲資料夾 + + + + Open Save Data Folder + 打開存檔資料夾 + + + + Open Log Folder + 打開日誌資料夾 + - Copy info - Copy info + Copy info... + Copy info...