mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-11-23 03:09:55 +00:00
Videocodec implementation (#1484)
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
* dummy videocodec * filled videodec parameters * vdec1 implementation * clang format fix * fixed codecType * added crop offset info * align output * align all h/w * some touchups * small touch (last one)
This commit is contained in:
parent
4fd7f67459
commit
7ab851592b
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
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;
|
||||
|
@ -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
|
||||
|
137
src/core/libraries/videodec/videodec.cpp
Normal file
137
src/core/libraries/videodec/videodec.cpp
Normal file
@ -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
|
108
src/core/libraries/videodec/videodec.h
Normal file
108
src/core/libraries/videodec/videodec.h
Normal file
@ -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
|
222
src/core/libraries/videodec/videodec_impl.cpp
Normal file
222
src/core/libraries/videodec/videodec_impl.cpp
Normal file
@ -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 <string>
|
||||
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
|
38
src/core/libraries/videodec/videodec_impl.h
Normal file
38
src/core/libraries/videodec/videodec_impl.h
Normal file
@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "videodec.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
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
|
Loading…
Reference in New Issue
Block a user