00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00066 #include <stdio.h>
00067 #include <stdlib.h>
00068 #include <string.h>
00069
00070 #include "libavutil/intreadwrite.h"
00071 #include "libavutil/imgutils.h"
00072 #include "avcodec.h"
00073 #include "bytestream.h"
00074
00075 #define PALETTE_COUNT 256
00076 #define VQA_HEADER_SIZE 0x2A
00077
00078
00079
00080 #define MAX_CODEBOOK_VECTORS 0xFF00
00081 #define SOLID_PIXEL_VECTORS 0x100
00082 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
00083 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4)
00084
00085 #define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
00086 #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
00087 #define CBP0_TAG MKBETAG('C', 'B', 'P', '0')
00088 #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')
00089 #define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
00090 #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
00091 #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
00092
00093 typedef struct VqaContext {
00094
00095 AVCodecContext *avctx;
00096 AVFrame frame;
00097 GetByteContext gb;
00098
00099 uint32_t palette[PALETTE_COUNT];
00100
00101 int width;
00102 int height;
00103 int vector_width;
00104 int vector_height;
00105 int vqa_version;
00106
00107 unsigned char *codebook;
00108 int codebook_size;
00109 unsigned char *next_codebook_buffer;
00110 int next_codebook_buffer_index;
00111
00112 unsigned char *decode_buffer;
00113 int decode_buffer_size;
00114
00115
00116 int partial_countdown;
00117 int partial_count;
00118
00119 } VqaContext;
00120
00121 static av_cold int vqa_decode_init(AVCodecContext *avctx)
00122 {
00123 VqaContext *s = avctx->priv_data;
00124 int i, j, codebook_index;
00125
00126 s->avctx = avctx;
00127 avctx->pix_fmt = PIX_FMT_PAL8;
00128
00129
00130 if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
00131 av_log(s->avctx, AV_LOG_ERROR, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE);
00132 return -1;
00133 }
00134
00135
00136 s->vqa_version = s->avctx->extradata[0];
00137 if (s->vqa_version < 1 || s->vqa_version > 3) {
00138 av_log(s->avctx, AV_LOG_ERROR, " VQA video: unsupported version %d\n", s->vqa_version);
00139 return -1;
00140 }
00141 s->width = AV_RL16(&s->avctx->extradata[6]);
00142 s->height = AV_RL16(&s->avctx->extradata[8]);
00143 if(av_image_check_size(s->width, s->height, 0, avctx)){
00144 s->width= s->height= 0;
00145 return -1;
00146 }
00147 s->vector_width = s->avctx->extradata[10];
00148 s->vector_height = s->avctx->extradata[11];
00149 s->partial_count = s->partial_countdown = s->avctx->extradata[13];
00150
00151
00152 if ((s->vector_width != 4) ||
00153 ((s->vector_height != 2) && (s->vector_height != 4))) {
00154
00155 return -1;
00156 }
00157
00158 if (s->width % s->vector_width || s->height % s->vector_height) {
00159 av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n");
00160 return AVERROR_INVALIDDATA;
00161 }
00162
00163
00164 s->codebook_size = MAX_CODEBOOK_SIZE;
00165 s->codebook = av_malloc(s->codebook_size);
00166 s->next_codebook_buffer = av_malloc(s->codebook_size);
00167
00168
00169 if (s->vector_height == 4) {
00170 codebook_index = 0xFF00 * 16;
00171 for (i = 0; i < 256; i++)
00172 for (j = 0; j < 16; j++)
00173 s->codebook[codebook_index++] = i;
00174 } else {
00175 codebook_index = 0xF00 * 8;
00176 for (i = 0; i < 256; i++)
00177 for (j = 0; j < 8; j++)
00178 s->codebook[codebook_index++] = i;
00179 }
00180 s->next_codebook_buffer_index = 0;
00181
00182
00183 s->decode_buffer_size = (s->width / s->vector_width) *
00184 (s->height / s->vector_height) * 2;
00185 s->decode_buffer = av_malloc(s->decode_buffer_size);
00186
00187 avcodec_get_frame_defaults(&s->frame);
00188 s->frame.data[0] = NULL;
00189
00190 return 0;
00191 }
00192
00193 #define CHECK_COUNT() \
00194 if (dest_index + count > dest_size) { \
00195 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00196 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
00197 dest_index, count, dest_size); \
00198 return AVERROR_INVALIDDATA; \
00199 }
00200
00201 #define CHECK_COPY(idx) \
00202 if (idx < 0 || idx + count > dest_size) { \
00203 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00204 av_log(NULL, AV_LOG_ERROR, " VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \
00205 src_pos, count, dest_size); \
00206 return AVERROR_INVALIDDATA; \
00207 }
00208
00209
00210 static int decode_format80(GetByteContext *gb, int src_size,
00211 unsigned char *dest, int dest_size, int check_size) {
00212
00213 int dest_index = 0;
00214 int count, opcode, start;
00215 int src_pos;
00216 unsigned char color;
00217 int i;
00218
00219 start = bytestream2_tell(gb);
00220 while (bytestream2_tell(gb) - start < src_size) {
00221 opcode = bytestream2_get_byte(gb);
00222 av_dlog(NULL, " opcode %02X: ", opcode);
00223
00224
00225 if (opcode == 0x80)
00226 return 0;
00227
00228 if (dest_index >= dest_size) {
00229 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
00230 dest_index, dest_size);
00231 return AVERROR_INVALIDDATA;
00232 }
00233
00234 if (opcode == 0xFF) {
00235
00236 count = bytestream2_get_le16(gb);
00237 src_pos = bytestream2_get_le16(gb);
00238 av_dlog(NULL, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
00239 CHECK_COUNT();
00240 CHECK_COPY(src_pos);
00241 for (i = 0; i < count; i++)
00242 dest[dest_index + i] = dest[src_pos + i];
00243 dest_index += count;
00244
00245 } else if (opcode == 0xFE) {
00246
00247 count = bytestream2_get_le16(gb);
00248 color = bytestream2_get_byte(gb);
00249 av_dlog(NULL, "(2) set %X bytes to %02X\n", count, color);
00250 CHECK_COUNT();
00251 memset(&dest[dest_index], color, count);
00252 dest_index += count;
00253
00254 } else if ((opcode & 0xC0) == 0xC0) {
00255
00256 count = (opcode & 0x3F) + 3;
00257 src_pos = bytestream2_get_le16(gb);
00258 av_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
00259 CHECK_COUNT();
00260 CHECK_COPY(src_pos);
00261 for (i = 0; i < count; i++)
00262 dest[dest_index + i] = dest[src_pos + i];
00263 dest_index += count;
00264
00265 } else if (opcode > 0x80) {
00266
00267 count = opcode & 0x3F;
00268 av_dlog(NULL, "(4) copy %X bytes from source to dest\n", count);
00269 CHECK_COUNT();
00270 bytestream2_get_buffer(gb, &dest[dest_index], count);
00271 dest_index += count;
00272
00273 } else {
00274
00275 count = ((opcode & 0x70) >> 4) + 3;
00276 src_pos = bytestream2_get_byte(gb) | ((opcode & 0x0F) << 8);
00277 av_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos);
00278 CHECK_COUNT();
00279 CHECK_COPY(dest_index - src_pos);
00280 for (i = 0; i < count; i++)
00281 dest[dest_index + i] = dest[dest_index - src_pos + i];
00282 dest_index += count;
00283 }
00284 }
00285
00286
00287
00288
00289
00290 if (check_size)
00291 if (dest_index < dest_size)
00292 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
00293 dest_index, dest_size);
00294
00295 return 0;
00296 }
00297
00298 static int vqa_decode_chunk(VqaContext *s)
00299 {
00300 unsigned int chunk_type;
00301 unsigned int chunk_size;
00302 int byte_skip;
00303 unsigned int index = 0;
00304 int i;
00305 unsigned char r, g, b;
00306 int index_shift;
00307 int res;
00308
00309 int cbf0_chunk = -1;
00310 int cbfz_chunk = -1;
00311 int cbp0_chunk = -1;
00312 int cbpz_chunk = -1;
00313 int cpl0_chunk = -1;
00314 int cplz_chunk = -1;
00315 int vptz_chunk = -1;
00316
00317 int x, y;
00318 int lines = 0;
00319 int pixel_ptr;
00320 int vector_index = 0;
00321 int lobyte = 0;
00322 int hibyte = 0;
00323 int lobytes = 0;
00324 int hibytes = s->decode_buffer_size / 2;
00325
00326
00327 while (bytestream2_get_bytes_left(&s->gb) >= 8) {
00328
00329 chunk_type = bytestream2_get_be32u(&s->gb);
00330 index = bytestream2_tell(&s->gb);
00331 chunk_size = bytestream2_get_be32u(&s->gb);
00332
00333 switch (chunk_type) {
00334
00335 case CBF0_TAG:
00336 cbf0_chunk = index;
00337 break;
00338
00339 case CBFZ_TAG:
00340 cbfz_chunk = index;
00341 break;
00342
00343 case CBP0_TAG:
00344 cbp0_chunk = index;
00345 break;
00346
00347 case CBPZ_TAG:
00348 cbpz_chunk = index;
00349 break;
00350
00351 case CPL0_TAG:
00352 cpl0_chunk = index;
00353 break;
00354
00355 case CPLZ_TAG:
00356 cplz_chunk = index;
00357 break;
00358
00359 case VPTZ_TAG:
00360 vptz_chunk = index;
00361 break;
00362
00363 default:
00364 av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
00365 (chunk_type >> 24) & 0xFF,
00366 (chunk_type >> 16) & 0xFF,
00367 (chunk_type >> 8) & 0xFF,
00368 (chunk_type >> 0) & 0xFF,
00369 chunk_type);
00370 break;
00371 }
00372
00373 byte_skip = chunk_size & 0x01;
00374 bytestream2_skip(&s->gb, chunk_size + byte_skip);
00375 }
00376
00377
00378 if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
00379
00380
00381 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n");
00382 return AVERROR_INVALIDDATA;
00383 }
00384
00385
00386 if (cplz_chunk != -1) {
00387
00388
00389
00390 }
00391
00392
00393 if (cpl0_chunk != -1) {
00394
00395 bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET);
00396 chunk_size = bytestream2_get_be32(&s->gb);
00397
00398 if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
00399 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found a palette chunk with %d colors\n",
00400 chunk_size / 3);
00401 return AVERROR_INVALIDDATA;
00402 }
00403 for (i = 0; i < chunk_size / 3; i++) {
00404
00405 r = bytestream2_get_byteu(&s->gb) * 4;
00406 g = bytestream2_get_byteu(&s->gb) * 4;
00407 b = bytestream2_get_byteu(&s->gb) * 4;
00408 s->palette[i] = 0xFF << 24 | r << 16 | g << 8 | b;
00409 s->palette[i] |= s->palette[i] >> 6 & 0x30303;
00410 }
00411 }
00412
00413
00414 if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
00415
00416
00417 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n");
00418 return AVERROR_INVALIDDATA;
00419 }
00420
00421
00422 if (cbfz_chunk != -1) {
00423
00424 bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
00425 chunk_size = bytestream2_get_be32(&s->gb);
00426 if ((res = decode_format80(&s->gb, chunk_size, s->codebook,
00427 s->codebook_size, 0)) < 0)
00428 return res;
00429 }
00430
00431
00432 if (cbf0_chunk != -1) {
00433
00434 bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
00435 chunk_size = bytestream2_get_be32(&s->gb);
00436
00437 if (chunk_size > MAX_CODEBOOK_SIZE) {
00438 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
00439 chunk_size);
00440 return AVERROR_INVALIDDATA;
00441 }
00442
00443 bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
00444 }
00445
00446
00447 if (vptz_chunk == -1) {
00448
00449
00450 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ chunk found\n");
00451 return AVERROR_INVALIDDATA;
00452 }
00453
00454 bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
00455 chunk_size = bytestream2_get_be32(&s->gb);
00456 if ((res = decode_format80(&s->gb, chunk_size,
00457 s->decode_buffer, s->decode_buffer_size, 1)) < 0)
00458 return res;
00459
00460
00461 if (s->vector_height == 4)
00462 index_shift = 4;
00463 else
00464 index_shift = 3;
00465 for (y = 0; y < s->frame.linesize[0] * s->height;
00466 y += s->frame.linesize[0] * s->vector_height) {
00467
00468 for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) {
00469 pixel_ptr = x;
00470
00471
00472
00473 switch (s->vqa_version) {
00474
00475 case 1:
00476 lobyte = s->decode_buffer[lobytes * 2];
00477 hibyte = s->decode_buffer[(lobytes * 2) + 1];
00478 vector_index = ((hibyte << 8) | lobyte) >> 3;
00479 vector_index <<= index_shift;
00480 lines = s->vector_height;
00481
00482 if (hibyte == 0xFF) {
00483 while (lines--) {
00484 s->frame.data[0][pixel_ptr + 0] = 255 - lobyte;
00485 s->frame.data[0][pixel_ptr + 1] = 255 - lobyte;
00486 s->frame.data[0][pixel_ptr + 2] = 255 - lobyte;
00487 s->frame.data[0][pixel_ptr + 3] = 255 - lobyte;
00488 pixel_ptr += s->frame.linesize[0];
00489 }
00490 lines=0;
00491 }
00492 break;
00493
00494 case 2:
00495 lobyte = s->decode_buffer[lobytes];
00496 hibyte = s->decode_buffer[hibytes];
00497 vector_index = (hibyte << 8) | lobyte;
00498 vector_index <<= index_shift;
00499 lines = s->vector_height;
00500 break;
00501
00502 case 3:
00503
00504 lines = 0;
00505 break;
00506 }
00507
00508 while (lines--) {
00509 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++];
00510 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++];
00511 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++];
00512 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++];
00513 pixel_ptr += s->frame.linesize[0];
00514 }
00515 }
00516 }
00517
00518
00519 if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
00520
00521 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n");
00522 return AVERROR_INVALIDDATA;
00523 }
00524
00525 if (cbp0_chunk != -1) {
00526
00527 bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET);
00528 chunk_size = bytestream2_get_be32(&s->gb);
00529
00530
00531 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00532 chunk_size);
00533 s->next_codebook_buffer_index += chunk_size;
00534
00535 s->partial_countdown--;
00536 if (s->partial_countdown == 0) {
00537
00538
00539 memcpy(s->codebook, s->next_codebook_buffer,
00540 s->next_codebook_buffer_index);
00541
00542
00543 s->next_codebook_buffer_index = 0;
00544 s->partial_countdown = s->partial_count;
00545 }
00546 }
00547
00548 if (cbpz_chunk != -1) {
00549
00550 bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET);
00551 chunk_size = bytestream2_get_be32(&s->gb);
00552
00553
00554 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00555 chunk_size);
00556 s->next_codebook_buffer_index += chunk_size;
00557
00558 s->partial_countdown--;
00559 if (s->partial_countdown == 0) {
00560 GetByteContext gb;
00561
00562 bytestream2_init(&gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
00563
00564 if ((res = decode_format80(&gb, s->next_codebook_buffer_index,
00565 s->codebook, s->codebook_size, 0)) < 0)
00566 return res;
00567
00568
00569 s->next_codebook_buffer_index = 0;
00570 s->partial_countdown = s->partial_count;
00571 }
00572 }
00573
00574 return 0;
00575 }
00576
00577 static int vqa_decode_frame(AVCodecContext *avctx,
00578 void *data, int *data_size,
00579 AVPacket *avpkt)
00580 {
00581 VqaContext *s = avctx->priv_data;
00582 int res;
00583
00584 if (s->frame.data[0])
00585 avctx->release_buffer(avctx, &s->frame);
00586
00587 if (avctx->get_buffer(avctx, &s->frame)) {
00588 av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n");
00589 return -1;
00590 }
00591
00592 bytestream2_init(&s->gb, avpkt->data, avpkt->size);
00593 if ((res = vqa_decode_chunk(s)) < 0)
00594 return res;
00595
00596
00597 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
00598 s->frame.palette_has_changed = 1;
00599
00600 *data_size = sizeof(AVFrame);
00601 *(AVFrame*)data = s->frame;
00602
00603
00604 return avpkt->size;
00605 }
00606
00607 static av_cold int vqa_decode_end(AVCodecContext *avctx)
00608 {
00609 VqaContext *s = avctx->priv_data;
00610
00611 av_free(s->codebook);
00612 av_free(s->next_codebook_buffer);
00613 av_free(s->decode_buffer);
00614
00615 if (s->frame.data[0])
00616 avctx->release_buffer(avctx, &s->frame);
00617
00618 return 0;
00619 }
00620
00621 AVCodec ff_vqa_decoder = {
00622 .name = "vqavideo",
00623 .type = AVMEDIA_TYPE_VIDEO,
00624 .id = CODEC_ID_WS_VQA,
00625 .priv_data_size = sizeof(VqaContext),
00626 .init = vqa_decode_init,
00627 .close = vqa_decode_end,
00628 .decode = vqa_decode_frame,
00629 .capabilities = CODEC_CAP_DR1,
00630 .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"),
00631 };