1 /*
2 * Resolume DXV encoder
3 * Copyright (C) 2024 Emma Worley <emma@emma.gg>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <stdint.h>
23
28
34
35 #define DXV_HEADER_LENGTH 12
36
37 /*
38 * Resolume will refuse to display frames that are not padded to 16x16 pixels.
39 */
40 #define DXV_ALIGN(x) FFALIGN(x, 16)
41
42 /*
43 * DXV uses LZ-like back-references to avoid copying words that have already
44 * appeared in the decompressed stream. Using a simple hash table (HT)
45 * significantly speeds up the lookback process while encoding.
46 */
47 #define LOOKBACK_HT_ELEMS 0x20202
48 #define LOOKBACK_WORDS 0x20202
49
52
54
57
58 /* Optimal number of slices for parallel decoding */
60
62
65
70
71 /* Converts an index offset value to a 2-bit opcode and pushes it to a stream.
72 * Inverse of CHECKPOINT in dxv.c. */
74 do { \
75 if (state == 16) { \
76 if (bytestream2_get_bytes_left_p(pbc) < 4) { \
77 return AVERROR_INVALIDDATA; \
78 } \
79 value = pbc->buffer; \
80 bytestream2_put_le32(pbc, 0); \
81 state = 0; \
82 } \
83 if (idx >= 0x102 * x) { \
84 op = 3; \
85 bytestream2_put_le16(pbc, (idx / x) - 0x102); \
86 } else if (idx >= 2 * x) { \
87 op = 2; \
88 bytestream2_put_byte(pbc, (idx / x) - 2); \
89 } else if (idx == x) { \
90 op = 1; \
91 } else { \
92 op = 0; \
93 } \
94 AV_WL32(value, AV_RL32(value) | (op << (state * 2))); \
95 state++; \
96 } while (0)
97
99 {
103 uint32_t idx, combo_idx, prev_pos, old_pos,
state = 16,
pos = 0,
op = 0;
104
108
110
111 bytestream2_put_le32(pbc,
AV_RL32(
ctx->tex_data));
114 bytestream2_put_le32(pbc,
AV_RL32(
ctx->tex_data + 4));
117
118 while (
pos + 2 <=
ctx->tex_size / 4) {
120 idx = combo_idx;
126 }
128
129 if (!combo_idx) {
132 if (!idx)
134 }
139 }
142
143 if (!combo_idx) {
146 if (!idx)
148 }
153 }
156 }
157
158 return 0;
159 }
160
163 {
167
168 /* unimplemented: needs to depend on compression ratio of tex format */
169 /* under DXT1, we need 3 words to encode load ops for 32 words.
170 * the first 2 words of the texture do not need load ops. */
174
175 if (
ctx->enc.tex_funct) {
176 uint8_t *safe_data[4] = {
frame->data[0], 0, 0, 0};
177 int safe_linesize[4] = {
frame->linesize[0], 0, 0, 0};
178
181 safe_data,
182 safe_linesize,
186 1);
189
191 safe_data,
192 safe_linesize,
198
201 for (
int y = 0; y < avctx->
height; y++) {
202 memset(safe_data[0] + y * safe_linesize[0] + 4*avctx->
width, 0, safe_linesize[0] - 4*avctx->
width);
203 }
204 }
207 memset(safe_data[0] + y * safe_linesize[0], 0, safe_linesize[0]);
208 }
209 }
210 }
211
212 ctx->enc.tex_data.out =
ctx->tex_data;
213 ctx->enc.frame_data.in = safe_data[0];
214 ctx->enc.stride = safe_linesize[0];
218
219 if (safe_data[0] !=
frame->data[0])
221 } else {
222 /* unimplemented: YCoCg formats */
224 }
225
227
228 bytestream2_put_le32(pbc,
ctx->tex_fmt);
229 bytestream2_put_byte(pbc, 4);
230 bytestream2_put_byte(pbc, 0);
231 bytestream2_put_byte(pbc, 0);
232 bytestream2_put_byte(pbc, 0);
233 /* Fill in compressed size later */
235
236 ret =
ctx->compress_tex(avctx);
239
242
243 *got_packet = 1;
244 return 0;
245 }
246
248 {
252
257 }
258
260
261 switch (
ctx->tex_fmt) {
265 ctx->enc.tex_ratio = 8;
266 break;
267 default:
270 }
271 ctx->enc.raw_ratio = 16;
276
278 if (!
ctx->tex_data) {
280 }
281
291
292 return 0;
293 }
294
296 {
298
300
304
305 return 0;
306 }
307
308 #define OFFSET(x) offsetof(DXVEncContext, x)
309 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
312 {
"dxt1",
"DXT1 (Normal Quality, No Alpha)", 0,
AV_OPT_TYPE_CONST, { .i64 =
DXV_FMT_DXT1 }, 0, 0,
FLAGS, .unit =
"format" },
314 };
315
320 };
321
337 };