mirror of
https://github.com/zeldaret/mm.git
synced 2026-08-09 10:52:09 -04:00
z_jpeg, jpegutils and jpegdecoder OK (#322)
* this is a disaster * two more * func_800F470C * split and rename jpegutils and jpegdecoder * match jpegutils * match jpegdecoder.c * audio_rodata * data split * Split rsp * Steal documentation from OoT * cleanup * Format * remove removed members in JpegContext * Update include/z64.h Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Update src/code/jpegdecoder.c Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Update include/functions.h Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Update src/code/jpegutils.c Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * review renames * true * Some type fixes * Update include/z64.h Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com> * add comment * Update src/code/z_jpeg.c Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com> * format * bss fix * decr * format * z64jpeg.h * Add stdbool * Rename audio_init_params * whoops * whoops++ * whoops# * remove extra dumb variables in variables.txt * fix Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#include "global.h"
|
||||
|
||||
// Blocks the current thread until all currently queued scheduler tasks have been completed
|
||||
void func_8010C1B0(void) {
|
||||
void MsgEvent_SendNullTask(void) {
|
||||
OSScTask task;
|
||||
OSMesgQueue queue;
|
||||
OSMesg msg;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "global.h"
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801AA020/func_801AA020.s")
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801AA020/func_801AA248.s")
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801AA020/func_801AA3E4.s")
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801AA020/func_801AA520.s")
|
||||
@@ -0,0 +1,193 @@
|
||||
#include "z64jpeg.h"
|
||||
#include "libc/stdbool.h"
|
||||
#include "macros.h"
|
||||
|
||||
u8* sJpegBitStreamPtr;
|
||||
u32 sJpegBitStreamByteIdx;
|
||||
u8 sJpegBitStreamBitIdx;
|
||||
u8 sJpegBitStreamDontSkip;
|
||||
u32 sJpegBitStreamCurWord;
|
||||
|
||||
s32 JpegDecoder_Decode(JpegDecoder* decoder, u16* mcuBuff, s32 count, u8 isFollowing, JpegDecoderState* state) {
|
||||
s16 pad;
|
||||
s16 unk0;
|
||||
s16 unk1;
|
||||
s16 unk2;
|
||||
u32 idx;
|
||||
s32 inc;
|
||||
u16 unkCount;
|
||||
|
||||
JpegHuffmanTable* hTable0;
|
||||
JpegHuffmanTable* hTable1;
|
||||
JpegHuffmanTable* hTable2;
|
||||
JpegHuffmanTable* hTable3;
|
||||
|
||||
inc = 0;
|
||||
sJpegBitStreamPtr = decoder->imageData;
|
||||
if (decoder->mode == 0) {
|
||||
unkCount = 2;
|
||||
} else {
|
||||
unkCount = 4;
|
||||
if (decoder->unk_05 == 1) {
|
||||
inc = 8 * 8 * 2;
|
||||
}
|
||||
}
|
||||
|
||||
hTable0 = decoder->hTablePtrs[0];
|
||||
hTable1 = decoder->hTablePtrs[1];
|
||||
hTable2 = decoder->hTablePtrs[2];
|
||||
hTable3 = decoder->hTablePtrs[3];
|
||||
|
||||
if (!isFollowing) {
|
||||
sJpegBitStreamByteIdx = 0;
|
||||
sJpegBitStreamBitIdx = 32;
|
||||
sJpegBitStreamCurWord = 0;
|
||||
sJpegBitStreamDontSkip = 0;
|
||||
unk0 = 0;
|
||||
unk1 = 0;
|
||||
unk2 = 0;
|
||||
} else {
|
||||
sJpegBitStreamByteIdx = state->byteIdx;
|
||||
sJpegBitStreamBitIdx = state->bitIdx;
|
||||
sJpegBitStreamCurWord = state->curWord;
|
||||
sJpegBitStreamDontSkip = state->dontSkip;
|
||||
unk0 = state->unk_0C;
|
||||
unk1 = state->unk_0E;
|
||||
unk2 = state->unk_10;
|
||||
}
|
||||
|
||||
while (count != 0) {
|
||||
for (idx = 0; idx < unkCount; idx++) {
|
||||
if (JpegDecoder_ProcessMcu(hTable0, hTable1, mcuBuff, &unk0)) {
|
||||
return 2;
|
||||
}
|
||||
mcuBuff += 8 * 8;
|
||||
}
|
||||
|
||||
if (JpegDecoder_ProcessMcu(hTable2, hTable3, mcuBuff, &unk1)) {
|
||||
return 2;
|
||||
}
|
||||
mcuBuff += 8 * 8;
|
||||
|
||||
if (JpegDecoder_ProcessMcu(hTable2, hTable3, mcuBuff, &unk2)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
count--;
|
||||
mcuBuff += 8 * 8;
|
||||
mcuBuff += inc;
|
||||
}
|
||||
|
||||
state->byteIdx = sJpegBitStreamByteIdx;
|
||||
state->bitIdx = sJpegBitStreamBitIdx;
|
||||
state->curWord = sJpegBitStreamCurWord;
|
||||
state->dontSkip = sJpegBitStreamDontSkip;
|
||||
state->unk_0C = unk0;
|
||||
state->unk_0E = unk1;
|
||||
state->unk_10 = unk2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 JpegDecoder_ProcessMcu(JpegHuffmanTable* hTable0, JpegHuffmanTable* hTable1, u16* mcu, s16* unk) {
|
||||
s8 i = 0;
|
||||
s8 zeroCount;
|
||||
s16 coeff;
|
||||
|
||||
if (JpegDecoder_ParseNextSymbol(hTable0, &coeff, &zeroCount)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*unk += coeff;
|
||||
mcu[i++] = *unk;
|
||||
while (i < 8 * 8) {
|
||||
if (JpegDecoder_ParseNextSymbol(hTable1, &coeff, &zeroCount)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (coeff == 0) {
|
||||
if (zeroCount == 0xF) {
|
||||
while (zeroCount-- >= 0) {
|
||||
mcu[i++] = 0;
|
||||
}
|
||||
} else {
|
||||
while (i < 8 * 8) {
|
||||
mcu[i++] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
while (0 < zeroCount--) {
|
||||
mcu[i++] = 0;
|
||||
}
|
||||
mcu[i++] = coeff;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 JpegDecoder_ParseNextSymbol(JpegHuffmanTable* hTable, s16* outCoeff, s8* outZeroCount) {
|
||||
u8 codeIdx;
|
||||
u8 sym;
|
||||
u16 codeOff = 0;
|
||||
u16 buff = JpegDecoder_ReadBits(16);
|
||||
|
||||
for (codeIdx = 0; codeIdx < ARRAY_COUNT(hTable->codesB); codeIdx++) {
|
||||
if (hTable->codesB[codeIdx] == 0xFFFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
codeOff = buff >> (15 - codeIdx);
|
||||
if (codeOff <= hTable->codesB[codeIdx]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (codeIdx >= ARRAY_COUNT(hTable->codesB)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sym = hTable->symbols[hTable->codeOffs[codeIdx] + codeOff - hTable->codesA[codeIdx]];
|
||||
*outZeroCount = sym >> 4;
|
||||
sym &= 0xF;
|
||||
|
||||
sJpegBitStreamBitIdx += codeIdx - 15;
|
||||
*outCoeff = 0;
|
||||
if (sym) {
|
||||
*outCoeff = JpegDecoder_ReadBits(sym);
|
||||
if (*outCoeff < (1 << (sym - 1))) {
|
||||
*outCoeff += (-1 << sym) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u16 JpegDecoder_ReadBits(u8 len) {
|
||||
u8 byteCount;
|
||||
u8 data;
|
||||
s32 ret;
|
||||
u32 temp;
|
||||
ret = 0; // this is required for some reason
|
||||
|
||||
for (byteCount = sJpegBitStreamBitIdx >> 3; byteCount > 0; byteCount--) {
|
||||
data = sJpegBitStreamPtr[sJpegBitStreamByteIdx++];
|
||||
if (sJpegBitStreamDontSkip) {
|
||||
if (data == 0) {
|
||||
data = sJpegBitStreamPtr[sJpegBitStreamByteIdx++];
|
||||
}
|
||||
}
|
||||
|
||||
sJpegBitStreamDontSkip = (data == 0xFF) ? true : false;
|
||||
|
||||
sJpegBitStreamCurWord <<= 8;
|
||||
sJpegBitStreamCurWord |= data;
|
||||
sJpegBitStreamBitIdx -= 8;
|
||||
}
|
||||
|
||||
ret = (sJpegBitStreamCurWord << (sJpegBitStreamBitIdx));
|
||||
temp = ret;
|
||||
ret = temp >> -len;
|
||||
sJpegBitStreamBitIdx += len;
|
||||
return ret;
|
||||
}
|
||||
+147
-9
@@ -1,17 +1,155 @@
|
||||
#include "global.h"
|
||||
#include "z64jpeg.h"
|
||||
#include "libc/stdbool.h"
|
||||
#include "macros.h"
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9B10.s")
|
||||
void JpegUtils_ProcessQuantizationTable(u8* dqt, JpegQuantizationTable* qt, u8 count) {
|
||||
u8 i;
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9B78.s")
|
||||
for (i = 0; i < count; i++) {
|
||||
u8 j;
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9BFC.s")
|
||||
dqt++;
|
||||
for (j = 0; j < ARRAY_COUNT(qt[i].table); j++) {
|
||||
qt[i].table[j] = *dqt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9C68.s")
|
||||
s32 JpegUtils_ParseHuffmanCodesLengths(u8* ptr, u8* codesLengths) {
|
||||
u8 off = 1;
|
||||
s16 count = 0;
|
||||
s16 idx = 1;
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9D10.s")
|
||||
while (off <= 16) {
|
||||
while (idx <= ptr[off - 1]) {
|
||||
codesLengths[count++] = off;
|
||||
idx++;
|
||||
}
|
||||
idx = 1;
|
||||
off++;
|
||||
}
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9DCC.s")
|
||||
codesLengths[count] = 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9EA4.s")
|
||||
s32 JpegUtils_GetHuffmanCodes(u8* codesLengths, u16* codes) {
|
||||
s16 idx = 0;
|
||||
u16 code = 0;
|
||||
u8 lastLen = codesLengths[0];
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/jpegutils/func_801A9F4C.s")
|
||||
while (true) {
|
||||
while (true) {
|
||||
codes[idx++] = code++;
|
||||
|
||||
if (codesLengths[idx] != lastLen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (codesLengths[idx] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (code <<= 1, codesLengths[idx] == ++lastLen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
s32 JpegUtils_SetHuffmanTable(u8* data, JpegHuffmanTable* ht, u16* codes) {
|
||||
u8 idx;
|
||||
u16 codeOff = 0;
|
||||
|
||||
for (idx = 0; idx < 16; idx++) {
|
||||
if (data[idx]) {
|
||||
ht->codeOffs[idx] = codeOff;
|
||||
ht->codesA[idx] = codes[codeOff];
|
||||
codeOff += data[idx] - 1;
|
||||
ht->codesB[idx] = codes[codeOff];
|
||||
codeOff++;
|
||||
} else {
|
||||
ht->codesB[idx] = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return codeOff;
|
||||
}
|
||||
|
||||
u32 JpegUtils_ProcessHuffmanTableImpl(u8* data, JpegHuffmanTable* ht, u8* codesLengths, u16* codes, u8 isAc) {
|
||||
s16 ret;
|
||||
s32 count = JpegUtils_ParseHuffmanCodesLengths(data, codesLengths);
|
||||
s32 temp;
|
||||
|
||||
ret = count;
|
||||
if (count == 0 || (isAc && count > 0x100) || (!isAc && count > 0x10)) {
|
||||
return 0;
|
||||
}
|
||||
if (ret != JpegUtils_GetHuffmanCodes(codesLengths, codes)) {
|
||||
return 0;
|
||||
}
|
||||
if (temp = JpegUtils_SetHuffmanTable(data, ht, codes), temp != ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 JpegUtils_ProcessHuffmanTable(u8* dht, JpegHuffmanTable* ht, u8* codesLengths, u16* codes, u8 count) {
|
||||
u8 idx;
|
||||
u32 codeCount;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
u32 ac = (*dht++ >> 4);
|
||||
|
||||
codeCount = JpegUtils_ProcessHuffmanTableImpl(dht, &ht[idx], codesLengths, codes, ac);
|
||||
if (codeCount == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dht += 16;
|
||||
ht[idx].symbols = dht;
|
||||
dht += codeCount;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JpegUtils_SetHuffmanTableOld(u8* data, JpegHuffmanTableOld* ht, u8* codesLengths, u16* codes, s16 count, u8 isAc) {
|
||||
s16 idx;
|
||||
u8 a;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
a = data[idx];
|
||||
if (isAc) {
|
||||
ht->acCodes[a] = codes[idx];
|
||||
ht->codeOffs[a] = codesLengths[idx];
|
||||
} else {
|
||||
ht->dcCodes[a] = codes[idx];
|
||||
ht->codeOffs[a] = codesLengths[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 JpegUtils_ProcessHuffmanTableImplOld(u8* dht, JpegHuffmanTableOld* ht, u8* codesLengths, u16* codes) {
|
||||
u8 isAc = *dht++ >> 4;
|
||||
s16 count2;
|
||||
s32 count;
|
||||
|
||||
count2 = count = JpegUtils_ParseHuffmanCodesLengths(dht, codesLengths);
|
||||
|
||||
if (count == 0 || (isAc && count > 0x100) || (!isAc && count > 0x10)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JpegUtils_GetHuffmanCodes(codesLengths, codes) != count2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JpegUtils_SetHuffmanTableOld(dht + 0x10, ht, codesLengths, codes, count2, isAc);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+299
-6
@@ -1,11 +1,304 @@
|
||||
#include "global.h"
|
||||
#include "z64jpeg.h"
|
||||
#include "libc/stdbool.h"
|
||||
#include "variables.h"
|
||||
#include "functions.h"
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/z_jpeg/func_800F42A0.s")
|
||||
#define MARKER_ESCAPE 0x00
|
||||
#define MARKER_SOI 0xD8
|
||||
#define MARKER_SOF 0xC0
|
||||
#define MARKER_DHT 0xC4
|
||||
#define MARKER_DQT 0xDB
|
||||
#define MARKER_DRI 0xDD
|
||||
#define MARKER_SOS 0xDA
|
||||
#define MARKER_APP0 0xE0
|
||||
#define MARKER_APP1 0xE1
|
||||
#define MARKER_APP2 0xE2
|
||||
#define MARKER_COM 0xFE
|
||||
#define MARKER_EOI 0xD9
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/z_jpeg/func_800F43BC.s")
|
||||
/**
|
||||
* Configures and schedules a JPEG decoder task and waits for it to finish.
|
||||
*/
|
||||
void Jpeg_ScheduleDecoderTask(JpegContext* jpegCtx) {
|
||||
static OSTask_t sJpegTask = {
|
||||
M_NJPEGTASK, // type
|
||||
0, // flags
|
||||
NULL, // ucode_boot
|
||||
0, // ucode_boot_size
|
||||
gJpegUCode, // ucode
|
||||
0x1000, // ucode_size
|
||||
gJpegUCodeData, // ucode_data
|
||||
0x800, // ucode_data_size
|
||||
NULL, // dram_stack
|
||||
0, // dram_stack_size
|
||||
NULL, // output_buff
|
||||
NULL, // output_buff_size
|
||||
NULL, // data_ptr
|
||||
sizeof(JpegTaskData), // data_size
|
||||
NULL, // yield_data_ptr
|
||||
0x200, // yield_data_size
|
||||
};
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/z_jpeg/func_800F44F4.s")
|
||||
JpegWork* workBuf = jpegCtx->workBuf;
|
||||
s32 pad[2];
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/z_jpeg/func_800F4540.s")
|
||||
workBuf->taskData.address = &workBuf->data;
|
||||
workBuf->taskData.mode = jpegCtx->mode;
|
||||
workBuf->taskData.mbCount = 4;
|
||||
workBuf->taskData.qTableYPtr = &workBuf->qTableY;
|
||||
workBuf->taskData.qTableUPtr = &workBuf->qTableU;
|
||||
workBuf->taskData.qTableVPtr = &workBuf->qTableV;
|
||||
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/code/z_jpeg/func_800F470C.s")
|
||||
sJpegTask.flags = 0;
|
||||
sJpegTask.ucodeBoot = SysUcode_GetUCodeBoot();
|
||||
sJpegTask.ucodeBootSize = SysUcode_GetUCodeBootSize();
|
||||
sJpegTask.yieldDataPtr = (u64*)&workBuf->yieldData;
|
||||
sJpegTask.dataPtr = (u64*)&workBuf->taskData;
|
||||
|
||||
jpegCtx->scTask.next = NULL;
|
||||
jpegCtx->scTask.flags = OS_SC_NEEDS_RSP;
|
||||
jpegCtx->scTask.msgQ = &jpegCtx->mq;
|
||||
jpegCtx->scTask.msg = NULL;
|
||||
jpegCtx->scTask.framebuffer = NULL;
|
||||
jpegCtx->scTask.list.t = sJpegTask;
|
||||
|
||||
osSendMesg(&gSchedContext.cmdQ, (OSMesg)&jpegCtx->scTask, OS_MESG_BLOCK);
|
||||
Sched_SendEntryMsg(&gSchedContext); // osScKickEntryMsg
|
||||
osRecvMesg(&jpegCtx->mq, NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a 16x16 block of decoded image data to the Z-buffer.
|
||||
*/
|
||||
void Jpeg_CopyToZbuffer(u16* src, u16* zbuffer, s32 x, s32 y) {
|
||||
u16* dst = zbuffer + (((y * SCREEN_WIDTH) + x) * 16);
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
dst[4] = src[4];
|
||||
dst[5] = src[5];
|
||||
dst[6] = src[6];
|
||||
dst[7] = src[7];
|
||||
dst[8] = src[8];
|
||||
dst[9] = src[9];
|
||||
dst[10] = src[10];
|
||||
dst[11] = src[11];
|
||||
dst[12] = src[12];
|
||||
dst[13] = src[13];
|
||||
dst[14] = src[14];
|
||||
dst[15] = src[15];
|
||||
|
||||
src += 16;
|
||||
dst += SCREEN_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an u16 from a possibly unaligned address in memory.
|
||||
*
|
||||
* Replaces unaligned 16-bit reads with a pair of aligned reads, allowing for reading the possibly
|
||||
* unaligned values in JPEG header files.
|
||||
*/
|
||||
u16 Jpeg_GetUnalignedU16(u8* ptr) {
|
||||
if (((u32)ptr & 1) == 0) {
|
||||
// Read the value normally if it's aligned to a 16-bit address.
|
||||
return *(u16*)ptr;
|
||||
} else {
|
||||
// Read unaligned values using two separate aligned memory accesses when it's not.
|
||||
return *(u16*)(ptr - 1) << 8 | (*(u16*)(ptr + 1) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the markers in the JPEG file, storing information such as the pointer to the image data
|
||||
* in `jpegCtx` for later processing.
|
||||
*/
|
||||
void Jpeg_ParseMarkers(u8* ptr, JpegContext* jpegCtx) {
|
||||
u32 exit = false;
|
||||
|
||||
jpegCtx->dqtCount = 0;
|
||||
jpegCtx->dhtCount = 0;
|
||||
|
||||
while (true) {
|
||||
if (exit) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 0xFF indicates the start of a JPEG marker, so look for the next.
|
||||
if (*ptr++ == 0xFF) {
|
||||
switch (*ptr++) {
|
||||
case MARKER_ESCAPE: {
|
||||
// Compressed value 0xFF is stored as 0xFF00 to escape it, so ignore it.
|
||||
break;
|
||||
}
|
||||
case MARKER_SOI: {
|
||||
// Start of Image
|
||||
break;
|
||||
}
|
||||
case MARKER_APP0: {
|
||||
// Application marker for JFIF
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_APP1: {
|
||||
// Application marker for EXIF
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_APP2: {
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_DQT: {
|
||||
// Define Quantization Table, stored for later processing
|
||||
jpegCtx->dqtPtr[jpegCtx->dqtCount++] = ptr + 2;
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_DHT: {
|
||||
// Define Huffman Table, stored for later processing
|
||||
jpegCtx->dhtPtr[jpegCtx->dhtCount++] = ptr + 2;
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_DRI: {
|
||||
// Define Restart Interval
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_SOF: {
|
||||
// Start of Frame, stores important metadata of the image.
|
||||
// Only used for extracting the sampling factors (jpegCtx->mode).
|
||||
|
||||
if (ptr[9] == 0x21) {
|
||||
// component Y : V0 == 1
|
||||
jpegCtx->mode = 0;
|
||||
} else if (ptr[9] == 0x22) {
|
||||
// component Y : V0 == 2
|
||||
jpegCtx->mode = 2;
|
||||
}
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
case MARKER_SOS: {
|
||||
// Start of Scan marker, indicates the start of the image data.
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
jpegCtx->imageData = ptr;
|
||||
break;
|
||||
}
|
||||
case MARKER_EOI: {
|
||||
// End of Image
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ptr += Jpeg_GetUnalignedU16(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 Jpeg_Decode(void* data, void* zbuffer, void* work, u32 workSize) {
|
||||
s32 y;
|
||||
s32 x;
|
||||
s32 j;
|
||||
s32 i;
|
||||
JpegContext jpegCtx;
|
||||
JpegHuffmanTable hTables[4];
|
||||
JpegDecoder decoder;
|
||||
JpegDecoderState state;
|
||||
JpegWork* workBuff = work;
|
||||
|
||||
if (workSize < sizeof(JpegWork)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
osCreateMesgQueue(&jpegCtx.mq, &jpegCtx.msg, 1);
|
||||
MsgEvent_SendNullTask();
|
||||
|
||||
jpegCtx.workBuf = workBuff;
|
||||
|
||||
Jpeg_ParseMarkers(data, &jpegCtx);
|
||||
|
||||
switch (jpegCtx.dqtCount) {
|
||||
case 1:
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[0], &workBuff->qTableY, 3);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[0], &workBuff->qTableY, 1);
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[1], &workBuff->qTableU, 1);
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[1], &workBuff->qTableV, 1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[0], &workBuff->qTableY, 1);
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[1], &workBuff->qTableU, 1);
|
||||
JpegUtils_ProcessQuantizationTable(jpegCtx.dqtPtr[2], &workBuff->qTableV, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (jpegCtx.dhtCount) {
|
||||
case 1:
|
||||
if (JpegUtils_ProcessHuffmanTable(jpegCtx.dhtPtr[0], &hTables[0], workBuff->codesLengths, workBuff->codes,
|
||||
4)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// This chained if-else has printfs inside it on debug
|
||||
if (JpegUtils_ProcessHuffmanTable(jpegCtx.dhtPtr[0], &hTables[0], workBuff->codesLengths, workBuff->codes,
|
||||
1)) {
|
||||
} else if (JpegUtils_ProcessHuffmanTable(jpegCtx.dhtPtr[1], &hTables[1], workBuff->codesLengths,
|
||||
workBuff->codes, 1)) {
|
||||
} else if (JpegUtils_ProcessHuffmanTable(jpegCtx.dhtPtr[2], &hTables[2], workBuff->codesLengths,
|
||||
workBuff->codes, 1)) {
|
||||
} else if (!JpegUtils_ProcessHuffmanTable(jpegCtx.dhtPtr[3], &hTables[3], workBuff->codesLengths,
|
||||
workBuff->codes, 1)) {
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
decoder.imageData = jpegCtx.imageData;
|
||||
decoder.mode = jpegCtx.mode;
|
||||
decoder.unk_05 = 2;
|
||||
|
||||
decoder.hTablePtrs[0] = &hTables[0];
|
||||
decoder.hTablePtrs[1] = &hTables[1];
|
||||
decoder.hTablePtrs[2] = &hTables[2];
|
||||
decoder.hTablePtrs[3] = &hTables[3];
|
||||
decoder.unk_18 = 0;
|
||||
|
||||
x = y = 0;
|
||||
for (i = 0; i < 300; i += 4) {
|
||||
if (!JpegDecoder_Decode(&decoder, (u16*)workBuff->data, 4, (i != 0), &state)) {
|
||||
Jpeg_ScheduleDecoderTask(&jpegCtx);
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
Jpeg_CopyToZbuffer(workBuff->data[j], zbuffer, x, y);
|
||||
x++;
|
||||
|
||||
if (x >= 20) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user