Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libwebp/src/enc/token_enc.c
21550 views
1
// Copyright 2011 Google Inc. All Rights Reserved.
2
//
3
// Use of this source code is governed by a BSD-style license
4
// that can be found in the COPYING file in the root of the source
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// Paginated token buffer
11
//
12
// A 'token' is a bit value associated with a probability, either fixed
13
// or a later-to-be-determined after statistics have been collected.
14
// For dynamic probability, we just record the slot id (idx) for the probability
15
// value in the final probability array (uint8_t* probas in VP8EmitTokens).
16
//
17
// Author: Skal ([email protected])
18
19
#include <assert.h>
20
#include <stdlib.h>
21
#include <string.h>
22
23
#include "src/dec/common_dec.h"
24
#include "src/dsp/dsp.h"
25
#include "src/enc/cost_enc.h"
26
#include "src/enc/vp8i_enc.h"
27
#include "src/utils/bit_writer_utils.h"
28
#include "src/utils/utils.h"
29
#include "src/webp/types.h"
30
31
#if !defined(DISABLE_TOKEN_BUFFER)
32
33
// we use pages to reduce the number of memcpy()
34
#define MIN_PAGE_SIZE 8192 // minimum number of token per page
35
#define FIXED_PROBA_BIT (1u << 14)
36
37
typedef uint16_t token_t; // bit #15: bit value
38
// bit #14: flags for constant proba or idx
39
// bits #0..13: slot or constant proba
40
struct VP8Tokens {
41
VP8Tokens* next; // pointer to next page
42
};
43
// Token data is located in memory just after the 'next' field.
44
// This macro is used to return their address and hide the trick.
45
#define TOKEN_DATA(p) ((const token_t*)&(p)[1])
46
47
//------------------------------------------------------------------------------
48
49
void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
50
b->tokens = NULL;
51
b->pages = NULL;
52
b->last_page = &b->pages;
53
b->left = 0;
54
b->page_size = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size;
55
b->error = 0;
56
}
57
58
void VP8TBufferClear(VP8TBuffer* const b) {
59
if (b != NULL) {
60
VP8Tokens* p = b->pages;
61
while (p != NULL) {
62
VP8Tokens* const next = p->next;
63
WebPSafeFree(p);
64
p = next;
65
}
66
VP8TBufferInit(b, b->page_size);
67
}
68
}
69
70
static int TBufferNewPage(VP8TBuffer* const b) {
71
VP8Tokens* page = NULL;
72
if (!b->error) {
73
const size_t size = sizeof(*page) + b->page_size * sizeof(token_t);
74
page = (VP8Tokens*)WebPSafeMalloc(1ULL, size);
75
}
76
if (page == NULL) {
77
b->error = 1;
78
return 0;
79
}
80
page->next = NULL;
81
82
*b->last_page = page;
83
b->last_page = &page->next;
84
b->left = b->page_size;
85
b->tokens = (token_t*)TOKEN_DATA(page);
86
return 1;
87
}
88
89
//------------------------------------------------------------------------------
90
91
#define TOKEN_ID(t, b, ctx) \
92
(NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t))))
93
94
static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit,
95
uint32_t proba_idx,
96
proba_t* const stats) {
97
assert(proba_idx < FIXED_PROBA_BIT);
98
assert(bit <= 1);
99
if (b->left > 0 || TBufferNewPage(b)) {
100
const int slot = --b->left;
101
b->tokens[slot] = (bit << 15) | proba_idx;
102
}
103
VP8RecordStats(bit, stats);
104
return bit;
105
}
106
107
static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
108
uint32_t bit, uint32_t proba) {
109
assert(proba < 256);
110
assert(bit <= 1);
111
if (b->left > 0 || TBufferNewPage(b)) {
112
const int slot = --b->left;
113
b->tokens[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
114
}
115
}
116
117
int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
118
VP8TBuffer* const tokens) {
119
const int16_t* const coeffs = res->coeffs;
120
const int coeff_type = res->coeff_type;
121
const int last = res->last;
122
int n = res->first;
123
uint32_t base_id = TOKEN_ID(coeff_type, n, ctx);
124
// should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1
125
proba_t* s = res->stats[n][ctx];
126
if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) {
127
return 0;
128
}
129
130
while (n < 16) {
131
const int c = coeffs[n++];
132
const int sign = c < 0;
133
const uint32_t v = sign ? -c : c;
134
if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) {
135
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0
136
s = res->stats[VP8EncBands[n]][0];
137
continue;
138
}
139
if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) {
140
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1
141
s = res->stats[VP8EncBands[n]][1];
142
} else {
143
if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) {
144
if (AddToken(tokens, v != 2, base_id + 4, s + 4)) {
145
AddToken(tokens, v == 4, base_id + 5, s + 5);
146
}
147
} else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) {
148
if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) {
149
AddConstantToken(tokens, v == 6, 159);
150
} else {
151
AddConstantToken(tokens, v >= 9, 165);
152
AddConstantToken(tokens, !(v & 1), 145);
153
}
154
} else {
155
int mask;
156
const uint8_t* tab;
157
uint32_t residue = v - 3;
158
if (residue < (8 << 1)) { // VP8Cat3 (3b)
159
AddToken(tokens, 0, base_id + 8, s + 8);
160
AddToken(tokens, 0, base_id + 9, s + 9);
161
residue -= (8 << 0);
162
mask = 1 << 2;
163
tab = VP8Cat3;
164
} else if (residue < (8 << 2)) { // VP8Cat4 (4b)
165
AddToken(tokens, 0, base_id + 8, s + 8);
166
AddToken(tokens, 1, base_id + 9, s + 9);
167
residue -= (8 << 1);
168
mask = 1 << 3;
169
tab = VP8Cat4;
170
} else if (residue < (8 << 3)) { // VP8Cat5 (5b)
171
AddToken(tokens, 1, base_id + 8, s + 8);
172
AddToken(tokens, 0, base_id + 10, s + 9);
173
residue -= (8 << 2);
174
mask = 1 << 4;
175
tab = VP8Cat5;
176
} else { // VP8Cat6 (11b)
177
AddToken(tokens, 1, base_id + 8, s + 8);
178
AddToken(tokens, 1, base_id + 10, s + 9);
179
residue -= (8 << 3);
180
mask = 1 << 10;
181
tab = VP8Cat6;
182
}
183
while (mask) {
184
AddConstantToken(tokens, !!(residue & mask), *tab++);
185
mask >>= 1;
186
}
187
}
188
base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2
189
s = res->stats[VP8EncBands[n]][2];
190
}
191
AddConstantToken(tokens, sign, 128);
192
if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) {
193
return 1; // EOB
194
}
195
}
196
return 1;
197
}
198
199
#undef TOKEN_ID
200
201
//------------------------------------------------------------------------------
202
// Final coding pass, with known probabilities
203
204
int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
205
const uint8_t* const probas, int final_pass) {
206
const VP8Tokens* p = b->pages;
207
assert(!b->error);
208
while (p != NULL) {
209
const VP8Tokens* const next = p->next;
210
const int N = (next == NULL) ? b->left : 0;
211
int n = b->page_size;
212
const token_t* const tokens = TOKEN_DATA(p);
213
while (n-- > N) {
214
const token_t token = tokens[n];
215
const int bit = (token >> 15) & 1;
216
if (token & FIXED_PROBA_BIT) {
217
VP8PutBit(bw, bit, token & 0xffu); // constant proba
218
} else {
219
VP8PutBit(bw, bit, probas[token & 0x3fffu]);
220
}
221
}
222
if (final_pass) WebPSafeFree((void*)p);
223
p = next;
224
}
225
if (final_pass) b->pages = NULL;
226
return 1;
227
}
228
229
// Size estimation
230
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
231
size_t size = 0;
232
const VP8Tokens* p = b->pages;
233
assert(!b->error);
234
while (p != NULL) {
235
const VP8Tokens* const next = p->next;
236
const int N = (next == NULL) ? b->left : 0;
237
int n = b->page_size;
238
const token_t* const tokens = TOKEN_DATA(p);
239
while (n-- > N) {
240
const token_t token = tokens[n];
241
const int bit = token & (1 << 15);
242
if (token & FIXED_PROBA_BIT) {
243
size += VP8BitCost(bit, token & 0xffu);
244
} else {
245
size += VP8BitCost(bit, probas[token & 0x3fffu]);
246
}
247
}
248
p = next;
249
}
250
return size;
251
}
252
253
//------------------------------------------------------------------------------
254
255
#else // DISABLE_TOKEN_BUFFER
256
257
void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
258
(void)b;
259
(void)page_size;
260
}
261
void VP8TBufferClear(VP8TBuffer* const b) {
262
(void)b;
263
}
264
265
#endif // !DISABLE_TOKEN_BUFFER
266
267