diff --git a/CMakeLists.txt b/CMakeLists.txt index 37021746d6..43760d5888 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,6 +338,13 @@ set(FIBER_LIB src/core/libraries/fiber/fiber.cpp src/core/libraries/fiber/fiber.h ) +set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp + src/core/libraries/videodec/videodec2_impl.h + src/core/libraries/videodec/videodec2.cpp + src/core/libraries/videodec/videodec2.h + src/core/libraries/videodec/videodec2_avc.h +) + set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp src/core/libraries/np_manager/np_manager.h src/core/libraries/np_score/np_score.cpp @@ -479,6 +486,7 @@ set(CORE src/core/aerolib/stubs.cpp ${MISC_LIBS} ${DIALOGS_LIB} ${FIBER_LIB} + ${VDEC_LIB} ${DEV_TOOLS} src/core/debug_state.cpp src/core/debug_state.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 051bbd79e5..a76c472a77 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -119,6 +119,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Remoteplay) \ SUB(Lib, SharePlay) \ SUB(Lib, Fiber) \ + SUB(Lib, Vdec2) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 39319d0dc2..fd7dcfd1aa 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -86,6 +86,7 @@ enum class Class : u8 { Lib_Remoteplay, ///< The LibSceRemotePlay implementation Lib_SharePlay, ///< The LibSceSharePlay implemenation Lib_Fiber, ///< The LibSceFiber implementation. + Lib_Vdec2, ///< The LibSceVideodec2 implementation. Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/fiber/fiber.cpp b/src/core/libraries/fiber/fiber.cpp index bd1575ddac..a0bfd68500 100644 --- a/src/core/libraries/fiber/fiber.cpp +++ b/src/core/libraries/fiber/fiber.cpp @@ -15,7 +15,7 @@ namespace Libraries::Fiber { -constexpr static u64 kFiberSignature = 0x054ad954; +static constexpr u64 kFiberSignature = 0x054ad954; thread_local SceFiber* gCurrentFiber = nullptr; thread_local void* gFiberThread = nullptr; diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index caa254fd84..2d953e0a57 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/videodec2.h" #include "core/libraries/videoout/video_out.h" namespace Libraries { @@ -80,6 +81,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::ErrorDialog::RegisterlibSceErrorDialog(sym); Libraries::ImeDialog::RegisterlibSceImeDialog(sym); Libraries::AvPlayer::RegisterlibSceAvPlayer(sym); + Libraries::Vdec2::RegisterlibSceVdec2(sym); Libraries::Audio3d::RegisterlibSceAudio3d(sym); Libraries::Ime::RegisterlibSceIme(sym); Libraries::GameLiveStreaming::RegisterlibSceGameLiveStreaming(sym); diff --git a/src/core/libraries/videodec/videodec2.cpp b/src/core/libraries/videodec/videodec2.cpp new file mode 100644 index 0000000000..2b85315f8a --- /dev/null +++ b/src/core/libraries/videodec/videodec2.cpp @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "videodec2.h" +#include "videodec2_impl.h" + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" + +namespace Libraries::Vdec2 { + +static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying + +int PS4_SYSV_ABI sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* pMemInfoOut) { + LOG_INFO(Lib_Vdec2, "called"); + + if (pMemInfoOut->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) { + return 0x811d0101; + } + + pMemInfoOut->pCpuGpuMemory = nullptr; + pMemInfoOut->cpuGpuMemorySize = kMinimumMemorySize; + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI +sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* pComputeCfgInfoIn, + const OrbisVideodec2ComputeMemoryInfo* pComputeMemInfoIn, + OrbisVideodec2ComputeQueue* pComputeQueueOut) { + LOG_INFO(Lib_Vdec2, "called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueueIn) { + LOG_INFO(Lib_Vdec2, "called"); + return ORBIS_OK; +} + +int PS4_SYSV_ABI +sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* pCfgInfoIn, + OrbisVideodec2DecoderMemoryInfo* pMemInfoOut) { + LOG_INFO(Lib_Vdec2, "called"); + + if ((pCfgInfoIn->thisSize == 0x48) && (pMemInfoOut->thisSize == 0x48)) { + pMemInfoOut->pCpuMemory = nullptr; + pMemInfoOut->pGpuMemory = nullptr; + pMemInfoOut->pCpuGpuMemory = nullptr; + + pMemInfoOut->cpuGpuMemorySize = kMinimumMemorySize; + pMemInfoOut->cpuMemorySize = kMinimumMemorySize; + pMemInfoOut->gpuMemorySize = kMinimumMemorySize; + + pMemInfoOut->maxFrameBufferSize = kMinimumMemorySize; + pMemInfoOut->frameBufferAlignment = kMinimumMemorySize; + } else { + return 0x811d0101; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI +sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* pDecoderConfigInfoIn, + const OrbisVideodec2DecoderMemoryInfo* pDecoderMemoryInfoIn, + OrbisVideodec2Decoder* pDecoderInstanceOut) { + LOG_INFO(Lib_Vdec2, "called"); + + *pDecoderInstanceOut = new VdecDecoder(*pDecoderConfigInfoIn, *pDecoderMemoryInfoIn); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) { + LOG_INFO(Lib_Vdec2, "called"); + delete decoder; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder, + const OrbisVideodec2InputData* pInputDataInOut, + OrbisVideodec2FrameBuffer* pFrameBufferInOut, + OrbisVideodec2OutputInfo* pOutputInfoOut) { + LOG_TRACE(Lib_Vdec2, "called"); + + if (decoder == nullptr) { + return 0x811D0103; // SCE_VIDEODEC2_ERROR_DECODER_INSTANCE; + } + + return decoder->Decode(*pInputDataInOut, *pFrameBufferInOut, *pOutputInfoOut); +} + +s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder, + OrbisVideodec2FrameBuffer* pFrameBufferInOut, + OrbisVideodec2OutputInfo* pOutputInfoOut) { + LOG_INFO(Lib_Vdec2, "called"); + + if (decoder == nullptr) { + return 0x811D0103; + } + + return decoder->Flush(*pFrameBufferInOut, *pOutputInfoOut); +} + +s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) { + LOG_INFO(Lib_Vdec2, "called"); + + if (decoder == nullptr) { + return 0x811D0103; + } + + return decoder->Reset(); +} + +s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* pOutputInfoIn, + void* p1stPictureInfoOut, void* p2ndPictureInfoOut) { + LOG_TRACE(Lib_Vdec2, "called"); + if (pOutputInfoIn->pictureCount == 0 || gPictureInfos.empty()) { + return 0; + } + + if (p1stPictureInfoOut) { + OrbisVideodec2AvcPictureInfo* picInfo = + static_cast(p1stPictureInfoOut); + *picInfo = gPictureInfos.back(); + } + + if (pOutputInfoIn->pictureCount > 1) { + UNREACHABLE(); + } + + return ORBIS_OK; +} + +void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("RnDibcGCPKw", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2QueryComputeMemoryInfo); + LIB_FUNCTION("eD+X2SmxUt4", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2AllocateComputeQueue); + LIB_FUNCTION("UvtA3FAiF4Y", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2ReleaseComputeQueue); + + LIB_FUNCTION("qqMCwlULR+E", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2QueryDecoderMemoryInfo); + LIB_FUNCTION("CNNRoRYd8XI", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2CreateDecoder); + LIB_FUNCTION("jwImxXRGSKA", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2DeleteDecoder); + LIB_FUNCTION("852F5+q6+iM", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Decode); + LIB_FUNCTION("l1hXwscLuCY", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Flush); + LIB_FUNCTION("wJXikG6QFN8", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Reset); + LIB_FUNCTION("NtXRa3dRzU0", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, + sceVideodec2GetPictureInfo); +} + +} // namespace Libraries::Vdec2 \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec2.h b/src/core/libraries/videodec/videodec2.h new file mode 100644 index 0000000000..8bb6fd7503 --- /dev/null +++ b/src/core/libraries/videodec/videodec2.h @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +#include "videodec2_avc.h" + +namespace Core::Loader { +class SymbolsResolver; +} +namespace Libraries::Vdec2 { + +class VdecDecoder; + +using OrbisVideodec2Decoder = VdecDecoder*; +typedef void* OrbisVideodec2ComputeQueue; + +struct OrbisVideodec2DecoderConfigInfo { + u64 thisSize; + u32 resourceType; + u32 codecType; + u32 profile; + u32 maxLevel; + s32 maxFrameWidth; + s32 maxFrameHeight; + s32 maxDpbFrameCount; + u32 decodePipelineDepth; + OrbisVideodec2ComputeQueue computeQueue; + u64 cpuAffinityMask; + s32 cpuThreadPriority; + bool optimizeProgressiveVideo; + bool checkMemoryType; + u8 reserved0; + u8 reserved1; + void* extraConfigInfo; +}; + +struct OrbisVideodec2DecoderMemoryInfo { + u64 thisSize; + u64 cpuMemorySize; + void* pCpuMemory; + u64 gpuMemorySize; + void* pGpuMemory; + u64 cpuGpuMemorySize; + void* pCpuGpuMemory; + u64 maxFrameBufferSize; + u32 frameBufferAlignment; + u32 reserved0; +}; + +struct OrbisVideodec2InputData { + u64 thisSize; + void* pAuData; + u64 auSize; + u64 ptsData; + u64 dtsData; + u64 attachedData; +}; + +struct OrbisVideodec2OutputInfo { + u64 thisSize; + bool isValid; + bool isErrorFrame; + u8 pictureCount; + u32 codecType; + u32 frameWidth; + u32 framePitch; + u32 frameHeight; + void* pFrameBuffer; + u64 frameBufferSize; +}; + +struct OrbisVideodec2FrameBuffer { + u64 thisSize; + void* pFrameBuffer; + u64 frameBufferSize; + bool isAccepted; +}; + +struct OrbisVideodec2ComputeMemoryInfo { + u64 thisSize; + u64 cpuGpuMemorySize; + void* pCpuGpuMemory; +}; + +struct OrbisVideodec2ComputeConfigInfo { + u64 thisSize; + u16 computePipeId; + u16 computeQueueId; + bool checkMemoryType; + u8 reserved0; + u16 reserved1; +}; + +s32 PS4_SYSV_ABI +sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* pComputeMemInfoOut); + +s32 PS4_SYSV_ABI +sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* pComputeCfgInfoIn, + const OrbisVideodec2ComputeMemoryInfo* pComputeMemInfoIn, + OrbisVideodec2ComputeQueue* pComputeQueueOut); + +s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueueIn); + +s32 PS4_SYSV_ABI +sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* pDecoderConfigInfoIn, + OrbisVideodec2DecoderMemoryInfo* pDecoderMemoryInfoOut); + +s32 PS4_SYSV_ABI +sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* pDecoderConfigInfoIn, + const OrbisVideodec2DecoderMemoryInfo* pDecoderMemoryInfoIn, + OrbisVideodec2Decoder* pDecoderInstanceOut); + +s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder); + +s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder, + const OrbisVideodec2InputData* pInputDataInOut, + OrbisVideodec2FrameBuffer* pFrameBufferInOut, + OrbisVideodec2OutputInfo* pOutputInfoOut); + +s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder, + OrbisVideodec2FrameBuffer* pFrameBufferInOut, + OrbisVideodec2OutputInfo* pOutputInfoOut); + +s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder); + +s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* pOutputInfoIn, + void* p1stPictureInfoOut, void* p2ndPictureInfoOut); + +void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Vdec2 \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec2_avc.h b/src/core/libraries/videodec/videodec2_avc.h new file mode 100644 index 0000000000..4109b5fd2c --- /dev/null +++ b/src/core/libraries/videodec/videodec2_avc.h @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +namespace Libraries::Vdec2 { + +struct OrbisVideodec2AvcPictureInfo { + u64 thisSize; + + bool isValid; + + u64 ptsData; + u64 dtsData; + u64 attachedData; + + u8 idrPictureflag; + + u8 profile_idc; + u8 level_idc; + u32 pic_width_in_mbs_minus1; + u32 pic_height_in_map_units_minus1; + u8 frame_mbs_only_flag; + + u8 frame_cropping_flag; + u32 frameCropLeftOffset; + u32 frameCropRightOffset; + u32 frameCropTopOffset; + u32 frameCropBottomOffset; + + u8 aspect_ratio_info_present_flag; + u8 aspect_ratio_idc; + u16 sar_width; + u16 sar_height; + + u8 video_signal_type_present_flag; + u8 video_format; + u8 video_full_range_flag; + u8 colour_description_present_flag; + u8 colour_primaries; + u8 transfer_characteristics; + u8 matrix_coefficients; + + u8 timing_info_present_flag; + u32 num_units_in_tick; + u32 time_scale; + u8 fixed_frame_rate_flag; + + u8 bitstream_restriction_flag; + u8 max_dec_frame_buffering; + + u8 pic_struct_present_flag; + u8 pic_struct; + u8 field_pic_flag; + u8 bottom_field_flag; +}; + +} // namespace Libraries::Vdec2 \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec2_impl.cpp b/src/core/libraries/videodec/videodec2_impl.cpp new file mode 100644 index 0000000000..3f2883dd41 --- /dev/null +++ b/src/core/libraries/videodec/videodec2_impl.cpp @@ -0,0 +1,216 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "videodec2_impl.h" + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" + +namespace Libraries::Vdec2 { + +std::vector gPictureInfos; + +static inline void CopyNV12Data(u8* dst, const AVFrame& src) { + const auto width = u32(src.width); + const auto height = u32(src.height); + + 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 OrbisVideodec2DecoderConfigInfo& configInfo, + const OrbisVideodec2DecoderMemoryInfo& memoryInfo) { + ASSERT(configInfo.codecType == 1); /* AVC */ + + const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); + + mCodecContext = avcodec_alloc_context3(codec); + mCodecContext->width = configInfo.maxFrameWidth; + mCodecContext->height = configInfo.maxFrameHeight; + + avcodec_open2(mCodecContext, codec, nullptr); +} + +VdecDecoder::~VdecDecoder() { + avcodec_free_context(&mCodecContext); + sws_freeContext(mSwsContext); + + gPictureInfos.clear(); +} + +s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData, + OrbisVideodec2FrameBuffer& frameBuffer, + OrbisVideodec2OutputInfo& outputInfo) { + frameBuffer.isAccepted = false; + outputInfo.isValid = false; + outputInfo.isErrorFrame = true; + outputInfo.pictureCount = 0; + + AVPacket* packet = av_packet_alloc(); + if (!packet) { + LOG_ERROR(Lib_Vdec2, "Failed to allocate packet"); + return 0; + } + + packet->data = (u8*)inputData.pAuData; + packet->size = inputData.auSize; + packet->pts = inputData.ptsData; + packet->dts = inputData.dtsData; + + int ret = avcodec_send_packet(mCodecContext, packet); + if (ret < 0) { + LOG_ERROR(Lib_Vdec2, "Error sending packet to decoder: {}", ret); + av_packet_free(&packet); + return 0; + } + + AVFrame* frame = av_frame_alloc(); + if (frame == nullptr) { + LOG_ERROR(Lib_Vdec2, "Failed to allocate frame"); + av_packet_free(&packet); + return 0; + } + + while (true) { + ret = avcodec_receive_frame(mCodecContext, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + LOG_ERROR(Lib_Vdec2, "Error receiving frame from decoder: {}", ret); + av_packet_free(&packet); + av_frame_free(&frame); + return 0; + } + + if (frame->format != AV_PIX_FMT_NV12) { + AVFrame* nv12_frame = ConvertNV12Frame(*frame); + av_frame_free(&frame); + frame = nv12_frame; + } + + CopyNV12Data((u8*)frameBuffer.pFrameBuffer, *frame); + frameBuffer.isAccepted = true; + + outputInfo.codecType = 1; // FIXME: Hardcoded to AVC + outputInfo.frameWidth = frame->width; + outputInfo.frameHeight = frame->height; + outputInfo.framePitch = frame->linesize[0]; + outputInfo.frameBufferSize = frameBuffer.frameBufferSize; + outputInfo.pFrameBuffer = frameBuffer.pFrameBuffer; + + outputInfo.isValid = true; + outputInfo.isErrorFrame = false; + outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video + + if (outputInfo.isValid) { + OrbisVideodec2AvcPictureInfo pictureInfo = {}; + + pictureInfo.thisSize = sizeof(OrbisVideodec2AvcPictureInfo); + pictureInfo.isValid = true; + + pictureInfo.ptsData = inputData.ptsData; + pictureInfo.dtsData = inputData.dtsData; + pictureInfo.attachedData = inputData.attachedData; + + pictureInfo.frameCropLeftOffset = frame->crop_left; + pictureInfo.frameCropRightOffset = frame->crop_right; + pictureInfo.frameCropTopOffset = frame->crop_top; + pictureInfo.frameCropBottomOffset = frame->crop_bottom; + + gPictureInfos.push_back(pictureInfo); + } + } + + av_packet_free(&packet); + av_frame_free(&frame); + return 0; +} + +s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer, + OrbisVideodec2OutputInfo& outputInfo) { + frameBuffer.isAccepted = false; + outputInfo.isValid = false; + outputInfo.isErrorFrame = true; + outputInfo.pictureCount = 0; + + AVFrame* frame = av_frame_alloc(); + if (!frame) { + LOG_ERROR(Lib_Vdec2, "Failed to allocate frame"); + return 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_Vdec2, "Error receiving frame from decoder: {}", ret); + av_frame_free(&frame); + return 0; + } + + if (frame->format != AV_PIX_FMT_NV12) { + AVFrame* nv12_frame = ConvertNV12Frame(*frame); + av_frame_free(&frame); + frame = nv12_frame; + } + + CopyNV12Data((u8*)frameBuffer.pFrameBuffer, *frame); + frameBuffer.isAccepted = true; + + outputInfo.frameWidth = frame->width; + outputInfo.frameHeight = frame->height; + outputInfo.framePitch = frame->linesize[0]; + outputInfo.frameBufferSize = frameBuffer.frameBufferSize; + outputInfo.pFrameBuffer = frameBuffer.pFrameBuffer; + + outputInfo.isValid = true; + outputInfo.isErrorFrame = false; + outputInfo.pictureCount++; + + // FIXME: Should we add picture info here too? + } + + av_frame_free(&frame); + return 0; +} + +s32 VdecDecoder::Reset() { + avcodec_flush_buffers(mCodecContext); + gPictureInfos.clear(); + return 0; +} + +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_Vdec2, "Could not convert to NV12: {}", av_err2str(res)); + return nullptr; + } + + return nv12_frame; +} + +} // namespace Libraries::Vdec2 \ No newline at end of file diff --git a/src/core/libraries/videodec/videodec2_impl.h b/src/core/libraries/videodec/videodec2_impl.h new file mode 100644 index 0000000000..1bcece6e1c --- /dev/null +++ b/src/core/libraries/videodec/videodec2_impl.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "videodec2.h" + +extern "C" { +#include +#include +#include +} + +namespace Libraries::Vdec2 { + +extern std::vector gPictureInfos; + +class VdecDecoder { +public: + VdecDecoder(const OrbisVideodec2DecoderConfigInfo& configInfo, + const OrbisVideodec2DecoderMemoryInfo& memoryInfo); + ~VdecDecoder(); + + s32 Decode(const OrbisVideodec2InputData& inputData, OrbisVideodec2FrameBuffer& frameBuffer, + OrbisVideodec2OutputInfo& outputInfo); + s32 Flush(OrbisVideodec2FrameBuffer& frameBuffer, OrbisVideodec2OutputInfo& outputInfo); + s32 Reset(); + +private: + AVFrame* ConvertNV12Frame(AVFrame& frame); + +private: + AVCodecContext* mCodecContext = nullptr; + SwsContext* mSwsContext = nullptr; +}; + +} // namespace Libraries::Vdec2 \ No newline at end of file diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp index 631f77732f..31b8a21cad 100644 --- a/src/core/libraries/videoout/video_out.cpp +++ b/src/core/libraries/videoout/video_out.cpp @@ -106,13 +106,13 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co } s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) { - LOG_INFO(Lib_VideoOut, "called"); + LOG_TRACE(Lib_VideoOut, "called"); driver->GetPort(handle)->flip_rate = rate; return ORBIS_OK; } s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) { - LOG_INFO(Lib_VideoOut, "called"); + LOG_TRACE(Lib_VideoOut, "called"); auto* port = driver->GetPort(handle); std::unique_lock lock{port->port_mutex}; s32 pending = port->flip_status.flipPendingNum;