Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Westwood Studios VQA Video Decoder |
||
3 | * Copyright (C) 2003 the ffmpeg project |
||
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 | /** |
||
23 | * @file |
||
24 | * VQA Video Decoder |
||
25 | * @author Mike Melanson (melanson@pcisys.net) |
||
26 | * @see http://wiki.multimedia.cx/index.php?title=VQA |
||
27 | * |
||
28 | * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending |
||
29 | * on the type of data in the file. |
||
30 | * |
||
31 | * This decoder needs the 42-byte VQHD header from the beginning |
||
32 | * of the VQA file passed through the extradata field. The VQHD header |
||
33 | * is laid out as: |
||
34 | * |
||
35 | * bytes 0-3 chunk fourcc: 'VQHD' |
||
36 | * bytes 4-7 chunk size in big-endian format, should be 0x0000002A |
||
37 | * bytes 8-49 VQHD chunk data |
||
38 | * |
||
39 | * Bytes 8-49 are what this decoder expects to see. |
||
40 | * |
||
41 | * Briefly, VQA is a vector quantized animation format that operates in a |
||
42 | * VGA palettized colorspace. It operates on pixel vectors (blocks) |
||
43 | * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector |
||
44 | * codebooks, palette information, and code maps for rendering vectors onto |
||
45 | * frames. Any of these components can also be compressed with a run-length |
||
46 | * encoding (RLE) algorithm commonly referred to as "format80". |
||
47 | * |
||
48 | * VQA takes a novel approach to rate control. Each group of n frames |
||
49 | * (usually, n = 8) relies on a different vector codebook. Rather than |
||
50 | * transporting an entire codebook every 8th frame, the new codebook is |
||
51 | * broken up into 8 pieces and sent along with the compressed video chunks |
||
52 | * for each of the 8 frames preceding the 8 frames which require the |
||
53 | * codebook. A full codebook is also sent on the very first frame of a |
||
54 | * file. This is an interesting technique, although it makes random file |
||
55 | * seeking difficult despite the fact that the frames are all intracoded. |
||
56 | * |
||
57 | * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were |
||
58 | * packed into bytes and then RLE compressed, bytewise, the results would |
||
59 | * be poor. That is why the coding method divides each index into 2 parts, |
||
60 | * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces |
||
61 | * together and the 8-bit pieces together. If most of the vectors are |
||
62 | * clustered into one group of 256 vectors, most of the 4-bit index pieces |
||
63 | * should be the same. |
||
64 | */ |
||
65 | |||
66 | #include |
||
67 | #include |
||
68 | #include |
||
69 | |||
70 | #include "libavutil/intreadwrite.h" |
||
71 | #include "libavutil/imgutils.h" |
||
72 | #include "avcodec.h" |
||
73 | #include "bytestream.h" |
||
74 | #include "internal.h" |
||
75 | |||
76 | #define PALETTE_COUNT 256 |
||
77 | #define VQA_HEADER_SIZE 0x2A |
||
78 | |||
79 | /* allocate the maximum vector space, regardless of the file version: |
||
80 | * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ |
||
81 | #define MAX_CODEBOOK_VECTORS 0xFF00 |
||
82 | #define SOLID_PIXEL_VECTORS 0x100 |
||
83 | #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) |
||
84 | #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4) |
||
85 | |||
86 | #define CBF0_TAG MKBETAG('C', 'B', 'F', '0') |
||
87 | #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') |
||
88 | #define CBP0_TAG MKBETAG('C', 'B', 'P', '0') |
||
89 | #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z') |
||
90 | #define CPL0_TAG MKBETAG('C', 'P', 'L', '0') |
||
91 | #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z') |
||
92 | #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z') |
||
93 | |||
94 | typedef struct VqaContext { |
||
95 | |||
96 | AVCodecContext *avctx; |
||
97 | GetByteContext gb; |
||
98 | |||
99 | uint32_t palette[PALETTE_COUNT]; |
||
100 | |||
101 | int width; /* width of a frame */ |
||
102 | int height; /* height of a frame */ |
||
103 | int vector_width; /* width of individual vector */ |
||
104 | int vector_height; /* height of individual vector */ |
||
105 | int vqa_version; /* this should be either 1, 2 or 3 */ |
||
106 | |||
107 | unsigned char *codebook; /* the current codebook */ |
||
108 | int codebook_size; |
||
109 | unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
||
110 | int next_codebook_buffer_index; |
||
111 | |||
112 | unsigned char *decode_buffer; |
||
113 | int decode_buffer_size; |
||
114 | |||
115 | /* number of frames to go before replacing codebook */ |
||
116 | int partial_countdown; |
||
117 | int partial_count; |
||
118 | |||
119 | } VqaContext; |
||
120 | |||
121 | static av_cold int vqa_decode_init(AVCodecContext *avctx) |
||
122 | { |
||
123 | VqaContext *s = avctx->priv_data; |
||
124 | int i, j, codebook_index, ret; |
||
125 | |||
126 | s->avctx = avctx; |
||
127 | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
||
128 | |||
129 | /* make sure the extradata made it */ |
||
130 | if (s->avctx->extradata_size != VQA_HEADER_SIZE) { |
||
131 | av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE); |
||
132 | return AVERROR(EINVAL); |
||
133 | } |
||
134 | |||
135 | /* load up the VQA parameters from the header */ |
||
136 | s->vqa_version = s->avctx->extradata[0]; |
||
137 | switch (s->vqa_version) { |
||
138 | case 1: |
||
139 | case 2: |
||
140 | break; |
||
141 | case 3: |
||
142 | avpriv_report_missing_feature(avctx, "VQA Version %d", s->vqa_version); |
||
143 | return AVERROR_PATCHWELCOME; |
||
144 | default: |
||
145 | avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version); |
||
146 | return AVERROR_PATCHWELCOME; |
||
147 | } |
||
148 | s->width = AV_RL16(&s->avctx->extradata[6]); |
||
149 | s->height = AV_RL16(&s->avctx->extradata[8]); |
||
150 | if ((ret = av_image_check_size(s->width, s->height, 0, avctx)) < 0) { |
||
151 | s->width= s->height= 0; |
||
152 | return ret; |
||
153 | } |
||
154 | s->vector_width = s->avctx->extradata[10]; |
||
155 | s->vector_height = s->avctx->extradata[11]; |
||
156 | s->partial_count = s->partial_countdown = s->avctx->extradata[13]; |
||
157 | |||
158 | /* the vector dimensions have to meet very stringent requirements */ |
||
159 | if ((s->vector_width != 4) || |
||
160 | ((s->vector_height != 2) && (s->vector_height != 4))) { |
||
161 | /* return without further initialization */ |
||
162 | return AVERROR_INVALIDDATA; |
||
163 | } |
||
164 | |||
165 | if (s->width % s->vector_width || s->height % s->vector_height) { |
||
166 | av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n"); |
||
167 | return AVERROR_INVALIDDATA; |
||
168 | } |
||
169 | |||
170 | /* allocate codebooks */ |
||
171 | s->codebook_size = MAX_CODEBOOK_SIZE; |
||
172 | s->codebook = av_malloc(s->codebook_size); |
||
173 | if (!s->codebook) |
||
174 | goto fail; |
||
175 | s->next_codebook_buffer = av_malloc(s->codebook_size); |
||
176 | if (!s->next_codebook_buffer) |
||
177 | goto fail; |
||
178 | |||
179 | /* allocate decode buffer */ |
||
180 | s->decode_buffer_size = (s->width / s->vector_width) * |
||
181 | (s->height / s->vector_height) * 2; |
||
182 | s->decode_buffer = av_malloc(s->decode_buffer_size); |
||
183 | if (!s->decode_buffer) |
||
184 | goto fail; |
||
185 | |||
186 | /* initialize the solid-color vectors */ |
||
187 | if (s->vector_height == 4) { |
||
188 | codebook_index = 0xFF00 * 16; |
||
189 | for (i = 0; i < 256; i++) |
||
190 | for (j = 0; j < 16; j++) |
||
191 | s->codebook[codebook_index++] = i; |
||
192 | } else { |
||
193 | codebook_index = 0xF00 * 8; |
||
194 | for (i = 0; i < 256; i++) |
||
195 | for (j = 0; j < 8; j++) |
||
196 | s->codebook[codebook_index++] = i; |
||
197 | } |
||
198 | s->next_codebook_buffer_index = 0; |
||
199 | |||
200 | return 0; |
||
201 | fail: |
||
202 | av_freep(&s->codebook); |
||
203 | av_freep(&s->next_codebook_buffer); |
||
204 | av_freep(&s->decode_buffer); |
||
205 | return AVERROR(ENOMEM); |
||
206 | } |
||
207 | |||
208 | #define CHECK_COUNT() \ |
||
209 | if (dest_index + count > dest_size) { \ |
||
210 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
||
211 | av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \ |
||
212 | dest_index, count, dest_size); \ |
||
213 | return AVERROR_INVALIDDATA; \ |
||
214 | } |
||
215 | |||
216 | #define CHECK_COPY(idx) \ |
||
217 | if (idx < 0 || idx + count > dest_size) { \ |
||
218 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
||
219 | av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \ |
||
220 | src_pos, count, dest_size); \ |
||
221 | return AVERROR_INVALIDDATA; \ |
||
222 | } |
||
223 | |||
224 | |||
225 | static int decode_format80(VqaContext *s, int src_size, |
||
226 | unsigned char *dest, int dest_size, int check_size) { |
||
227 | |||
228 | int dest_index = 0; |
||
229 | int count, opcode, start; |
||
230 | int src_pos; |
||
231 | unsigned char color; |
||
232 | int i; |
||
233 | |||
234 | start = bytestream2_tell(&s->gb); |
||
235 | while (bytestream2_tell(&s->gb) - start < src_size) { |
||
236 | opcode = bytestream2_get_byte(&s->gb); |
||
237 | av_dlog(s->avctx, "opcode %02X: ", opcode); |
||
238 | |||
239 | /* 0x80 means that frame is finished */ |
||
240 | if (opcode == 0x80) |
||
241 | return 0; |
||
242 | |||
243 | if (dest_index >= dest_size) { |
||
244 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
||
245 | dest_index, dest_size); |
||
246 | return AVERROR_INVALIDDATA; |
||
247 | } |
||
248 | |||
249 | if (opcode == 0xFF) { |
||
250 | |||
251 | count = bytestream2_get_le16(&s->gb); |
||
252 | src_pos = bytestream2_get_le16(&s->gb); |
||
253 | av_dlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos); |
||
254 | CHECK_COUNT(); |
||
255 | CHECK_COPY(src_pos); |
||
256 | for (i = 0; i < count; i++) |
||
257 | dest[dest_index + i] = dest[src_pos + i]; |
||
258 | dest_index += count; |
||
259 | |||
260 | } else if (opcode == 0xFE) { |
||
261 | |||
262 | count = bytestream2_get_le16(&s->gb); |
||
263 | color = bytestream2_get_byte(&s->gb); |
||
264 | av_dlog(s->avctx, "(2) set %X bytes to %02X\n", count, color); |
||
265 | CHECK_COUNT(); |
||
266 | memset(&dest[dest_index], color, count); |
||
267 | dest_index += count; |
||
268 | |||
269 | } else if ((opcode & 0xC0) == 0xC0) { |
||
270 | |||
271 | count = (opcode & 0x3F) + 3; |
||
272 | src_pos = bytestream2_get_le16(&s->gb); |
||
273 | av_dlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos); |
||
274 | CHECK_COUNT(); |
||
275 | CHECK_COPY(src_pos); |
||
276 | for (i = 0; i < count; i++) |
||
277 | dest[dest_index + i] = dest[src_pos + i]; |
||
278 | dest_index += count; |
||
279 | |||
280 | } else if (opcode > 0x80) { |
||
281 | |||
282 | count = opcode & 0x3F; |
||
283 | av_dlog(s->avctx, "(4) copy %X bytes from source to dest\n", count); |
||
284 | CHECK_COUNT(); |
||
285 | bytestream2_get_buffer(&s->gb, &dest[dest_index], count); |
||
286 | dest_index += count; |
||
287 | |||
288 | } else { |
||
289 | |||
290 | count = ((opcode & 0x70) >> 4) + 3; |
||
291 | src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8); |
||
292 | av_dlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos); |
||
293 | CHECK_COUNT(); |
||
294 | CHECK_COPY(dest_index - src_pos); |
||
295 | for (i = 0; i < count; i++) |
||
296 | dest[dest_index + i] = dest[dest_index - src_pos + i]; |
||
297 | dest_index += count; |
||
298 | } |
||
299 | } |
||
300 | |||
301 | /* validate that the entire destination buffer was filled; this is |
||
302 | * important for decoding frame maps since each vector needs to have a |
||
303 | * codebook entry; it is not important for compressed codebooks because |
||
304 | * not every entry needs to be filled */ |
||
305 | if (check_size) |
||
306 | if (dest_index < dest_size) |
||
307 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", |
||
308 | dest_index, dest_size); |
||
309 | |||
310 | return 0; // let's display what we decoded anyway |
||
311 | } |
||
312 | |||
313 | static int vqa_decode_chunk(VqaContext *s, AVFrame *frame) |
||
314 | { |
||
315 | unsigned int chunk_type; |
||
316 | unsigned int chunk_size; |
||
317 | int byte_skip; |
||
318 | unsigned int index = 0; |
||
319 | int i; |
||
320 | unsigned char r, g, b; |
||
321 | int index_shift; |
||
322 | int res; |
||
323 | |||
324 | int cbf0_chunk = -1; |
||
325 | int cbfz_chunk = -1; |
||
326 | int cbp0_chunk = -1; |
||
327 | int cbpz_chunk = -1; |
||
328 | int cpl0_chunk = -1; |
||
329 | int cplz_chunk = -1; |
||
330 | int vptz_chunk = -1; |
||
331 | |||
332 | int x, y; |
||
333 | int lines = 0; |
||
334 | int pixel_ptr; |
||
335 | int vector_index = 0; |
||
336 | int lobyte = 0; |
||
337 | int hibyte = 0; |
||
338 | int lobytes = 0; |
||
339 | int hibytes = s->decode_buffer_size / 2; |
||
340 | |||
341 | /* first, traverse through the frame and find the subchunks */ |
||
342 | while (bytestream2_get_bytes_left(&s->gb) >= 8) { |
||
343 | |||
344 | chunk_type = bytestream2_get_be32u(&s->gb); |
||
345 | index = bytestream2_tell(&s->gb); |
||
346 | chunk_size = bytestream2_get_be32u(&s->gb); |
||
347 | |||
348 | switch (chunk_type) { |
||
349 | |||
350 | case CBF0_TAG: |
||
351 | cbf0_chunk = index; |
||
352 | break; |
||
353 | |||
354 | case CBFZ_TAG: |
||
355 | cbfz_chunk = index; |
||
356 | break; |
||
357 | |||
358 | case CBP0_TAG: |
||
359 | cbp0_chunk = index; |
||
360 | break; |
||
361 | |||
362 | case CBPZ_TAG: |
||
363 | cbpz_chunk = index; |
||
364 | break; |
||
365 | |||
366 | case CPL0_TAG: |
||
367 | cpl0_chunk = index; |
||
368 | break; |
||
369 | |||
370 | case CPLZ_TAG: |
||
371 | cplz_chunk = index; |
||
372 | break; |
||
373 | |||
374 | case VPTZ_TAG: |
||
375 | vptz_chunk = index; |
||
376 | break; |
||
377 | |||
378 | default: |
||
379 | av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %c%c%c%c (%08X)\n", |
||
380 | (chunk_type >> 24) & 0xFF, |
||
381 | (chunk_type >> 16) & 0xFF, |
||
382 | (chunk_type >> 8) & 0xFF, |
||
383 | (chunk_type >> 0) & 0xFF, |
||
384 | chunk_type); |
||
385 | break; |
||
386 | } |
||
387 | |||
388 | byte_skip = chunk_size & 0x01; |
||
389 | bytestream2_skip(&s->gb, chunk_size + byte_skip); |
||
390 | } |
||
391 | |||
392 | /* next, deal with the palette */ |
||
393 | if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { |
||
394 | |||
395 | /* a chunk should not have both chunk types */ |
||
396 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n"); |
||
397 | return AVERROR_INVALIDDATA; |
||
398 | } |
||
399 | |||
400 | /* decompress the palette chunk */ |
||
401 | if (cplz_chunk != -1) { |
||
402 | |||
403 | /* yet to be handled */ |
||
404 | |||
405 | } |
||
406 | |||
407 | /* convert the RGB palette into the machine's endian format */ |
||
408 | if (cpl0_chunk != -1) { |
||
409 | |||
410 | bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); |
||
411 | chunk_size = bytestream2_get_be32(&s->gb); |
||
412 | /* sanity check the palette size */ |
||
413 | if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { |
||
414 | av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n", |
||
415 | chunk_size / 3); |
||
416 | return AVERROR_INVALIDDATA; |
||
417 | } |
||
418 | for (i = 0; i < chunk_size / 3; i++) { |
||
419 | /* scale by 4 to transform 6-bit palette -> 8-bit */ |
||
420 | r = bytestream2_get_byteu(&s->gb) * 4; |
||
421 | g = bytestream2_get_byteu(&s->gb) * 4; |
||
422 | b = bytestream2_get_byteu(&s->gb) * 4; |
||
423 | s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b; |
||
424 | s->palette[i] |= s->palette[i] >> 6 & 0x30303; |
||
425 | } |
||
426 | } |
||
427 | |||
428 | /* next, look for a full codebook */ |
||
429 | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { |
||
430 | |||
431 | /* a chunk should not have both chunk types */ |
||
432 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); |
||
433 | return AVERROR_INVALIDDATA; |
||
434 | } |
||
435 | |||
436 | /* decompress the full codebook chunk */ |
||
437 | if (cbfz_chunk != -1) { |
||
438 | |||
439 | bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); |
||
440 | chunk_size = bytestream2_get_be32(&s->gb); |
||
441 | if ((res = decode_format80(s, chunk_size, s->codebook, |
||
442 | s->codebook_size, 0)) < 0) |
||
443 | return res; |
||
444 | } |
||
445 | |||
446 | /* copy a full codebook */ |
||
447 | if (cbf0_chunk != -1) { |
||
448 | |||
449 | bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); |
||
450 | chunk_size = bytestream2_get_be32(&s->gb); |
||
451 | /* sanity check the full codebook size */ |
||
452 | if (chunk_size > MAX_CODEBOOK_SIZE) { |
||
453 | av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", |
||
454 | chunk_size); |
||
455 | return AVERROR_INVALIDDATA; |
||
456 | } |
||
457 | |||
458 | bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); |
||
459 | } |
||
460 | |||
461 | /* decode the frame */ |
||
462 | if (vptz_chunk == -1) { |
||
463 | |||
464 | /* something is wrong if there is no VPTZ chunk */ |
||
465 | av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n"); |
||
466 | return AVERROR_INVALIDDATA; |
||
467 | } |
||
468 | |||
469 | bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); |
||
470 | chunk_size = bytestream2_get_be32(&s->gb); |
||
471 | if ((res = decode_format80(s, chunk_size, |
||
472 | s->decode_buffer, s->decode_buffer_size, 1)) < 0) |
||
473 | return res; |
||
474 | |||
475 | /* render the final PAL8 frame */ |
||
476 | if (s->vector_height == 4) |
||
477 | index_shift = 4; |
||
478 | else |
||
479 | index_shift = 3; |
||
480 | for (y = 0; y < s->height; y += s->vector_height) { |
||
481 | for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) { |
||
482 | pixel_ptr = y * frame->linesize[0] + x; |
||
483 | |||
484 | /* get the vector index, the method for which varies according to |
||
485 | * VQA file version */ |
||
486 | switch (s->vqa_version) { |
||
487 | |||
488 | case 1: |
||
489 | lobyte = s->decode_buffer[lobytes * 2]; |
||
490 | hibyte = s->decode_buffer[(lobytes * 2) + 1]; |
||
491 | vector_index = ((hibyte << 8) | lobyte) >> 3; |
||
492 | vector_index <<= index_shift; |
||
493 | lines = s->vector_height; |
||
494 | /* uniform color fill - a quick hack */ |
||
495 | if (hibyte == 0xFF) { |
||
496 | while (lines--) { |
||
497 | frame->data[0][pixel_ptr + 0] = 255 - lobyte; |
||
498 | frame->data[0][pixel_ptr + 1] = 255 - lobyte; |
||
499 | frame->data[0][pixel_ptr + 2] = 255 - lobyte; |
||
500 | frame->data[0][pixel_ptr + 3] = 255 - lobyte; |
||
501 | pixel_ptr += frame->linesize[0]; |
||
502 | } |
||
503 | lines=0; |
||
504 | } |
||
505 | break; |
||
506 | |||
507 | case 2: |
||
508 | lobyte = s->decode_buffer[lobytes]; |
||
509 | hibyte = s->decode_buffer[hibytes]; |
||
510 | vector_index = (hibyte << 8) | lobyte; |
||
511 | vector_index <<= index_shift; |
||
512 | lines = s->vector_height; |
||
513 | break; |
||
514 | |||
515 | case 3: |
||
516 | /* not implemented yet */ |
||
517 | lines = 0; |
||
518 | break; |
||
519 | } |
||
520 | |||
521 | while (lines--) { |
||
522 | frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++]; |
||
523 | frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++]; |
||
524 | frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++]; |
||
525 | frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++]; |
||
526 | pixel_ptr += frame->linesize[0]; |
||
527 | } |
||
528 | } |
||
529 | } |
||
530 | |||
531 | /* handle partial codebook */ |
||
532 | if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { |
||
533 | /* a chunk should not have both chunk types */ |
||
534 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n"); |
||
535 | return AVERROR_INVALIDDATA; |
||
536 | } |
||
537 | |||
538 | if (cbp0_chunk != -1) { |
||
539 | |||
540 | bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); |
||
541 | chunk_size = bytestream2_get_be32(&s->gb); |
||
542 | |||
543 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
||
544 | av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n", |
||
545 | chunk_size); |
||
546 | return AVERROR_INVALIDDATA; |
||
547 | } |
||
548 | |||
549 | /* accumulate partial codebook */ |
||
550 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
||
551 | chunk_size); |
||
552 | s->next_codebook_buffer_index += chunk_size; |
||
553 | |||
554 | s->partial_countdown--; |
||
555 | if (s->partial_countdown <= 0) { |
||
556 | |||
557 | /* time to replace codebook */ |
||
558 | memcpy(s->codebook, s->next_codebook_buffer, |
||
559 | s->next_codebook_buffer_index); |
||
560 | |||
561 | /* reset accounting */ |
||
562 | s->next_codebook_buffer_index = 0; |
||
563 | s->partial_countdown = s->partial_count; |
||
564 | } |
||
565 | } |
||
566 | |||
567 | if (cbpz_chunk != -1) { |
||
568 | |||
569 | bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); |
||
570 | chunk_size = bytestream2_get_be32(&s->gb); |
||
571 | |||
572 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
||
573 | av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n", |
||
574 | chunk_size); |
||
575 | return AVERROR_INVALIDDATA; |
||
576 | } |
||
577 | |||
578 | /* accumulate partial codebook */ |
||
579 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
||
580 | chunk_size); |
||
581 | s->next_codebook_buffer_index += chunk_size; |
||
582 | |||
583 | s->partial_countdown--; |
||
584 | if (s->partial_countdown <= 0) { |
||
585 | bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index); |
||
586 | /* decompress codebook */ |
||
587 | if ((res = decode_format80(s, s->next_codebook_buffer_index, |
||
588 | s->codebook, s->codebook_size, 0)) < 0) |
||
589 | return res; |
||
590 | |||
591 | /* reset accounting */ |
||
592 | s->next_codebook_buffer_index = 0; |
||
593 | s->partial_countdown = s->partial_count; |
||
594 | } |
||
595 | } |
||
596 | |||
597 | return 0; |
||
598 | } |
||
599 | |||
600 | static int vqa_decode_frame(AVCodecContext *avctx, |
||
601 | void *data, int *got_frame, |
||
602 | AVPacket *avpkt) |
||
603 | { |
||
604 | VqaContext *s = avctx->priv_data; |
||
605 | AVFrame *frame = data; |
||
606 | int res; |
||
607 | |||
608 | if ((res = ff_get_buffer(avctx, frame, 0)) < 0) |
||
609 | return res; |
||
610 | |||
611 | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
||
612 | if ((res = vqa_decode_chunk(s, frame)) < 0) |
||
613 | return res; |
||
614 | |||
615 | /* make the palette available on the way out */ |
||
616 | memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); |
||
617 | frame->palette_has_changed = 1; |
||
618 | |||
619 | *got_frame = 1; |
||
620 | |||
621 | /* report that the buffer was completely consumed */ |
||
622 | return avpkt->size; |
||
623 | } |
||
624 | |||
625 | static av_cold int vqa_decode_end(AVCodecContext *avctx) |
||
626 | { |
||
627 | VqaContext *s = avctx->priv_data; |
||
628 | |||
629 | av_freep(&s->codebook); |
||
630 | av_freep(&s->next_codebook_buffer); |
||
631 | av_freep(&s->decode_buffer); |
||
632 | |||
633 | return 0; |
||
634 | } |
||
635 | |||
636 | AVCodec ff_vqa_decoder = { |
||
637 | .name = "vqavideo", |
||
638 | .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), |
||
639 | .type = AVMEDIA_TYPE_VIDEO, |
||
640 | .id = AV_CODEC_ID_WS_VQA, |
||
641 | .priv_data_size = sizeof(VqaContext), |
||
642 | .init = vqa_decode_init, |
||
643 | .close = vqa_decode_end, |
||
644 | .decode = vqa_decode_frame, |
||
645 | .capabilities = CODEC_CAP_DR1, |
||
646 | };>>>=>=>=><=>><>=><=>><>>>>>><>><>><>>>>>><>>>>>>>>>> |