mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-11-26 20:50:40 +00:00
core/libraries: Videodec2 implementation
Some checks failed
Build and Release / reuse (push) Has been cancelled
Build and Release / clang-format (push) Has been cancelled
Build and Release / get-info (push) Has been cancelled
Build and Release / windows-sdl (push) Has been cancelled
Build and Release / windows-qt (push) Has been cancelled
Build and Release / macos-sdl (push) Has been cancelled
Build and Release / macos-qt (push) Has been cancelled
Build and Release / linux-sdl (push) Has been cancelled
Build and Release / linux-qt (push) Has been cancelled
Build and Release / pre-release (push) Has been cancelled
Some checks failed
Build and Release / reuse (push) Has been cancelled
Build and Release / clang-format (push) Has been cancelled
Build and Release / get-info (push) Has been cancelled
Build and Release / windows-sdl (push) Has been cancelled
Build and Release / windows-qt (push) Has been cancelled
Build and Release / macos-sdl (push) Has been cancelled
Build and Release / macos-qt (push) Has been cancelled
Build and Release / linux-sdl (push) Has been cancelled
Build and Release / linux-qt (push) Has been cancelled
Build and Release / pre-release (push) Has been cancelled
This commit is contained in:
parent
6e00121eb5
commit
4c1ae8afac
@ -348,6 +348,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
|
||||
@ -503,6 +510,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||
${MISC_LIBS}
|
||||
${IME_LIB}
|
||||
${FIBER_LIB}
|
||||
${VDEC_LIB}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -552,4 +552,42 @@ constexpr int ORBIS_IME_ERROR_INVALID_PARAM = 0x80BC0030;
|
||||
constexpr int ORBIS_IME_ERROR_INVALID_ADDRESS = 0x80BC0031;
|
||||
constexpr int ORBIS_IME_ERROR_INVALID_RESERVED = 0x80BC0032;
|
||||
constexpr int ORBIS_IME_ERROR_INVALID_TIMING = 0x80BC0033;
|
||||
constexpr int ORBIS_IME_ERROR_INTERNAL = 0x80BC00FF;
|
||||
constexpr int ORBIS_IME_ERROR_INTERNAL = 0x80BC00FF;
|
||||
|
||||
// Videodec2 library
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_API_FAIL = 0x811D0100;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE = 0x811D0101;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER = 0x811D0102;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE = 0x811D0103;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_MEMORY_SIZE = 0x811D0104;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_MEMORY_POINTER = 0x811D0105;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_FRAME_BUFFER_SIZE = 0x811D0106;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_FRAME_BUFFER_POINTER = 0x811D0107;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_FRAME_BUFFER_ALIGNMENT = 0x811D0108;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_NOT_ONION_MEMORY = 0x811D0109;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_NOT_GARLIC_MEMORY = 0x811D010A;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_NOT_DIRECT_MEMORY = 0x811D010B;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_MEMORY_INFO = 0x811D010C;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_SIZE = 0x811D010D;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER = 0x811D010E;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_OUTPUT_INFO = 0x811D010F;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_COMPUTE_QUEUE = 0x811D0110;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_FATAL_STATE = 0x811D0111;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_PRESET_VALUE = 0x811D0112;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_CONFIG_INFO = 0x811D0200;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_COMPUTE_PIPE_ID = 0x811D0201;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_COMPUTE_QUEUE_ID = 0x811D0202;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_RESOURCE_TYPE = 0x811D0203;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_CODEC_TYPE = 0x811D0204;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_PROFILE_LEVEL = 0x811D0205;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_PIPELINE_DEPTH = 0x811D0206;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_AFFINITY_MASK = 0x811D0207;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_THREAD_PRIORITY = 0x811D0208;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_DPB_FRAME_COUNT = 0x811D0209;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_FRAME_WIDTH_HEIGHT = 0x811D020A;
|
||||
constexpr int ORBIS_VIDEODEC2_ERROR_EXTRA_CONFIG_INFO = 0x811D020B;
|
||||
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;
|
@ -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;
|
||||
|
@ -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);
|
||||
|
200
src/core/libraries/videodec/videodec2.cpp
Normal file
200
src/core/libraries/videodec/videodec2.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
// 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
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!computeMemInfo) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
computeMemInfo->cpuGpuMemory = nullptr;
|
||||
computeMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo,
|
||||
const OrbisVideodec2ComputeMemoryInfo* computeMemInfo,
|
||||
OrbisVideodec2ComputeQueue* computeQueue) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
|
||||
OrbisVideodec2DecoderMemoryInfo* decoderMemInfo) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
decoderMemInfo->cpuMemory = nullptr;
|
||||
decoderMemInfo->gpuMemory = nullptr;
|
||||
decoderMemInfo->cpuGpuMemory = nullptr;
|
||||
|
||||
decoderMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
|
||||
decoderMemInfo->cpuMemorySize = kMinimumMemorySize;
|
||||
decoderMemInfo->gpuMemorySize = kMinimumMemorySize;
|
||||
|
||||
decoderMemInfo->maxFrameBufferSize = kMinimumMemorySize;
|
||||
decoderMemInfo->frameBufferAlignment = 0x100;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
|
||||
const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo,
|
||||
OrbisVideodec2Decoder* decoder) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
|
||||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
*decoder = new VdecDecoder(*decoderCfgInfo, *decoderMemInfo);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
delete decoder;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
|
||||
const OrbisVideodec2InputData* inputData,
|
||||
OrbisVideodec2FrameBuffer* frameBuffer,
|
||||
OrbisVideodec2OutputInfo* outputInfo) {
|
||||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!inputData || !frameBuffer || !outputInfo) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
|
||||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
return decoder->Decode(*inputData, *frameBuffer, *outputInfo);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
|
||||
OrbisVideodec2FrameBuffer* frameBuffer,
|
||||
OrbisVideodec2OutputInfo* outputInfo) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
if (!frameBuffer || !outputInfo) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
|
||||
outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
|
||||
return decoder->Flush(*frameBuffer, *outputInfo);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
|
||||
LOG_INFO(Lib_Vdec2, "called");
|
||||
|
||||
if (!decoder) {
|
||||
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
|
||||
}
|
||||
|
||||
return decoder->Reset();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo,
|
||||
void* p1stPictureInfoOut, void* p2ndPictureInfoOut) {
|
||||
LOG_TRACE(Lib_Vdec2, "called");
|
||||
|
||||
if (!outputInfo) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
|
||||
}
|
||||
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
if (p1stPictureInfoOut) {
|
||||
OrbisVideodec2AvcPictureInfo* picInfo =
|
||||
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
|
||||
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
|
||||
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
|
||||
}
|
||||
*picInfo = gPictureInfos.back();
|
||||
}
|
||||
|
||||
if (outputInfo->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
|
139
src/core/libraries/videodec/videodec2.h
Normal file
139
src/core/libraries/videodec/videodec2.h
Normal file
@ -0,0 +1,139 @@
|
||||
// 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;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2DecoderConfigInfo) == 0x48);
|
||||
|
||||
struct OrbisVideodec2DecoderMemoryInfo {
|
||||
u64 thisSize;
|
||||
u64 cpuMemorySize;
|
||||
void* cpuMemory;
|
||||
u64 gpuMemorySize;
|
||||
void* gpuMemory;
|
||||
u64 cpuGpuMemorySize;
|
||||
void* cpuGpuMemory;
|
||||
u64 maxFrameBufferSize;
|
||||
u32 frameBufferAlignment;
|
||||
u32 reserved0;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2DecoderMemoryInfo) == 0x48);
|
||||
|
||||
struct OrbisVideodec2InputData {
|
||||
u64 thisSize;
|
||||
void* auData;
|
||||
u64 auSize;
|
||||
u64 ptsData;
|
||||
u64 dtsData;
|
||||
u64 attachedData;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2InputData) == 0x30);
|
||||
|
||||
struct OrbisVideodec2OutputInfo {
|
||||
u64 thisSize;
|
||||
bool isValid;
|
||||
bool isErrorFrame;
|
||||
u8 pictureCount;
|
||||
u32 codecType;
|
||||
u32 frameWidth;
|
||||
u32 framePitch;
|
||||
u32 frameHeight;
|
||||
void* frameBuffer;
|
||||
u64 frameBufferSize;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2OutputInfo) == 0x30);
|
||||
|
||||
struct OrbisVideodec2FrameBuffer {
|
||||
u64 thisSize;
|
||||
void* frameBuffer;
|
||||
u64 frameBufferSize;
|
||||
bool isAccepted;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2FrameBuffer) == 0x20);
|
||||
|
||||
struct OrbisVideodec2ComputeMemoryInfo {
|
||||
u64 thisSize;
|
||||
u64 cpuGpuMemorySize;
|
||||
void* cpuGpuMemory;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2ComputeMemoryInfo) == 0x18);
|
||||
|
||||
struct OrbisVideodec2ComputeConfigInfo {
|
||||
u64 thisSize;
|
||||
u16 computePipeId;
|
||||
u16 computeQueueId;
|
||||
bool checkMemoryType;
|
||||
u8 reserved0;
|
||||
u16 reserved1;
|
||||
};
|
||||
static_assert(sizeof(OrbisVideodec2ComputeConfigInfo) == 0x10);
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo,
|
||||
const OrbisVideodec2ComputeMemoryInfo* computeMemInfo,
|
||||
OrbisVideodec2ComputeQueue* computeQueue);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue);
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
|
||||
OrbisVideodec2DecoderMemoryInfo* decoderMemInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
|
||||
const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo,
|
||||
OrbisVideodec2Decoder* decoder);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
|
||||
const OrbisVideodec2InputData* inputData,
|
||||
OrbisVideodec2FrameBuffer* frameBuffer,
|
||||
OrbisVideodec2OutputInfo* outputInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
|
||||
OrbisVideodec2FrameBuffer* frameBuffer,
|
||||
OrbisVideodec2OutputInfo* outputInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder);
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo,
|
||||
void* p1stPictureInfo, void* p2ndPictureInfo);
|
||||
|
||||
void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Vdec2
|
60
src/core/libraries/videodec/videodec2_avc.h
Normal file
60
src/core/libraries/videodec/videodec2_avc.h
Normal file
@ -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
|
228
src/core/libraries/videodec/videodec2_impl.cpp
Normal file
228
src/core/libraries/videodec/videodec2_impl.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
// 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"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
namespace Libraries::Vdec2 {
|
||||
|
||||
std::vector<OrbisVideodec2AvcPictureInfo> gPictureInfos;
|
||||
|
||||
static inline void CopyNV12Data(u8* dst, const AVFrame& src) {
|
||||
std::memcpy(dst, src.data[0], src.width * src.height);
|
||||
std::memcpy(dst + (src.width * src.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);
|
||||
ASSERT(codec);
|
||||
|
||||
mCodecContext = avcodec_alloc_context3(codec);
|
||||
ASSERT(mCodecContext);
|
||||
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.thisSize = sizeof(OrbisVideodec2OutputInfo);
|
||||
outputInfo.isValid = false;
|
||||
outputInfo.isErrorFrame = true;
|
||||
outputInfo.pictureCount = 0;
|
||||
|
||||
if (!inputData.auData) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER;
|
||||
}
|
||||
if (inputData.auSize == 0) {
|
||||
return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_SIZE;
|
||||
}
|
||||
|
||||
AVPacket* packet = av_packet_alloc();
|
||||
if (!packet) {
|
||||
LOG_ERROR(Lib_Vdec2, "Failed to allocate packet");
|
||||
return ORBIS_VIDEODEC2_ERROR_API_FAIL;
|
||||
}
|
||||
|
||||
packet->data = (u8*)inputData.auData;
|
||||
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 ORBIS_VIDEODEC2_ERROR_API_FAIL;
|
||||
}
|
||||
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
if (frame == nullptr) {
|
||||
LOG_ERROR(Lib_Vdec2, "Failed to allocate frame");
|
||||
av_packet_free(&packet);
|
||||
return ORBIS_VIDEODEC2_ERROR_API_FAIL;
|
||||
}
|
||||
|
||||
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 ORBIS_VIDEODEC2_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*)frameBuffer.frameBuffer, *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.frameBuffer = frameBuffer.frameBuffer;
|
||||
|
||||
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 ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer,
|
||||
OrbisVideodec2OutputInfo& outputInfo) {
|
||||
frameBuffer.isAccepted = false;
|
||||
outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo);
|
||||
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 ORBIS_VIDEODEC2_ERROR_API_FAIL;
|
||||
}
|
||||
|
||||
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 ORBIS_VIDEODEC2_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*)frameBuffer.frameBuffer, *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.frameBuffer = frameBuffer.frameBuffer;
|
||||
|
||||
outputInfo.isValid = true;
|
||||
outputInfo.isErrorFrame = false;
|
||||
outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video
|
||||
|
||||
// FIXME: Should we add picture info here too?
|
||||
}
|
||||
|
||||
av_frame_free(&frame);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 VdecDecoder::Reset() {
|
||||
avcodec_flush_buffers(mCodecContext);
|
||||
gPictureInfos.clear();
|
||||
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_Vdec2, "Could not convert to NV12: {}", av_err2str(res));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nv12_frame;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Vdec2
|
39
src/core/libraries/videodec/videodec2_impl.h
Normal file
39
src/core/libraries/videodec/videodec2_impl.h
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "videodec2.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
namespace Libraries::Vdec2 {
|
||||
|
||||
extern std::vector<OrbisVideodec2AvcPictureInfo> 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
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user