/src/ffmpeg/libavcodec/vqavideo.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Westwood Studios VQA Video Decoder |
3 | | * Copyright (c) 2003 Mike Melanson <melanson@pcisys.net> |
4 | | * Copyright (c) 2021 Pekka Väänänen <pekka.vaananen@iki.fi> |
5 | | * |
6 | | * This file is part of FFmpeg. |
7 | | * |
8 | | * FFmpeg is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2.1 of the License, or (at your option) any later version. |
12 | | * |
13 | | * FFmpeg is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with FFmpeg; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /** |
24 | | * @file |
25 | | * VQA Video Decoder |
26 | | * @author Mike Melanson (melanson@pcisys.net) |
27 | | * @see http://wiki.multimedia.cx/index.php?title=VQA |
28 | | * |
29 | | * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending |
30 | | * on the type of data in the file. |
31 | | * |
32 | | * This decoder needs the 42-byte VQHD header from the beginning |
33 | | * of the VQA file passed through the extradata field. The VQHD header |
34 | | * is laid out as: |
35 | | * |
36 | | * bytes 0-3 chunk fourcc: 'VQHD' |
37 | | * bytes 4-7 chunk size in big-endian format, should be 0x0000002A |
38 | | * bytes 8-49 VQHD chunk data |
39 | | * |
40 | | * Bytes 8-49 are what this decoder expects to see. |
41 | | * |
42 | | * Briefly, VQA is a vector quantized animation format that operates in a |
43 | | * VGA palettized colorspace. It operates on pixel vectors (blocks) |
44 | | * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector |
45 | | * codebooks, palette information, and code maps for rendering vectors onto |
46 | | * frames. Any of these components can also be compressed with a run-length |
47 | | * encoding (RLE) algorithm commonly referred to as "format80". |
48 | | * |
49 | | * VQA takes a novel approach to rate control. Each group of n frames |
50 | | * (usually, n = 8) relies on a different vector codebook. Rather than |
51 | | * transporting an entire codebook every 8th frame, the new codebook is |
52 | | * broken up into 8 pieces and sent along with the compressed video chunks |
53 | | * for each of the 8 frames preceding the 8 frames which require the |
54 | | * codebook. A full codebook is also sent on the very first frame of a |
55 | | * file. This is an interesting technique, although it makes random file |
56 | | * seeking difficult despite the fact that the frames are all intracoded. |
57 | | * |
58 | | * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were |
59 | | * packed into bytes and then RLE compressed, bytewise, the results would |
60 | | * be poor. That is why the coding method divides each index into 2 parts, |
61 | | * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces |
62 | | * together and the 8-bit pieces together. If most of the vectors are |
63 | | * clustered into one group of 256 vectors, most of the 4-bit index pieces |
64 | | * should be the same. |
65 | | * |
66 | | * VQA3 introduces a 15-bit high color codebook, delta coding, replaces |
67 | | * the above "split byte" scheme with RLE compression, and extends the |
68 | | * "format80" compression with relative references. In VQA3 the whole |
69 | | * codebook is always updated as a whole without splitting it into pieces. |
70 | | */ |
71 | | |
72 | | #include <stdio.h> |
73 | | #include <string.h> |
74 | | |
75 | | #include "libavutil/intreadwrite.h" |
76 | | #include "libavutil/mem.h" |
77 | | #include "avcodec.h" |
78 | | #include "bytestream.h" |
79 | | #include "codec_internal.h" |
80 | | #include "decode.h" |
81 | | |
82 | 37.6k | #define PALETTE_COUNT 256 |
83 | 1.49k | #define VQA_HEADER_SIZE 0x2A |
84 | | |
85 | | /* allocate the maximum vector space, regardless of the file version: |
86 | | * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ |
87 | 80.4k | #define MAX_CODEBOOK_VECTORS 0xFF00 |
88 | 80.4k | #define SOLID_PIXEL_VECTORS 0x100 |
89 | 80.4k | #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) |
90 | 8.53k | #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t)) |
91 | | |
92 | 2.21k | #define CBF0_TAG MKBETAG('C', 'B', 'F', '0') |
93 | 1.54k | #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') |
94 | 1.63k | #define CBP0_TAG MKBETAG('C', 'B', 'P', '0') |
95 | 4.61k | #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z') |
96 | 1.81k | #define CPL0_TAG MKBETAG('C', 'P', 'L', '0') |
97 | 447 | #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z') |
98 | 45.8k | #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z') |
99 | 1.27k | #define VPTR_TAG MKBETAG('V', 'P', 'T', 'R') |
100 | 3.26k | #define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z') |
101 | | |
102 | | typedef struct VqaContext { |
103 | | AVFrame *frame; |
104 | | AVCodecContext *avctx; |
105 | | GetByteContext gb; |
106 | | |
107 | | uint32_t palette[PALETTE_COUNT]; |
108 | | |
109 | | int width; /* width of a frame */ |
110 | | int height; /* height of a frame */ |
111 | | int vector_width; /* width of individual vector */ |
112 | | int vector_height; /* height of individual vector */ |
113 | | int vqa_version; /* this should be either 1, 2 or 3 */ |
114 | | |
115 | | unsigned char *codebook; /* the current codebook */ |
116 | | int codebook_size; |
117 | | unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
118 | | int next_codebook_buffer_index; |
119 | | |
120 | | unsigned char *decode_buffer; |
121 | | int decode_buffer_size; |
122 | | |
123 | | /* number of frames to go before replacing codebook */ |
124 | | int partial_countdown; |
125 | | int partial_count; |
126 | | } VqaContext; |
127 | | |
128 | | static av_cold int vqa_decode_init(AVCodecContext *avctx) |
129 | 1.29k | { |
130 | 1.29k | VqaContext *s = avctx->priv_data; |
131 | 1.29k | int i, j, codebook_index, ret; |
132 | 1.29k | int colors; |
133 | | |
134 | 1.29k | s->avctx = avctx; |
135 | | |
136 | | /* make sure the extradata made it */ |
137 | 1.29k | if (s->avctx->extradata_size != VQA_HEADER_SIZE) { |
138 | 202 | av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE); |
139 | 202 | return AVERROR(EINVAL); |
140 | 202 | } |
141 | | |
142 | | /* load up the VQA parameters from the header */ |
143 | 1.09k | s->vqa_version = s->avctx->extradata[0]; |
144 | | |
145 | 1.09k | if (s->vqa_version < 1 || s->vqa_version > 3) { |
146 | 3 | avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version); |
147 | 3 | return AVERROR_INVALIDDATA; |
148 | 3 | } |
149 | | |
150 | 1.09k | s->width = AV_RL16(&s->avctx->extradata[6]); |
151 | 1.09k | s->height = AV_RL16(&s->avctx->extradata[8]); |
152 | 1.09k | if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) { |
153 | 3 | s->width= s->height= 0; |
154 | 3 | return ret; |
155 | 3 | } |
156 | 1.08k | s->vector_width = s->avctx->extradata[10]; |
157 | 1.08k | s->vector_height = s->avctx->extradata[11]; |
158 | 1.08k | s->partial_count = s->partial_countdown = s->avctx->extradata[13]; |
159 | | |
160 | 1.08k | colors = (s->avctx->extradata[14] << 8) | s->avctx->extradata[15]; |
161 | | |
162 | 1.08k | if (colors > 0) { |
163 | 751 | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
164 | 751 | } else { |
165 | 336 | avctx->pix_fmt = AV_PIX_FMT_RGB555LE; |
166 | 336 | } |
167 | | |
168 | | /* the vector dimensions have to meet very stringent requirements */ |
169 | 1.08k | if ((s->vector_width != 4) || |
170 | 1.08k | ((s->vector_height != 2) && (s->vector_height != 4))) { |
171 | | /* return without further initialization */ |
172 | 12 | return AVERROR_INVALIDDATA; |
173 | 12 | } |
174 | | |
175 | 1.07k | if (s->width % s->vector_width || s->height % s->vector_height) { |
176 | 3 | av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n"); |
177 | 3 | return AVERROR_INVALIDDATA; |
178 | 3 | } |
179 | | |
180 | 1.07k | s->frame = av_frame_alloc(); |
181 | 1.07k | if (!s->frame) |
182 | 0 | return AVERROR(ENOMEM); |
183 | | |
184 | | /* allocate codebooks */ |
185 | 1.07k | s->codebook_size = MAX_CODEBOOK_SIZE; |
186 | 1.07k | s->codebook = av_malloc(s->codebook_size); |
187 | 1.07k | if (!s->codebook) |
188 | 0 | return AVERROR(ENOMEM); |
189 | 1.07k | s->next_codebook_buffer = av_malloc(s->codebook_size); |
190 | 1.07k | if (!s->next_codebook_buffer) |
191 | 0 | return AVERROR(ENOMEM); |
192 | | |
193 | | /* allocate decode buffer */ |
194 | 1.07k | s->decode_buffer_size = (s->width / s->vector_width) * |
195 | 1.07k | (s->height / s->vector_height) * 2; |
196 | 1.07k | s->decode_buffer = av_mallocz(s->decode_buffer_size); |
197 | 1.07k | if (!s->decode_buffer) |
198 | 0 | return AVERROR(ENOMEM); |
199 | | |
200 | | /* initialize the solid-color vectors */ |
201 | 1.07k | if (s->vector_height == 4) { |
202 | 46 | codebook_index = 0xFF00 * 16; |
203 | 11.8k | for (i = 0; i < 256; i++) |
204 | 200k | for (j = 0; j < 16; j++) |
205 | 188k | s->codebook[codebook_index++] = i; |
206 | 1.02k | } else { |
207 | 1.02k | codebook_index = 0xF00 * 8; |
208 | 263k | for (i = 0; i < 256; i++) |
209 | 2.36M | for (j = 0; j < 8; j++) |
210 | 2.10M | s->codebook[codebook_index++] = i; |
211 | 1.02k | } |
212 | 1.07k | s->next_codebook_buffer_index = 0; |
213 | | |
214 | 1.07k | return 0; |
215 | 1.07k | } |
216 | | |
217 | | #define CHECK_COUNT() \ |
218 | 11.4M | if (dest_index + count > dest_size) { \ |
219 | 1.10k | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
220 | 1.10k | av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \ |
221 | 1.10k | dest_index, count, dest_size); \ |
222 | 1.10k | return AVERROR_INVALIDDATA; \ |
223 | 1.10k | } |
224 | | |
225 | | #define CHECK_COPY(idx) \ |
226 | 11.4M | if (idx < 0 || idx + count > dest_size) { \ |
227 | 2.52k | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
228 | 2.52k | av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \ |
229 | 2.52k | src_pos, count, dest_size); \ |
230 | 2.52k | return AVERROR_INVALIDDATA; \ |
231 | 2.52k | } |
232 | | |
233 | | |
234 | | static int decode_format80(VqaContext *s, int src_size, |
235 | 51.4k | unsigned char *dest, int dest_size, int check_size) { |
236 | | |
237 | 51.4k | int dest_index = 0; |
238 | 51.4k | int count, opcode, start; |
239 | 51.4k | int src_pos; |
240 | 51.4k | unsigned char color; |
241 | 51.4k | int i; |
242 | 51.4k | int relative = 0; |
243 | | |
244 | 51.4k | if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) { |
245 | 1.95k | av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n", |
246 | 1.95k | src_size); |
247 | 1.95k | return AVERROR_INVALIDDATA; |
248 | 1.95k | } |
249 | | |
250 | | /* the "new" scheme makes references relative to destination pointer */ |
251 | 49.4k | if (bytestream2_peek_byte(&s->gb) == 0x00) { |
252 | 33.6k | relative = 1; |
253 | 33.6k | bytestream2_get_byte(&s->gb); |
254 | 33.6k | ff_tlog(s->avctx, "found new format stream "); |
255 | 33.6k | } |
256 | | |
257 | 49.4k | start = bytestream2_tell(&s->gb); |
258 | 11.4M | while (bytestream2_tell(&s->gb) - start < src_size) { |
259 | 11.4M | opcode = bytestream2_get_byte(&s->gb); |
260 | 11.4M | ff_tlog(s->avctx, "opcode %02X: ", opcode); |
261 | | |
262 | | /* 0x80 means that frame is finished */ |
263 | 11.4M | if (opcode == 0x80) |
264 | 212 | break; |
265 | | |
266 | 11.4M | if (dest_index >= dest_size) { |
267 | 220 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
268 | 220 | dest_index, dest_size); |
269 | 220 | return AVERROR_INVALIDDATA; |
270 | 220 | } |
271 | | |
272 | 11.4M | if (opcode == 0xFF) { |
273 | | |
274 | 9.15k | count = bytestream2_get_le16(&s->gb); |
275 | 9.15k | src_pos = bytestream2_get_le16(&s->gb); |
276 | 9.15k | if (relative) |
277 | 1.97k | src_pos = dest_index - src_pos; |
278 | 9.15k | ff_tlog(s->avctx, "(1) copy %X bytes from pos %X\n", count, src_pos); |
279 | 9.15k | CHECK_COUNT(); |
280 | 8.90k | CHECK_COPY(src_pos); |
281 | 387M | for (i = 0; i < count; i++) |
282 | 387M | dest[dest_index + i] = dest[src_pos + i]; |
283 | 8.39k | dest_index += count; |
284 | | |
285 | 11.4M | } else if (opcode == 0xFE) { |
286 | | |
287 | 2.99k | count = bytestream2_get_le16(&s->gb); |
288 | 2.99k | color = bytestream2_get_byte(&s->gb); |
289 | 2.99k | ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color); |
290 | 2.99k | CHECK_COUNT(); |
291 | 2.77k | memset(&dest[dest_index], color, count); |
292 | 2.77k | dest_index += count; |
293 | | |
294 | 11.4M | } else if ((opcode & 0xC0) == 0xC0) { |
295 | | |
296 | 5.98k | count = (opcode & 0x3F) + 3; |
297 | 5.98k | src_pos = bytestream2_get_le16(&s->gb); |
298 | 5.98k | if (relative) |
299 | 1.18k | src_pos = dest_index - src_pos; |
300 | 5.98k | ff_tlog(s->avctx, "(3) copy %X bytes from pos %X\n", count, src_pos); |
301 | 5.98k | CHECK_COUNT(); |
302 | 5.76k | CHECK_COPY(src_pos); |
303 | 182k | for (i = 0; i < count; i++) |
304 | 177k | dest[dest_index + i] = dest[src_pos + i]; |
305 | 5.32k | dest_index += count; |
306 | | |
307 | 11.4M | } else if (opcode > 0x80) { |
308 | | |
309 | 1.04k | count = opcode & 0x3F; |
310 | 1.04k | ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count); |
311 | 1.04k | CHECK_COUNT(); |
312 | 841 | bytestream2_get_buffer(&s->gb, &dest[dest_index], count); |
313 | 841 | dest_index += count; |
314 | | |
315 | 11.4M | } else { |
316 | | |
317 | 11.4M | count = ((opcode & 0x70) >> 4) + 3; |
318 | 11.4M | src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8); |
319 | 11.4M | ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos); |
320 | 11.4M | CHECK_COUNT(); |
321 | 11.4M | CHECK_COPY(dest_index - src_pos); |
322 | 45.7M | for (i = 0; i < count; i++) |
323 | 34.3M | dest[dest_index + i] = dest[dest_index - src_pos + i]; |
324 | 11.4M | dest_index += count; |
325 | 11.4M | } |
326 | 11.4M | } |
327 | | |
328 | | /* validate that the entire destination buffer was filled; this is |
329 | | * important for decoding frame maps since each vector needs to have a |
330 | | * codebook entry; it is not important for compressed codebooks because |
331 | | * not every entry needs to be filled */ |
332 | 45.6k | if (check_size) |
333 | 40.3k | if (dest_index < dest_size) { |
334 | 40.1k | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", |
335 | 40.1k | dest_index, dest_size); |
336 | 40.1k | memset(dest + dest_index, 0, dest_size - dest_index); |
337 | 40.1k | } |
338 | | |
339 | 45.6k | return 0; // let's display what we decoded anyway |
340 | 49.4k | } |
341 | | |
342 | | static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame) |
343 | 61.4k | { |
344 | 61.4k | unsigned int chunk_type; |
345 | 61.4k | unsigned int chunk_size; |
346 | 61.4k | int byte_skip; |
347 | 61.4k | unsigned int index = 0; |
348 | 61.4k | int i; |
349 | 61.4k | unsigned char r, g, b; |
350 | 61.4k | int index_shift; |
351 | 61.4k | int res; |
352 | | |
353 | 61.4k | int cbf0_chunk = -1; |
354 | 61.4k | int cbfz_chunk = -1; |
355 | 61.4k | int cbp0_chunk = -1; |
356 | 61.4k | int cbpz_chunk = -1; |
357 | 61.4k | int cpl0_chunk = -1; |
358 | 61.4k | int cplz_chunk = -1; |
359 | 61.4k | int vptz_chunk = -1; |
360 | | |
361 | 61.4k | int x, y; |
362 | 61.4k | int lines = 0; |
363 | 61.4k | int pixel_ptr; |
364 | 61.4k | int vector_index = 0; |
365 | 61.4k | int lobyte = 0; |
366 | 61.4k | int hibyte = 0; |
367 | 61.4k | int lobytes = 0; |
368 | 61.4k | int hibytes = s->decode_buffer_size / 2; |
369 | | |
370 | | /* first, traverse through the frame and find the subchunks */ |
371 | 197k | while (bytestream2_get_bytes_left(&s->gb) >= 8) { |
372 | | |
373 | 136k | chunk_type = bytestream2_get_be32u(&s->gb); |
374 | 136k | index = bytestream2_tell(&s->gb); |
375 | 136k | chunk_size = bytestream2_get_be32u(&s->gb); |
376 | | |
377 | 136k | switch (chunk_type) { |
378 | | |
379 | 1.10k | case CBF0_TAG: |
380 | 1.10k | cbf0_chunk = index; |
381 | 1.10k | break; |
382 | | |
383 | 792 | case CBFZ_TAG: |
384 | 792 | cbfz_chunk = index; |
385 | 792 | break; |
386 | | |
387 | 1.63k | case CBP0_TAG: |
388 | 1.63k | cbp0_chunk = index; |
389 | 1.63k | break; |
390 | | |
391 | 4.61k | case CBPZ_TAG: |
392 | 4.61k | cbpz_chunk = index; |
393 | 4.61k | break; |
394 | | |
395 | 1.81k | case CPL0_TAG: |
396 | 1.81k | cpl0_chunk = index; |
397 | 1.81k | break; |
398 | | |
399 | 447 | case CPLZ_TAG: |
400 | 447 | cplz_chunk = index; |
401 | 447 | break; |
402 | | |
403 | 45.8k | case VPTZ_TAG: |
404 | 45.8k | vptz_chunk = index; |
405 | 45.8k | break; |
406 | | |
407 | 79.7k | default: |
408 | 79.7k | av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n", |
409 | 79.7k | av_fourcc2str(av_bswap32(chunk_type)), chunk_type); |
410 | 79.7k | break; |
411 | 136k | } |
412 | | |
413 | 136k | byte_skip = chunk_size & 0x01; |
414 | 136k | bytestream2_skip(&s->gb, chunk_size + byte_skip); |
415 | 136k | } |
416 | | |
417 | | /* next, deal with the palette */ |
418 | 61.4k | if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { |
419 | | |
420 | | /* a chunk should not have both chunk types */ |
421 | 236 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n"); |
422 | 236 | return AVERROR_INVALIDDATA; |
423 | 236 | } |
424 | | |
425 | | /* decompress the palette chunk */ |
426 | 61.1k | if (cplz_chunk != -1) { |
427 | | |
428 | | /* yet to be handled */ |
429 | | |
430 | 166 | } |
431 | | |
432 | | /* convert the RGB palette into the machine's endian format */ |
433 | 61.1k | if (cpl0_chunk != -1) { |
434 | | |
435 | 1.44k | bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); |
436 | 1.44k | chunk_size = bytestream2_get_be32(&s->gb); |
437 | | /* sanity check the palette size */ |
438 | 1.44k | if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { |
439 | 894 | av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n", |
440 | 894 | chunk_size / 3); |
441 | 894 | return AVERROR_INVALIDDATA; |
442 | 894 | } |
443 | 2.32k | for (i = 0; i < chunk_size / 3; i++) { |
444 | | /* scale by 4 to transform 6-bit palette -> 8-bit */ |
445 | 1.77k | r = bytestream2_get_byteu(&s->gb) * 4; |
446 | 1.77k | g = bytestream2_get_byteu(&s->gb) * 4; |
447 | 1.77k | b = bytestream2_get_byteu(&s->gb) * 4; |
448 | 1.77k | s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b; |
449 | 1.77k | s->palette[i] |= s->palette[i] >> 6 & 0x30303; |
450 | 1.77k | } |
451 | 549 | } |
452 | | |
453 | | /* next, look for a full codebook */ |
454 | 60.3k | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { |
455 | | |
456 | | /* a chunk should not have both chunk types */ |
457 | 245 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); |
458 | 245 | return AVERROR_INVALIDDATA; |
459 | 245 | } |
460 | | |
461 | | /* decompress the full codebook chunk */ |
462 | 60.0k | if (cbfz_chunk != -1) { |
463 | | |
464 | 542 | bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); |
465 | 542 | chunk_size = bytestream2_get_be32(&s->gb); |
466 | 542 | if ((res = decode_format80(s, chunk_size, s->codebook, |
467 | 542 | s->codebook_size, 0)) < 0) |
468 | 288 | return res; |
469 | 542 | } |
470 | | |
471 | | /* copy a full codebook */ |
472 | 59.7k | if (cbf0_chunk != -1) { |
473 | | |
474 | 859 | bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); |
475 | 859 | chunk_size = bytestream2_get_be32(&s->gb); |
476 | | /* sanity check the full codebook size */ |
477 | 859 | if (chunk_size > MAX_CODEBOOK_SIZE) { |
478 | 361 | av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", |
479 | 361 | chunk_size); |
480 | 361 | return AVERROR_INVALIDDATA; |
481 | 361 | } |
482 | | |
483 | 498 | bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); |
484 | 498 | } |
485 | | |
486 | | /* decode the frame */ |
487 | 59.4k | if (vptz_chunk == -1) { |
488 | | |
489 | | /* something is wrong if there is no VPTZ chunk */ |
490 | 15.7k | av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n"); |
491 | 15.7k | return AVERROR_INVALIDDATA; |
492 | 15.7k | } |
493 | | |
494 | 43.6k | bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); |
495 | 43.6k | chunk_size = bytestream2_get_be32(&s->gb); |
496 | 43.6k | if ((res = decode_format80(s, chunk_size, |
497 | 43.6k | s->decode_buffer, s->decode_buffer_size, 1)) < 0) |
498 | 3.24k | return res; |
499 | | |
500 | | /* render the final PAL8 frame */ |
501 | 40.3k | if (s->vector_height == 4) |
502 | 1.61k | index_shift = 4; |
503 | 38.7k | else |
504 | 38.7k | index_shift = 3; |
505 | 750k | for (y = 0; y < s->height; y += s->vector_height) { |
506 | 22.0M | for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) { |
507 | 21.3M | pixel_ptr = y * frame->linesize[0] + x; |
508 | | |
509 | | /* get the vector index, the method for which varies according to |
510 | | * VQA file version */ |
511 | 21.3M | switch (s->vqa_version) { |
512 | | |
513 | 19.9M | case 1: |
514 | 19.9M | lobyte = s->decode_buffer[lobytes * 2]; |
515 | 19.9M | hibyte = s->decode_buffer[(lobytes * 2) + 1]; |
516 | 19.9M | vector_index = ((hibyte << 8) | lobyte) >> 3; |
517 | 19.9M | vector_index <<= index_shift; |
518 | 19.9M | lines = s->vector_height; |
519 | | /* uniform color fill - a quick hack */ |
520 | 19.9M | if (hibyte == 0xFF) { |
521 | 13.7k | while (lines--) { |
522 | 9.18k | frame->data[0][pixel_ptr + 0] = 255 - lobyte; |
523 | 9.18k | frame->data[0][pixel_ptr + 1] = 255 - lobyte; |
524 | 9.18k | frame->data[0][pixel_ptr + 2] = 255 - lobyte; |
525 | 9.18k | frame->data[0][pixel_ptr + 3] = 255 - lobyte; |
526 | 9.18k | pixel_ptr += frame->linesize[0]; |
527 | 9.18k | } |
528 | 4.57k | lines=0; |
529 | 4.57k | } |
530 | 19.9M | break; |
531 | | |
532 | 1.43M | case 2: |
533 | 1.43M | lobyte = s->decode_buffer[lobytes]; |
534 | 1.43M | hibyte = s->decode_buffer[hibytes]; |
535 | 1.43M | vector_index = (hibyte << 8) | lobyte; |
536 | 1.43M | vector_index <<= index_shift; |
537 | 1.43M | lines = s->vector_height; |
538 | 1.43M | break; |
539 | | |
540 | 219 | case 3: |
541 | 219 | av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette"); |
542 | 219 | return AVERROR_INVALIDDATA; |
543 | 21.3M | } |
544 | | |
545 | 67.5M | while (lines--) { |
546 | 46.2M | frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++]; |
547 | 46.2M | frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++]; |
548 | 46.2M | frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++]; |
549 | 46.2M | frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++]; |
550 | 46.2M | pixel_ptr += frame->linesize[0]; |
551 | 46.2M | } |
552 | 21.3M | } |
553 | 710k | } |
554 | | |
555 | | /* handle partial codebook */ |
556 | 40.1k | if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { |
557 | | /* a chunk should not have both chunk types */ |
558 | 207 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n"); |
559 | 207 | return AVERROR_INVALIDDATA; |
560 | 207 | } |
561 | | |
562 | 39.9k | if (cbp0_chunk != -1) { |
563 | | |
564 | 1.40k | bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); |
565 | 1.40k | chunk_size = bytestream2_get_be32(&s->gb); |
566 | | |
567 | 1.40k | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
568 | 245 | av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n", |
569 | 245 | chunk_size); |
570 | 245 | return AVERROR_INVALIDDATA; |
571 | 245 | } |
572 | | |
573 | | /* accumulate partial codebook */ |
574 | 1.15k | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
575 | 1.15k | chunk_size); |
576 | 1.15k | s->next_codebook_buffer_index += chunk_size; |
577 | | |
578 | 1.15k | s->partial_countdown--; |
579 | 1.15k | if (s->partial_countdown <= 0) { |
580 | | |
581 | | /* time to replace codebook */ |
582 | 299 | memcpy(s->codebook, s->next_codebook_buffer, |
583 | 299 | s->next_codebook_buffer_index); |
584 | | |
585 | | /* reset accounting */ |
586 | 299 | s->next_codebook_buffer_index = 0; |
587 | 299 | s->partial_countdown = s->partial_count; |
588 | 299 | } |
589 | 1.15k | } |
590 | | |
591 | 39.7k | if (cbpz_chunk != -1) { |
592 | | |
593 | 4.34k | bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); |
594 | 4.34k | chunk_size = bytestream2_get_be32(&s->gb); |
595 | | |
596 | 4.34k | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
597 | 371 | av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n", |
598 | 371 | chunk_size); |
599 | 371 | return AVERROR_INVALIDDATA; |
600 | 371 | } |
601 | | |
602 | | /* accumulate partial codebook */ |
603 | 3.97k | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
604 | 3.97k | chunk_size); |
605 | 3.97k | s->next_codebook_buffer_index += chunk_size; |
606 | | |
607 | 3.97k | s->partial_countdown--; |
608 | 3.97k | if (s->partial_countdown <= 0) { |
609 | 3.47k | bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index); |
610 | | /* decompress codebook */ |
611 | 3.47k | res = decode_format80(s, s->next_codebook_buffer_index, |
612 | 3.47k | s->codebook, s->codebook_size, 0); |
613 | | |
614 | | /* reset accounting */ |
615 | 3.47k | s->next_codebook_buffer_index = 0; |
616 | 3.47k | s->partial_countdown = s->partial_count; |
617 | 3.47k | if (res < 0) |
618 | 1.72k | return res; |
619 | 3.47k | } |
620 | 3.97k | } |
621 | | |
622 | 37.6k | return 0; |
623 | 39.7k | } |
624 | | |
625 | | static int vqa_decode_frame_hicolor(VqaContext *s, AVFrame *frame) |
626 | 11.1k | { |
627 | 11.1k | unsigned int chunk_type; |
628 | 11.1k | unsigned int chunk_size; |
629 | 11.1k | unsigned int index = 0; |
630 | 11.1k | int res; |
631 | | |
632 | 11.1k | int cbf0_chunk = -1; |
633 | 11.1k | int cbfz_chunk = -1; |
634 | 11.1k | int vptr_chunk = -1; |
635 | 11.1k | int vprz_chunk = -1; |
636 | | |
637 | 11.1k | GetByteContext gb_stream; |
638 | | |
639 | 43.0k | while (bytestream2_get_bytes_left(&s->gb) >= 8) { |
640 | 31.8k | chunk_type = bytestream2_get_be32u(&s->gb); |
641 | 31.8k | index = bytestream2_tell(&s->gb); |
642 | 31.8k | chunk_size = bytestream2_get_be32u(&s->gb); |
643 | | |
644 | 31.8k | switch (chunk_type) { |
645 | 1.10k | case CBF0_TAG: |
646 | 1.10k | cbf0_chunk = index; |
647 | 1.10k | break; |
648 | 753 | case CBFZ_TAG: |
649 | 753 | cbfz_chunk = index; |
650 | 753 | break; |
651 | 1.27k | case VPTR_TAG: |
652 | 1.27k | vptr_chunk = index; |
653 | 1.27k | break; |
654 | 3.26k | case VPRZ_TAG: |
655 | 3.26k | vprz_chunk = index; |
656 | 3.26k | break; |
657 | 25.4k | default: |
658 | 25.4k | av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n", |
659 | 25.4k | av_fourcc2str(av_bswap32(chunk_type)), chunk_type); |
660 | 25.4k | break; |
661 | 31.8k | } |
662 | | |
663 | 31.8k | bytestream2_skip(&s->gb, chunk_size + (chunk_size & 0x01)); |
664 | 31.8k | } |
665 | | |
666 | | /* next, look for a full codebook */ |
667 | 11.1k | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { |
668 | | /* a chunk should not have both chunk types */ |
669 | 254 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); |
670 | 254 | return AVERROR_INVALIDDATA; |
671 | 254 | } |
672 | | |
673 | | /* decompress the full codebook chunk */ |
674 | 10.9k | if (cbfz_chunk != -1) { |
675 | 497 | bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); |
676 | 497 | chunk_size = bytestream2_get_be32(&s->gb); |
677 | 497 | if ((res = decode_format80(s, chunk_size, s->codebook, |
678 | 497 | s->codebook_size, 0)) < 0) |
679 | 247 | return res; |
680 | 497 | } |
681 | | |
682 | | /* copy a full codebook */ |
683 | 10.6k | if (cbf0_chunk != -1) { |
684 | 853 | bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); |
685 | 853 | chunk_size = bytestream2_get_be32(&s->gb); |
686 | | /* sanity check the full codebook size */ |
687 | 853 | if (chunk_size > MAX_CODEBOOK_SIZE) { |
688 | 222 | av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", |
689 | 222 | chunk_size); |
690 | 222 | return AVERROR_INVALIDDATA; |
691 | 222 | } |
692 | | |
693 | 631 | bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); |
694 | 631 | } |
695 | | |
696 | | /* decode the frame */ |
697 | | |
698 | 10.4k | if (vptr_chunk != -1) { |
699 | | /* copy uncompressed tile data */ |
700 | 1.27k | bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET); |
701 | 1.27k | chunk_size = bytestream2_get_be32(&s->gb); |
702 | 1.27k | if (chunk_size > s->decode_buffer_size) { |
703 | 285 | av_log(s->avctx, AV_LOG_ERROR, "VPTR chunk didn't fit in decode buffer"); |
704 | 285 | return AVERROR_INVALIDDATA; |
705 | 285 | } |
706 | 985 | bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size); |
707 | 9.16k | } else if (vprz_chunk != -1) { |
708 | | /* decompress the tile data */ |
709 | 3.26k | bytestream2_seek(&s->gb, vprz_chunk, SEEK_SET); |
710 | | |
711 | 3.26k | chunk_size = bytestream2_get_be32(&s->gb); |
712 | 3.26k | if ((res = decode_format80(s, chunk_size, s->decode_buffer, s->decode_buffer_size, 0)) < 0) |
713 | 296 | return res; |
714 | 5.89k | } else { |
715 | 5.89k | av_log(s->avctx, AV_LOG_ERROR, "frame has no block data\n"); |
716 | 5.89k | return AVERROR_INVALIDDATA; |
717 | 5.89k | } |
718 | | |
719 | | /* now uncompress the per-row RLE of the decode buffer and draw the blocks in framebuffer */ |
720 | | |
721 | 3.95k | bytestream2_init(&gb_stream, s->decode_buffer, s->decode_buffer_size); |
722 | | |
723 | 6.49k | for (int y_pos = 0; y_pos < s->height; y_pos += s->vector_height) { |
724 | 4.26k | int x_pos = 0; |
725 | | |
726 | 1.47M | while (x_pos < s->width) { |
727 | 1.46M | int vector_index = 0; |
728 | 1.46M | int count = 0; |
729 | 1.46M | uint16_t code; |
730 | 1.46M | int type; |
731 | | |
732 | 1.46M | if (bytestream2_get_bytes_left(&gb_stream) < 2) |
733 | 1.11k | return AVERROR_INVALIDDATA; |
734 | | |
735 | 1.46M | code = bytestream2_get_le16(&gb_stream); |
736 | | |
737 | 1.46M | type = code >> 13; |
738 | 1.46M | code &= 0x1fff; |
739 | | |
740 | 1.46M | if (type == 0) { |
741 | 1.46M | x_pos += 4 * code; |
742 | 1.46M | continue; |
743 | 1.46M | } else if (type < 3) { |
744 | 1.35k | vector_index = code & 0xff; |
745 | 1.35k | count = ((code & 0x1f00) >> 7) + 1 + type; |
746 | 1.88k | } else if (type < 5) { |
747 | 927 | vector_index = code; |
748 | 927 | count = 1; |
749 | 959 | } else if (type < 7) { |
750 | 722 | vector_index = code; |
751 | 722 | count = bytestream2_get_byte(&gb_stream); |
752 | 722 | } else { |
753 | 237 | av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type); |
754 | 237 | return AVERROR_INVALIDDATA; |
755 | 237 | } |
756 | | |
757 | 3.00k | if (count < 0 || count > (s->width - x_pos) / s->vector_width) { |
758 | 372 | av_log(s->avctx, AV_LOG_ERROR, "invalid count: %d\n", count); |
759 | 372 | return AVERROR_INVALIDDATA; |
760 | 372 | } |
761 | | |
762 | 74.5k | while (count-- && x_pos < s->width) { |
763 | 71.8k | const int bytes_per_vector = 4 * s->vector_height * sizeof(uint16_t); |
764 | 71.8k | unsigned char *src = s->codebook + vector_index * bytes_per_vector; |
765 | 71.8k | unsigned char *dst = s->frame->data[0] + y_pos * s->frame->linesize[0] |
766 | 71.8k | + sizeof(uint16_t) * x_pos; |
767 | | |
768 | 71.8k | if (vector_index >= MAX_VECTORS) |
769 | 0 | return AVERROR_INVALIDDATA; |
770 | | |
771 | 215k | for (int y = 0; y < s->vector_height; y++) { |
772 | 143k | int size = 4 * sizeof(uint16_t); |
773 | 143k | memcpy(dst, src, size); |
774 | 143k | dst += s->frame->linesize[0]; |
775 | 143k | src += size; |
776 | 143k | } |
777 | | |
778 | | /* we might want to read the next block index from stream */ |
779 | 71.8k | if ((type == 2) && count > 0) { |
780 | 9.67k | vector_index = bytestream2_get_byte(&gb_stream); |
781 | 9.67k | } |
782 | | |
783 | 71.8k | x_pos += 4; |
784 | 71.8k | } |
785 | | |
786 | 2.62k | if (count > 0) { |
787 | 0 | av_log(s->avctx, AV_LOG_ERROR, "had %d leftover vectors\n", count); |
788 | 0 | return AVERROR_BUG; |
789 | 0 | } |
790 | 2.62k | } |
791 | 4.26k | } |
792 | | |
793 | 2.23k | return 0; |
794 | 3.95k | } |
795 | | |
796 | | static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe, |
797 | | int *got_frame, AVPacket *avpkt) |
798 | 72.6k | { |
799 | 72.6k | VqaContext *s = avctx->priv_data; |
800 | 72.6k | int res; |
801 | | |
802 | 72.6k | if ((res = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
803 | 89 | return res; |
804 | | |
805 | 72.5k | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
806 | | |
807 | 72.5k | if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { |
808 | 61.4k | if ((res = vqa_decode_frame_pal8(s, s->frame)) < 0) |
809 | 23.8k | return res; |
810 | | |
811 | | /* make the palette available on the way out */ |
812 | 37.6k | memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4); |
813 | 37.6k | #if FF_API_PALETTE_HAS_CHANGED |
814 | 37.6k | FF_DISABLE_DEPRECATION_WARNINGS |
815 | 37.6k | s->frame->palette_has_changed = 1; |
816 | 37.6k | FF_ENABLE_DEPRECATION_WARNINGS |
817 | 37.6k | #endif |
818 | 37.6k | } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { |
819 | 11.1k | if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0) |
820 | 8.92k | return res; |
821 | 11.1k | } else { |
822 | 0 | av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n"); |
823 | 0 | return AVERROR_BUG; |
824 | 0 | } |
825 | | |
826 | 39.8k | if ((res = av_frame_ref(rframe, s->frame)) < 0) |
827 | 0 | return res; |
828 | | |
829 | 39.8k | *got_frame = 1; |
830 | | |
831 | | /* report that the buffer was completely consumed */ |
832 | 39.8k | return avpkt->size; |
833 | 39.8k | } |
834 | | |
835 | | static av_cold int vqa_decode_end(AVCodecContext *avctx) |
836 | 1.29k | { |
837 | 1.29k | VqaContext *s = avctx->priv_data; |
838 | | |
839 | 1.29k | av_frame_free(&s->frame); |
840 | 1.29k | av_freep(&s->codebook); |
841 | 1.29k | av_freep(&s->next_codebook_buffer); |
842 | 1.29k | av_freep(&s->decode_buffer); |
843 | | |
844 | 1.29k | return 0; |
845 | 1.29k | } |
846 | | |
847 | | static const FFCodecDefault vqa_defaults[] = { |
848 | | { "max_pixels", "640*480" }, |
849 | | { NULL }, |
850 | | }; |
851 | | |
852 | | const FFCodec ff_vqa_decoder = { |
853 | | .p.name = "vqavideo", |
854 | | CODEC_LONG_NAME("Westwood Studios VQA (Vector Quantized Animation) video"), |
855 | | .p.type = AVMEDIA_TYPE_VIDEO, |
856 | | .p.id = AV_CODEC_ID_WS_VQA, |
857 | | .priv_data_size = sizeof(VqaContext), |
858 | | .init = vqa_decode_init, |
859 | | .close = vqa_decode_end, |
860 | | FF_CODEC_DECODE_CB(vqa_decode_frame), |
861 | | .p.capabilities = AV_CODEC_CAP_DR1, |
862 | | .defaults = vqa_defaults, |
863 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
864 | | }; |