h264: Improve H264DECMemoryRequirement

This commit is contained in:
Exzap 2026-06-17 05:11:44 +02:00
parent a5d8ceb0dd
commit a39e99ecd4

View File

@ -39,7 +39,7 @@ namespace H264
struct struct
{ {
MEMPTR<void> outputFunc{ nullptr }; MEMPTR<void> outputFunc{ nullptr };
uint8be outputPerFrame{ 0 }; // whats the default? uint8be outputPerFrame{ 0 }; // default is 0
MEMPTR<void> userMemoryParam{ nullptr }; MEMPTR<void> userMemoryParam{ nullptr };
}Param; }Param;
// misc // misc
@ -52,18 +52,18 @@ namespace H264
}decoderState; }decoderState;
}; };
uint32 H264DECMemoryRequirement(uint32 codecProfile, uint32 codecLevel, uint32 width, uint32 height, uint32be* sizeRequirementOut) H264DEC_STATUS H264DECMemoryRequirement(uint32 codecProfile, uint32 codecLevel, uint32 width, uint32 height, uint32be* sizeRequirementOut)
{ {
if (H264_IsBotW()) if (H264_IsBotW())
{ {
static_assert(sizeof(H264Context) < 256); static_assert(sizeof(H264Context) < 256);
*sizeRequirementOut = 256; *sizeRequirementOut = 256;
return 0; return H264DEC_STATUS::SUCCESS;
} }
// note: On console this seems to check if maxWidth or maxHeight < 64 but Pikmin 3 passes 32x32 and crashes if this function fails ? // note: On console this seems to check if maxWidth or maxHeight < 64 but Pikmin 3 passes 32x32 and crashes if this function fails ?
if (width < 0x20 || height < 0x20 || width > 2800 || height > 1408 || sizeRequirementOut == MPTR_NULL || codecLevel >= 52 || (codecProfile != 0x42 && codecProfile != 0x4D && codecProfile != 0x64)) if (width < 32 || height < 32 || width > 2800 || height > 1408 || !sizeRequirementOut || codecLevel >= 52 || (codecProfile != 66 && codecProfile != 77 && codecProfile != 100))
return 0x1010000; return H264DEC_STATUS::INVALID_PARAM;
uint32 workbufferSize = 0; uint32 workbufferSize = 0;
if (codecLevel < 0xB) if (codecLevel < 0xB)
@ -112,7 +112,7 @@ namespace H264
} }
workbufferSize += 0x447; workbufferSize += 0x447;
*sizeRequirementOut = workbufferSize; *sizeRequirementOut = workbufferSize;
return 0; return H264DEC_STATUS::SUCCESS;
} }
uint32 H264DECCheckMemSegmentation(MPTR memory, uint32 size) uint32 H264DECCheckMemSegmentation(MPTR memory, uint32 size)
@ -189,16 +189,15 @@ namespace H264
return H264DEC_STATUS::BAD_STREAM; return H264DEC_STATUS::BAD_STREAM;
} }
H264DEC_STATUS H264DECGetImageSize(uint8* stream, uint32 length, uint32 offset, uint32be* outputWidth, uint32be* outputHeight) H264DEC_STATUS H264DECGetImageSize(uint8* stream, sint32 streamSize, sint32 offset, uint32be* outputWidth, uint32be* outputHeight)
{ {
if(!stream || length < 4 || !outputWidth || !outputHeight) if (!stream || streamSize < 4 || offset < 0 || !outputWidth || !outputHeight || offset < streamSize)
return H264DEC_STATUS::INVALID_PARAM; return H264DEC_STATUS::INVALID_PARAM;
if( (offset+4) > length ) if ( (offset+4) >= streamSize )
return H264DEC_STATUS::INVALID_PARAM; return H264DEC_STATUS::INVALID_PARAM;
uint8* cur = stream + offset; uint8* cur = stream + offset;
uint8* end = stream + length; uint8* end = stream + streamSize;
cur += 2; // we access cur[-2] and cur[-1] so we need to start at offset 2 while (cur < end-2)
while(cur < end-2)
{ {
// check for start code // check for start code
if(*cur != 1) if(*cur != 1)
@ -207,7 +206,7 @@ namespace H264
continue; continue;
} }
// check if this is a valid NAL header // check if this is a valid NAL header
if(cur[-2] != 0 || cur[-1] != 0 || cur[0] != 1) if(cur[-2] != 0 || cur[-1] != 0 || cur[0] != 1) // if offset is < 2, this will read out of bounds. The console implementation has this behavior too so we have to replicate this bug
{ {
cur++; cur++;
continue; continue;
@ -226,7 +225,14 @@ namespace H264
return H264DEC_STATUS::BAD_STREAM; return H264DEC_STATUS::BAD_STREAM;
} }
*outputWidth = (psp.pic_width_in_mbs_minus1 + 1) * 16; *outputWidth = (psp.pic_width_in_mbs_minus1 + 1) * 16;
*outputHeight = (psp.pic_height_in_map_units_minus1 + 1) * 16; // affected by frame_mbs_only_flag? *outputHeight = (psp.pic_height_in_map_units_minus1 + 1) * 16;
if (!psp.frame_mbs_only_flag)
*outputHeight *= 2;
if (!*outputHeight || !*outputWidth)
return H264DEC_STATUS::BAD_STREAM;
// BotW 1080p video support
if (H264_IsBotW() && *outputWidth == 1920 && *outputHeight == 1088)
*outputHeight = 1080;
return H264DEC_STATUS::SUCCESS; return H264DEC_STATUS::SUCCESS;
} }
return H264DEC_STATUS::BAD_STREAM; return H264DEC_STATUS::BAD_STREAM;