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