mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
h264: Use asynchronous decoding when possible (#1257)
This commit is contained in:
@@ -374,7 +374,9 @@ add_library(CemuCafe
|
||||
OS/libs/gx2/GX2_Texture.h
|
||||
OS/libs/gx2/GX2_TilingAperture.cpp
|
||||
OS/libs/h264_avc/H264Dec.cpp
|
||||
OS/libs/h264_avc/H264DecBackendAVC.cpp
|
||||
OS/libs/h264_avc/h264dec.h
|
||||
OS/libs/h264_avc/H264DecInternal.h
|
||||
OS/libs/h264_avc/parser
|
||||
OS/libs/h264_avc/parser/H264Parser.cpp
|
||||
OS/libs/h264_avc/parser/H264Parser.h
|
||||
|
||||
@@ -14,13 +14,10 @@ namespace coreinit
|
||||
return coreinit::MEMAllocFromExpHeapEx(_sysHeapHandle, size, alignment);
|
||||
}
|
||||
|
||||
void export_OSAllocFromSystem(PPCInterpreter_t* hCPU)
|
||||
void OSFreeToSystem(void* ptr)
|
||||
{
|
||||
ppcDefineParamU32(size, 0);
|
||||
ppcDefineParamS32(alignment, 1);
|
||||
MEMPTR<void> mem = OSAllocFromSystem(size, alignment);
|
||||
cemuLog_logDebug(LogType::Force, "OSAllocFromSystem(0x{:x}, {}) -> 0x{:08x}", size, alignment, mem.GetMPTR());
|
||||
osLib_returnFromFunction(hCPU, mem.GetMPTR());
|
||||
_sysHeapFreeCounter++;
|
||||
coreinit::MEMFreeToExpHeap(_sysHeapHandle, ptr);
|
||||
}
|
||||
|
||||
void InitSysHeap()
|
||||
@@ -34,7 +31,8 @@ namespace coreinit
|
||||
|
||||
void InitializeSysHeap()
|
||||
{
|
||||
osLib_addFunction("coreinit", "OSAllocFromSystem", export_OSAllocFromSystem);
|
||||
cafeExportRegister("h264", OSAllocFromSystem, LogType::CoreinitMem);
|
||||
cafeExportRegister("h264", OSFreeToSystem, LogType::CoreinitMem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,5 +4,8 @@ namespace coreinit
|
||||
{
|
||||
void InitSysHeap();
|
||||
|
||||
void* OSAllocFromSystem(uint32 size, uint32 alignment);
|
||||
void OSFreeToSystem(void* ptr);
|
||||
|
||||
void InitializeSysHeap();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/helpers/Semaphore.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Thread.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_SysHeap.h"
|
||||
|
||||
#include "Cafe/OS/libs/h264_avc/parser/H264Parser.h"
|
||||
|
||||
namespace H264
|
||||
{
|
||||
class H264DecoderBackend
|
||||
{
|
||||
protected:
|
||||
struct DataToDecode
|
||||
{
|
||||
uint8* m_data;
|
||||
uint32 m_length;
|
||||
std::vector<uint8> m_buffer;
|
||||
};
|
||||
|
||||
static constexpr uint32 CMD_FLUSH = 0xFFFFFFFF;
|
||||
|
||||
public:
|
||||
struct DecodeResult
|
||||
{
|
||||
bool isDecoded{false};
|
||||
bool hasFrame{false}; // set to true if a full frame was successfully decoded
|
||||
double timestamp{};
|
||||
void* imageOutput{nullptr};
|
||||
sint32 frameWidth{0};
|
||||
sint32 frameHeight{0};
|
||||
uint32 bytesPerRow{0};
|
||||
bool cropEnable{false};
|
||||
sint32 cropTop{0};
|
||||
sint32 cropBottom{0};
|
||||
sint32 cropLeft{0};
|
||||
sint32 cropRight{0};
|
||||
};
|
||||
|
||||
struct DecodedSlice
|
||||
{
|
||||
bool isUsed{false};
|
||||
DecodeResult result;
|
||||
DataToDecode dataToDecode;
|
||||
};
|
||||
|
||||
H264DecoderBackend()
|
||||
{
|
||||
m_displayQueueEvt = (coreinit::OSEvent*)coreinit::OSAllocFromSystem(sizeof(coreinit::OSEvent), 4);
|
||||
coreinit::OSInitEvent(m_displayQueueEvt, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);
|
||||
m_flushEvt = (coreinit::OSEvent*)coreinit::OSAllocFromSystem(sizeof(coreinit::OSEvent), 4);
|
||||
coreinit::OSInitEvent(m_flushEvt, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);
|
||||
};
|
||||
|
||||
virtual ~H264DecoderBackend()
|
||||
{
|
||||
coreinit::OSFreeToSystem(m_displayQueueEvt);
|
||||
coreinit::OSFreeToSystem(m_flushEvt);
|
||||
};
|
||||
|
||||
virtual void Init(bool isBufferedMode) = 0;
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
void QueueForDecode(uint8* data, uint32 length, double timestamp, void* imagePtr)
|
||||
{
|
||||
std::unique_lock _l(m_decodeQueueMtx);
|
||||
|
||||
DecodedSlice& ds = GetFreeDecodedSliceEntry();
|
||||
|
||||
ds.dataToDecode.m_buffer.assign(data, data + length);
|
||||
ds.dataToDecode.m_data = ds.dataToDecode.m_buffer.data();
|
||||
ds.dataToDecode.m_length = length;
|
||||
|
||||
ds.result.isDecoded = false;
|
||||
ds.result.imageOutput = imagePtr;
|
||||
ds.result.timestamp = timestamp;
|
||||
|
||||
m_decodeQueue.push_back(std::distance(m_decodedSliceArray.data(), &ds));
|
||||
m_decodeSem.increment();
|
||||
}
|
||||
|
||||
void QueueFlush()
|
||||
{
|
||||
std::unique_lock _l(m_decodeQueueMtx);
|
||||
m_decodeQueue.push_back(CMD_FLUSH);
|
||||
m_decodeSem.increment();
|
||||
}
|
||||
|
||||
bool GetFrameOutputIfReady(DecodeResult& result)
|
||||
{
|
||||
std::unique_lock _l(m_decodeQueueMtx);
|
||||
if(m_displayQueue.empty())
|
||||
return false;
|
||||
uint32 sliceIndex = m_displayQueue.front();
|
||||
DecodedSlice& ds = m_decodedSliceArray[sliceIndex];
|
||||
cemu_assert_debug(ds.result.isDecoded);
|
||||
std::swap(result, ds.result);
|
||||
ds.isUsed = false;
|
||||
m_displayQueue.erase(m_displayQueue.begin());
|
||||
return true;
|
||||
}
|
||||
|
||||
coreinit::OSEvent& GetFrameOutputEvent()
|
||||
{
|
||||
return *m_displayQueueEvt;
|
||||
}
|
||||
|
||||
coreinit::OSEvent& GetFlushEvent()
|
||||
{
|
||||
return *m_flushEvt;
|
||||
}
|
||||
|
||||
protected:
|
||||
DecodedSlice& GetFreeDecodedSliceEntry()
|
||||
{
|
||||
for (auto& slice : m_decodedSliceArray)
|
||||
{
|
||||
if (!slice.isUsed)
|
||||
{
|
||||
slice.isUsed = true;
|
||||
return slice;
|
||||
}
|
||||
}
|
||||
cemu_assert_suspicious();
|
||||
return m_decodedSliceArray[0];
|
||||
}
|
||||
|
||||
std::mutex m_decodeQueueMtx;
|
||||
std::vector<uint32> m_decodeQueue; // indices into m_decodedSliceArray, in order of decode input
|
||||
CounterSemaphore m_decodeSem;
|
||||
std::vector<uint32> m_displayQueue; // indices into m_decodedSliceArray, in order of frame display output
|
||||
coreinit::OSEvent* m_displayQueueEvt; // signalled when a new frame is ready for display
|
||||
coreinit::OSEvent* m_flushEvt; // signalled after flush operation finished and all queued slices are decoded
|
||||
|
||||
// frame output queue
|
||||
std::mutex m_frameOutputMtx;
|
||||
std::array<DecodedSlice, 32> m_decodedSliceArray;
|
||||
};
|
||||
}
|
||||
@@ -319,6 +319,17 @@ bool parseNAL_pic_parameter_set_rbsp(h264ParserState_t* h264ParserState, h264Par
|
||||
return true;
|
||||
}
|
||||
|
||||
bool h264Parser_ParseSPS(uint8* data, uint32 length, h264State_seq_parameter_set_t& sps)
|
||||
{
|
||||
h264ParserState_t parserState;
|
||||
RBSPInputBitstream nalStream(data, length);
|
||||
bool r = parseNAL_seq_parameter_set_rbsp(&parserState, nullptr, nalStream);
|
||||
if(!r || !parserState.hasSPS)
|
||||
return false;
|
||||
sps = parserState.sps;
|
||||
return true;
|
||||
}
|
||||
|
||||
void parseNAL_ref_pic_list_modification(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)
|
||||
{
|
||||
if (!sliceHeader->slice_type.isSliceTypeI() && !sliceHeader->slice_type.isSliceTypeSI())
|
||||
@@ -688,9 +699,8 @@ void _calculateFrameOrder(h264ParserState_t* h264ParserState, const h264State_se
|
||||
else if (sps.pic_order_cnt_type == 2)
|
||||
{
|
||||
// display order matches decode order
|
||||
|
||||
uint32 prevFrameNum = h264ParserState->picture_order.prevFrameNum;
|
||||
;
|
||||
|
||||
uint32 FrameNumOffset;
|
||||
if (sliceHeader->IdrPicFlag)
|
||||
{
|
||||
@@ -706,9 +716,6 @@ void _calculateFrameOrder(h264ParserState_t* h264ParserState, const h264State_se
|
||||
FrameNumOffset = prevFrameNumOffset + sps.getMaxFrameNum();
|
||||
else
|
||||
FrameNumOffset = prevFrameNumOffset;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
uint32 tempPicOrderCnt;
|
||||
|
||||
@@ -513,6 +513,8 @@ typedef struct
|
||||
void h264Parse(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, uint8* data, uint32 length, bool parseSlices = true);
|
||||
sint32 h264GetUnitLength(h264ParserState_t* h264ParserState, uint8* data, uint32 length);
|
||||
|
||||
bool h264Parser_ParseSPS(uint8* data, uint32 length, h264State_seq_parameter_set_t& sps);
|
||||
|
||||
void h264Parser_getScalingMatrix4x4(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix4x4);
|
||||
void h264Parser_getScalingMatrix8x8(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix8x8);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user