Files
dusklight/src/d/actor/d_a_movie_player.cpp
T
PJB3005 89acf923e0 Fix THP shutdown crash
Cleanly shut down movie player threads on exit.

I'm not 100% fond of having to manually insert a call like this into the shutdown logic, but the other solution is shutting down all processes and that's likely to result in causing more crashes.
2026-04-21 01:11:49 +02:00

4591 lines
133 KiB
C++

/**
* @file d_a_movie_player.cpp
*
*/
#include "d/dolzel_rel.h" // IWYU pragma: keep
// This TU seems to disable inlining entirely, as there are several weak functions that get inlined
// in other TUs, but not here.
#pragma dont_inline on
// Unsure about the optimization level here. Shield looks like it definitely uses O4,p for this TU,
// but gamecube has functions that imply O3,p and others that match better on O4,p.
#pragma optimization_level 4
#pragma optimize_for_size off
#include <cstring>
#include <span>
#include "JSystem/JAudio2/JASAiCtrl.h"
#include "JSystem/JAudio2/JASDriverIF.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#include "Z2AudioLib/Z2Instances.h"
#include "d/actor/d_a_movie_player.h"
#include <cassert>
#include "f_op/f_op_overlap_mng.h"
#include "dusk/gx_helper.h"
#include "dusk/os.h"
#include "dusk/layout.hpp"
#include "JSystem/JAudio2/JASCriticalSection.h"
#if MOVIE_SUPPORT
#include "turbojpeg.h"
#endif
inline s32 daMP_NEXT_READ_SIZE(daMP_THPReadBuffer* readBuf) {
return *(BE(s32)*)readBuf->ptr;
}
#if TARGET_PC
// idk what OS_THREAD_ATTR_DETACH does, and it stops OSThreadJoin()
// probably the difference doesn't matter since we are using OS threads anyways.
#define OS_THREAD_ATTR 0
#else
#define OS_THREAD_ATTR OS_THREAD_ATTR_DETACH
#endif
#if defined(__cplusplus) && !TARGET_PC
extern "C" {
#endif
static u32 THPAudioDecode(s16* audioBuffer, u8* audioFrame, s32 flag) {
THPAudioRecordHeader* header;
THPAudioDecodeInfo decInfo;
u8 *left, *right;
s16 *decLeftPtr, *decRightPtr;
s16 yn1, yn2;
s32 i;
s32 step;
s32 sample;
s64 yn;
if (audioBuffer == NULL || audioFrame == NULL) {
return 0;
}
header = (THPAudioRecordHeader*)audioFrame;
left = audioFrame + sizeof(THPAudioRecordHeader);
right = left + header->offsetNextChannel;
if (flag == 1) {
decRightPtr = audioBuffer;
decLeftPtr = audioBuffer + header->sampleSize;
step = 1;
} else {
decRightPtr = audioBuffer;
decLeftPtr = audioBuffer + 1;
step = 2;
}
if (header->offsetNextChannel == 0) {
__THPAudioInitialize(&decInfo, left);
yn1 = header->lYn1;
yn2 = header->lYn2;
for (i = 0; i < header->sampleSize; i++) {
sample = __THPAudioGetNewSample(&decInfo);
yn = header->lCoef[decInfo.predictor][1] * yn2;
yn += header->lCoef[decInfo.predictor][0] * yn1;
yn += (sample << decInfo.scale) << 11;
yn <<= 5;
u16 temp = yn & 0xffff;
if (temp > 0x8000) {
yn += 0x10000;
} else if (temp == 0x8000 && (yn & 0x10000)) {
yn += 0x10000;
}
if (yn > 2147483647LL) {
yn = 2147483647LL;
}
if (yn < -2147483648LL) {
yn = -2147483648LL;
}
*decLeftPtr = (s16)(yn >> 16);
decLeftPtr += step;
*decRightPtr = (s16)(yn >> 16);
decRightPtr += step;
yn2 = yn1;
yn1 = (s16)(yn >> 16);
}
} else {
__THPAudioInitialize(&decInfo, left);
yn1 = header->lYn1;
yn2 = header->lYn2;
for (i = 0; i < header->sampleSize; i++) {
sample = __THPAudioGetNewSample(&decInfo);
yn = header->lCoef[decInfo.predictor][1] * yn2;
yn += header->lCoef[decInfo.predictor][0] * yn1;
yn += (sample << decInfo.scale) << 11;
yn <<= 5;
u16 temp = yn & 0xffff;
if (temp > 0x8000) {
yn += 0x10000;
} else if (temp == 0x8000 && (yn & 0x10000)) {
yn += 0x10000;
}
if (yn > 2147483647LL) {
yn = 2147483647LL;
}
if (yn < -2147483648LL) {
yn = -2147483648LL;
}
*decLeftPtr = (s16)(yn >> 16);
decLeftPtr += step;
yn2 = yn1;
yn1 = (s16)(yn >> 16);
}
__THPAudioInitialize(&decInfo, right);
yn1 = header->rYn1;
yn2 = header->rYn2;
for (i = 0; i < header->sampleSize; i++) {
sample = __THPAudioGetNewSample(&decInfo);
yn = header->rCoef[decInfo.predictor][1] * yn2;
yn += header->rCoef[decInfo.predictor][0] * yn1;
yn += (sample << decInfo.scale) << 11;
yn <<= 5;
u16 temp = yn & 0xffff;
if (temp > 0x8000) {
yn += 0x10000;
} else if (temp == 0x8000 && (yn & 0x10000)) {
yn += 0x10000;
}
if (yn > 2147483647LL) {
yn = 2147483647LL;
}
if (yn < -2147483648LL) {
yn = -2147483648LL;
}
*decRightPtr = (s16)(yn >> 16);
decRightPtr += step;
yn2 = yn1;
yn1 = (s16)(yn >> 16);
}
}
return header->sampleSize;
}
static s32 __THPAudioGetNewSample(THPAudioDecodeInfo* info) {
s32 sample;
if (!(info->offsetNibbles & 0x0f)) {
info->predictor = (u8)((*(info->encodeData) & 0x70) >> 4);
info->scale = (u8)((*(info->encodeData) & 0xF));
info->encodeData++;
info->offsetNibbles += 2;
}
if (info->offsetNibbles & 0x1) {
sample = (s32)((*(info->encodeData) & 0xF) << 28) >> 28;
info->encodeData++;
} else {
sample = (s32)((*(info->encodeData) & 0xF0) << 24) >> 28;
}
info->offsetNibbles++;
return sample;
}
static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr) {
info->encodeData = ptr;
info->offsetNibbles = 2;
info->predictor = (u8)((*(info->encodeData) & 0x70) >> 4);
info->scale = (u8)((*(info->encodeData) & 0xF));
info->encodeData++;
}
#if !TARGET_PC
static u8 THPStatistics[1120] ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Ydchuff ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Udchuff ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Vdchuff ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Yachuff ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Uachuff ATTRIBUTE_ALIGN(32);
static THPHuffmanTab* Vachuff ATTRIBUTE_ALIGN(32);
static f32 __THPIDCTWorkspace[64] ATTRIBUTE_ALIGN(32);
static u8* __THPHuffmanBits;
static u8* __THPHuffmanSizeTab;
static u16* __THPHuffmanCodeTab;
static THPSample* Gbase ATTRIBUTE_ALIGN(32);
static u32 Gwid ATTRIBUTE_ALIGN(32);
static f32* Gq ATTRIBUTE_ALIGN(32);
static u8* __THPLCWork512[3];
static u8* __THPLCWork640[3];
static u32 __THPOldGQR5;
static u32 __THPOldGQR6;
static u8* __THPWorkArea;
static THPCoeff* __THPMCUBuffer[6];
static THPFileInfo* __THPInfo;
static BOOL __THPInitFlag;
static s32 THPVideoDecode(void* file, void* tileY, void* tileU, void* tileV, void* work) {
u8 all_done, status;
s32 errorCode;
if (!file) {
goto _err_no_input;
}
if (tileY == NULL || tileU == NULL || tileV == NULL) {
goto _err_no_output;
}
if (!work) {
goto _err_no_work;
}
if (!(PPCMfhid2() & 0x10000000)) {
goto _err_lc_not_enabled;
}
if (__THPInitFlag == FALSE) {
goto _err_not_initialized;
}
__THPWorkArea = (u8*)work;
__THPInfo = (THPFileInfo*)OSRoundUp32B(__THPWorkArea);
__THPWorkArea = (u8*)OSRoundUp32B(__THPWorkArea) + sizeof(THPFileInfo);
DCZeroRange(__THPInfo, sizeof(THPFileInfo));
__THPInfo->cnt = 33;
__THPInfo->decompressedY = 0;
__THPInfo->c = (u8*)file;
all_done = FALSE;
for (;;) {
if ((*(__THPInfo->c)++) != 255) {
goto _err_bad_syntax;
}
while (*__THPInfo->c == 255) {
((__THPInfo->c)++);
}
status = (*(__THPInfo->c)++);
if (status <= 0xD7) {
if (status == 196) {
status = __THPReadHuffmanTableSpecification();
if (status != 0) {
goto _err_bad_status;
}
}
else if (status == 192) {
status = __THPReadFrameHeader();
if (status != 0) {
goto _err_bad_status;
}
}
else {
goto _err_unsupported_marker;
}
}
else if (0xD8 <= status && status <= 0xDF) {
if (status == 221) {
__THPRestartDefinition();
}
else if (status == 219) {
status = __THPReadQuantizationTable();
if (status != 0) {
goto _err_bad_status;
}
}
else if (status == 218) {
status = __THPReadScaneHeader();
if (status != 0) {
goto _err_bad_status;
}
all_done = TRUE;
} else if (status == 216) {
// empty but required for match
} else {
goto _err_unsupported_marker;
}
}
else if (0xE0 <= status) {
if ((224 <= status && status <= 239) || status == 254) {
__THPInfo->c += (__THPInfo->c)[0] << 8 | (__THPInfo->c)[1];
} else {
goto _err_unsupported_marker;
}
}
if (all_done) {
break;
}
}
__THPSetupBuffers();
__THPDecompressYUV(tileY, tileU, tileV);
return 0;
_err_no_input:
errorCode = 25;
goto _err_exit;
_err_no_output:
errorCode = 27;
goto _err_exit;
_err_no_work:
errorCode = 26;
goto _err_exit;
_err_unsupported_marker:
errorCode = 11;
goto _err_exit;
_err_bad_resource:
errorCode = 1;
goto _err_exit;
_err_no_mem:
errorCode = 6;
goto _err_exit;
_err_bad_syntax:
errorCode = 3;
goto _err_exit;
_err_bad_status:
errorCode = status;
goto _err_exit;
_err_lc_not_enabled:
errorCode = 28;
goto _err_exit;
_err_not_initialized:
errorCode = 29;
goto _err_exit;
_err_exit:
return errorCode;
}
static void __THPSetupBuffers() {
u8 i;
THPCoeff* buffer;
buffer = (THPCoeff*)OSRoundUp32B(__THPWorkArea);
for (i = 0; i < 6; i++) {
__THPMCUBuffer[i] = &buffer[i * 64];
}
}
static u8 __THPReadFrameHeader() {
u8 i, utmp8;
__THPInfo->c += 2;
utmp8 = (*(__THPInfo->c)++);
if (utmp8 != 8) {
return 10;
}
__THPInfo->yPixelSize = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]);
__THPInfo->c += 2;
__THPInfo->xPixelSize = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]);
__THPInfo->c += 2;
utmp8 = (*(__THPInfo->c)++);
if (utmp8 != 3) {
return 12;
}
for (i = 0; i < 3; i++) {
utmp8 = (*(__THPInfo->c)++);
utmp8 = (*(__THPInfo->c)++);
if ((i == 0 && utmp8 != 0x22) || (i > 0 && utmp8 != 0x11)) {
return 19;
}
__THPInfo->components[i].quantizationTableSelector = (*(__THPInfo->c)++);
}
return 0;
}
#define THPROUNDUP(a, b) ((((s32)(a)) + ((s32)(b)-1L)) / ((s32)(b)))
static u8 __THPReadScaneHeader() {
u8 i, utmp8;
__THPInfo->c += 2;
utmp8 = (*(__THPInfo->c)++);
if (utmp8 != 3) {
return 12;
}
for (i = 0; i < 3; i++) {
utmp8 = (*(__THPInfo->c)++);
utmp8 = (*(__THPInfo->c)++);
__THPInfo->components[i].DCTableSelector = (u8)(utmp8 >> 4);
__THPInfo->components[i].ACTableSelector = (u8)(utmp8 & 15);
if ((__THPInfo->validHuffmanTabs & (1 << ((utmp8 >> 4)))) == 0) {
return 15;
}
if ((__THPInfo->validHuffmanTabs & (1 << ((utmp8 & 15) + 1))) == 0) {
return 15;
}
}
__THPInfo->c += 3;
__THPInfo->MCUsPerRow = (u16)THPROUNDUP(__THPInfo->xPixelSize, 16);
__THPInfo->components[0].predDC = 0;
__THPInfo->components[1].predDC = 0;
__THPInfo->components[2].predDC = 0;
return 0;
}
static const u8 __THPJpegNaturalOrder[80] = {
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33,
40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54,
47, 55, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
};
static const f64 __THPAANScaleFactor[8] = {
1.0f, 1.387039845f, 1.306562965f, 1.175875602f, 1.0f, 0.785694958f, 0.541196100f, 0.275899379f,
};
static u8 __THPReadQuantizationTable() {
int length;
u16 id, i, row, col;
f32 q_temp[64];
length = ((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]) & 0xffff;
__THPInfo->c += 2;
length -= 2;
for (;;) {
id = (*(__THPInfo->c)++);
for (i = 0; i < 64; i++) {
q_temp[__THPJpegNaturalOrder[i]] = (f32)(*(__THPInfo->c)++);
}
i = 0;
for (row = 0; row < 8; row++) {
for (col = 0; col < 8; col++) {
__THPInfo->quantTabs[id][i]
= (f32)((f64)q_temp[i] * __THPAANScaleFactor[row]
* __THPAANScaleFactor[col]);
i++;
}
}
length -= 65;
if ((u16)length == 0) {
break;
}
}
return 0;
}
static u8 __THPReadHuffmanTableSpecification() {
u8 t_class, id, i, tab_index;
u16 length, num_Vij;
__THPHuffmanSizeTab = __THPWorkArea;
__THPHuffmanCodeTab = (u16*)((uintptr_t)__THPWorkArea + 256 + 1);
length = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]);
__THPInfo->c += 2;
#if PLATFORM_SHIELD
length -= (u16)2;
#else
length -= 2;
#endif
for (;;) {
i = (*(__THPInfo->c)++);
id = (u8)(i & 15);
t_class = (u8)(i >> 4);
__THPHuffmanBits = __THPInfo->c;
tab_index = (u8)((id << 1) + t_class);
num_Vij = 0;
for (i = 0; i < 16; i++) {
num_Vij += (*(__THPInfo->c)++);
}
__THPInfo->huffmanTabs[tab_index].Vij = __THPInfo->c;
__THPInfo->c += num_Vij;
__THPHuffGenerateSizeTable();
__THPHuffGenerateCodeTable();
__THPHuffGenerateDecoderTables(tab_index);
#if PLATFORM_SHIELD
__THPInfo->validHuffmanTabs |= (u8)(1 << tab_index);
#else
__THPInfo->validHuffmanTabs |= (1 << tab_index);
#endif
U16_SUB_2(length, (17 + num_Vij));
if (length == 0) {
break;
}
}
return 0;
}
static void __THPHuffGenerateSizeTable() {
s32 p, l, i;
p = 0;
for (l = 1; l <= 16; l++) {
i = (s32)__THPHuffmanBits[l - 1];
while (i--) {
__THPHuffmanSizeTab[p++] = (u8)l;
}
}
__THPHuffmanSizeTab[p] = 0;
}
static void __THPHuffGenerateCodeTable() {
u8 si;
u16 p, code;
p = 0;
code = 0;
si = __THPHuffmanSizeTab[0];
while (__THPHuffmanSizeTab[p]) {
while (__THPHuffmanSizeTab[p] == si) {
__THPHuffmanCodeTab[p++] = code;
code++;
}
code <<= 1;
si++;
}
}
static void __THPHuffGenerateDecoderTables(u8 tabIndex) {
s32 p, l;
THPHuffmanTab* h;
p = 0;
h = &__THPInfo->huffmanTabs[tabIndex];
for (l = 1; l <= 16; l++) {
if (__THPHuffmanBits[l - 1]) {
h->valPtr[l] = p - __THPHuffmanCodeTab[p];
p += __THPHuffmanBits[l - 1];
h->maxCode[l] = __THPHuffmanCodeTab[p - 1];
} else {
h->maxCode[l] = -1;
h->valPtr[l] = -1;
}
}
h->maxCode[17] = 0xfffffL;
}
static void __THPRestartDefinition() {
__THPInfo->RST = TRUE;
__THPInfo->c += 2;
__THPInfo->nMCU = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]);
__THPInfo->c += 2;
__THPInfo->currMCU = __THPInfo->nMCU;
}
static void __THPPrepBitStream() {
u32* ptr;
u32 offset, i, j, k;
ptr = (u32*)((uintptr_t)__THPInfo->c & 0xFFFFFFFC);
offset = (uintptr_t)__THPInfo->c & 3;
ASSERTLINE(3799, __THPInfo->cnt <= 33);
if (__THPInfo->cnt != 33) {
__THPInfo->cnt -= (3 - offset) * 8;
} else {
__THPInfo->cnt = (offset * 8) + 1;
}
ASSERTLINE(3810, __THPInfo->cnt <= 33);
__THPInfo->c = (u8*)ptr;
__THPInfo->currByte = *ptr;
for (i = 0; i < 4; i++) {
if (__THPInfo->validHuffmanTabs & (1 << i)) {
for (j = 0; j < 32; j++) {
__THPInfo->huffmanTabs[i].quick[j] = 0xFF;
for (k = 0; k < 5; k++) {
s32 code = (s32)(j >> (5 - k - 1));
if (code <= __THPInfo->huffmanTabs[i].maxCode[k + 1]) {
__THPInfo->huffmanTabs[i].quick[j]
= __THPInfo->huffmanTabs[i].Vij[(s32)(code + __THPInfo->huffmanTabs[i].valPtr[k + 1])];
__THPInfo->huffmanTabs[i].increment[j] = (u8)(k + 1);
k = 99;
} else {
}
}
}
}
}
{
s32 YdcTab, UdcTab, VdcTab, YacTab, UacTab, VacTab;
YdcTab = (__THPInfo->components[0].DCTableSelector << 1);
UdcTab = (__THPInfo->components[1].DCTableSelector << 1);
VdcTab = (__THPInfo->components[2].DCTableSelector << 1);
YacTab = (__THPInfo->components[0].ACTableSelector << 1) + 1;
UacTab = (__THPInfo->components[1].ACTableSelector << 1) + 1;
VacTab = (__THPInfo->components[2].ACTableSelector << 1) + 1;
Ydchuff = &__THPInfo->huffmanTabs[YdcTab];
Udchuff = &__THPInfo->huffmanTabs[UdcTab];
Vdchuff = &__THPInfo->huffmanTabs[VdcTab];
Yachuff = &__THPInfo->huffmanTabs[YacTab];
Uachuff = &__THPInfo->huffmanTabs[UacTab];
Vachuff = &__THPInfo->huffmanTabs[VacTab];
}
}
static void __THPDecompressYUV(void* tileY, void* tileU, void* tileV) {
u16 currentY, targetY;
__THPInfo->dLC[0] = (u8*)tileY;
__THPInfo->dLC[1] = (u8*)tileU;
__THPInfo->dLC[2] = (u8*)tileV;
currentY = __THPInfo->decompressedY;
targetY = __THPInfo->yPixelSize;
__THPGQRSetup();
__THPPrepBitStream();
if (__THPInfo->xPixelSize == 512 && targetY == 448) {
while (currentY < targetY) {
__THPDecompressiMCURow512x448();
U16_ADD(currentY, 16);
}
} else if (__THPInfo->xPixelSize == 640 && targetY == 480) {
while (currentY < targetY) {
__THPDecompressiMCURow640x480();
U16_ADD(currentY, 16);
}
} else {
while (currentY < targetY) {
__THPDecompressiMCURowNxN();
U16_ADD(currentY, 16);
}
}
__THPGQRRestore();
}
static void __THPGQRRestore() {
#ifdef __MWERKS__
register u32 tmp1, tmp2;
tmp1 = __THPOldGQR5;
tmp2 = __THPOldGQR6;
// clang-format off
asm {
mtspr GQR5, tmp1;
mtspr GQR6, tmp2;
}
#endif
// clang-format on
}
static void __THPGQRSetup() {
#ifdef __MWERKS__
register u32 tmp1, tmp2;
// clang-format off
asm {
mfspr tmp1, GQR5;
mfspr tmp2, GQR6;
}
__THPOldGQR5 = tmp1;
__THPOldGQR6 = tmp2;
asm {
li r3, 0x0007
oris r3, r3, 0x0007
mtspr GQR5, r3
li r3, 0x3D04
oris r3, r3, 0x3D04
mtspr GQR6, r3
}
#endif
// clang-format on
}
static void __THPDecompressiMCURow512x448() {
u8 cl_num;
u32 x_pos;
THPComponent* comp;
LCQueueWait(3);
for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) {
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[0]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]);
__THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]);
__THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]);
comp = &__THPInfo->components[0];
Gbase = __THPLCWork512[0];
Gwid = 512;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos = (u32)(cl_num * 16);
__THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos);
__THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8);
__THPInverseDCTY8(__THPMCUBuffer[2], x_pos);
__THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8);
comp = &__THPInfo->components[1];
Gbase = __THPLCWork512[1];
Gwid = 256;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos /= 2;
__THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos);
comp = &__THPInfo->components[2];
Gbase = __THPLCWork512[2];
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
__THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos);
if (__THPInfo->RST != 0) {
if ((--__THPInfo->currMCU) == 0) {
__THPInfo->currMCU = __THPInfo->nMCU;
__THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8);
if (__THPInfo->cnt > 33) {
__THPInfo->cnt = 33;
}
__THPInfo->components[0].predDC = 0;
__THPInfo->components[1].predDC = 0;
__THPInfo->components[2].predDC = 0;
}
}
}
LCStoreData(__THPInfo->dLC[0], __THPLCWork512[0], 0x2000);
LCStoreData(__THPInfo->dLC[1], __THPLCWork512[1], 0x800);
LCStoreData(__THPInfo->dLC[2], __THPLCWork512[2], 0x800);
__THPInfo->dLC[0] += 0x2000;
__THPInfo->dLC[1] += 0x800;
__THPInfo->dLC[2] += 0x800;
}
static void __THPInverseDCTY8(__REGISTER THPCoeff* in, __REGISTER u32 xPos) {
#ifdef __MWERKS__
register f32 *q, *ws;
register f32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
register f32 tmp10, tmp11, tmp12, tmp13;
register f32 tmp20, tmp21, tmp22, tmp23;
register f32 cc4 = 1.414213562F;
register f32 cc2 = 1.847759065F;
register f32 cc2c6s = 1.082392200F;
register f32 cc2c6a = -2.613125930F;
register f32 bias = 1024.0F;
q = Gq;
ws = &__THPIDCTWorkspace[0] - 2;
{
register u32 itmp0, itmp1, itmp2, itmp3;
// clang-format off
asm {
li itmp2, 8
mtctr itmp2
_loopHead0:
psq_l tmp10, 0(in), 0, 5
psq_l tmp11, 0(q), 0, 0
lwz itmp0, 12(in)
lwz itmp3, 8(in)
ps_mul tmp10, tmp10, tmp11
lwz itmp1, 4(in)
lhz itmp2, 2(in)
or itmp0, itmp0, itmp3
_loopHead1:
cmpwi itmp0, 0
bne _regularIDCT
ps_merge00 tmp0, tmp10, tmp10
cmpwi itmp1, 0
psq_st tmp0, 8(ws), 0, 0
bne _halfIDCT
psq_st tmp0, 16(ws), 0, 0
cmpwi itmp2, 0
psq_st tmp0, 24(ws), 0, 0
bne _quarterIDCT
addi q, q, 8*sizeof(f32)
psq_stu tmp0, 32(ws), 0, 0
addi in, in, 8*sizeof(THPCoeff)
bdnz _loopHead0
b _loopEnd
_quarterIDCT:
ps_msub tmp2, tmp10, cc2, tmp10
addi in, in, 8*sizeof(THPCoeff)
ps_merge00 tmp9, tmp10, tmp10
addi q, q, 8*sizeof(f32)
ps_sub tmp1, cc2, cc2c6s
lwz itmp1, 4(in)
ps_msub tmp3, tmp10, cc4, tmp2
lhz itmp2, 2(in)
ps_merge11 tmp5, tmp10, tmp2
psq_l tmp11, 0(q), 0, 0
ps_nmsub tmp4, tmp10, tmp1, tmp3
ps_add tmp7, tmp9, tmp5
psq_l tmp10, 0(in), 0, 5
ps_merge11 tmp6, tmp3, tmp4
ps_sub tmp5, tmp9, tmp5
lwz itmp0, 12(in)
ps_add tmp8, tmp9, tmp6
lwz itmp3, 8(in)
ps_sub tmp6, tmp9, tmp6
psq_stu tmp7, 8(ws), 0, 0
ps_merge10 tmp6, tmp6, tmp6
psq_stu tmp8, 8(ws), 0, 0
ps_merge10 tmp5, tmp5, tmp5
or itmp0, itmp0, itmp3
psq_stu tmp6, 8(ws), 0, 0
ps_mul tmp10, tmp10, tmp11
psq_stu tmp5, 8(ws), 0, 0
bdnz _loopHead1
b _loopEnd
_halfIDCT:
psq_l tmp1, 4(in), 0, 5
psq_l tmp9, 8(q), 0, 0
addi in, in, 8*sizeof(THPCoeff)
ps_mul tmp1, tmp1, tmp9
addi q, q, 8*sizeof(f32)
ps_sub tmp3, tmp10, tmp1
ps_add tmp2, tmp10, tmp1
lwz itmp0, 12(in)
ps_madd tmp4, tmp1, cc4, tmp3
ps_nmsub tmp5, tmp1, cc4, tmp2
ps_mul tmp8, tmp3, cc2
ps_merge00 tmp4, tmp2, tmp4
lwz itmp3, 8(in)
ps_nmsub tmp6, tmp1, cc2c6a, tmp8
ps_merge00 tmp5, tmp5, tmp3
lwz itmp1, 4(in)
ps_sub tmp6, tmp6, tmp2
ps_nmsub tmp7, tmp10, cc2c6s, tmp8
lhz itmp2, 2(in)
ps_merge11 tmp2, tmp2, tmp6
ps_msub tmp8, tmp3, cc4, tmp6
psq_l tmp10, 0(in), 0, 5
ps_add tmp9, tmp4, tmp2
ps_sub tmp7, tmp7, tmp8
psq_l tmp11, 0(q), 0, 0
ps_merge11 tmp3, tmp8, tmp7
ps_sub tmp4, tmp4, tmp2
psq_stu tmp9, 8(ws), 0, 0
ps_add tmp0, tmp5, tmp3
ps_sub tmp1, tmp5, tmp3
or itmp0, itmp0, itmp3
psq_stu tmp0, 8(ws), 0, 0
ps_merge10 tmp1, tmp1, tmp1
ps_merge10 tmp4, tmp4, tmp4
psq_stu tmp1, 8(ws), 0, 0
ps_mul tmp10, tmp10, tmp11
psq_stu tmp4, 8(ws), 0, 0
bdnz _loopHead1
b _loopEnd
_regularIDCT:
psq_l tmp9, 4(in), 0, 5
psq_l tmp5, 8(q), 0, 0
ps_mul tmp9, tmp9, tmp5
psq_l tmp2, 8(in), 0, 5
psq_l tmp6, 16(q), 0, 0
ps_merge01 tmp0, tmp10, tmp9
psq_l tmp3, 12(in), 0, 5
ps_merge01 tmp1, tmp9, tmp10
psq_l tmp7, 24(q), 0, 0
addi in, in, 8*sizeof(THPCoeff)
ps_madd tmp4, tmp2, tmp6, tmp0
ps_nmsub tmp5, tmp2, tmp6, tmp0
ps_madd tmp6, tmp3, tmp7, tmp1
ps_nmsub tmp7, tmp3, tmp7, tmp1
addi q, q, 8*sizeof(f32)
ps_add tmp0, tmp4, tmp6
ps_sub tmp3, tmp4, tmp6
ps_msub tmp2, tmp7, cc4, tmp6
lwz itmp0, 12(in)
ps_sub tmp8, tmp7, tmp5
ps_add tmp1, tmp5, tmp2
ps_sub tmp2, tmp5, tmp2
ps_mul tmp8, tmp8, cc2
lwz itmp3, 8(in)
ps_merge00 tmp1, tmp0, tmp1
ps_nmsub tmp6, tmp5, cc2c6a, tmp8
ps_msub tmp4, tmp7, cc2c6s, tmp8
lwz itmp1, 4(in)
ps_sub tmp6, tmp6, tmp0
ps_merge00 tmp2, tmp2, tmp3
lhz itmp2, 2(in)
ps_madd tmp5, tmp3, cc4, tmp6
ps_merge11 tmp7, tmp0, tmp6
psq_l tmp10, 0(in), 0, 5
ps_sub tmp4, tmp4, tmp5
ps_add tmp3, tmp1, tmp7
psq_l tmp11, 0(q), 0, 0
ps_merge11 tmp4, tmp5, tmp4
ps_sub tmp0, tmp1, tmp7
ps_mul tmp10, tmp10, tmp11
ps_add tmp5, tmp2, tmp4
ps_sub tmp6, tmp2, tmp4
ps_merge10 tmp5, tmp5, tmp5
psq_stu tmp3, 8(ws), 0, 0
ps_merge10 tmp0, tmp0, tmp0
psq_stu tmp6, 8(ws), 0, 0
psq_stu tmp5, 8(ws), 0, 0
or itmp0, itmp0, itmp3
psq_stu tmp0, 8(ws), 0, 0
bdnz _loopHead1
_loopEnd:
}
// clang-format on
}
ws = &__THPIDCTWorkspace[0];
{
register THPSample* obase = Gbase;
register u32 wid = Gwid;
register u32 itmp0, off0, off1;
register THPSample *out0, *out1;
// clang-format off
asm {
psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0
slwi off0, wid, 3;
psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0
slwi xPos, xPos, 2
psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0
slwi off1, wid, 2
ps_add tmp6, tmp10, tmp11
add off0, off0, xPos
psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0
ps_sub tmp8, tmp10, tmp11
add off1, off0, off1
ps_add tmp6, tmp6, bias
li itmp0, 3
ps_add tmp7, tmp12, tmp13
add out0, obase, off0
ps_sub tmp9, tmp12, tmp13
ps_add tmp0, tmp6, tmp7
add out1, obase, off1
ps_add tmp8, tmp8, bias
mtctr itmp0
_loopHead10:
psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0
ps_msub tmp9, tmp9, cc4, tmp7
psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0
ps_sub tmp3, tmp6, tmp7
ps_add tmp1, tmp8, tmp9
psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0
ps_sub tmp2, tmp8, tmp9
psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0
ps_add tmp8, tmp6, tmp5
ps_sub tmp6, tmp6, tmp5
addi ws, ws, 2*sizeof(f32)
ps_add tmp9, tmp4, tmp7
ps_sub tmp4, tmp4, tmp7
psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0
ps_add tmp7, tmp9, tmp8
ps_sub tmp5, tmp9, tmp8
ps_add tmp8, tmp6, tmp4
psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0
ps_add tmp9, tmp0, tmp7
ps_mul tmp8, tmp8, cc2
psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0
ps_sub tmp23, tmp0, tmp7
ps_madd tmp6, tmp6, cc2c6a, tmp8
psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0
ps_sub tmp6, tmp6, tmp7
addi off0, off0, 2*sizeof(THPSample)
psq_st tmp9, 0(out0), 0, 6
ps_msub tmp4, tmp4, cc2c6s, tmp8
ps_add tmp9, tmp1, tmp6
ps_msub tmp5, tmp5, cc4, tmp6
ps_sub tmp22, tmp1, tmp6
psq_st tmp9, 8(out0), 0, 6
ps_add tmp8, tmp2, tmp5
ps_add tmp4, tmp4, tmp5
psq_st tmp8, 16(out0), 0, 6
addi off1, off1, 2*sizeof(THPSample)
ps_sub tmp9, tmp3, tmp4
ps_add tmp20, tmp3, tmp4
psq_st tmp9, 24(out0), 0, 6
ps_sub tmp21, tmp2, tmp5
ps_add tmp6, tmp10, tmp11
psq_st tmp20, 0(out1), 0, 6
ps_sub tmp8, tmp10, tmp11
ps_add tmp6, tmp6, bias
psq_st tmp21, 8(out1), 0, 6
ps_add tmp7, tmp12, tmp13
ps_sub tmp9, tmp12, tmp13
psq_st tmp22, 16(out1), 0, 6
add out0, obase, off0
ps_add tmp0, tmp6, tmp7
psq_st tmp23, 24(out1), 0, 6
ps_add tmp8, tmp8, bias
add out1, obase, off1
bdnz _loopHead10
psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0
ps_msub tmp9, tmp9, cc4, tmp7
psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0
ps_sub tmp3, tmp6, tmp7
ps_add tmp1, tmp8, tmp9
psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0
ps_sub tmp2, tmp8, tmp9
psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0
ps_add tmp8, tmp6, tmp5
ps_sub tmp6, tmp6, tmp5
ps_add tmp9, tmp4, tmp7
ps_sub tmp4, tmp4, tmp7
ps_add tmp7, tmp9, tmp8
ps_sub tmp5, tmp9, tmp8
ps_add tmp8, tmp6, tmp4
ps_add tmp9, tmp0, tmp7
ps_mul tmp8, tmp8, cc2
ps_sub tmp23, tmp0, tmp7
ps_madd tmp6, tmp6, cc2c6a, tmp8
psq_st tmp9, 0(out0), 0, 6
ps_sub tmp6, tmp6, tmp7
ps_msub tmp4, tmp4, cc2c6s, tmp8
psq_st tmp23, 24(out1), 0, 6
ps_add tmp9, tmp1, tmp6
ps_msub tmp5, tmp5, cc4, tmp6
ps_sub tmp22, tmp1, tmp6
psq_st tmp9, 8(out0), 0, 6
ps_add tmp8, tmp2, tmp5
ps_add tmp4, tmp4, tmp5
psq_st tmp8, 16(out0), 0, 6
ps_sub tmp9, tmp3, tmp4
psq_st tmp22, 16(out1), 0, 6
ps_add tmp20, tmp3, tmp4
psq_st tmp9, 24(out0), 0, 6
ps_sub tmp21, tmp2, tmp5
psq_st tmp20, 0(out1), 0, 6
psq_st tmp21, 8(out1), 0, 6
}
// clang-format on
}
#endif
}
static void __THPInverseDCTNoYPos(__REGISTER THPCoeff* in, __REGISTER u32 xPos) {
#ifdef __MWERKS__
register f32 *q, *ws;
register f32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
register f32 tmp10, tmp11, tmp12, tmp13;
register f32 tmp20, tmp21, tmp22, tmp23;
register f32 cc4 = 1.414213562F;
register f32 cc2 = 1.847759065F;
register f32 cc2c6s = 1.082392200F;
register f32 cc2c6a = -2.613125930F;
register f32 bias = 1024.0F;
q = Gq;
ws = &__THPIDCTWorkspace[0] - 2;
{
register u32 itmp0, itmp1, itmp2, itmp3;
// clang-format off
asm {
li itmp2, 8
mtctr itmp2
_loopHead0:
psq_l tmp10, 0(in), 0, 5
psq_l tmp11, 0(q), 0, 0
lwz itmp0, 12(in)
lwz itmp3, 8(in)
ps_mul tmp10, tmp10, tmp11
lwz itmp1, 4(in)
lhz itmp2, 2(in)
or. itmp0, itmp0, itmp3
_loopHead1:
cmpwi itmp0, 0
bne _regularIDCT
ps_merge00 tmp0, tmp10, tmp10
cmpwi itmp1, 0
psq_st tmp0, 8(ws), 0, 0
bne _halfIDCT
psq_st tmp0, 16(ws), 0, 0
cmpwi itmp2, 0
psq_st tmp0, 24(ws), 0, 0
bne _quarterIDCT
addi q, q, 8*sizeof(f32)
psq_stu tmp0, 32(ws), 0, 0
addi in, in, 8*sizeof(THPCoeff)
bdnz _loopHead0
b _loopEnd
_quarterIDCT:
addi in, in, 8*sizeof(THPCoeff)
ps_msub tmp2, tmp10, cc2, tmp10
addi q, q, 8*sizeof(f32)
ps_merge00 tmp9, tmp10, tmp10
lwz itmp1, 4(in)
ps_sub tmp1, cc2, cc2c6s
ps_msub tmp3, tmp10, cc4, tmp2
lhz itmp2, 2(in)
ps_merge11 tmp5, tmp10, tmp2
psq_l tmp11, 0(q), 0, 0
ps_nmsub tmp4, tmp10, tmp1, tmp3
ps_add tmp7, tmp9, tmp5
psq_l tmp10, 0(in), 0, 5
ps_merge11 tmp6, tmp3, tmp4
ps_sub tmp5, tmp9, tmp5
lwz itmp0, 12(in)
ps_add tmp8, tmp9, tmp6
lwz itmp3, 8(in)
ps_sub tmp6, tmp9, tmp6
psq_stu tmp7, 8(ws), 0, 0
ps_merge10 tmp6, tmp6, tmp6
psq_stu tmp8, 8(ws), 0, 0
ps_merge10 tmp5, tmp5, tmp5
or itmp0, itmp0, itmp3
psq_stu tmp6, 8(ws), 0, 0
ps_mul tmp10, tmp10, tmp11
psq_stu tmp5, 8(ws), 0, 0
bdnz _loopHead1
b _loopEnd
_halfIDCT:
psq_l tmp1, 4(in), 0, 5
psq_l tmp9, 8(q), 0, 0
addi in, in, 8*sizeof(THPCoeff)
ps_mul tmp1, tmp1, tmp9
addi q, q, 8*sizeof(f32)
ps_sub tmp3, tmp10, tmp1
ps_add tmp2, tmp10, tmp1
lwz itmp0, 12(in)
ps_madd tmp4, tmp1, cc4, tmp3
ps_nmsub tmp5, tmp1, cc4, tmp2
ps_mul tmp8, tmp3, cc2
ps_merge00 tmp4, tmp2, tmp4
lwz itmp3, 8(in)
ps_nmsub tmp6, tmp1, cc2c6a, tmp8
ps_merge00 tmp5, tmp5, tmp3
lwz itmp1, 4(in)
ps_sub tmp6, tmp6, tmp2
ps_nmsub tmp7, tmp10, cc2c6s, tmp8
lhz itmp2, 2(in)
ps_merge11 tmp2, tmp2, tmp6
ps_msub tmp8, tmp3, cc4, tmp6
psq_l tmp10, 0(in), 0, 5
ps_add tmp9, tmp4, tmp2
ps_sub tmp7, tmp7, tmp8
psq_l tmp11, 0(q), 0, 0
ps_merge11 tmp3, tmp8, tmp7
ps_sub tmp4, tmp4, tmp2
psq_stu tmp9, 8(ws), 0, 0
ps_add tmp0, tmp5, tmp3
ps_sub tmp1, tmp5, tmp3
or itmp0, itmp0, itmp3
psq_stu tmp0, 8(ws), 0, 0
ps_merge10 tmp1, tmp1, tmp1
ps_merge10 tmp4, tmp4, tmp4
psq_stu tmp1, 8(ws), 0, 0
ps_mul tmp10, tmp10, tmp11
psq_stu tmp4, 8(ws), 0, 0
bdnz _loopHead1
b _loopEnd
_regularIDCT:
psq_l tmp9, 4(in), 0, 5
psq_l tmp5, 8(q), 0, 0
ps_mul tmp9, tmp9, tmp5
psq_l tmp2, 8(in), 0, 5
psq_l tmp6, 16(q), 0, 0
ps_merge01 tmp0, tmp10, tmp9
psq_l tmp3, 12(in), 0, 5
ps_merge01 tmp1, tmp9, tmp10
psq_l tmp7, 24(q), 0, 0
addi in, in, 8*sizeof(THPCoeff)
ps_madd tmp4, tmp2, tmp6, tmp0
ps_nmsub tmp5, tmp2, tmp6, tmp0
ps_madd tmp6, tmp3, tmp7, tmp1
ps_nmsub tmp7, tmp3, tmp7, tmp1
addi q, q, 8*sizeof(f32)
ps_add tmp0, tmp4, tmp6
ps_sub tmp3, tmp4, tmp6
ps_msub tmp2, tmp7, cc4, tmp6
lwz itmp0, 12(in)
ps_sub tmp8, tmp7, tmp5
ps_add tmp1, tmp5, tmp2
ps_sub tmp2, tmp5, tmp2
ps_mul tmp8, tmp8, cc2
lwz itmp3, 8(in)
ps_merge00 tmp1, tmp0, tmp1
ps_nmsub tmp6, tmp5, cc2c6a, tmp8
ps_msub tmp4, tmp7, cc2c6s, tmp8
lwz itmp1, 4(in)
ps_sub tmp6, tmp6, tmp0
ps_merge00 tmp2, tmp2, tmp3
lhz itmp2, 2(in)
ps_madd tmp5, tmp3, cc4, tmp6
ps_merge11 tmp7, tmp0, tmp6
psq_l tmp10, 0(in), 0, 5
ps_sub tmp4, tmp4, tmp5
ps_add tmp3, tmp1, tmp7
psq_l tmp11, 0(q), 0, 0
ps_merge11 tmp4, tmp5, tmp4
ps_sub tmp0, tmp1, tmp7
ps_mul tmp10, tmp10, tmp11
ps_add tmp5, tmp2, tmp4
ps_sub tmp6, tmp2, tmp4
ps_merge10 tmp5, tmp5, tmp5
psq_stu tmp3, 8(ws), 0, 0
ps_merge10 tmp0, tmp0, tmp0
psq_stu tmp6, 8(ws), 0, 0
psq_stu tmp5, 8(ws), 0, 0
or itmp0, itmp0, itmp3
psq_stu tmp0, 8(ws), 0, 0
bdnz _loopHead1
_loopEnd:
}
// clang-format on
}
ws = &__THPIDCTWorkspace[0];
{
register THPSample* obase = Gbase;
register u32 wid = Gwid;
register u32 itmp0, off0, off1;
register THPSample *out0, *out1;
// clang-format off
asm {
psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0
slwi xPos, xPos, 2
psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0
slwi off1, wid, 2
psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0
mr off0, xPos
ps_add tmp6, tmp10, tmp11
psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0
ps_sub tmp8, tmp10, tmp11
add off1, off0, off1
ps_add tmp6, tmp6, bias
li itmp0, 3
ps_add tmp7, tmp12, tmp13
add out0, obase, off0
ps_sub tmp9, tmp12, tmp13
ps_add tmp0, tmp6, tmp7
add out1, obase, off1
ps_add tmp8, tmp8, bias
mtctr itmp0
_loopHead10:
psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0
ps_msub tmp9, tmp9, cc4, tmp7
psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0
ps_sub tmp3, tmp6, tmp7
ps_add tmp1, tmp8, tmp9
psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0
ps_sub tmp2, tmp8, tmp9
psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0
ps_add tmp8, tmp6, tmp5
ps_sub tmp6, tmp6, tmp5
addi ws, ws, 2*sizeof(f32)
ps_add tmp9, tmp4, tmp7
ps_sub tmp4, tmp4, tmp7
psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0
ps_add tmp7, tmp9, tmp8
ps_sub tmp5, tmp9, tmp8
ps_add tmp8, tmp6, tmp4
psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0
ps_add tmp9, tmp0, tmp7
ps_mul tmp8, tmp8, cc2
psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0
ps_sub tmp23, tmp0, tmp7
ps_madd tmp6, tmp6, cc2c6a, tmp8
psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0
ps_sub tmp6, tmp6, tmp7
addi off0, off0, 2*sizeof(THPSample)
psq_st tmp9, 0(out0), 0, 6
ps_msub tmp4, tmp4, cc2c6s, tmp8
ps_add tmp9, tmp1, tmp6
ps_msub tmp5, tmp5, cc4, tmp6
ps_sub tmp22, tmp1, tmp6
psq_st tmp9, 8(out0), 0, 6
ps_add tmp8, tmp2, tmp5
ps_add tmp4, tmp4, tmp5
psq_st tmp8, 16(out0), 0, 6
addi off1, off1, 2*sizeof(THPSample)
ps_sub tmp9, tmp3, tmp4
ps_add tmp20, tmp3, tmp4
psq_st tmp9, 24(out0), 0, 6
ps_sub tmp21, tmp2, tmp5
ps_add tmp6, tmp10, tmp11
psq_st tmp20, 0(out1), 0, 6
ps_sub tmp8, tmp10, tmp11
ps_add tmp6, tmp6, bias
psq_st tmp21, 8(out1), 0, 6
ps_add tmp7, tmp12, tmp13
ps_sub tmp9, tmp12, tmp13
psq_st tmp22, 16(out1), 0, 6
add out0, obase, off0
ps_add tmp0, tmp6, tmp7
psq_st tmp23, 24(out1), 0, 6
ps_add tmp8, tmp8, bias
add out1, obase, off1
bdnz _loopHead10
psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0
ps_msub tmp9, tmp9, cc4, tmp7
psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0
ps_sub tmp3, tmp6, tmp7
ps_add tmp1, tmp8, tmp9
psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0
ps_sub tmp2, tmp8, tmp9
psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0
ps_add tmp8, tmp6, tmp5
ps_sub tmp6, tmp6, tmp5
ps_add tmp9, tmp4, tmp7
ps_sub tmp4, tmp4, tmp7
ps_add tmp7, tmp9, tmp8
ps_sub tmp5, tmp9, tmp8
ps_add tmp8, tmp6, tmp4
ps_add tmp9, tmp0, tmp7
ps_mul tmp8, tmp8, cc2
ps_sub tmp23, tmp0, tmp7
ps_madd tmp6, tmp6, cc2c6a, tmp8
psq_st tmp9, 0(out0), 0, 6
ps_sub tmp6, tmp6, tmp7
ps_msub tmp4, tmp4, cc2c6s, tmp8
psq_st tmp23, 24(out1), 0, 6
ps_add tmp9, tmp1, tmp6
ps_msub tmp5, tmp5, cc4, tmp6
ps_sub tmp22, tmp1, tmp6
psq_st tmp9, 8(out0), 0, 6
ps_add tmp8, tmp2, tmp5
ps_add tmp4, tmp4, tmp5
psq_st tmp22, 16(out1), 0, 6
psq_st tmp8, 16(out0), 0, 6
ps_sub tmp9, tmp3, tmp4
ps_add tmp20, tmp3, tmp4
psq_st tmp9, 24(out0), 0, 6
ps_sub tmp21, tmp2, tmp5
psq_st tmp20, 0(out1), 0, 6
psq_st tmp21, 8(out1), 0, 6
}
// clang-format on
}
#endif
}
static void __THPDecompressiMCURow640x480() {
u8 cl_num;
u32 x_pos;
THPComponent* comp;
LCQueueWait(3);
{
for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) {
THPFileInfo* um = __THPInfo;
__THPHuffDecodeDCTCompY(um, __THPMCUBuffer[0]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]);
__THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]);
__THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]);
comp = &__THPInfo->components[0];
Gbase = __THPLCWork640[0];
Gwid = 640;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos = (u32)(cl_num * 16);
__THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos);
__THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8);
__THPInverseDCTY8(__THPMCUBuffer[2], x_pos);
__THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8);
comp = &__THPInfo->components[1];
Gbase = __THPLCWork640[1];
Gwid = 320;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos /= 2;
__THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos);
comp = &__THPInfo->components[2];
Gbase = __THPLCWork640[2];
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
__THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos);
if (__THPInfo->RST != 0) {
__THPInfo->currMCU--;
if (__THPInfo->currMCU == 0) {
__THPInfo->currMCU = __THPInfo->nMCU;
__THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8);
if (__THPInfo->cnt > 32) {
__THPInfo->cnt = 33;
}
__THPInfo->components[0].predDC = 0;
__THPInfo->components[1].predDC = 0;
__THPInfo->components[2].predDC = 0;
}
}
}
}
LCStoreData(__THPInfo->dLC[0], __THPLCWork640[0], 0x2800);
LCStoreData(__THPInfo->dLC[1], __THPLCWork640[1], 0xA00);
LCStoreData(__THPInfo->dLC[2], __THPLCWork640[2], 0xA00);
__THPInfo->dLC[0] += 0x2800;
__THPInfo->dLC[1] += 0xA00;
__THPInfo->dLC[2] += 0xA00;
}
static void __THPDecompressiMCURowNxN() {
u8 cl_num;
u32 x_pos, x;
THPComponent* comp;
x = __THPInfo->xPixelSize;
LCQueueWait(3);
for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) {
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[0]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]);
__THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]);
__THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]);
__THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]);
comp = &__THPInfo->components[0];
Gbase = __THPLCWork640[0];
Gwid = x;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos = (u32)(cl_num * 16);
__THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos);
__THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8);
__THPInverseDCTY8(__THPMCUBuffer[2], x_pos);
__THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8);
comp = &__THPInfo->components[1];
Gbase = __THPLCWork640[1];
Gwid = x / 2;
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
x_pos /= 2;
__THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos);
comp = &__THPInfo->components[2];
Gbase = __THPLCWork640[2];
Gq = __THPInfo->quantTabs[comp->quantizationTableSelector];
__THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos);
if (__THPInfo->RST != 0) {
__THPInfo->currMCU--;
if (__THPInfo->currMCU == 0) {
__THPInfo->currMCU = __THPInfo->nMCU;
__THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8);
if (__THPInfo->cnt > 32) {
__THPInfo->cnt = 33;
}
__THPInfo->components[0].predDC = 0;
__THPInfo->components[1].predDC = 0;
__THPInfo->components[2].predDC = 0;
}
}
}
LCStoreData(__THPInfo->dLC[0], __THPLCWork640[0], ((4 * sizeof(u8) * 64) * (x / 16)));
LCStoreData(__THPInfo->dLC[1], __THPLCWork640[1], ((sizeof(u8) * 64) * (x / 16)));
LCStoreData(__THPInfo->dLC[2], __THPLCWork640[2], ((sizeof(u8) * 64) * (x / 16)));
__THPInfo->dLC[0] += ((4 * sizeof(u8) * 64) * (x / 16));
__THPInfo->dLC[1] += ((sizeof(u8) * 64) * (x / 16));
__THPInfo->dLC[2] += ((sizeof(u8) * 64) * (x / 16));
}
static void __THPHuffDecodeDCTCompY(__REGISTER THPFileInfo* info, THPCoeff* block) {
{
__REGISTER s32 t;
THPCoeff dc;
__REGISTER THPCoeff diff;
__dcbz((void*)block, 0);
t = __THPHuffDecodeTab(info, Ydchuff);
__dcbz((void*)block, 32);
diff = 0;
__dcbz((void*)block, 64);
if (t) {
{
__REGISTER s32 v;
__REGISTER u32 cb;
__REGISTER u32 cnt;
__REGISTER u32 code;
__REGISTER u32 tmp;
__REGISTER u32 cnt1;
__REGISTER u32 tmp1;
// clang-format off
#ifdef __MWERKS__
asm {
lwz cnt,info->cnt;
subfic code,cnt,33;
lwz cb,info->currByte;
subfc. tmp, code, t;
subi cnt1,cnt,1;
bgt _notEnoughBitsDIFF;
add v,cnt,t;
slw cnt,cb,cnt1;
stw v,info->cnt;
subfic v,t,32;
srw diff,cnt,v;
}
#endif
// clang-format on
ASSERTLINE(4309, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
b _DoneDIFF;
_notEnoughBitsDIFF:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi tmp, tmp, 1;
stw cb, info->currByte;
srw cb, cb, code;
stw tmp1, info->c;
add v, cb, v;
stw tmp, info->cnt;
subfic tmp, t, 32;
srw diff, v, tmp;
_DoneDIFF:
}
#endif
// clang-format on
ASSERTLINE(4336, info->cnt <=33);
}
if (__cntlzw((u32)diff) > 32 - t) {
S16_ADD_2(diff, (0xFFFFFFFF << t) + 1);
}
};
__dcbz((void*)block, 96);
dc = (s16)(info->components[0].predDC + diff);
block[0] = info->components[0].predDC = dc;
}
{
__REGISTER s32 k;
__REGISTER s32 code;
__REGISTER u32 cnt;
__REGISTER u32 cb;
__REGISTER u32 increment;
__REGISTER s32 tmp;
__REGISTER THPHuffmanTab* h = Yachuff;
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt, info->cnt;
addi increment, h, 32;
lwz cb, info->currByte;
}
#endif
// clang-format on
for (k = 1; k < 64; k++)
{
__REGISTER s32 ssss;
__REGISTER s32 rrrr;
// clang-format off
#ifdef __MWERKS__
asm {
addi code, cnt, 4;
cmpwi cnt, 28;
rlwnm tmp, cb, code, 27, 31;
bgt _notEnoughBits;
lbzx ssss, h, tmp;
lbzx code, increment, tmp;
cmpwi ssss, 0xFF;
beq _FailedCheckEnoughBits;
add cnt, cnt, code;
b _DoneDecodeTab;
}
#endif
// clang-format on
{
__REGISTER u32 maxcodebase;
__REGISTER u32 tmp2;
_FailedCheckEnoughBits:
cnt += 5;
maxcodebase = (uintptr_t) & (h->maxCode);
// clang-format off
#ifdef __MWERKS__
asm {
li tmp2, sizeof(s32)*(5);
li code, 5;
add maxcodebase, maxcodebase, tmp2;
__WHILE_START:
cmpwi cnt, 33;
slwi tmp, tmp, 1
beq _FCEB_faster;
rlwnm ssss, cb, cnt, 31, 31;
lwzu tmp2, 4(maxcodebase);
or tmp, tmp, ssss
addi cnt, cnt, 1;
b __WHILE_CHECK;
_FCEB_faster:
lwz ssss, info->c;
li cnt, 1;
lwzu cb, 4(ssss);
lwzu tmp2, 4(maxcodebase);
stw ssss, info->c;
rlwimi tmp, cb, 1,31,31;
b __FL_WHILE_CHECK;
__FL_WHILE_START:
slwi tmp, tmp, 1;
rlwnm ssss, cb, cnt, 31, 31;
lwzu tmp2, 4(maxcodebase);
or tmp, tmp, ssss;
__FL_WHILE_CHECK:
cmpw tmp,tmp2
addi cnt, cnt, 1;
addi code, code, 1
bgt __FL_WHILE_START;
b _FCEB_Done;
__WHILE_CHECK:
cmpw tmp,tmp2
addi code, code, 1
bgt __WHILE_START;
}
#endif
// clang-format on
}
_FCEB_Done:
ssss = (h->Vij[(s32)(tmp + h->valPtr[code])]);
goto _DoneDecodeTab;
_notEnoughBits:
// clang-format off
#ifdef __MWERKS__
asm
{
cmpwi cnt, 33;
lwz tmp, info->c;
beq _getfullword;
cmpwi cnt, 32;
rlwnm code, cb, code, 27, 31
beq _1bitleft;
lbzx ssss, h, code;
lbzx rrrr, increment, code;
cmpwi ssss, 0xFF;
add code, cnt, rrrr;
beq _FailedCheckNoBits0;
cmpwi code, 33;
bgt _FailedCheckNoBits1;
}
#endif
// clang-format on
cnt = (u32)code;
goto _DoneDecodeTab;
_getfullword : {
// clang-format off
#ifdef __MWERKS__
asm
{
lwzu cb, 4(tmp);
rlwinm code, cb, 5, 27, 31
stw tmp, info->c;
lbzx ssss, h, code;
lbzx tmp, increment, code;
cmpwi ssss, 0xFF
addi cnt, tmp, 1
beq _FailedCheckEnoughbits_Updated;
}
#endif
// clang-format on
}
goto _DoneDecodeTab;
_FailedCheckEnoughbits_Updated:
ssss = 5;
do {
// clang-format off
#ifdef __MWERKS__
asm
{
subfic tmp, ssss, 31;
addi ssss, ssss, 1;
srw code, cb, tmp;
}
#endif
// clang-format on
} while (code > h->maxCode[ssss]);
cnt = (u32)(ssss + 1);
ssss = (h->Vij[(s32)(code + h->valPtr[ssss])]);
goto _DoneDecodeTab;
_1bitleft:
// clang-format off
#ifdef __MWERKS__
asm {
lwzu cb, 4(tmp);
stw tmp, info->c;
rlwimi code, cb, 4, 28, 31;
lbzx ssss, h, code;
lbzx cnt, increment, code
cmpwi ssss, 0xFF
beq _Read4;
}
#endif
// clang-format on
goto _DoneDecodeTab;
_Read4 : {
__REGISTER u32 maxcodebase = (uintptr_t) & (h->maxCode);
__REGISTER u32 tmp2;
// clang-format off
#ifdef __MWERKS__
asm {
li cnt, sizeof(s32)*5;
add maxcodebase, maxcodebase, cnt;
slwi tmp, code, 32-5;
li cnt,5;
rlwimi tmp, cb, 32-1, 1,31;
__DR4_WHILE_START:
subfic ssss, cnt, 31;
lwzu tmp2, 4(maxcodebase);
srw code, tmp, ssss;
__DR4_WHILE_CHECK:
cmpw code, tmp2
addi cnt, cnt, 1
bgt __DR4_WHILE_START;
}
#endif
// clang-format on
}
ssss = (h->Vij[(s32)(code + h->valPtr[cnt])]);
goto _DoneDecodeTab;
_FailedCheckNoBits0:
_FailedCheckNoBits1:
_REALFAILEDCHECKNOBITS : {
__REGISTER u32 mask = 0xFFFFFFFF << (33 - cnt);
__REGISTER u32 tmp2;
__REGISTER u32 tmp3;
code = (uintptr_t)(cb & (~mask));
mask = (uintptr_t) & (h->maxCode);
// clang-format off
#ifdef __MWERKS__
asm {
lwz tmp, info->c;
subfic tmp2, cnt, 33;
addi tmp3, tmp2, 1;
slwi tmp2, tmp2, 2;
lwzu cb, 4(tmp);
add mask,mask, tmp2;
stw tmp, info->c;
slwi code, code, 1;
rlwimi code, cb, 1, 31, 31;
lwzu tmp2, 4(mask);
li cnt, 2;
b __FCNB1_WHILE_CHECK;
__FCNB1_WHILE_START:
slwi code, code, 1;
addi tmp3, tmp3, 1;
lwzu tmp2, 4(mask);
add code, code, rrrr;
addi cnt, cnt, 1;
__FCNB1_WHILE_CHECK:
cmpw code, tmp2;
rlwnm rrrr, cb, cnt, 31, 31;
bgt __FCNB1_WHILE_START;
}
#endif
// clang-format on
ssss = (h->Vij[(s32)(code + h->valPtr[tmp3])]);
}
goto _DoneDecodeTab;
_DoneDecodeTab:
// clang-format off
#ifdef __MWERKS__
asm {
andi. rrrr, ssss, 15;
srawi ssss, ssss, 4;
beq _RECV_SSSS_ZERO;
}
#endif
// clang-format on
{
k += ssss;
{
__REGISTER s32 v;
__REGISTER u32 cnt1;
__REGISTER u32 tmp1;
// clang-format off
#ifdef __MWERKS__
asm
{
subfic code,cnt,33;
subfc. tmp, code, rrrr;
subi cnt1,cnt,1;
bgt _RECVnotEnoughBits;
add cnt,cnt,rrrr;
slw tmp1,cb,cnt1;
subfic v,rrrr,32;
srw ssss,tmp1,v;
}
#endif
// clang-format on
// clang-format off
#ifdef __MWERKS__
asm
{
b _RECVDone;
_RECVnotEnoughBits:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi cnt, tmp, 1;
stw tmp1, info->c;
srw tmp1, cb, code;
add v, tmp1, v;
subfic tmp, rrrr, 32;
srw ssss, v, tmp;
_RECVDone:
}
#endif
// clang-format on
}
if (__cntlzw((u32)ssss) > 32 - rrrr) {
ssss += ((0xFFFFFFFF << rrrr) + 1);
}
block[__THPJpegNaturalOrder[k]] = (s16)ssss;
#ifdef __MWERKS__
goto _RECV_END;
#else
continue;
#endif
}
{
_RECV_SSSS_ZERO:
if (ssss != 15) {
break;
}
k += 15;
};
// clang-format off
#ifdef __MWERKS__
asm
{
_RECV_END:
}
#endif
// clang-format on
}
info->cnt = cnt;
info->currByte = cb;
}
}
static s32 __THPHuffDecodeTab(__REGISTER THPFileInfo* info, __REGISTER THPHuffmanTab* h) {
__REGISTER s32 code;
__REGISTER u32 cnt;
__REGISTER s32 cb;
__REGISTER u32 increment;
__REGISTER s32 tmp;
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt, info->cnt;
addi increment, h, 32;
lwz cb, info->currByte;
addi code, cnt, 4;
cmpwi cnt, 28;
rlwnm tmp, cb, code, 27, 31;
bgt _notEnoughBits;
lbzx code, h, tmp;
lbzx increment, increment, tmp;
cmpwi code, 0xFF;
beq _FailedCheckEnoughBits;
add cnt, cnt, increment;
stw cnt, info->cnt;
}
#endif
// clang-format on
ASSERTLINE(1164, info->cnt <=33);
_done:
return code;
{
__REGISTER u32 maxcodebase;
__REGISTER u32 tmp2;
_FailedCheckEnoughBits:
maxcodebase = (uintptr_t) & (h->maxCode);
cnt += 5;
// clang-format off
#ifdef __MWERKS__
asm {
li tmp2, sizeof(s32)*(5);
li code, 5;
add maxcodebase, maxcodebase, tmp2;
__WHILE_START:
cmpwi cnt, 33;
slwi tmp, tmp, 1
beq _FCEB_faster;
rlwnm increment, cb, cnt, 31, 31;
lwzu tmp2, 4(maxcodebase);
or tmp, tmp, increment
addi cnt, cnt, 1;
b __WHILE_CHECK;
_FCEB_faster:
lwz increment, info->c;
li cnt, 1;
lwzu cb, 4(increment);
lwzu tmp2, 4(maxcodebase);
stw increment, info->c;
rlwimi tmp, cb, 1,31,31;
stw cb, info->currByte;
b __FL_WHILE_CHECK;
__FL_WHILE_START:
slwi tmp, tmp, 1;
rlwnm increment, cb, cnt, 31, 31;
lwzu tmp2, 4(maxcodebase);
or tmp, tmp, increment;
__FL_WHILE_CHECK:
cmpw tmp,tmp2
addi cnt, cnt, 1;
addi code, code, 1
bgt __FL_WHILE_START;
b _FCEB_Done;
__WHILE_CHECK:
cmpw tmp,tmp2
addi code, code, 1
bgt __WHILE_START;
}
#endif
// clang-format on
}
_FCEB_Done:
info->cnt = cnt;
return (h->Vij[(s32)(tmp + h->valPtr[code])]);
// clang-format off
#ifdef __MWERKS__
asm
{
_notEnoughBits:
cmpwi cnt, 33;
lwz tmp, info->c;
beq _getfullword;
cmpwi cnt, 32;
rlwnm code, cb, code, 27, 31
beq _1bitleft;
lbzx tmp, h, code;
lbzx increment, increment, code;
cmpwi tmp, 0xFF;
add code, cnt, increment;
beq _FailedCheckNoBits0;
cmpwi code, 33;
stw code, info->cnt;
bgt _FailedCheckNoBits1;
}
#endif
// clang-format on
ASSERTLINE(1259, info->cnt <=33);
return tmp;
// clang-format off
#ifdef __MWERKS__
asm {
_1bitleft:
lwzu cb, 4(tmp);
stw tmp, info->c;
rlwimi code, cb, 4, 28, 31;
lbzx tmp, h, code;
lbzx increment, increment, code
stw cb, info->currByte;
cmpwi tmp, 0xFF
stw increment, info->cnt;
beq _Read4;
}
#endif
// clang-format on
ASSERTLINE(1278, info->cnt <=33);
return tmp;
_Read4 : {
__REGISTER u32 maxcodebase = (uintptr_t) & (h->maxCode);
__REGISTER u32 tmp2;
// clang-format off
#ifdef __MWERKS__
asm
{
li cnt, sizeof(s32)*5;
add maxcodebase, maxcodebase, cnt;
slwi tmp, code, 32-5;
li cnt,5;
rlwimi tmp, cb, 32-1, 1,31;
__DR4_WHILE_START:
subfic cb, cnt, 31;
lwzu tmp2, 4(maxcodebase);
srw code, tmp, cb;
__DR4_WHILE_CHECK:
cmpw code, tmp2
addi cnt, cnt, 1
bgt __DR4_WHILE_START;
}
#endif
// clang-format on
}
info->cnt = cnt;
ASSERTLINE(1311, info->cnt <=33);
__CODE_PLUS_VP_CNT:
return (h->Vij[(s32)(code + h->valPtr[cnt])]);
_getfullword:
// clang-format off
#ifdef __MWERKS__
asm
{
lwzu cb, 4(tmp);
rlwinm code, cb, 5, 27, 31
stw tmp, info->c;
lbzx cnt, h, code;
lbzx increment, increment, code;
cmpwi cnt, 0xFF
stw cb, info->currByte;
addi increment, increment, 1
beq _FailedCheckEnoughbits_Updated;
stw increment, info->cnt;
}
#endif
// clang-format on
ASSERTLINE(1339, info->cnt <=33);
return (s32)cnt;
_FailedCheckEnoughbits_Updated:
cnt = 5;
do {
// clang-format off
#ifdef __MWERKS__
asm
{
subfic tmp, cnt, 31;
addi cnt, cnt, 1;
srw code, cb, tmp;
}
#endif
// clang-format on
} while (code > h->maxCode[cnt]);
info->cnt = cnt + 1;
ASSERTLINE(1357, info->cnt <=33);
goto __CODE_PLUS_VP_CNT;
_FailedCheckNoBits0:
_FailedCheckNoBits1:
{
__REGISTER u32 mask = 0xFFFFFFFF << (33 - cnt);
__REGISTER u32 tmp2;
code = (s32)(cb & (~mask));
mask = (uintptr_t) & (h->maxCode);
// clang-format off
#ifdef __MWERKS__
asm
{
lwz tmp, info->c;
subfic tmp2, cnt, 33;
addi cnt, tmp2, 1;
slwi tmp2, tmp2, 2;
lwzu cb, 4(tmp);
add mask,mask, tmp2;
stw tmp, info->c;
slwi code, code, 1;
stw cb, info->currByte;
rlwimi code, cb, 1, 31, 31;
lwzu tmp2, 4(mask);
li tmp, 2;
b __FCNB1_WHILE_CHECK;
__FCNB1_WHILE_START:
slwi code, code, 1;
addi cnt, cnt, 1;
lwzu tmp2, 4(mask);
add code, code, increment;
addi tmp, tmp, 1;
__FCNB1_WHILE_CHECK:
cmpw code, tmp2;
rlwnm increment, cb, tmp, 31, 31;
bgt __FCNB1_WHILE_START;
}
#endif
// clang-format on
}
info->cnt = (u32)tmp;
ASSERTLINE(1419, info->cnt <=33);
return (h->Vij[(s32)(code + h->valPtr[cnt])]);
}
static void __THPHuffDecodeDCTCompU(__REGISTER THPFileInfo* info, THPCoeff* block) {
__REGISTER s32 t;
__REGISTER THPCoeff diff;
THPCoeff dc;
__REGISTER s32 v;
__REGISTER u32 cb;
__REGISTER u32 cnt;
__REGISTER u32 cnt33;
__REGISTER u32 tmp;
__REGISTER u32 cnt1;
__REGISTER u32 tmp1;
__REGISTER s32 k;
__REGISTER s32 ssss;
__REGISTER s32 rrrr;
__dcbz((void*)block, 0);
t = __THPHuffDecodeTab(info, Udchuff);
__dcbz((void*)block, 32);
diff = 0;
__dcbz((void*)block, 64);
if (t) {
ASSERTLINE(5023, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt,info->cnt;
subfic cnt33,cnt,33;
lwz cb,info->currByte;
subfc. tmp, cnt33, t;
subi cnt1,cnt,1;
bgt _notEnoughBitsDIFF;
add v,cnt,t;
slw cnt,cb,cnt1;
stw v,info->cnt;
subfic v,t,32;
srw diff,cnt,v;
}
#endif
// clang-format on
ASSERTLINE(5043, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
b _DoneDIFF;
_notEnoughBitsDIFF:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi tmp, tmp, 1;
stw cb, info->currByte;
srw cb, cb, cnt33;
stw tmp1, info->c;
add v, cb, v;
stw tmp, info->cnt;
subfic tmp, t, 32;
srw diff, v, tmp;
_DoneDIFF:
}
#endif
// clang-format on
ASSERTLINE(5070, info->cnt <=33);
if (__cntlzw((u32)diff) > 32 - t) {
S16_ADD_2(diff, (0xFFFFFFFF << t) + 1);
}
}
__dcbz((void*)block, 96);
dc = (s16)(info->components[1].predDC + diff);
block[0] = info->components[1].predDC = dc;
for (k = 1; k < 64; k++) {
ssss = __THPHuffDecodeTab(info, Uachuff);
rrrr = ssss >> 4;
ssss &= 15;
if (ssss) {
k += rrrr;
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt,info->cnt;
subfic cnt33,cnt,33;
lwz cb,info->currByte;
subf. tmp, cnt33, ssss;
subi cnt1,cnt,1;
bgt _notEnoughBits;
add v,cnt,ssss;
slw cnt,cb,cnt1;
stw v,info->cnt;
subfic v,ssss,32;
srw rrrr,cnt,v;
}
#endif
// clang-format on
ASSERTLINE(5110, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
b _Done;
_notEnoughBits:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi tmp, tmp, 1;
stw cb, info->currByte;
srw cb, cb, cnt33;
stw tmp1, info->c;
add v, cb, v;
stw tmp, info->cnt;
subfic tmp, ssss, 32;
srw rrrr, v, tmp;
_Done:
}
#endif
// clang-format on
ASSERTLINE(5137, info->cnt <=33);
if (__cntlzw((u32)rrrr) > 32 - ssss) {
rrrr += ((0xFFFFFFFF << ssss) + 1);
}
block[__THPJpegNaturalOrder[k]] = (s16)rrrr;
}
else {
if (rrrr != 15)
break;
k += 15;
}
}
}
static void __THPHuffDecodeDCTCompV(__REGISTER THPFileInfo* info, THPCoeff* block) {
__REGISTER s32 t;
__REGISTER THPCoeff diff;
THPCoeff dc;
__REGISTER s32 v;
__REGISTER u32 cb;
__REGISTER u32 cnt;
__REGISTER u32 cnt33;
__REGISTER u32 tmp;
__REGISTER u32 cnt1;
__REGISTER u32 tmp1;
__REGISTER s32 k;
__REGISTER s32 ssss;
__REGISTER s32 rrrr;
__dcbz((void*)block, 0);
t = __THPHuffDecodeTab(info, Vdchuff);
__dcbz((void*)block, 32);
diff = 0;
__dcbz((void*)block, 64);
if (t) {
ASSERTLINE(5208, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt,info->cnt;
subfic cnt33,cnt,33;
lwz cb,info->currByte;
subf. tmp, cnt33, t;
subi cnt1,cnt,1;
bgt _notEnoughBitsDIFF;
add v,cnt,t;
slw cnt,cb,cnt1;
stw v,info->cnt;
subfic v,t,32;
srw diff,cnt,v;
}
#endif
// clang-format on
ASSERTLINE(5228, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
b _DoneDIFF;
_notEnoughBitsDIFF:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi tmp, tmp, 1;
stw cb, info->currByte;
srw cb, cb, cnt33;
stw tmp1, info->c;
add v, cb, v;
stw tmp, info->cnt;
subfic tmp, t, 32;
srw diff, v, tmp;
_DoneDIFF:
}
#endif
// clang-format on
ASSERTLINE(5255, info->cnt <=33);
if (__cntlzw((u32)diff) > 32 - t) {
S16_ADD_2(diff, (0xFFFFFFFF << t) + 1);
}
}
__dcbz((void*)block, 96);
dc = (s16)(info->components[2].predDC + diff);
block[0] = info->components[2].predDC = dc;
for (k = 1; k < 64; k++) {
ssss = __THPHuffDecodeTab(info, Vachuff);
rrrr = ssss >> 4;
ssss &= 15;
if (ssss) {
k += rrrr;
// clang-format off
#ifdef __MWERKS__
asm
{
lwz cnt,info->cnt;
subfic cnt33,cnt,33;
lwz cb,info->currByte;
subf. tmp, cnt33, ssss;
subi cnt1,cnt,1;
bgt _notEnoughBits;
add v,cnt,ssss;
slw cnt,cb,cnt1;
stw v,info->cnt;
subfic v,ssss,32;
srw rrrr,cnt,v;
}
#endif
// clang-format on
ASSERTLINE(5296, info->cnt <=33);
// clang-format off
#ifdef __MWERKS__
asm
{
b _Done;
_notEnoughBits:
lwz tmp1, info->c;
slw v, cb, cnt1;
lwzu cb, 4(tmp1);
addi tmp, tmp, 1;
stw cb, info->currByte;
srw cb, cb, cnt33;
stw tmp1, info->c;
add v, cb, v;
stw tmp, info->cnt;
subfic tmp, ssss, 32;
srw rrrr, v, tmp;
_Done:
}
#endif
// clang-format on
ASSERTLINE(5323, info->cnt <=33);
if (__cntlzw((u32)rrrr) > 32 - ssss) {
rrrr += ((0xFFFFFFFF << ssss) + 1);
}
block[__THPJpegNaturalOrder[k]] = (s16)rrrr;
} else {
if (rrrr != 15)
break;
k += 15;
}
}
}
#else // !TARGET_PC
static daMP_THPPlayer daMP_ActivePlayer;
#if MOVIE_SUPPORT
static std::vector<u8> FixedJpegData;
static tjhandle JpegDecompressHandle;
static const std::vector<u8>& FixJpeg(const std::span<u8> data) {
FixedJpegData.resize(0);
FixedJpegData.reserve(data.size());
size_t startOfScanLocation = 0;
for (; startOfScanLocation < data.size() - 1; startOfScanLocation++) {
if (data[startOfScanLocation] == 0xFF && data[startOfScanLocation + 1] == 0xDA) {
goto sosFound;
}
}
CRASH("Unable to find SOS marker!");
sosFound:
startOfScanLocation += 2; // TODO: Skip entire SOS header?
size_t endOfImage = data.size() - 1;
for (; endOfImage > startOfScanLocation; endOfImage--) {
if (data[endOfImage] == 0xFF && data[endOfImage + 1] == 0xD9) {
goto eoiFound;
}
}
CRASH("Unable to find EOI marker!");
eoiFound:
// Copy data before SOS
for (size_t i = 0; i < startOfScanLocation; i++) {
FixedJpegData.push_back(data[i]);
}
// Copy data inside SOS, fixing up lacking of "byte shuffling"
for (size_t i = startOfScanLocation; i < endOfImage; i++) {
u8 value = data[i];
FixedJpegData.push_back(value);
if (value == 0xFF) {
FixedJpegData.push_back(0x00);
}
}
// Copy data after SOS.
for (size_t i = endOfImage; i < data.size(); i++) {
FixedJpegData.push_back(data[i]);
}
return FixedJpegData;
}
static s32 THPVideoDecode(void* file, size_t fileSize, void* tileY, void* tileU, void* tileV, void*) {
assert(JpegDecompressHandle);
const auto handle = JpegDecompressHandle;
const auto fixedData = FixJpeg(std::span(static_cast<u8*>(file), fileSize));
auto ret = tj3DecompressHeader(handle, fixedData.data(), fixedData.size());
if (ret == -1) {
OSReport_Error("Parsing JPEG header failed: %s", tj3GetErrorStr(handle));
return 1;
}
if (tj3Get(handle, TJPARAM_JPEGWIDTH) != daMP_ActivePlayer.videoInfo.xSize) {
OSReport_Error("Invalid width in video frame!");
return 1;
}
if (tj3Get(handle, TJPARAM_JPEGHEIGHT) != daMP_ActivePlayer.videoInfo.ySize) {
OSReport_Error("Invalid height in video frame!");
return 1;
}
ret = tj3Set(handle, TJPARAM_SUBSAMP, TJSAMP_420);
if (ret != 0) {
OSReport_Error("Failed to set subsampling mode: %s", tj3GetErrorStr(handle));
return 1;
}
u8* planes[3] = {static_cast<u8*>(tileY), static_cast<u8*>(tileU), static_cast<u8*>(tileV)};
ret = tj3DecompressToYUVPlanes8(handle, fixedData.data(), fixedData.size(), planes, nullptr);
if (ret != 0) {
OSReport_Error("Image decompression failed: %s", tj3GetErrorStr(handle));
return 1;
}
return 0;
}
#else // MOVIE_SUPPORT
static s32 THPVideoDecode(void*, size_t, void*, void*, void*, void*) {
return 1; // Immediate error.
}
#endif
#endif
static BOOL THPInit() {
#if !TARGET_PC
u8* base;
base = (u8*)(0xE000 << 16);
__THPLCWork512[0] = base;
base += 0x2000;
__THPLCWork512[1] = base;
base += 0x800;
__THPLCWork512[2] = base;
base += 0x200;
base = (u8*)(0xE000 << 16);
__THPLCWork640[0] = base;
base += 0x2800;
__THPLCWork640[1] = base;
base += 0xA00;
__THPLCWork640[2] = base;
base += 0xA00;
OSInitFastCast();
__THPInitFlag = TRUE;
#endif
return TRUE;
}
#if defined(__cplusplus) && !TARGET_PC
}
#endif
#if !TARGET_PC // Defined earlier in file.
static daMP_THPPlayer daMP_ActivePlayer;
#endif
#if TARGET_PC
static BOOL ReadThreadCancelled;
#endif
static BOOL daMP_ReadThreadCreated;
static OSMessageQueue daMP_FreeReadBufferQueue;
static OSMessageQueue daMP_ReadedBufferQueue;
void* daMP_PopReadedBuffer() {
OSMessage buffer;
OSReceiveMessage(&daMP_ReadedBufferQueue, &buffer, 1);
return buffer;
}
void daMP_PushReadedBuffer(void* buffer) {
OSSendMessage(&daMP_ReadedBufferQueue, buffer, 1);
}
void* daMP_PopFreeReadBuffer() {
OSMessage buffer;
OSReceiveMessage(&daMP_FreeReadBufferQueue, &buffer, 1);
return buffer;
}
void daMP_PushFreeReadBuffer(void* buffer) {
OSSendMessage(&daMP_FreeReadBufferQueue, buffer, 1);
}
static OSMessageQueue daMP_ReadedBufferQueue2;
void* daMP_PopReadedBuffer2() {
OSMessage buffer;
OSReceiveMessage(&daMP_ReadedBufferQueue2, &buffer, 1);
return buffer;
}
void daMP_PushReadedBuffer2(void* buffer) {
OSSendMessage(&daMP_ReadedBufferQueue2, buffer, 1);
}
static OSMessage daMP_FreeReadBufferMessage[10];
static OSMessage daMP_ReadedBufferMessage[10];
static OSMessage daMP_ReadedBufferMessage2[10];
static OSThread daMP_ReadThread;
void daMP_ReadThreadStart() {
if (daMP_ReadThreadCreated) {
OSResumeThread(&daMP_ReadThread);
}
}
void daMP_ReadThreadCancel() {
if (daMP_ReadThreadCreated) {
#if TARGET_PC
ReadThreadCancelled = TRUE;
OSReceiveMessage(&daMP_ReadedBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
OSSendMessage(&daMP_FreeReadBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
OSJoinThread(&daMP_ReadThread, nullptr);
#else
OSCancelThread(&daMP_ReadThread);
#endif
daMP_ReadThreadCreated = FALSE;
}
}
void* daMP_Reader(void*) {
#if TARGET_PC
OSSetCurrentThreadName("movie player reader");
#endif
daMP_THPReadBuffer* buf;
s32 curFrame;
s32 status;
s32 offset;
s32 initReadSize;
s32 frame = 0;
offset = daMP_ActivePlayer.initOffset;
initReadSize = daMP_ActivePlayer.initReadSize;
#if TARGET_PC
while (!ReadThreadCancelled) {
#else
while (TRUE) {
#endif
buf = (daMP_THPReadBuffer*)daMP_PopFreeReadBuffer();
#if TARGET_PC
if (!buf) {
return nullptr;
}
#endif
status = DVDReadPrio(&daMP_ActivePlayer.fileInfo, buf->ptr, initReadSize, offset, 2);
if (status != initReadSize) {
if (status == -1)
daMP_ActivePlayer.dvdError = -1;
if (frame == 0)
daMP_PrepareReady(FALSE);
#if TARGET_PC
return nullptr;
#else
OSSuspendThread(&daMP_ReadThread);
#endif
}
buf->frameNumber = frame;
daMP_PushReadedBuffer(buf);
offset += initReadSize;
initReadSize = daMP_NEXT_READ_SIZE(buf);
u32 numFrames = daMP_ActivePlayer.header.numFrames;
curFrame = (frame + daMP_ActivePlayer.initReadFrame) % numFrames;
if (curFrame == daMP_ActivePlayer.header.numFrames - 1) {
if (daMP_ActivePlayer.playFlag & 1)
offset = daMP_ActivePlayer.header.movieDataOffsets;
else {
#if TARGET_PC
return nullptr;
#else
OSSuspendThread(&daMP_ReadThread);
#endif
}
}
frame++;
}
#if TARGET_PC
return nullptr;
#endif
}
static u8 daMP_ReadThreadStack[0x2000];
#if TARGET_PC
static BOOL VideoThreadCancelled;
#endif
static BOOL daMP_VideoDecodeThreadCreated;
static BOOL daMP_CreateReadThread(s32 param_0) {
#if TARGET_PC
ReadThreadCancelled = FALSE;
#endif
if (!OSCreateThread(&daMP_ReadThread, daMP_Reader, 0, daMP_ReadThreadStack + sizeof(daMP_ReadThreadStack), sizeof(daMP_ReadThreadStack), param_0, OS_THREAD_ATTR)) {
OSReport("Can't create read thread\n");
return FALSE;
}
OSInitMessageQueue(&daMP_FreeReadBufferQueue, daMP_FreeReadBufferMessage, 10);
OSInitMessageQueue(&daMP_ReadedBufferQueue, daMP_ReadedBufferMessage, 10);
OSInitMessageQueue(&daMP_ReadedBufferQueue2, daMP_ReadedBufferMessage2, 10);
daMP_ReadThreadCreated = TRUE;
return TRUE;
}
static OSThread daMP_VideoDecodeThread;
static u8 daMP_VideoDecodeThreadStack[0x64000];
static OSMessageQueue daMP_FreeTextureSetQueue;
void* daMP_PopFreeTextureSet() {
OSMessage tex;
OSReceiveMessage(&daMP_FreeTextureSetQueue, &tex, 1);
return tex;
}
void daMP_PushFreeTextureSet(void* tex) {
OSSendMessage(&daMP_FreeTextureSetQueue, tex, 0);
}
static OSMessageQueue daMP_DecodedTextureSetQueue;
void* daMP_PopDecodedTextureSet(s32 flags) {
OSMessage tex;
if (OSReceiveMessage(&daMP_DecodedTextureSetQueue, &tex, flags) == TRUE) {
return tex;
} else {
return NULL;
}
}
void daMP_PushDecodedTextureSet(void* tex) {
OSSendMessage(&daMP_DecodedTextureSetQueue, tex, 1);
}
static OSMessage daMP_FreeTextureSetMessage[3];
static OSMessage daMP_DecodedTextureSetMessage[3];
static BOOL daMP_First;
static void daMP_VideoDecode(daMP_THPReadBuffer* readBuffer) {
THPTextureSet* textureSet;
s32 i;
BE(u32)* tileOffsets;
u8* tile;
tileOffsets = (BE(u32)*)(readBuffer->ptr + 8);
tile = &readBuffer->ptr[daMP_ActivePlayer.compInfo.numComponents * 4] + 8;
textureSet = (THPTextureSet*)daMP_PopFreeTextureSet();
#if TARGET_PC
if (textureSet == nullptr) {
return;
}
#endif
for (i = 0; i < daMP_ActivePlayer.compInfo.numComponents; i++) {
switch (daMP_ActivePlayer.compInfo.frameComp[i]) {
case 0: {
if ((daMP_ActivePlayer.videoError = THPVideoDecode(
tile,
#if TARGET_PC
*tileOffsets,
#endif
textureSet->ytexture, textureSet->utexture,
textureSet->vtexture,
daMP_ActivePlayer.thpWork))) {
if (daMP_First) {
daMP_PrepareReady(FALSE);
daMP_First = FALSE;
}
OSSuspendThread(&daMP_VideoDecodeThread);
}
textureSet->frameNumber = readBuffer->frameNumber;
daMP_PushDecodedTextureSet(textureSet);
BOOL enable = OSDisableInterrupts();
daMP_ActivePlayer.videoDecodeCount++;
OSRestoreInterrupts(enable);
}
}
tile += *tileOffsets;
tileOffsets++;
}
if (daMP_First) {
daMP_PrepareReady(1);
daMP_First = 0;
}
}
static void* daMP_VideoDecoder(void* param_0) {
#if TARGET_PC
OSSetCurrentThreadName("movie video decoder");
#endif
daMP_THPReadBuffer* thpBuffer;
#if TARGET_PC
while (!VideoThreadCancelled) {
#else
while (TRUE) {
#endif
if (daMP_ActivePlayer.audioExist) {
for (; daMP_ActivePlayer.videoDecodeCount < 0;) {
thpBuffer = (daMP_THPReadBuffer*)daMP_PopReadedBuffer2();
#if TARGET_PC
if (thpBuffer == nullptr) {
goto exit;
}
#endif
s32 remaining
= ((thpBuffer->frameNumber + daMP_ActivePlayer.initReadFrame)
% daMP_ActivePlayer.header.numFrames);
if (remaining == (daMP_ActivePlayer.header.numFrames - 1)
&& (daMP_ActivePlayer.playFlag & 1) == 0)
daMP_VideoDecode(thpBuffer);
daMP_PushFreeReadBuffer(thpBuffer);
BOOL enable = OSDisableInterrupts();
daMP_ActivePlayer.videoDecodeCount++;
OSRestoreInterrupts(enable);
}
}
if (daMP_ActivePlayer.audioExist)
thpBuffer = (daMP_THPReadBuffer*)daMP_PopReadedBuffer2();
else
thpBuffer = (daMP_THPReadBuffer*)daMP_PopReadedBuffer();
#if TARGET_PC
if (thpBuffer == nullptr) {
goto exit;
}
#endif
daMP_VideoDecode(thpBuffer);
daMP_PushFreeReadBuffer(thpBuffer);
}
#if TARGET_PC
exit:;
return nullptr;
#endif
}
static void* daMP_VideoDecoderForOnMemory(void* param_0) {
#if TARGET_PC
OSSetCurrentThreadName("movie video decoder");
#endif
daMP_THPReadBuffer readBuffer;
s32 readSize;
s32 frame;
s32 remaining;
readSize = daMP_ActivePlayer.initReadSize;
readBuffer.ptr = (u8*)param_0;
frame = 0;
while (TRUE) {
if (daMP_ActivePlayer.audioExist) {
while (daMP_ActivePlayer.videoDecodeCount < 0) {
BOOL enable = OSDisableInterrupts();
daMP_ActivePlayer.videoDecodeCount++;
OSRestoreInterrupts(enable);
remaining = (frame + daMP_ActivePlayer.initReadFrame)
% daMP_ActivePlayer.header.numFrames;
if (remaining == daMP_ActivePlayer.header.numFrames - 1) {
if ((daMP_ActivePlayer.playFlag & 1) == 0)
break;
readSize = *(s32*)readBuffer.ptr;
readBuffer.ptr = daMP_ActivePlayer.movieData;
} else {
s32 size = *(s32*)readBuffer.ptr;
readBuffer.ptr += readSize;
readSize = size;
}
frame++;
}
}
readBuffer.frameNumber = frame;
daMP_VideoDecode(&readBuffer);
remaining = (frame + daMP_ActivePlayer.initReadFrame)
% daMP_ActivePlayer.header.numFrames;
if (remaining == daMP_ActivePlayer.header.numFrames - 1) {
if ((daMP_ActivePlayer.playFlag & 1)) {
readSize = *(s32*)readBuffer.ptr;
readBuffer.ptr = daMP_ActivePlayer.movieData;
} else {
OSSuspendThread(&daMP_VideoDecodeThread);
}
} else {
s32 size = *(s32*)readBuffer.ptr;
readBuffer.ptr += readSize;
readSize = size;
}
frame++;
}
}
static BOOL daMP_CreateVideoDecodeThread(OSPriority prio, u8* param_1) {
#if TARGET_PC
VideoThreadCancelled = FALSE;
#endif
if (param_1 != NULL) {
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoderForOnMemory, param_1, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, OS_THREAD_ATTR)) {
OSReport("Can't create video decode thread\n");
return FALSE;
}
} else {
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoder, NULL, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, OS_THREAD_ATTR)) {
OSReport("Can't create video decode thread\n");
return FALSE;
}
}
OSInitMessageQueue(&daMP_FreeTextureSetQueue, daMP_FreeTextureSetMessage, 3);
OSInitMessageQueue(&daMP_DecodedTextureSetQueue, daMP_DecodedTextureSetMessage, 3);
daMP_First = daMP_VideoDecodeThreadCreated = TRUE;
return TRUE;
}
static void daMP_VideoDecodeThreadStart() {
if (daMP_VideoDecodeThreadCreated) {
OSResumeThread(&daMP_VideoDecodeThread);
}
}
void daMP_VideoDecodeThreadCancel() {
if (daMP_VideoDecodeThreadCreated) {
#if TARGET_PC
VideoThreadCancelled = TRUE;
// Push junk into the queues so the thread unblocks and can exit cleanly.
daMP_PushFreeTextureSet(nullptr);
daMP_PushReadedBuffer(nullptr);
daMP_PushReadedBuffer2(nullptr);
OSJoinThread(&daMP_VideoDecodeThread, nullptr);
#else
OSCancelThread(&daMP_VideoDecodeThread);
#endif
daMP_VideoDecodeThreadCreated = FALSE;
}
}
static BOOL daMP_AudioDecodeThreadCreated;
#if TARGET_PC
static BOOL AudioThreadCancelled;
#endif
static OSThread daMP_AudioDecodeThread;
static u8 daMP_AudioDecodeThreadStack[0x64000];
static OSMessageQueue daMP_FreeAudioBufferQueue;
static void* daMP_PopFreeAudioBuffer() {
OSMessage buffer;
OSReceiveMessage(&daMP_FreeAudioBufferQueue, &buffer, OS_MESSAGE_BLOCK);
return buffer;
}
static void daMP_PushFreeAudioBuffer(void* buffer) {
OSSendMessage(&daMP_FreeAudioBufferQueue, buffer, OS_MESSAGE_NOBLOCK);
}
static OSMessageQueue daMP_DecodedAudioBufferQueue;
static void* daMP_PopDecodedAudioBuffer(s32 flags) {
OSMessage buffer;
if (OSReceiveMessage(&daMP_DecodedAudioBufferQueue, &buffer, flags) == 1) {
return buffer;
}
return NULL;
}
static void daMP_PushDecodedAudioBuffer(void* buffer) {
OSSendMessage(&daMP_DecodedAudioBufferQueue, buffer, OS_MESSAGE_BLOCK);
}
static void daMP_AudioDecode(daMP_THPReadBuffer* readBuffer) {
THPAudioBuffer* audioBuf;
s32 i;
BE(u32)* offsets;
u8* audioData;
offsets = (BE(u32)*)(readBuffer->ptr + 8);
audioData = &readBuffer->ptr[daMP_ActivePlayer.compInfo.numComponents * 4] + 8;
audioBuf = (THPAudioBuffer*)daMP_PopFreeAudioBuffer();
#if TARGET_PC
if (!audioBuf) {
return;
}
#endif
for (i = 0; i < daMP_ActivePlayer.compInfo.numComponents; i++) {
switch (daMP_ActivePlayer.compInfo.frameComp[i]) {
case 1: {
audioBuf->validSample = THPAudioDecode(
audioBuf->buffer,
(audioData + *offsets * daMP_ActivePlayer.curAudioTrack), 0);
audioBuf->curPtr = audioBuf->buffer;
daMP_PushDecodedAudioBuffer(audioBuf);
return;
}
}
audioData += *offsets;
offsets++;
}
}
static void* daMP_AudioDecoder(void* param_0) {
#if TARGET_PC
OSSetCurrentThreadName("movie audio decoder");
#endif
daMP_THPReadBuffer* buf;
#if TARGET_PC
while (!AudioThreadCancelled) {
#else
while (TRUE) {
#endif
buf = (daMP_THPReadBuffer*)daMP_PopReadedBuffer();
#if TARGET_PC
if (!buf) {
return nullptr;
}
#endif
daMP_AudioDecode(buf);
daMP_PushReadedBuffer2(buf);
}
return nullptr;
}
static void* daMP_AudioDecoderForOnMemory(void* param_0) {
#if TARGET_PC
OSSetCurrentThreadName("movie audio decoder");
#endif
s32 size;
s32 readSize;
daMP_THPReadBuffer readBuffer;
s32 frame;
s32 remaining;
readSize = daMP_ActivePlayer.initReadSize;
readBuffer.ptr = (u8*)param_0;
frame = 0;
#if TARGET_PC
while (!AudioThreadCancelled) {
#else
while (TRUE) {
#endif
readBuffer.frameNumber = frame;
daMP_AudioDecode(&readBuffer);
remaining = (frame + daMP_ActivePlayer.initReadFrame) % daMP_ActivePlayer.header.numFrames;
if (remaining == daMP_ActivePlayer.header.numFrames - 1) {
if ((daMP_ActivePlayer.playFlag & 1)) {
readSize = *(s32*)readBuffer.ptr;
readBuffer.ptr = daMP_ActivePlayer.movieData;
} else {
#if TARGET_PC
return nullptr;
#else
OSSuspendThread(&daMP_AudioDecodeThread);
#endif
}
} else {
size = *(s32*)readBuffer.ptr;
readBuffer.ptr += readSize;
readSize = size;
}
frame++;
}
return nullptr;
}
static OSMessage daMP_FreeAudioBufferMessage[3];
static OSMessage daMP_DecodedAudioBufferMessage[3];
static BOOL daMP_CreateAudioDecodeThread(OSPriority prio, u8* param_1) {
#if TARGET_PC
AudioThreadCancelled = FALSE;
#endif
if (param_1 != NULL) {
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoderForOnMemory, param_1, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, OS_THREAD_ATTR)) {
OS_REPORT("Can't create audio decode thread\n");
return FALSE;
}
} else {
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoder, NULL, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, OS_THREAD_ATTR)) {
OSReport("Can't create audio decode thread\n");
return FALSE;
}
}
OSInitMessageQueue(&daMP_FreeAudioBufferQueue, daMP_FreeAudioBufferMessage, 3);
OSInitMessageQueue(&daMP_DecodedAudioBufferQueue, daMP_DecodedAudioBufferMessage, 3);
daMP_AudioDecodeThreadCreated = TRUE;
return TRUE;
}
void daMP_AudioDecodeThreadStart() {
if (daMP_AudioDecodeThreadCreated) {
OSResumeThread(&daMP_AudioDecodeThread);
}
}
void daMP_AudioDecodeThreadCancel() {
if (daMP_AudioDecodeThreadCreated) {
#if TARGET_PC
AudioThreadCancelled = TRUE;
// Push junk into the queues so the thread unblocks and can exit cleanly.
OSSendMessage(&daMP_ReadedBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
daMP_PushFreeAudioBuffer(nullptr);
OSReceiveMessage(&daMP_ReadedBufferQueue2, nullptr, OS_MESSAGE_NOBLOCK);
OSReceiveMessage(&daMP_DecodedAudioBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
OSJoinThread(&daMP_AudioDecodeThread, nullptr);
#else
OSCancelThread(&daMP_AudioDecodeThread);
#endif
daMP_AudioDecodeThreadCreated = FALSE;
}
}
static void daMP_THPGXRestore() {
GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_DISABLE);
GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_SET);
GXSetNumTexGens(1);
GXSetNumChans(0);
GXSetNumTevStages(1);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevSwapMode(GX_TEVSTAGE2, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA);
GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA);
GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA);
}
static f32 dummyLiteral() {
f32 temp = 100.0f;
temp += 60.0f;
return temp;
}
static void daMP_THPGXYuv2RgbSetup(const GXRenderModeObj* rmode) {
s32 w, h;
f32 var_f31;
Mtx44 m;
Mtx e_m;
w = rmode->fbWidth;
h = rmode->efbHeight;
var_f31 = 0.0f;
#if WIDESCREEN_SUPPORT
if (!mDoGph_gInf_c::isWide()) {
var_f31 = (rmode->efbHeight - (h * 808.0f) / 608.0f) * 0.5f;
}
#endif
GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
C_MTXOrtho(m, var_f31, h - var_f31, 0.0f, w, 0.0f, -1.0f);
GXSetProjection(m, GX_ORTHOGRAPHIC);
GXSetViewport(0.0f, 0.0f, w, h, 0.0f, 1.0f);
GXSetScissor(0, 0, w, h);
MTXIdentity(e_m);
GXLoadPosMtxImm(e_m, GX_PNMTX0);
GXSetCurrentMtx(0);
GXSetZCompLoc(GX_TRUE);
GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_DISABLE);
GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
GXSetFog(GX_FOG_NONE, 0.0f, 0.0f, 0.0f, 0.0f, g_clearColor);
GXSetFogRangeAdj(GX_DISABLE, 0, NULL);
GXSetCullMode(GX_CULL_NONE);
GXSetDither(GX_ENABLE);
GXSetColorUpdate(GX_ENABLE);
GXSetAlphaUpdate(GX_DISABLE);
GXSetNumIndStages(0);
GXSetNumChans(0);
GXSetNumTexGens(2);
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 60);
GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, 60);
GXInvalidateTexAll();
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT7, GX_VA_POS, GX_CLR_RGBA, GX_RGBA4, 0);
GXSetVtxAttrFmt(GX_VTXFMT7, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBX8, 0);
GXSetNumTevStages(4);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_KONST, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_KONST, GX_CA_A0);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_SUB, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV);
GXSetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
GXSetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_A);
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP2, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, GX_CC_KONST, GX_CC_CPREV);
GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_2, GX_FALSE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_TEXA, GX_CA_KONST, GX_CA_APREV);
GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_SUB, GX_TB_ZERO, GX_CS_SCALE_1, GX_FALSE, GX_TEVPREV);
GXSetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K1);
GXSetTevKAlphaSel(GX_TEVSTAGE1, GX_TEV_KASEL_K1_A);
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE2, GX_CC_ZERO, GX_CC_TEXC, GX_CC_ONE, GX_CC_CPREV);
GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE2, GX_CA_TEXA, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
GXSetTevAlphaOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevSwapMode(GX_TEVSTAGE2, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevColorIn(GX_TEVSTAGE3, GX_CC_APREV, GX_CC_CPREV, GX_CC_KONST, GX_CC_ZERO);
GXSetTevColorOp(GX_TEVSTAGE3, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE3, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE3, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP0, GX_TEV_SWAP0);
GXSetTevKColorSel(GX_TEVSTAGE3, GX_TEV_KCSEL_K2);
GXColorS10 spA8 = {-0x5A, 0x00, -0x72, 0x87};
GXSetTevColorS10(GX_TEVREG0, spA8);
GXColor spB0 = {0x00, 0x00, 0xE2, 0x58};
GXSetTevKColor(GX_KCOLOR0, spB0);
GXColor spB4 = {0xB3, 0x00, 0x00, 0xB6};
GXSetTevKColor(GX_KCOLOR1, spB4);
GXColor spB8 = {0xFF, 0x00, 0xFF, 0x80};
GXSetTevKColor(GX_KCOLOR2, spB8);
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
}
static void daMP_THPGXYuv2RgbDraw(u8* y_data, u8* u_data, u8* v_data, s16 x,
s16 y, s16 textureWidth, s16 textureHeight, s16 polygonWidth,
s16 polygonHeight) {
TGXTexObj tobj0;
TGXTexObj tobj1;
TGXTexObj tobj2;
#if TARGET_PC
#define FMT (GXTexFmt)GX_TF_R8_PC
#else
#define FMT GX_TF_I8
#endif
GXInitTexObj(&tobj0, y_data, textureWidth, textureHeight, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
GXInitTexObjLOD(&tobj0, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
GXLoadTexObj(&tobj0, GX_TEXMAP0);
GXInitTexObj(&tobj1, u_data, textureWidth >> 1, textureHeight >> 1, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
GXInitTexObjLOD(&tobj1, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
GXLoadTexObj(&tobj1, GX_TEXMAP1);
GXInitTexObj(&tobj2, v_data, textureWidth >> 1, textureHeight >> 1, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
GXInitTexObjLOD(&tobj2, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
GXLoadTexObj(&tobj2, GX_TEXMAP2);
#undef FMT
GXBegin(GX_QUADS, GX_VTXFMT7, 4);
GXPosition3s16(x, y, 0);
GXTexCoord2u16(0, 0);
GXPosition3s16(x + polygonWidth, y, 0);
GXTexCoord2u16(1, 0);
GXPosition3s16(x + polygonWidth, y + polygonHeight, 0);
GXTexCoord2u16(1, 1);
GXPosition3s16(x, y + polygonHeight, 0);
GXTexCoord2u16(0, 1);
GXEnd();
#if TARGET_PC
GXDestroyTexObj(&tobj0);
GXDestroyTexObj(&tobj1);
GXDestroyTexObj(&tobj2);
#endif
}
static u16 daMP_VolumeTable[] = {
0x0000, 0x0002, 0x0008, 0x0012, 0x0020, 0x0032, 0x0049, 0x0063,
0x0082, 0x00A4, 0x00CB, 0x00F5, 0x0124, 0x0157, 0x018E, 0x01C9,
0x0208, 0x024B, 0x0292, 0x02DD, 0x032C, 0x037F, 0x03D7, 0x0432,
0x0492, 0x04F5, 0x055D, 0x05C9, 0x0638, 0x06AC, 0x0724, 0x07A0,
0x0820, 0x08A4, 0x092C, 0x09B8, 0x0A48, 0x0ADD, 0x0B75, 0x0C12,
0x0CB2, 0x0D57, 0x0DFF, 0x0EAC, 0x0F5D, 0x1012, 0x10CA, 0x1187,
0x1248, 0x130D, 0x13D7, 0x14A4, 0x1575, 0x164A, 0x1724, 0x1801,
0x18E3, 0x19C8, 0x1AB2, 0x1BA0, 0x1C91, 0x1D87, 0x1E81, 0x1F7F,
0x2081, 0x2187, 0x2291, 0x239F, 0x24B2, 0x25C8, 0x26E2, 0x2801,
0x2923, 0x2A4A, 0x2B75, 0x2CA3, 0x2DD6, 0x2F0D, 0x3048, 0x3187,
0x32CA, 0x3411, 0x355C, 0x36AB, 0x37FF, 0x3956, 0x3AB1, 0x3C11,
0x3D74, 0x3EDC, 0x4048, 0x41B7, 0x432B, 0x44A3, 0x461F, 0x479F,
0x4923, 0x4AAB, 0x4C37, 0x4DC7, 0x4F5C, 0x50F4, 0x5290, 0x5431,
0x55D6, 0x577E, 0x592B, 0x5ADC, 0x5C90, 0x5E49, 0x6006, 0x61C7,
0x638C, 0x6555, 0x6722, 0x68F4, 0x6AC9, 0x6CA2, 0x6E80, 0x7061,
0x7247, 0x7430, 0x761E, 0x7810, 0x7A06, 0x7C00, 0x7DFE, 0x8000,
};
#pragma push
#pragma optimization_level 3
static void daMP_MixAudio(s16* destination, s16*, u32 sample) {
if (daMP_ActivePlayer.open && daMP_ActivePlayer.internalState == 2 && daMP_ActivePlayer.audioExist) {
u32 sampleNum;
u32 requestSample;
s32 i;
s16* dst;
s16* curPtr;
s32 l_mix, r_mix;
u16 attenuation;
requestSample = sample;
dst = destination;
BOOL loop = TRUE;
do {
do {
if (daMP_ActivePlayer.playAudioBuffer == (THPAudioBuffer*)NULL) {
if (!(daMP_ActivePlayer.playAudioBuffer = (THPAudioBuffer*)daMP_PopDecodedAudioBuffer(0))) {
memset(dst, 0, requestSample * 4);
return;
}
daMP_ActivePlayer.curAudioNumber++;
}
} while ((sampleNum = daMP_ActivePlayer.playAudioBuffer->validSample) == 0);
if (sampleNum >= requestSample) {
sampleNum = requestSample;
}
curPtr = daMP_ActivePlayer.playAudioBuffer->curPtr;
for (i = 0; i < sampleNum; i++) {
if (daMP_ActivePlayer.rampCount != 0) {
daMP_ActivePlayer.rampCount--;
daMP_ActivePlayer.curVolume += daMP_ActivePlayer.deltaVolume;
} else {
daMP_ActivePlayer.curVolume = daMP_ActivePlayer.targetVolume;
}
attenuation = daMP_VolumeTable[(s32)daMP_ActivePlayer.curVolume];
l_mix = 0.7f * (attenuation * curPtr[0] >> 15);
// clamp volume
if (l_mix < -32768)
l_mix = -32768;
if (l_mix > 32767)
l_mix = 32767;
r_mix = 0.7f * (attenuation * curPtr[1] >> 15);
if (r_mix < -32768)
r_mix = -32768;
if (r_mix > 32767)
r_mix = 32767;
if (JASDriver::getOutputMode() == JAS_OUTPUT_MONO) {
l_mix = r_mix = ((r_mix >> 1) + (l_mix >> 1));
r_mix = (s16)r_mix;
l_mix = (s16)l_mix;
}
dst[0] = l_mix;
dst[1] = r_mix;
dst += 2;
curPtr += 2;
}
requestSample -= sampleNum;
daMP_ActivePlayer.playAudioBuffer->validSample -= sampleNum;
daMP_ActivePlayer.playAudioBuffer->curPtr = curPtr;
if ((daMP_ActivePlayer.playAudioBuffer)->validSample == 0) {
daMP_PushFreeAudioBuffer(daMP_ActivePlayer.playAudioBuffer);
daMP_ActivePlayer.playAudioBuffer = (THPAudioBuffer*)NULL;
}
if (requestSample == 0) {
break;
}
} while (loop);
} else {
memset(destination, 0, sample * 4);
}
}
#pragma pop
static BOOL daMP_Initialized;
static u32 daMP_WorkBuffer[16] ATTRIBUTE_ALIGN(32);
static OSMessageQueue daMP_PrepareReadyQueue;
static OSMessageQueue daMP_UsedTextureSetQueue;
static OSMessage daMP_PrepareReadyMessage;
static OSMessage daMP_UsedTextureSetMessage[3];
static VIRetraceCallback daMP_OldVIPostCallback;
static u32 daMP_SoundBufferIndex;
static u32 daMP_OldAIDCallback;
static void* daMP_LastAudioBuffer;
static void* daMP_CurAudioBuffer;
static s32 daMP_AudioSystem;
static u8 daMP_SoundBuffer[2][0x8C0] ATTRIBUTE_ALIGN(32);
static s16* daMP_audioCallbackWithMSound(s32 sample) {
if (daMP_ActivePlayer.open == 0 || daMP_ActivePlayer.internalState != 2 || daMP_ActivePlayer.audioExist == 0) {
return NULL;
}
BOOL enable = OSEnableInterrupts();
daMP_SoundBufferIndex ^= 1;
daMP_MixAudio((s16*)daMP_SoundBuffer[daMP_SoundBufferIndex], NULL, sample);
OSRestoreInterrupts(enable);
return (s16*)daMP_SoundBuffer[daMP_SoundBufferIndex];
}
static void daMP_audioInitWithMSound() {
JASDriver::registerMixCallback(daMP_audioCallbackWithMSound, MIX_MODE_INTERLEAVE);
}
static void daMP_audioQuitWithMSound() {
JASDriver::registerMixCallback(NULL, MIX_MODE_MONO);
}
static void daMP_PushUsedTextureSet(void* tex) {
OSSendMessage(&daMP_UsedTextureSetQueue, tex, OS_MESSAGE_NOBLOCK);
}
static void* daMP_PopUsedTextureSet() {
OSMessage tex;
if (OSReceiveMessage(&daMP_UsedTextureSetQueue, &tex, OS_MESSAGE_NOBLOCK) == 1) {
return tex;
}
return NULL;
}
static int daMP_THPPlayerInit(s32 param_0) {
BOOL enable;
ASSERTMSGLINE(7593, param_0 >= 0 && param_0 <= 2, "audioSystem flag is invalid\n");
memset(&daMP_ActivePlayer, 0, sizeof(daMP_ActivePlayer));
LCEnable();
OSInitMessageQueue(&daMP_UsedTextureSetQueue, daMP_UsedTextureSetMessage, 3);
if (!THPInit()) {
return 0;
}
enable = OSDisableInterrupts();
daMP_AudioSystem = param_0;
daMP_SoundBufferIndex = 0;
daMP_LastAudioBuffer = NULL;
daMP_CurAudioBuffer = NULL;
daMP_audioInitWithMSound();
OSRestoreInterrupts(enable);
if (daMP_AudioSystem == 0) {
memset(daMP_SoundBuffer, 0, sizeof(daMP_SoundBuffer));
DCStoreRange(daMP_SoundBuffer, sizeof(daMP_SoundBuffer));
}
daMP_Initialized = TRUE;
return 1;
}
static void daMP_THPPlayerQuit() {
LCDisable();
daMP_audioQuitWithMSound();
daMP_Initialized = FALSE;
daMP_ActivePlayer.dvdError = 0;
daMP_ActivePlayer.videoError = 0;
}
static BOOL daMP_THPPlayerOpen(char const* filename, BOOL onMemory) {
s32 offset;
s32 i;
if (!daMP_Initialized) {
OSReport("You must call daMP_THPPlayerInit before you call this function\n");
return 0;
}
if (daMP_ActivePlayer.open) {
OSReport("Can't open %s. Because thp file have already opened.\n");
return 0;
}
memset(&daMP_ActivePlayer.videoInfo, 0, sizeof(THPVideoInfo));
memset(&daMP_ActivePlayer.audioInfo, 0, sizeof(THPAudioInfo));
if (!DVDOpen(filename, &daMP_ActivePlayer.fileInfo)) {
OSReport("Can't open %s.\n", filename);
return 0;
}
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_WorkBuffer, sizeof(daMP_WorkBuffer), 0, 2) < 0) {
OSReport("Fail to read the header from THP file.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
memcpy(&daMP_ActivePlayer.header, daMP_WorkBuffer, sizeof(THPHeader));
if (strcmp(daMP_ActivePlayer.header.magic, "THP") != 0) {
OSReport("This file is not THP file.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
if (daMP_ActivePlayer.header.version != 0x11000) {
OSReport("invalid version.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
offset = daMP_ActivePlayer.header.compInfoDataOffsets;
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_WorkBuffer, 0x20, offset, 2) < 0) {
OSReport("Fail to read the frame component infomation from THP file.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
memcpy(&daMP_ActivePlayer.compInfo, daMP_WorkBuffer, sizeof(THPFrameCompInfo));
offset += sizeof(THPFrameCompInfo);
daMP_ActivePlayer.audioExist = 0;
for (i = 0; i < daMP_ActivePlayer.compInfo.numComponents; i++) {
switch (daMP_ActivePlayer.compInfo.frameComp[i]) {
case 0:
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_WorkBuffer, 0x20, offset, 2) < 0) {
OSReport("Fail to read the video infomation from THP file.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
memcpy(&daMP_ActivePlayer.videoInfo, daMP_WorkBuffer, sizeof(THPVideoInfo));
offset += sizeof(THPVideoInfo);
break;
case 1:
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_WorkBuffer, 0x20, offset, 2) < 0) {
OSReport("Fail to read the video infomation from THP file.\n");
DVDClose(&daMP_ActivePlayer.fileInfo);
return 0;
}
memcpy(&daMP_ActivePlayer.audioInfo, daMP_WorkBuffer, sizeof(THPAudioInfo));
daMP_ActivePlayer.audioExist = 1;
offset += sizeof(THPAudioInfo);
break;
default:
OSReport("Unknow frame components.\n");
return 0;
}
}
daMP_ActivePlayer.internalState = 0;
daMP_ActivePlayer.state = 0;
daMP_ActivePlayer.playFlag = 0;
daMP_ActivePlayer.onMemory = onMemory;
daMP_ActivePlayer.open = 1;
daMP_ActivePlayer.curVolume = 127.0f;
daMP_ActivePlayer.targetVolume = 127.0f;
daMP_ActivePlayer.rampCount = 0;
return 1;
}
static BOOL daMP_THPPlayerClose() {
#if TARGET_PC && MOVIE_SUPPORT
tj3Destroy(JpegDecompressHandle);
JpegDecompressHandle = nullptr;
FixedJpegData.clear();
#endif
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state == 0) {
daMP_ActivePlayer.open = 0;
DVDClose(&daMP_ActivePlayer.fileInfo);
return TRUE;
}
return FALSE;
}
static u32 daMP_THPPlayerCalcNeedMemory() {
if (daMP_ActivePlayer.open) {
u32 size = daMP_ActivePlayer.onMemory
? ALIGN_NEXT(daMP_ActivePlayer.header.movieDataSize, 32)
: ALIGN_NEXT(daMP_ActivePlayer.header.bufsize, 32) * 10;
size += ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize, 32) * 3;
size += ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize / 4, 32) * 3;
size += ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize / 4, 32) * 3;
if (daMP_ActivePlayer.audioExist) {
size += ALIGN_NEXT(daMP_ActivePlayer.header.audioMaxSamples * 4, 32) * THP_AUDIO_BUFFER_COUNT;
}
return size + 0x1000;
}
return 0;
}
static BOOL daMP_THPPlayerSetBuffer(u8* buffer) {
u32 i;
u8* ptr;
u32 ysize;
u32 uvsize;
ASSERTMSGLINE(7939, buffer != NULL, "buffer is NULL");
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state == 0) {
ptr = buffer;
if (daMP_ActivePlayer.onMemory) {
daMP_ActivePlayer.movieData = buffer;
ptr += daMP_ActivePlayer.header.movieDataSize;
} else {
for (i = 0; i < ARRAY_SIZE(daMP_ActivePlayer.readBuffer); i++) {
daMP_ActivePlayer.readBuffer[i].ptr = ptr;
ptr += ALIGN_NEXT(daMP_ActivePlayer.header.bufsize, 32);
}
}
ysize = ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize, 32);
uvsize = ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize / 4, 32);
#if TARGET_PC
assert(ysize >= tj3YUVPlaneSize(0, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
assert(uvsize >= tj3YUVPlaneSize(1, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
assert(uvsize >= tj3YUVPlaneSize(2, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
#endif
for (i = 0; i < ARRAY_SIZE(daMP_ActivePlayer.textureSet); i++) {
daMP_ActivePlayer.textureSet[i].ytexture = ptr;
DCInvalidateRange(ptr, ysize);
ptr += ysize;
daMP_ActivePlayer.textureSet[i].utexture = ptr;
DCInvalidateRange(ptr, uvsize);
ptr += uvsize;
daMP_ActivePlayer.textureSet[i].vtexture = ptr;
DCInvalidateRange(ptr, uvsize);
ptr += uvsize;
}
if (daMP_ActivePlayer.audioExist) {
for (i = 0; i < ARRAY_SIZE(daMP_ActivePlayer.audioBuffer); i++) {
daMP_ActivePlayer.audioBuffer[i].buffer = (s16*)ptr;
daMP_ActivePlayer.audioBuffer[i].curPtr = (s16*)ptr;
daMP_ActivePlayer.audioBuffer[i].validSample = 0;
ptr += ALIGN_NEXT(daMP_ActivePlayer.header.audioMaxSamples * 4, 32);
}
}
daMP_ActivePlayer.thpWork = ptr;
return TRUE;
}
return FALSE;
}
static void daMP_InitAllMessageQueue() {
int i;
if (daMP_ActivePlayer.onMemory == FALSE) {
for (i = 0; i < THP_READ_BUFFER_COUNT; i++) {
daMP_PushFreeReadBuffer(&daMP_ActivePlayer.readBuffer[i]);
}
}
for (i = 0; i < THP_TEXTURE_SET_COUNT; i++) {
daMP_PushFreeTextureSet(&daMP_ActivePlayer.textureSet[i]);
}
if (daMP_ActivePlayer.audioExist) {
for (i = 0; i < THP_AUDIO_BUFFER_COUNT; i++) {
daMP_PushFreeAudioBuffer(&daMP_ActivePlayer.audioBuffer[i]);
}
}
OSInitMessageQueue(&daMP_PrepareReadyQueue, &daMP_PrepareReadyMessage, 1);
}
static BOOL daMP_ProperTimingForStart() {
if (daMP_ActivePlayer.videoInfo.videoType & 1) {
if (VIGetNextField() == 0)
return TRUE;
} else if (daMP_ActivePlayer.videoInfo.videoType & 2) {
if (VIGetNextField() == 1)
return TRUE;
} else
return TRUE;
return FALSE;
}
static BOOL daMP_ProperTimingForGettingNextFrame() {
if ((daMP_ActivePlayer.videoInfo.videoType & 1)) {
if (VIGetNextField() == 0) {
return TRUE;
}
} else if ((daMP_ActivePlayer.videoInfo.videoType & 2)) {
if (VIGetNextField() == 1) {
return TRUE;
}
} else {
s32 frameRate = daMP_ActivePlayer.header.frameRate * 100.0f;
#if TARGET_PC
// DUSK HACK: We only fire retrace callbacks *half* as often as the game expects,
// because we only run them once per frame, and normally there should be two scans
// per game frame.
frameRate *= 2;
#endif
if (VIGetTvFormat() == VI_PAL) {
daMP_ActivePlayer.curCount = daMP_ActivePlayer.retaceCount * frameRate / 5000;
} else {
daMP_ActivePlayer.curCount = daMP_ActivePlayer.retaceCount * frameRate / 5994;
}
if (daMP_ActivePlayer.prevCount != daMP_ActivePlayer.curCount) {
daMP_ActivePlayer.prevCount = daMP_ActivePlayer.curCount;
return TRUE;
}
}
return FALSE;
}
static void daMP_PlayControl(u32 retraceCnt) {
THPTextureSet* decodedTexture;
if (daMP_OldVIPostCallback != NULL)
daMP_OldVIPostCallback(retraceCnt);
decodedTexture = (THPTextureSet*)-1;
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state == 2) {
if (daMP_ActivePlayer.dvdError || daMP_ActivePlayer.videoError) {
daMP_ActivePlayer.internalState = 5;
daMP_ActivePlayer.state = 5;
return;
}
++daMP_ActivePlayer.retaceCount;
if (daMP_ActivePlayer.retaceCount == 0) {
if (daMP_ProperTimingForStart()) {
if (daMP_ActivePlayer.audioExist) {
if (daMP_ActivePlayer.curVideoNumber - daMP_ActivePlayer.curAudioNumber <= 1) {
decodedTexture = (THPTextureSet*)daMP_PopDecodedTextureSet(0);
daMP_ActivePlayer.videoDecodeCount--;
daMP_ActivePlayer.curVideoNumber++;
} else {
daMP_ActivePlayer.internalState = 2;
}
} else {
decodedTexture = (THPTextureSet*)daMP_PopDecodedTextureSet(0);
}
} else {
daMP_ActivePlayer.retaceCount = -1;
}
} else {
if (daMP_ActivePlayer.retaceCount == 1) {
daMP_ActivePlayer.internalState = 2;
}
if (daMP_ProperTimingForGettingNextFrame()) {
if (daMP_ActivePlayer.audioExist) {
if (daMP_ActivePlayer.curVideoNumber - daMP_ActivePlayer.curAudioNumber <= 1) {
decodedTexture = (THPTextureSet*)daMP_PopDecodedTextureSet(0);
daMP_ActivePlayer.videoDecodeCount--;
daMP_ActivePlayer.curVideoNumber++;
}
} else {
decodedTexture = (THPTextureSet*)daMP_PopDecodedTextureSet(0);
}
}
}
if (decodedTexture != NULL && decodedTexture != (THPTextureSet*)-1) {
if (daMP_ActivePlayer.dispTextureSet != NULL)
daMP_PushUsedTextureSet(daMP_ActivePlayer.dispTextureSet);
daMP_ActivePlayer.dispTextureSet = decodedTexture;
}
if ((daMP_ActivePlayer.playFlag & 1) == 0) {
if (daMP_ActivePlayer.audioExist) {
s32 audioFrame = daMP_ActivePlayer.curAudioNumber + daMP_ActivePlayer.initReadFrame;
if (audioFrame == daMP_ActivePlayer.header.numFrames && daMP_ActivePlayer.playAudioBuffer == NULL) {
daMP_ActivePlayer.internalState = 3;
daMP_ActivePlayer.state = 3;
}
} else {
s32 curFrame;
if (daMP_ActivePlayer.dispTextureSet != NULL)
curFrame = daMP_ActivePlayer.dispTextureSet->frameNumber + daMP_ActivePlayer.initReadFrame;
else
curFrame = daMP_ActivePlayer.initReadFrame - 1;
if (curFrame == daMP_ActivePlayer.header.numFrames - 1 && decodedTexture == NULL) {
daMP_ActivePlayer.internalState = 3;
daMP_ActivePlayer.state = 3;
}
}
}
}
}
BOOL daMP_WaitUntilPrepare() {
OSMessage msg;
OSReceiveMessage(&daMP_PrepareReadyQueue, &msg, 1);
if ((intptr_t)msg) {
return TRUE;
} else {
return FALSE;
}
}
void daMP_PrepareReady(BOOL msg) {
OSSendMessage(&daMP_PrepareReadyQueue, (OSMessage)(uintptr_t)msg, 1);
}
static BOOL daMP_THPPlayerPrepare(s32 frame, s32 flag, s32 audioTrack) {
u8* threadData;
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state == 0) {
if (frame > 0) {
if (daMP_ActivePlayer.header.offsetDataOffsets == 0) {
OSReport("This thp file doesn't have the offset data\n");
return FALSE;
}
if (daMP_ActivePlayer.header.numFrames > frame) {
int offset = daMP_ActivePlayer.header.offsetDataOffsets + (frame - 1) * 4;
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_WorkBuffer, 0x20, offset, 2) < 0) {
OSReport("Fail to read the offset data from THP file.\n");
return FALSE;
}
daMP_ActivePlayer.initOffset = daMP_ActivePlayer.header.movieDataOffsets + daMP_WorkBuffer[0];
daMP_ActivePlayer.initReadFrame = frame;
daMP_ActivePlayer.initReadSize = daMP_WorkBuffer[1] - daMP_WorkBuffer[0];
} else {
OSReport("Specified frame number is over total frame number\n");
return FALSE;
}
} else {
daMP_ActivePlayer.initOffset = daMP_ActivePlayer.header.movieDataOffsets;
daMP_ActivePlayer.initReadSize = daMP_ActivePlayer.header.firstFrameSize;
daMP_ActivePlayer.initReadFrame = frame;
}
if (daMP_ActivePlayer.audioExist) {
if (audioTrack < 0 || audioTrack >= daMP_ActivePlayer.audioInfo.sndNumTracks) {
OSReport("Specified audio track number is invalid\n");
return FALSE;
}
daMP_ActivePlayer.curAudioTrack = audioTrack;
}
flag &= 1;
daMP_ActivePlayer.playFlag = flag;
daMP_ActivePlayer.videoDecodeCount = 0;
if (daMP_ActivePlayer.onMemory) {
if (DVDReadPrio(&daMP_ActivePlayer.fileInfo, daMP_ActivePlayer.movieData, daMP_ActivePlayer.header.movieDataSize, daMP_ActivePlayer.header.movieDataOffsets, 2) < 0) {
OSReport("Fail to read all movie data from THP file\n");
return FALSE;
}
threadData = daMP_ActivePlayer.movieData + daMP_ActivePlayer.initOffset - daMP_ActivePlayer.header.movieDataOffsets;
daMP_CreateVideoDecodeThread(20, threadData);
if (daMP_ActivePlayer.audioExist)
daMP_CreateAudioDecodeThread(12, threadData);
} else {
daMP_CreateVideoDecodeThread(20, 0);
if (daMP_ActivePlayer.audioExist)
daMP_CreateAudioDecodeThread(12, NULL);
daMP_CreateReadThread(8);
}
daMP_InitAllMessageQueue();
daMP_VideoDecodeThreadStart();
if (daMP_ActivePlayer.audioExist)
daMP_AudioDecodeThreadStart();
if (daMP_ActivePlayer.onMemory == 0)
daMP_ReadThreadStart();
if (!daMP_WaitUntilPrepare())
return FALSE;
daMP_ActivePlayer.state = 1;
daMP_ActivePlayer.internalState = 0;
daMP_ActivePlayer.dispTextureSet = (THPTextureSet*)NULL;
daMP_ActivePlayer.playAudioBuffer = (THPAudioBuffer*)NULL;
daMP_ActivePlayer.curVideoNumber = 0;
daMP_ActivePlayer.curAudioNumber = 0;
daMP_OldVIPostCallback = VISetPostRetraceCallback(daMP_PlayControl);
return TRUE;
}
return FALSE;
}
static void daMP_THPPlayerDrawDone() {
GXDrawDone();
if (daMP_Initialized) {
while (TRUE) {
void* tex = daMP_PopUsedTextureSet();
if (tex == NULL) {
break;
}
daMP_PushFreeTextureSet(tex);
}
}
}
static BOOL daMP_THPPlayerPlay() {
if (daMP_ActivePlayer.open != 0 && (daMP_ActivePlayer.state == 1 || daMP_ActivePlayer.state == 4)) {
daMP_ActivePlayer.state = 2;
daMP_ActivePlayer.prevCount = 0;
daMP_ActivePlayer.curCount = 0;
daMP_ActivePlayer.retaceCount = -1;
return TRUE;
}
return FALSE;
}
static void daMP_THPPlayerStop() {
if (daMP_ActivePlayer.open != 0 && daMP_ActivePlayer.state != 0) {
daMP_ActivePlayer.internalState = 0;
daMP_ActivePlayer.state = 0;
VISetPostRetraceCallback(daMP_OldVIPostCallback);
if (daMP_ActivePlayer.onMemory == 0) {
DVDCancel(&daMP_ActivePlayer.fileInfo.cb);
daMP_ReadThreadCancel();
}
daMP_VideoDecodeThreadCancel();
if (daMP_ActivePlayer.audioExist != 0) {
daMP_AudioDecodeThreadCancel();
daMP_audioQuitWithMSound();
}
while (daMP_PopUsedTextureSet() != NULL) {}
daMP_ActivePlayer.curVolume = daMP_ActivePlayer.targetVolume;
daMP_ActivePlayer.rampCount = 0.0f;
}
}
static int daMP_THPPlayerPause() {
if (daMP_ActivePlayer.open != 0 && daMP_ActivePlayer.state == 2) {
daMP_ActivePlayer.internalState = 4;
daMP_ActivePlayer.state = 4;
return 1;
}
return 0;
}
static int daMP_THPPlayerDrawCurrentFrame(const GXRenderModeObj* rmode, u32 x,
u32 y, u32 polygonW, u32 polygonH) {
s32 frame;
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state != 0 && daMP_ActivePlayer.dispTextureSet != NULL) {
daMP_THPGXYuv2RgbSetup(rmode);
daMP_THPGXYuv2RgbDraw(daMP_ActivePlayer.dispTextureSet->ytexture,
daMP_ActivePlayer.dispTextureSet->utexture,
daMP_ActivePlayer.dispTextureSet->vtexture, x, y,
daMP_ActivePlayer.videoInfo.xSize,
daMP_ActivePlayer.videoInfo.ySize, polygonW, polygonH);
daMP_THPGXRestore();
frame = (daMP_ActivePlayer.dispTextureSet->frameNumber + daMP_ActivePlayer.initReadFrame) % daMP_ActivePlayer.header.numFrames;
if (mDoGph_gInf_c::isFade()) {
mDoGph_gInf_c::fadeIn(1.0f);
}
return frame;
}
return -1;
}
static int daMP_THPPlayerGetVideoInfo(THPVideoInfo* info) {
if (daMP_ActivePlayer.open != 0) {
memcpy(info, &daMP_ActivePlayer.videoInfo, sizeof(THPVideoInfo));
return 1;
}
return 0;
}
static int daMP_THPPlayerGetAudioInfo(THPAudioInfo* info) {
if (daMP_ActivePlayer.open != 0) {
memcpy(info, &daMP_ActivePlayer.audioInfo, sizeof(THPAudioInfo));
return 1;
}
return 0;
}
static u32 daMP_THPPlayerGetTotalFrame() {
if (daMP_ActivePlayer.open != 0) {
return daMP_ActivePlayer.header.numFrames;
}
return 0;
}
static int daMP_THPPlayerGetState() {
return daMP_ActivePlayer.state;
}
static BOOL daMP_THPPlayerSetVolume(s32 vol, s32 duration) {
u32 numSamples;
BOOL interrupt;
if (daMP_ActivePlayer.open && daMP_ActivePlayer.audioExist) {
numSamples = AIGetDSPSampleRate() == 0 ? 32 : 48;
// clamp volume
if (vol > 127)
vol = 127;
if (vol < 0)
vol = 0;
// clamp duration
if (duration > 60000)
duration = 60000;
if (duration < 0)
duration = 0;
#if TARGET_PC
JASCriticalSection section;
#endif
interrupt = OSDisableInterrupts();
daMP_ActivePlayer.targetVolume = vol;
if (duration != 0) {
daMP_ActivePlayer.rampCount = numSamples * duration;
daMP_ActivePlayer.deltaVolume = (daMP_ActivePlayer.targetVolume - daMP_ActivePlayer.curVolume) / daMP_ActivePlayer.rampCount;
} else {
daMP_ActivePlayer.rampCount = 0;
daMP_ActivePlayer.curVolume = daMP_ActivePlayer.targetVolume;
}
OSRestoreInterrupts(interrupt);
return TRUE;
}
return FALSE;
}
static THPVideoInfo daMP_videoInfo;
static THPAudioInfo daMP_audioInfo;
static u32 daMP_DrawPosX;
static u32 daMP_DrawPosY;
static void* daMP_buffer;
static BOOL daMP_ActivePlayer_Init(char const* moviePath) {
daMP_THPPlayerInit(0);
if (!daMP_THPPlayerOpen(moviePath, 0)) {
OSReport("Fail to open the thp file\n");
#if DEBUG
JUT_ASSERT(9135, FALSE);
#else
return 0;
#endif
}
daMP_THPPlayerGetVideoInfo(&daMP_videoInfo);
daMP_THPPlayerGetAudioInfo(&daMP_audioInfo);
#if !TARGET_PC
// Window can be resized during playback, update this during draw.
u16 width = JUTVideo::getManager()->getRenderMode()->fbWidth;
u16 height = JUTVideo::getManager()->getRenderMode()->efbHeight;
daMP_DrawPosX = (width - daMP_videoInfo.xSize) >> 1;
daMP_DrawPosY = (height - daMP_videoInfo.ySize) >> 1;
#endif
// "The memory needed for this THP movie is %d bytes\n"
OS_REPORT("このTHPムービーが必要なメモリは%dバイトです\n", daMP_THPPlayerCalcNeedMemory());
daMP_buffer = mDoExt_getArchiveHeap()->alloc(daMP_THPPlayerCalcNeedMemory(), 0x20);
if (daMP_buffer == NULL) {
OSReport("Can't allocate the memory");
#if DEBUG
JUT_ASSERT(9162, FALSE);
#else
return 0;
#endif
}
daMP_THPPlayerSetBuffer((u8*)daMP_buffer);
#if TARGET_PC && MOVIE_SUPPORT
assert(JpegDecompressHandle == nullptr);
JpegDecompressHandle = tj3Init(TJINIT_DECOMPRESS);
if (JpegDecompressHandle == nullptr) {
OSReport_Error("Failed to create turbojpeg handle: %s", tj3GetErrorStr(nullptr));
return 0;
}
#endif
if (!daMP_THPPlayerPrepare(0, 0, daMP_audioInfo.sndNumTracks != 1 ? OSGetTick() % daMP_audioInfo.sndNumTracks : 0)) {
OSReport("Fail to prepare\n");
#if DEBUG
JUT_ASSERT(9190, FALSE);
#else
return 0;
#endif
}
return 1;
}
static void daMP_ActivePlayer_Finish() {
daMP_THPPlayerStop();
daMP_THPPlayerClose();
daMP_THPPlayerQuit();
if (daMP_buffer != NULL) {
JKRFree(daMP_buffer);
}
}
static void daMP_ActivePlayer_Main() {
if (daMP_THPPlayerGetState() == 5) {
daMP_THPPlayerStop();
daMP_THPPlayerClose();
if (daMP_buffer != NULL) {
JKRFree(daMP_buffer);
}
OSReport("Error happen");
}
}
#if TARGET_PC && 0
#include "imgui.h"
#endif
static void daMP_ActivePlayer_Draw() {
#if TARGET_PC
u16 width = JUTVideo::getManager()->getFbWidth();
u16 height = JUTVideo::getManager()->getEfbHeight();
const auto rect = dusk::LayoutRect::FitRectInRect(
width,
height,
static_cast<f32>(daMP_videoInfo.xSize),
static_cast<f32>(daMP_videoInfo.ySize));
daMP_DrawPosX = static_cast<u32>(rect.PosX);
daMP_DrawPosY = static_cast<u32>(rect.PosY);
daMP_THPPlayerSetVolume((dusk::getSettings().audio.masterVolume / 100.0f) * 127.0f, 0);
#endif
int frame = daMP_THPPlayerDrawCurrentFrame(
JUTVideo::getManager()->getRenderMode(),
daMP_DrawPosX, daMP_DrawPosY,
#if TARGET_PC
static_cast<u32>(rect.Width()),
static_cast<u32>(rect.Height()));
#else
daMP_videoInfo.xSize,
daMP_videoInfo.ySize);
#endif
daMP_THPPlayerDrawDone();
if (!fopOvlpM_IsPeek() && frame > 0 && (cAPICPad_ANY_BUTTON(0) || !daMP_c::daMP_c_Get_MovieRestFrame())) {
dComIfGp_event_reset();
daMP_c::daMP_c_Set_PercentMovieVolume(0.0f);
}
#if TARGET_PC && 0
if (ImGui::Begin("Movie player")) {
ImGui::Text("daMP_ReadedBufferQueue: %d", daMP_ReadedBufferQueue.usedCount);
ImGui::Text("daMP_ReadedBufferQueue2: %d", daMP_ReadedBufferQueue2.usedCount);
ImGui::Text("daMP_FreeReadBufferQueue: %d", daMP_FreeReadBufferQueue.usedCount);
ImGui::Text("daMP_DecodedTextureSetQueue: %d", daMP_DecodedTextureSetQueue.usedCount);
ImGui::Text("daMP_FreeTextureSetQueue: %d", daMP_FreeTextureSetQueue.usedCount);
ImGui::Text("daMP_DecodedAudioBufferQueue: %d", daMP_DecodedAudioBufferQueue.usedCount);
ImGui::Text("daMP_FreeAudioBufferQueue: %d", daMP_FreeAudioBufferQueue.usedCount);
}
ImGui::End();
#endif
}
static BOOL daMP_Fail_alloc;
static u32 daMP_Get_MovieRestFrame() {
int temp_r31;
if (daMP_Fail_alloc != 0 || daMP_THPPlayerGetState() == 5) {
return 0;
}
if (daMP_ActivePlayer.open && daMP_ActivePlayer.dispTextureSet != NULL) {
temp_r31 = (daMP_ActivePlayer.dispTextureSet->frameNumber + daMP_ActivePlayer.initReadFrame) % daMP_ActivePlayer.header.numFrames;
} else {
return -1;
}
int temp_r3 = daMP_THPPlayerGetTotalFrame();
if ((u32)temp_r3 == 0) {
return 0;
}
if ((u32)temp_r3 <= 1) {
return 0;
}
if ((u32)temp_r3 - 1 <= temp_r31) {
return 0;
}
return (temp_r3 - 1) - temp_r31;
}
static void daMP_Set_PercentMovieVolume(f32 volume) {
if (!daMP_Fail_alloc) {
s32 player_vol;
if (volume >= 1.0f) {
player_vol = 127;
} else if (volume <= 0.0f) {
player_vol = 0;
} else {
player_vol = volume / 127.0f;
}
daMP_THPPlayerSetVolume(player_vol, 1000);
}
}
int daMP_c::daMP_c_Get_arg_demoNo() {
return ((u32)(fopAcM_GetParam(this) >> 7)) & 0x7F;
}
int daMP_c::daMP_c_Get_arg_movieNo() {
return fopAcM_GetParam(this) & 0x7F;
}
int daMP_c::daMP_c_Init() {
JUT_ASSERT(9469, m_myObj == NULL);
#if !TARGET_PC // We don't properly simulate retrace interval so this doesn't work.
mDoGph_gInf_c::setFrameRate(1);
#endif
daMP_Fail_alloc = FALSE;
int demoNo = daMP_c_Get_arg_demoNo();
JUT_ASSERT(9505, 0 <= demoNo && demoNo <= 99);
int movieNo = daMP_c_Get_arg_movieNo();
JUT_ASSERT(9507, 0 <= movieNo && movieNo <= 99);
char path[32];
sprintf(path, "/Movie/demo_movie%02d_%02d.thp", demoNo, movieNo);
if (!daMP_ActivePlayer_Init(path)) {
daMP_Fail_alloc = TRUE;
}
mpGetMovieRestFrame = daMP_Get_MovieRestFrame;
mpSetPercentMovieVol = daMP_Set_PercentMovieVolume;
mpTHPGetTotalFrame = daMP_THPPlayerGetTotalFrame;
mpTHPPlay = daMP_THPPlayerPlay;
mpTHPStop = daMP_THPPlayerStop;
mpTHPPause = daMP_THPPlayerPause;
m_myObj = this;
return cPhs_COMPLEATE_e;
}
int daMP_c::daMP_c_Finish() {
daMP_ActivePlayer_Finish();
m_myObj = NULL;
return 1;
}
int daMP_c::daMP_c_Main() {
daMP_ActivePlayer_Main();
return 1;
}
void daMP_Dlst_base_c::draw() {
daMP_ActivePlayer_Draw();
}
static daMP_Dlst_base_c daMP_c_Dlst_base;
int daMP_c::daMP_c_Draw() {
dComIfGd_set2DOpa(&daMP_c_Dlst_base);
return 1;
}
int daMP_c::daMP_c_Callback_Init(fopAc_ac_c* i_this) {
fopAcM_ct(i_this, daMP_c);
return ((daMP_c*)i_this)->daMP_c_Init();
}
int daMP_c::daMP_c_Callback_Finish(daMP_c* i_this) {
return i_this->daMP_c_Finish();
}
int daMP_c::daMP_c_Callback_Main(daMP_c* i_this) {
#if PLATFORM_WII || PLATFORM_SHIELD
mDoGph_gInf_c::resetDimming();
#endif
if (daMP_Fail_alloc) {
return 1;
}
return i_this->daMP_c_Main();
}
int daMP_c::daMP_c_Callback_Draw(daMP_c* i_this) {
if (daMP_Fail_alloc) {
return 1;
}
return i_this->daMP_c_Draw();
}
static int daMP_Callback_Dummy(daMP_c* i_this) {
return 1;
}
static actor_method_class daMP_METHODS = {
(process_method_func)daMP_c::daMP_c_Callback_Init,
(process_method_func)daMP_c::daMP_c_Callback_Finish,
(process_method_func)daMP_c::daMP_c_Callback_Main,
(process_method_func)daMP_Callback_Dummy,
(process_method_func)daMP_c::daMP_c_Callback_Draw,
};
actor_process_profile_definition g_profile_MOVIE_PLAYER = {
/* Layer ID */ fpcLy_CURRENT_e,
/* List ID */ 7,
/* List Prio */ fpcPi_CURRENT_e,
/* Proc Name */ fpcNm_MOVIE_PLAYER_e,
/* Proc SubMtd */ &g_fpcLf_Method.base,
/* Size */ sizeof(daMP_c),
/* Size Other */ 0,
/* Parameters */ 0,
/* Leaf SubMtd */ &g_fopAc_Method.base,
/* Draw Prio */ fpcDwPi_MOVIE_PLAYER_e,
/* Actor SubMtd */ &daMP_METHODS,
/* Status */ fopAcStts_UNK_0x40000_e | fopAcStts_NOPAUSE_e | fopAcStts_STAFF_PRIMARY_e | fopAcStts_UNK_0x4000_e,
/* Group */ fopAc_ACTOR_e,
/* Cull Type */ fopAc_CULLBOX_CUSTOM_e,
};
AUDIO_INSTANCES;
#if TARGET_PC
void dusk::MoviePlayerShutdown() {
// We need to cleanly shut down the threads to avoid crashes on shutdown.
if (daMP_c::m_myObj) {
daMP_c::m_myObj->daMP_c_Finish();
}
}
#endif