aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxpress/vlc.c
blob: 4e3e283208aa06fd39cfde37f0bc4db3168edcf4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * PSn00bSDK MDEC library (support code for the main VLC decompressor)
 * (C) 2022 spicyjpeg - MPL licensed
 */

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <psxpress.h>

/* Huffman code lookup table */

#define _val1(rl, dc)		(((rl) << 10) | ((uint16_t) (dc) & 0x3ff))
#define _val2(rl, dc, len)	(_val1(rl, dc) | (len << 16))

#define _pair(rl, dc)		_val1(rl, dc), _val1(rl, -(dc))
#define _pair2(rl, dc, len)	_val2(rl, dc, len), _val2(rl, -(dc), len)
#define _pair3(rl, dc, len) \
	_val2(rl, dc, len), _val2(rl, dc, len), \
	_val2(rl, -(dc), len), _val2(rl, -(dc), len)
#define _pair4(rl, dc, len) \
	_val2(rl, dc, len), _val2(rl, dc, len), _val2(rl, dc, len), _val2(rl, dc, len), \
	_val2(rl, dc, len), _val2(rl, dc, len), _val2(rl, dc, len), _val2(rl, dc, len), \
	_val2(rl, -(dc), len), _val2(rl, -(dc), len), _val2(rl, -(dc), len), _val2(rl, -(dc), len), \
	_val2(rl, -(dc), len), _val2(rl, -(dc), len), _val2(rl, -(dc), len), _val2(rl, -(dc), len)

// This table isn't compressed since it makes no sense to compress less than a
// kilobyte's worth of data.
static const DECDCTTAB _default_huffman_table = {
	.lut0 = {
		// 11 x
		_pair( 0,  1)
	},
	.lut2 = {
		// 01 0xx
		_pair2( 0,  2, 5), _pair2( 2,  1, 5),
		// 01 1x-
		_pair3( 1,  1, 4)
	},
	.lut3 = {
		// 001 00xxxx
		_pair2(13,  1, 9), _pair2( 0,  6, 9), _pair2(12,  1, 9), _pair2(11,  1, 9),
		_pair2( 3,  2, 9), _pair2( 1,  3, 9), _pair2( 0,  5, 9), _pair2(10,  1, 9),
		// 001 xxx---
		_pair4( 0,  3, 6), _pair4( 4,  1, 6), _pair4( 3,  1, 6)
	},
	.lut4 = {
		// 0001 xxx
		_pair( 7,  1), _pair( 6,  1), _pair( 1,  2), _pair( 5,  1)
	},
	.lut5 = {
		// 00001 xxx
		_pair( 2,  2), _pair( 9,  1), _pair( 0,  4), _pair( 8,  1)
	},
	.lut7 = {
		// 0000001 xxxx
		_pair(16,  1), _pair( 5,  2), _pair( 0,  7), _pair( 2,  3),
		_pair( 1,  4), _pair(15,  1), _pair(14,  1), _pair( 4,  2)
	},
	.lut8 = {
		// 00000001 xxxxx
		_pair( 0, 11), _pair( 8,  2), _pair( 4,  3), _pair( 0, 10),
		_pair( 2,  4), _pair( 7,  2), _pair(21,  1), _pair(20,  1),
		_pair( 0,  9), _pair(19,  1), _pair(18,  1), _pair( 1,  5),
		_pair( 3,  3), _pair( 0,  8), _pair( 6,  2), _pair(17,  1)
	},
	.lut9 = {
		// 000000001 xxxxx
		_pair(10,  2), _pair( 9,  2), _pair( 5,  3), _pair( 3,  4),
		_pair( 2,  5), _pair( 1,  7), _pair( 1,  6), _pair( 0, 15),
		_pair( 0, 14), _pair( 0, 13), _pair( 0, 12), _pair(26,  1),
		_pair(25,  1), _pair(24,  1), _pair(23,  1), _pair(22,  1)
	},
	.lut10 = {
		// 0000000001 xxxxx
		_pair( 0, 31), _pair( 0, 30), _pair( 0, 29), _pair( 0, 28),
		_pair( 0, 27), _pair( 0, 26), _pair( 0, 25), _pair( 0, 24),
		_pair( 0, 23), _pair( 0, 22), _pair( 0, 21), _pair( 0, 20),
		_pair( 0, 19), _pair( 0, 18), _pair( 0, 17), _pair( 0, 16)
	},
	.lut11 = {
		// 00000000001 xxxxx
		_pair( 0, 40), _pair( 0, 39), _pair( 0, 38), _pair( 0, 37),
		_pair( 0, 36), _pair( 0, 35), _pair( 0, 34), _pair( 0, 33),
		_pair( 0, 32), _pair( 1, 14), _pair( 1, 13), _pair( 1, 12),
		_pair( 1, 11), _pair( 1, 10), _pair( 1,  9), _pair( 1,  8)
	},
	.lut12 = {
		// 000000000001 xxxxx
		_pair( 1, 18), _pair( 1, 17), _pair( 1, 16), _pair( 1, 15),
		_pair( 6,  3), _pair(16,  2), _pair(15,  2), _pair(14,  2),
		_pair(13,  2), _pair(12,  2), _pair(11,  2), _pair(31,  1),
		_pair(30,  1), _pair(29,  1), _pair(28,  1), _pair(27,  1)
	}
};

/* Internal globals */

// Note that DecDCTvlc() and DecDCTvlc2() do *not* share the same variables.
static VLC_Context	_default_context;
static size_t		_max_buffer_size = 0;

const DECDCTTAB		*_vlc_huffman_table = &_default_huffman_table;

/* Stateful VLC decoder API (for Sony SDK compatibility) */

int DecDCTvlc(const uint32_t *bs, uint32_t *buf) {
	if (bs)
		return DecDCTvlcStart(&_default_context, buf, _max_buffer_size, bs);
	else
		return DecDCTvlcContinue(&_default_context, buf, _max_buffer_size);
}

size_t DecDCTvlcSize(size_t size) {
	size_t old_size  = _max_buffer_size;
	_max_buffer_size = size;

	return old_size;
}

/* Lookup table relocation API */

void DecDCTvlcCopyTable(DECDCTTAB *addr) {
	if (addr) {
		_vlc_huffman_table = addr;
		memcpy(addr, &_default_huffman_table, sizeof(DECDCTTAB));
	} else {
		_vlc_huffman_table = &_default_huffman_table;
	}
}