Mercurial > libavcodec.hg
comparison vqavideo.c @ 1501:dc6f46cd4a7b libavcodec
added solid color vectors; basic PAL8, 4x2-vector video (as in
Command & Conquer) looks great now; also added compressed codebook
support, but files using these (Lands of Lore) are not correct yet
author | tmmm |
---|---|
date | Sat, 04 Oct 2003 17:47:22 +0000 |
parents | b78a9ba6a568 |
children | e0c02032d0f2 |
comparison
equal
deleted
inserted
replaced
1500:726a81d83ddd | 1501:dc6f46cd4a7b |
---|---|
22 * @file vqavideo.c | 22 * @file vqavideo.c |
23 * VQA Video Decoder by Mike Melanson (melanson@pcisys.net) | 23 * VQA Video Decoder by Mike Melanson (melanson@pcisys.net) |
24 * For more information about the RPZA format, visit: | 24 * For more information about the RPZA format, visit: |
25 * http://www.pcisys.net/~melanson/codecs/ | 25 * http://www.pcisys.net/~melanson/codecs/ |
26 * | 26 * |
27 * The VQA video decoder outputs PAL8 colorspace data. | 27 * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending |
28 * on the type of data in the file. | |
28 * | 29 * |
29 * This decoder needs the 42-byte VQHD header from the beginning | 30 * This decoder needs the 42-byte VQHD header from the beginning |
30 * of the VQA file passed through the extradata field. The VQHD header | 31 * of the VQA file passed through the extradata field. The VQHD header |
31 * is laid out as: | 32 * is laid out as: |
32 * | 33 * |
33 * bytes 0-3 chunk fourcc: 'VQHD' | 34 * bytes 0-3 chunk fourcc: 'VQHD' |
34 * bytes 4-7 chunk size in big-endian format, should be 0x0000002A | 35 * bytes 4-7 chunk size in big-endian format, should be 0x0000002A |
35 * bytes 8-50 VQHD chunk data | 36 * bytes 8-49 VQHD chunk data |
36 * | 37 * |
37 * Bytes 8-50 are what this decoder expects to see. | 38 * Bytes 8-49 are what this decoder expects to see. |
38 * | 39 * |
39 * Briefly, VQA is a vector quantized animation format that operates in a | 40 * Briefly, VQA is a vector quantized animation format that operates in a |
40 * 6-bit VGA palettized colorspace. It operates on pixel vectors (blocks) | 41 * VGA palettized colorspace. It operates on pixel vectors (blocks) |
41 * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector | 42 * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector |
42 * codebooks, palette information, and code maps for rendering vectors onto | 43 * codebooks, palette information, and code maps for rendering vectors onto |
43 * frames. Any of these components can also be compressed with a run-length | 44 * frames. Any of these components can also be compressed with a run-length |
44 * encoding (RLE) algorithm commonly referred to as "format80". | 45 * encoding (RLE) algorithm commonly referred to as "format80". |
45 * | 46 * |
53 * seeking difficult despite the fact that the frames are all intracoded. | 54 * seeking difficult despite the fact that the frames are all intracoded. |
54 * | 55 * |
55 * V1,2 VQA uses 12-bit codebook indices. If the 12-bit indices were | 56 * V1,2 VQA uses 12-bit codebook indices. If the 12-bit indices were |
56 * packed into bytes and then RLE compressed, bytewise, the results would | 57 * packed into bytes and then RLE compressed, bytewise, the results would |
57 * be poor. That is why the coding method divides each index into 2 parts, | 58 * be poor. That is why the coding method divides each index into 2 parts, |
58 * the top 4 bits and the bottom 8 bits, the RL encodes the 4-bit pieces | 59 * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces |
59 * together and the 8-bit pieces together. If most of the vectors are | 60 * together and the 8-bit pieces together. If most of the vectors are |
60 * clustered into one group of 256 vectors, most of the 4-bit index pieces | 61 * clustered into one group of 256 vectors, most of the 4-bit index pieces |
61 * should be the same. | 62 * should be the same. |
62 */ | 63 */ |
63 | 64 |
72 | 73 |
73 #define PALETTE_COUNT 256 | 74 #define PALETTE_COUNT 256 |
74 #define VQA_HEADER_SIZE 0x2A | 75 #define VQA_HEADER_SIZE 0x2A |
75 #define CHUNK_PREAMBLE_SIZE 8 | 76 #define CHUNK_PREAMBLE_SIZE 8 |
76 | 77 |
77 /* v1, v2 files: each vector codebook entry is 4x2=8 pixels = 8 bytes */ | 78 /* allocate the maximum vector space, regardless of the file version: |
78 #define V1_2_VECTOR_SIZE 8 | 79 * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ |
79 #define V1_2_MAX_VECTORS 0xF00 | 80 #define MAX_CODEBOOK_VECTORS 0xFF00 |
80 /* v3 files: each vector codebook entry is 4x4=16 pixels = 16 bytes */ | 81 #define SOLID_PIXEL_VECTORS 0x100 |
81 #define V3_VECTOR_SIZE 16 | 82 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) |
82 #define V3_MAX_VECTORS 0xFF00 | 83 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4) |
83 | 84 |
84 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | 85 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) |
85 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | 86 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) |
86 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ | 87 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ |
87 (((uint8_t*)(x))[1] << 16) | \ | 88 (((uint8_t*)(x))[1] << 16) | \ |
126 int vector_width; /* width of individual vector */ | 127 int vector_width; /* width of individual vector */ |
127 int vector_height; /* height of individual vector */ | 128 int vector_height; /* height of individual vector */ |
128 int vqa_version; /* this should be either 1, 2 or 3 */ | 129 int vqa_version; /* this should be either 1, 2 or 3 */ |
129 | 130 |
130 unsigned char *codebook; /* the current codebook */ | 131 unsigned char *codebook; /* the current codebook */ |
132 int codebook_size; | |
131 unsigned char *next_codebook_buffer; /* accumulator for next codebook */ | 133 unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
132 int next_codebook_buffer_index; | 134 int next_codebook_buffer_index; |
133 | 135 |
134 unsigned char *decode_buffer; | 136 unsigned char *decode_buffer; |
135 int decode_buffer_size; | 137 int decode_buffer_size; |
142 | 144 |
143 static int vqa_decode_init(AVCodecContext *avctx) | 145 static int vqa_decode_init(AVCodecContext *avctx) |
144 { | 146 { |
145 VqaContext *s = (VqaContext *)avctx->priv_data; | 147 VqaContext *s = (VqaContext *)avctx->priv_data; |
146 unsigned char *vqa_header; | 148 unsigned char *vqa_header; |
149 int i, j, codebook_index;; | |
147 | 150 |
148 s->avctx = avctx; | 151 s->avctx = avctx; |
149 avctx->pix_fmt = PIX_FMT_PAL8; | 152 avctx->pix_fmt = PIX_FMT_PAL8; |
150 avctx->has_b_frames = 0; | 153 avctx->has_b_frames = 0; |
151 dsputil_init(&s->dsp, avctx); | 154 dsputil_init(&s->dsp, avctx); |
171 /* return without further initialization */ | 174 /* return without further initialization */ |
172 return -1; | 175 return -1; |
173 } | 176 } |
174 | 177 |
175 /* allocate codebooks */ | 178 /* allocate codebooks */ |
176 if (s->vqa_version == 3) { | 179 s->codebook_size = MAX_CODEBOOK_SIZE; |
177 s->codebook = av_malloc(V3_VECTOR_SIZE * V3_MAX_VECTORS); | 180 s->codebook = av_malloc(s->codebook_size); |
178 s->next_codebook_buffer = av_malloc(V3_VECTOR_SIZE * V3_MAX_VECTORS); | 181 s->next_codebook_buffer = av_malloc(s->codebook_size); |
182 | |
183 /* initialize the solid-color vectors */ | |
184 if (s->vector_height == 4) { | |
185 codebook_index = 0xFF00 * 16; | |
186 for (i = 0; i < 256; i++) | |
187 for (j = 0; j < 16; j++) | |
188 s->codebook[codebook_index++] = i; | |
179 } else { | 189 } else { |
180 s->codebook = av_malloc(V1_2_VECTOR_SIZE * V1_2_MAX_VECTORS); | 190 codebook_index = 0xF00 * 8; |
181 s->next_codebook_buffer = av_malloc(V1_2_VECTOR_SIZE * V1_2_MAX_VECTORS); | 191 for (i = 0; i < 256; i++) |
192 for (j = 0; j < 8; j++) | |
193 s->codebook[codebook_index++] = i; | |
182 } | 194 } |
183 s->next_codebook_buffer_index = 0; | 195 s->next_codebook_buffer_index = 0; |
184 | 196 |
185 /* allocate decode buffer */ | 197 /* allocate decode buffer */ |
186 s->decode_buffer_size = (s->width / s->vector_width) * | 198 s->decode_buffer_size = (s->width / s->vector_width) * |
192 return 0; | 204 return 0; |
193 } | 205 } |
194 | 206 |
195 #define CHECK_COUNT() \ | 207 #define CHECK_COUNT() \ |
196 if (dest_index + count > dest_size) { \ | 208 if (dest_index + count > dest_size) { \ |
197 printf ("vqavideo: decode_format80 problem: next op would overflow dest_index\n"); \ | 209 printf (" VQA video: decode_format80 problem: next op would overflow dest_index\n"); \ |
198 printf ("vqavideo: current dest_index = %d, count = %d, dest_size = %d\n", \ | 210 printf (" VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \ |
199 dest_index, count, dest_size); \ | 211 dest_index, count, dest_size); \ |
200 return; \ | 212 return; \ |
201 } | 213 } |
202 | 214 |
203 static void decode_format80(unsigned char *src, int src_size, | 215 static void decode_format80(unsigned char *src, int src_size, |
204 unsigned char *dest, int dest_size) { | 216 unsigned char *dest, int dest_size, int check_size) { |
205 | 217 |
206 int src_index = 0; | 218 int src_index = 0; |
207 int dest_index = 0; | 219 int dest_index = 0; |
208 int count; | 220 int count; |
209 int src_pos; | 221 int src_pos; |
217 /* 0x80 means that frame is finished */ | 229 /* 0x80 means that frame is finished */ |
218 if (src[src_index] == 0x80) | 230 if (src[src_index] == 0x80) |
219 return; | 231 return; |
220 | 232 |
221 if (dest_index >= dest_size) { | 233 if (dest_index >= dest_size) { |
222 printf ("vqavideo: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", | 234 printf (" VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
223 dest_index, dest_size); | 235 dest_index, dest_size); |
224 return; | 236 return; |
225 } | 237 } |
226 | 238 |
227 if (src[src_index] == 0xFF) { | 239 if (src[src_index] == 0xFF) { |
279 dest[dest_index + i] = dest[dest_index - src_pos + i]; | 291 dest[dest_index + i] = dest[dest_index - src_pos + i]; |
280 dest_index += count; | 292 dest_index += count; |
281 } | 293 } |
282 } | 294 } |
283 | 295 |
284 if (dest_index < dest_size) | 296 /* validate that the entire destination buffer was filled; this is |
285 printf ("vqavideo: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", | 297 * important for decoding frame maps since each vector needs to have a |
286 dest_index, dest_size); | 298 * codebook entry; it is not important for compressed codebooks because |
299 * not every entry needs to be filled */ | |
300 if (check_size) | |
301 if (dest_index < dest_size) | |
302 printf (" VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", | |
303 dest_index, dest_size); | |
287 } | 304 } |
288 | 305 |
289 static void vqa_decode_chunk(VqaContext *s) | 306 static void vqa_decode_chunk(VqaContext *s) |
290 { | 307 { |
291 | |
292 //static int frame = 0; | |
293 unsigned int chunk_type; | 308 unsigned int chunk_type; |
294 unsigned int chunk_size; | 309 unsigned int chunk_size; |
295 int byte_skip; | 310 int byte_skip; |
296 unsigned int index = 0; | 311 unsigned int index = 0; |
297 int i; | 312 int i; |
313 int lobyte = 0; | 328 int lobyte = 0; |
314 int hibyte = 0; | 329 int hibyte = 0; |
315 int lobytes = 0; | 330 int lobytes = 0; |
316 int hibytes = s->decode_buffer_size / 2; | 331 int hibytes = s->decode_buffer_size / 2; |
317 | 332 |
318 //printf (" **** decoding frame #%d, stride = %d\n", frame++, s->frame.linesize[0]); | |
319 /* first, traverse through the frame and find the subchunks */ | 333 /* first, traverse through the frame and find the subchunks */ |
320 while (index < s->size) { | 334 while (index < s->size) { |
321 | 335 |
322 chunk_type = BE_32(&s->buf[index]); | 336 chunk_type = BE_32(&s->buf[index]); |
323 chunk_size = BE_32(&s->buf[index + 4]); | 337 chunk_size = BE_32(&s->buf[index + 4]); |
385 if (cpl0_chunk != -1) { | 399 if (cpl0_chunk != -1) { |
386 | 400 |
387 chunk_size = BE_32(&s->buf[cpl0_chunk + 4]); | 401 chunk_size = BE_32(&s->buf[cpl0_chunk + 4]); |
388 /* sanity check the palette size */ | 402 /* sanity check the palette size */ |
389 if (chunk_size / 3 > 256) { | 403 if (chunk_size / 3 > 256) { |
390 printf ("vqavideo: problem: found a palette chunk with %d colors\n", | 404 printf (" VQA video: problem: found a palette chunk with %d colors\n", |
391 chunk_size / 3); | 405 chunk_size / 3); |
392 return; | 406 return; |
393 } | 407 } |
394 cpl0_chunk += CHUNK_PREAMBLE_SIZE; | 408 cpl0_chunk += CHUNK_PREAMBLE_SIZE; |
395 palette32 = (unsigned int *)s->palette; | 409 palette32 = (unsigned int *)s->palette; |
408 /* a chunk should not have both chunk types */ | 422 /* a chunk should not have both chunk types */ |
409 printf (" VQA video: problem: found both CBF0 and CBFZ chunks\n"); | 423 printf (" VQA video: problem: found both CBF0 and CBFZ chunks\n"); |
410 return; | 424 return; |
411 } | 425 } |
412 | 426 |
413 /* decompress the full codebook chunk into the codebook accumulation | 427 /* decompress the full codebook chunk */ |
414 * buffer; this is safe since only the first frame is supposed to have | |
415 * a full codebook */ | |
416 if (cbfz_chunk != -1) { | 428 if (cbfz_chunk != -1) { |
417 | 429 |
418 /* yet to be handled */ | 430 chunk_size = BE_32(&s->buf[cbfz_chunk + 4]); |
419 | 431 cbfz_chunk += CHUNK_PREAMBLE_SIZE; |
432 decode_format80(&s->buf[cbfz_chunk], chunk_size, | |
433 s->codebook, s->codebook_size, 0); | |
420 } | 434 } |
421 | 435 |
422 /* copy a full codebook */ | 436 /* copy a full codebook */ |
423 if (cbf0_chunk != -1) { | 437 if (cbf0_chunk != -1) { |
424 | 438 |
425 index = cbf0_chunk; | |
426 | |
427 chunk_size = BE_32(&s->buf[cbf0_chunk + 4]); | 439 chunk_size = BE_32(&s->buf[cbf0_chunk + 4]); |
428 /* sanity check the full codebook size */ | 440 /* sanity check the full codebook size */ |
429 if (s->vqa_version == 3) { | 441 if (chunk_size > MAX_CODEBOOK_SIZE) { |
430 if (chunk_size / (V3_VECTOR_SIZE) > V3_MAX_VECTORS) { | 442 printf (" VQA video: problem: CBF0 chunk too large (0x%X bytes)\n", |
431 printf (" VQA video: problem: CBF0 chunk too large (0x%X bytes)\n", | 443 chunk_size); |
432 chunk_size); | 444 return; |
433 return; | |
434 } | |
435 } else { | |
436 if (chunk_size / (V1_2_VECTOR_SIZE) > V1_2_MAX_VECTORS) { | |
437 printf (" VQA video: problem: CBF0 chunk too large (0x%X bytes)\n", | |
438 chunk_size); | |
439 return; | |
440 } | |
441 } | 445 } |
442 cbf0_chunk += CHUNK_PREAMBLE_SIZE; | 446 cbf0_chunk += CHUNK_PREAMBLE_SIZE; |
443 | 447 |
444 memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size); | 448 memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size); |
445 } | 449 } |
450 /* something is wrong if there is no VPTZ chunk */ | 454 /* something is wrong if there is no VPTZ chunk */ |
451 printf (" VQA video: problem: no VPTZ chunk found\n"); | 455 printf (" VQA video: problem: no VPTZ chunk found\n"); |
452 return; | 456 return; |
453 } | 457 } |
454 | 458 |
455 /* decode frame */ | |
456 chunk_size = BE_32(&s->buf[vptz_chunk + 4]); | 459 chunk_size = BE_32(&s->buf[vptz_chunk + 4]); |
457 vptz_chunk += CHUNK_PREAMBLE_SIZE; | 460 vptz_chunk += CHUNK_PREAMBLE_SIZE; |
458 decode_format80(&s->buf[vptz_chunk], chunk_size, | 461 decode_format80(&s->buf[vptz_chunk], chunk_size, |
459 s->decode_buffer, s->decode_buffer_size); | 462 s->decode_buffer, s->decode_buffer_size, 1); |
460 | |
461 | |
462 if (0) | |
463 { | |
464 int count = 0; | |
465 printf (" finished decoding frame..."); | |
466 for (index = 8000; index < 16000; index++) | |
467 if (s->decode_buffer[index] > 0x0F) | |
468 count++; | |
469 printf (" %d/8000 hibytes exceeded 0x0F\n", count); | |
470 } | |
471 | |
472 | 463 |
473 /* render the final PAL8 frame */ | 464 /* render the final PAL8 frame */ |
474 for (y = 0; y < s->frame.linesize[0] * s->height; | 465 for (y = 0; y < s->frame.linesize[0] * s->height; |
475 y += s->frame.linesize[0] * s->vector_height) { | 466 y += s->frame.linesize[0] * s->vector_height) { |
476 | 467 |
488 break; | 479 break; |
489 | 480 |
490 case 2: | 481 case 2: |
491 lobyte = s->decode_buffer[lobytes]; | 482 lobyte = s->decode_buffer[lobytes]; |
492 hibyte = s->decode_buffer[hibytes]; | 483 hibyte = s->decode_buffer[hibytes]; |
493 if (hibyte > 0x0F) { | |
494 printf (" VQA video: problem: vector #%d/%d high byte out of range (0x%X >= 0x0F)\n", | |
495 lobytes, s->decode_buffer_size / 2, hibyte); | |
496 hibyte = lobyte = 0; | |
497 } else if (hibyte == 0x0F) | |
498 hibyte = 0; | |
499 vector_index = (hibyte << 8) | lobyte; | 484 vector_index = (hibyte << 8) | lobyte; |
500 vector_index *= V1_2_VECTOR_SIZE; | 485 vector_index *= 8; |
501 lines = 2; | 486 lines = s->vector_height; |
502 break; | 487 break; |
503 | 488 |
504 case 3: | 489 case 3: |
505 /* not implemented yet */ | 490 /* not implemented yet */ |
506 lines = 0; | 491 lines = 0; |
547 } | 532 } |
548 } | 533 } |
549 | 534 |
550 if (cbpz_chunk != -1) { | 535 if (cbpz_chunk != -1) { |
551 | 536 |
552 /* more partial codebook handling ... */ | 537 chunk_size = BE_32(&s->buf[cbpz_chunk + 4]); |
553 | 538 cbpz_chunk += CHUNK_PREAMBLE_SIZE; |
539 | |
540 /* accumulate partial codebook */ | |
541 memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index], | |
542 &s->buf[cbpz_chunk], chunk_size); | |
543 s->next_codebook_buffer_index += chunk_size; | |
544 | |
545 s->partial_countdown--; | |
546 if (s->partial_countdown == 0) { | |
547 | |
548 /* decompress codebook */ | |
549 decode_format80(s->next_codebook_buffer, | |
550 s->next_codebook_buffer_index, | |
551 s->codebook, s->codebook_size, 0); | |
552 | |
553 /* reset accounting */ | |
554 s->next_codebook_buffer_index = 0; | |
555 s->partial_countdown = s->partial_count; | |
556 } | |
554 } | 557 } |
555 } | 558 } |
556 | 559 |
557 static int vqa_decode_frame(AVCodecContext *avctx, | 560 static int vqa_decode_frame(AVCodecContext *avctx, |
558 void *data, int *data_size, | 561 void *data, int *data_size, |