From 69a50fa7132f27f73754aebe15be953546f5ace2 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Wed, 11 Jun 2025 14:22:34 -0500 Subject: [PATCH] Struct update fixes (#3087) Neither sceVideodec2Decode or sceVideodec2Flush should be modifying the output's `thisSize`, doing so breaks older games now that we have the updated structs. We should also only set frameFormat and framePitchInBytes if the game inputted the newer struct, since otherwise we're modifying memory the game never gave us. These changes might fix the regression in Hatsune Miku Project Diva X, though it's hard to tell due to some weird caching issue with Windows, and the ancient regression this game had on Linux. --- .../libraries/videodec/videodec2_impl.cpp | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/core/libraries/videodec/videodec2_impl.cpp b/src/core/libraries/videodec/videodec2_impl.cpp index a643239a3..373809c14 100644 --- a/src/core/libraries/videodec/videodec2_impl.cpp +++ b/src/core/libraries/videodec/videodec2_impl.cpp @@ -44,11 +44,14 @@ 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; - outputInfo.frameFormat = 0; + + // Only set frameFormat if the game uses the newer struct version. + if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) { + outputInfo.frameFormat = 0; + } if (!inputData.auData) { return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER; @@ -107,7 +110,6 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData, outputInfo.frameWidth = frame->width; outputInfo.frameHeight = frame->height; outputInfo.framePitch = frame->linesize[0]; - outputInfo.framePitchInBytes = frame->linesize[0]; outputInfo.frameBufferSize = frameBuffer.frameBufferSize; outputInfo.frameBuffer = frameBuffer.frameBuffer; @@ -115,6 +117,11 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData, outputInfo.isErrorFrame = false; outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video + // Only set framePitchInBytes if the game uses the newer struct version. + if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) { + outputInfo.framePitchInBytes = frame->linesize[0]; + } + if (outputInfo.isValid) { OrbisVideodec2AvcPictureInfo pictureInfo = {}; @@ -142,11 +149,14 @@ s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData, s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer, OrbisVideodec2OutputInfo& outputInfo) { frameBuffer.isAccepted = false; - outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo); outputInfo.isValid = false; outputInfo.isErrorFrame = true; outputInfo.pictureCount = 0; - outputInfo.frameFormat = 0; + + // Only set frameFormat if the game uses the newer struct version. + if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) { + outputInfo.frameFormat = 0; + } AVFrame* frame = av_frame_alloc(); if (!frame) { @@ -178,7 +188,6 @@ s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer, outputInfo.frameWidth = frame->width; outputInfo.frameHeight = frame->height; outputInfo.framePitch = frame->linesize[0]; - outputInfo.framePitchInBytes = frame->linesize[0]; outputInfo.frameBufferSize = frameBuffer.frameBufferSize; outputInfo.frameBuffer = frameBuffer.frameBuffer; @@ -186,6 +195,11 @@ s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer, outputInfo.isErrorFrame = false; outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video + // Only set framePitchInBytes if the game uses the newer struct version. + if (outputInfo.thisSize == sizeof(OrbisVideodec2OutputInfo)) { + outputInfo.framePitchInBytes = frame->linesize[0]; + } + // FIXME: Should we add picture info here too? }