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, "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, "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 if (!s->codebook)
00167 goto fail;
00168 s->next_codebook_buffer = av_malloc(s->codebook_size);
00169 if (!s->next_codebook_buffer)
00170 goto fail;
00171
00172
00173 s->decode_buffer_size = (s->width / s->vector_width) *
00174 (s->height / s->vector_height) * 2;
00175 s->decode_buffer = av_malloc(s->decode_buffer_size);
00176 if (!s->decode_buffer)
00177 goto fail;
00178
00179
00180 if (s->vector_height == 4) {
00181 codebook_index = 0xFF00 * 16;
00182 for (i = 0; i < 256; i++)
00183 for (j = 0; j < 16; j++)
00184 s->codebook[codebook_index++] = i;
00185 } else {
00186 codebook_index = 0xF00 * 8;
00187 for (i = 0; i < 256; i++)
00188 for (j = 0; j < 8; j++)
00189 s->codebook[codebook_index++] = i;
00190 }
00191 s->next_codebook_buffer_index = 0;
00192
00193 avcodec_get_frame_defaults(&s->frame);
00194 s->frame.data[0] = NULL;
00195
00196 return 0;
00197 fail:
00198 av_freep(&s->codebook);
00199 av_freep(&s->next_codebook_buffer);
00200 av_freep(&s->decode_buffer);
00201 return AVERROR(ENOMEM);
00202 }
00203
00204 #define CHECK_COUNT() \
00205 if (dest_index + count > dest_size) { \
00206 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00207 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
00208 dest_index, count, dest_size); \
00209 return AVERROR_INVALIDDATA; \
00210 }
00211
00212 #define CHECK_COPY(idx) \
00213 if (idx < 0 || idx + count > dest_size) { \
00214 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00215 av_log(NULL, AV_LOG_ERROR, " VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \
00216 src_pos, count, dest_size); \
00217 return AVERROR_INVALIDDATA; \
00218 }
00219
00220
00221 static int decode_format80(GetByteContext *gb, int src_size,
00222 unsigned char *dest, int dest_size, int check_size) {
00223
00224 int dest_index = 0;
00225 int count, opcode, start;
00226 int src_pos;
00227 unsigned char color;
00228 int i;
00229
00230 start = bytestream2_tell(gb);
00231 while (bytestream2_tell(gb) - start < src_size) {
00232 opcode = bytestream2_get_byte(gb);
00233 av_dlog(NULL, " opcode %02X: ", opcode);
00234
00235
00236 if (opcode == 0x80)
00237 return 0;
00238
00239 if (dest_index >= dest_size) {
00240 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
00241 dest_index, dest_size);
00242 return AVERROR_INVALIDDATA;
00243 }
00244
00245 if (opcode == 0xFF) {
00246
00247 count = bytestream2_get_le16(gb);
00248 src_pos = bytestream2_get_le16(gb);
00249 av_dlog(NULL, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
00250 CHECK_COUNT();
00251 CHECK_COPY(src_pos);
00252 for (i = 0; i < count; i++)
00253 dest[dest_index + i] = dest[src_pos + i];
00254 dest_index += count;
00255
00256 } else if (opcode == 0xFE) {
00257
00258 count = bytestream2_get_le16(gb);
00259 color = bytestream2_get_byte(gb);
00260 av_dlog(NULL, "(2) set %X bytes to %02X\n", count, color);
00261 CHECK_COUNT();
00262 memset(&dest[dest_index], color, count);
00263 dest_index += count;
00264
00265 } else if ((opcode & 0xC0) == 0xC0) {
00266
00267 count = (opcode & 0x3F) + 3;
00268 src_pos = bytestream2_get_le16(gb);
00269 av_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
00270 CHECK_COUNT();
00271 CHECK_COPY(src_pos);
00272 for (i = 0; i < count; i++)
00273 dest[dest_index + i] = dest[src_pos + i];
00274 dest_index += count;
00275
00276 } else if (opcode > 0x80) {
00277
00278 count = opcode & 0x3F;
00279 av_dlog(NULL, "(4) copy %X bytes from source to dest\n", count);
00280 CHECK_COUNT();
00281 bytestream2_get_buffer(gb, &dest[dest_index], count);
00282 dest_index += count;
00283
00284 } else {
00285
00286 count = ((opcode & 0x70) >> 4) + 3;
00287 src_pos = bytestream2_get_byte(gb) | ((opcode & 0x0F) << 8);
00288 av_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos);
00289 CHECK_COUNT();
00290 CHECK_COPY(dest_index - src_pos);
00291 for (i = 0; i < count; i++)
00292 dest[dest_index + i] = dest[dest_index - src_pos + i];
00293 dest_index += count;
00294 }
00295 }
00296
00297
00298
00299
00300
00301 if (check_size)
00302 if (dest_index < dest_size)
00303 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
00304 dest_index, dest_size);
00305
00306 return 0;
00307 }
00308
00309 static int vqa_decode_chunk(VqaContext *s)
00310 {
00311 unsigned int chunk_type;
00312 unsigned int chunk_size;
00313 int byte_skip;
00314 unsigned int index = 0;
00315 int i;
00316 unsigned char r, g, b;
00317 int index_shift;
00318 int res;
00319
00320 int cbf0_chunk = -1;
00321 int cbfz_chunk = -1;
00322 int cbp0_chunk = -1;
00323 int cbpz_chunk = -1;
00324 int cpl0_chunk = -1;
00325 int cplz_chunk = -1;
00326 int vptz_chunk = -1;
00327
00328 int x, y;
00329 int lines = 0;
00330 int pixel_ptr;
00331 int vector_index = 0;
00332 int lobyte = 0;
00333 int hibyte = 0;
00334 int lobytes = 0;
00335 int hibytes = s->decode_buffer_size / 2;
00336
00337
00338 while (bytestream2_get_bytes_left(&s->gb) >= 8) {
00339
00340 chunk_type = bytestream2_get_be32u(&s->gb);
00341 index = bytestream2_tell(&s->gb);
00342 chunk_size = bytestream2_get_be32u(&s->gb);
00343
00344 switch (chunk_type) {
00345
00346 case CBF0_TAG:
00347 cbf0_chunk = index;
00348 break;
00349
00350 case CBFZ_TAG:
00351 cbfz_chunk = index;
00352 break;
00353
00354 case CBP0_TAG:
00355 cbp0_chunk = index;
00356 break;
00357
00358 case CBPZ_TAG:
00359 cbpz_chunk = index;
00360 break;
00361
00362 case CPL0_TAG:
00363 cpl0_chunk = index;
00364 break;
00365
00366 case CPLZ_TAG:
00367 cplz_chunk = index;
00368 break;
00369
00370 case VPTZ_TAG:
00371 vptz_chunk = index;
00372 break;
00373
00374 default:
00375 av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %c%c%c%c (%08X)\n",
00376 (chunk_type >> 24) & 0xFF,
00377 (chunk_type >> 16) & 0xFF,
00378 (chunk_type >> 8) & 0xFF,
00379 (chunk_type >> 0) & 0xFF,
00380 chunk_type);
00381 break;
00382 }
00383
00384 byte_skip = chunk_size & 0x01;
00385 bytestream2_skip(&s->gb, chunk_size + byte_skip);
00386 }
00387
00388
00389 if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
00390
00391
00392 av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n");
00393 return AVERROR_INVALIDDATA;
00394 }
00395
00396
00397 if (cplz_chunk != -1) {
00398
00399
00400
00401 }
00402
00403
00404 if (cpl0_chunk != -1) {
00405
00406 bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET);
00407 chunk_size = bytestream2_get_be32(&s->gb);
00408
00409 if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
00410 av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n",
00411 chunk_size / 3);
00412 return AVERROR_INVALIDDATA;
00413 }
00414 for (i = 0; i < chunk_size / 3; i++) {
00415
00416 r = bytestream2_get_byteu(&s->gb) * 4;
00417 g = bytestream2_get_byteu(&s->gb) * 4;
00418 b = bytestream2_get_byteu(&s->gb) * 4;
00419 s->palette[i] = 0xFF << 24 | r << 16 | g << 8 | b;
00420 s->palette[i] |= s->palette[i] >> 6 & 0x30303;
00421 }
00422 }
00423
00424
00425 if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
00426
00427
00428 av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
00429 return AVERROR_INVALIDDATA;
00430 }
00431
00432
00433 if (cbfz_chunk != -1) {
00434
00435 bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
00436 chunk_size = bytestream2_get_be32(&s->gb);
00437 if ((res = decode_format80(&s->gb, chunk_size, s->codebook,
00438 s->codebook_size, 0)) < 0)
00439 return res;
00440 }
00441
00442
00443 if (cbf0_chunk != -1) {
00444
00445 bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
00446 chunk_size = bytestream2_get_be32(&s->gb);
00447
00448 if (chunk_size > MAX_CODEBOOK_SIZE) {
00449 av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
00450 chunk_size);
00451 return AVERROR_INVALIDDATA;
00452 }
00453
00454 bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
00455 }
00456
00457
00458 if (vptz_chunk == -1) {
00459
00460
00461 av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n");
00462 return AVERROR_INVALIDDATA;
00463 }
00464
00465 bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
00466 chunk_size = bytestream2_get_be32(&s->gb);
00467 if ((res = decode_format80(&s->gb, chunk_size,
00468 s->decode_buffer, s->decode_buffer_size, 1)) < 0)
00469 return res;
00470
00471
00472 if (s->vector_height == 4)
00473 index_shift = 4;
00474 else
00475 index_shift = 3;
00476 for (y = 0; y < s->height; y += s->vector_height) {
00477 for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) {
00478 pixel_ptr = y * s->frame.linesize[0] + x;
00479
00480
00481
00482 switch (s->vqa_version) {
00483
00484 case 1:
00485 lobyte = s->decode_buffer[lobytes * 2];
00486 hibyte = s->decode_buffer[(lobytes * 2) + 1];
00487 vector_index = ((hibyte << 8) | lobyte) >> 3;
00488 vector_index <<= index_shift;
00489 lines = s->vector_height;
00490
00491 if (hibyte == 0xFF) {
00492 while (lines--) {
00493 s->frame.data[0][pixel_ptr + 0] = 255 - lobyte;
00494 s->frame.data[0][pixel_ptr + 1] = 255 - lobyte;
00495 s->frame.data[0][pixel_ptr + 2] = 255 - lobyte;
00496 s->frame.data[0][pixel_ptr + 3] = 255 - lobyte;
00497 pixel_ptr += s->frame.linesize[0];
00498 }
00499 lines=0;
00500 }
00501 break;
00502
00503 case 2:
00504 lobyte = s->decode_buffer[lobytes];
00505 hibyte = s->decode_buffer[hibytes];
00506 vector_index = (hibyte << 8) | lobyte;
00507 vector_index <<= index_shift;
00508 lines = s->vector_height;
00509 break;
00510
00511 case 3:
00512
00513 lines = 0;
00514 break;
00515 }
00516
00517 while (lines--) {
00518 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++];
00519 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++];
00520 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++];
00521 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++];
00522 pixel_ptr += s->frame.linesize[0];
00523 }
00524 }
00525 }
00526
00527
00528 if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
00529
00530 av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n");
00531 return AVERROR_INVALIDDATA;
00532 }
00533
00534 if (cbp0_chunk != -1) {
00535
00536 bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET);
00537 chunk_size = bytestream2_get_be32(&s->gb);
00538
00539
00540 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00541 chunk_size);
00542 s->next_codebook_buffer_index += chunk_size;
00543
00544 s->partial_countdown--;
00545 if (s->partial_countdown <= 0) {
00546
00547
00548 memcpy(s->codebook, s->next_codebook_buffer,
00549 s->next_codebook_buffer_index);
00550
00551
00552 s->next_codebook_buffer_index = 0;
00553 s->partial_countdown = s->partial_count;
00554 }
00555 }
00556
00557 if (cbpz_chunk != -1) {
00558
00559 bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET);
00560 chunk_size = bytestream2_get_be32(&s->gb);
00561
00562
00563 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00564 chunk_size);
00565 s->next_codebook_buffer_index += chunk_size;
00566
00567 s->partial_countdown--;
00568 if (s->partial_countdown <= 0) {
00569 GetByteContext gb;
00570
00571 bytestream2_init(&gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
00572
00573 if ((res = decode_format80(&gb, s->next_codebook_buffer_index,
00574 s->codebook, s->codebook_size, 0)) < 0)
00575 return res;
00576
00577
00578 s->next_codebook_buffer_index = 0;
00579 s->partial_countdown = s->partial_count;
00580 }
00581 }
00582
00583 return 0;
00584 }
00585
00586 static int vqa_decode_frame(AVCodecContext *avctx,
00587 void *data, int *data_size,
00588 AVPacket *avpkt)
00589 {
00590 VqaContext *s = avctx->priv_data;
00591 int res;
00592
00593 if (s->frame.data[0])
00594 avctx->release_buffer(avctx, &s->frame);
00595
00596 if (avctx->get_buffer(avctx, &s->frame)) {
00597 av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n");
00598 return -1;
00599 }
00600
00601 bytestream2_init(&s->gb, avpkt->data, avpkt->size);
00602 if ((res = vqa_decode_chunk(s)) < 0)
00603 return res;
00604
00605
00606 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
00607 s->frame.palette_has_changed = 1;
00608
00609 *data_size = sizeof(AVFrame);
00610 *(AVFrame*)data = s->frame;
00611
00612
00613 return avpkt->size;
00614 }
00615
00616 static av_cold int vqa_decode_end(AVCodecContext *avctx)
00617 {
00618 VqaContext *s = avctx->priv_data;
00619
00620 av_freep(&s->codebook);
00621 av_freep(&s->next_codebook_buffer);
00622 av_freep(&s->decode_buffer);
00623
00624 if (s->frame.data[0])
00625 avctx->release_buffer(avctx, &s->frame);
00626
00627 return 0;
00628 }
00629
00630 AVCodec ff_vqa_decoder = {
00631 .name = "vqavideo",
00632 .type = AVMEDIA_TYPE_VIDEO,
00633 .id = CODEC_ID_WS_VQA,
00634 .priv_data_size = sizeof(VqaContext),
00635 .init = vqa_decode_init,
00636 .close = vqa_decode_end,
00637 .decode = vqa_decode_frame,
00638 .capabilities = CODEC_CAP_DR1,
00639 .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"),
00640 };