00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045 #include <unistd.h>
00046
00047 #include "libavutil/intreadwrite.h"
00048 #include "avcodec.h"
00049
00050 #define VMD_HEADER_SIZE 0x330
00051 #define PALETTE_COUNT 256
00052
00053
00054
00055
00056
00057 typedef struct VmdVideoContext {
00058
00059 AVCodecContext *avctx;
00060 AVFrame frame;
00061 AVFrame prev_frame;
00062
00063 const unsigned char *buf;
00064 int size;
00065
00066 unsigned char palette[PALETTE_COUNT * 4];
00067 unsigned char *unpack_buffer;
00068 int unpack_buffer_size;
00069
00070 int x_off, y_off;
00071 } VmdVideoContext;
00072
00073 #define QUEUE_SIZE 0x1000
00074 #define QUEUE_MASK 0x0FFF
00075
00076 static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_len)
00077 {
00078 const unsigned char *s;
00079 unsigned char *d;
00080 unsigned char *d_end;
00081 unsigned char queue[QUEUE_SIZE];
00082 unsigned int qpos;
00083 unsigned int dataleft;
00084 unsigned int chainofs;
00085 unsigned int chainlen;
00086 unsigned int speclen;
00087 unsigned char tag;
00088 unsigned int i, j;
00089
00090 s = src;
00091 d = dest;
00092 d_end = d + dest_len;
00093 dataleft = AV_RL32(s);
00094 s += 4;
00095 memset(queue, 0x20, QUEUE_SIZE);
00096 if (AV_RL32(s) == 0x56781234) {
00097 s += 4;
00098 qpos = 0x111;
00099 speclen = 0xF + 3;
00100 } else {
00101 qpos = 0xFEE;
00102 speclen = 100;
00103 }
00104
00105 while (dataleft > 0) {
00106 tag = *s++;
00107 if ((tag == 0xFF) && (dataleft > 8)) {
00108 if (d + 8 > d_end)
00109 return;
00110 for (i = 0; i < 8; i++) {
00111 queue[qpos++] = *d++ = *s++;
00112 qpos &= QUEUE_MASK;
00113 }
00114 dataleft -= 8;
00115 } else {
00116 for (i = 0; i < 8; i++) {
00117 if (dataleft == 0)
00118 break;
00119 if (tag & 0x01) {
00120 if (d + 1 > d_end)
00121 return;
00122 queue[qpos++] = *d++ = *s++;
00123 qpos &= QUEUE_MASK;
00124 dataleft--;
00125 } else {
00126 chainofs = *s++;
00127 chainofs |= ((*s & 0xF0) << 4);
00128 chainlen = (*s++ & 0x0F) + 3;
00129 if (chainlen == speclen)
00130 chainlen = *s++ + 0xF + 3;
00131 if (d + chainlen > d_end)
00132 return;
00133 for (j = 0; j < chainlen; j++) {
00134 *d = queue[chainofs++ & QUEUE_MASK];
00135 queue[qpos++] = *d++;
00136 qpos &= QUEUE_MASK;
00137 }
00138 dataleft -= chainlen;
00139 }
00140 tag >>= 1;
00141 }
00142 }
00143 }
00144 }
00145
00146 static int rle_unpack(const unsigned char *src, unsigned char *dest,
00147 int src_len, int dest_len)
00148 {
00149 const unsigned char *ps;
00150 unsigned char *pd;
00151 int i, l;
00152 unsigned char *dest_end = dest + dest_len;
00153
00154 ps = src;
00155 pd = dest;
00156 if (src_len & 1)
00157 *pd++ = *ps++;
00158
00159 src_len >>= 1;
00160 i = 0;
00161 do {
00162 l = *ps++;
00163 if (l & 0x80) {
00164 l = (l & 0x7F) * 2;
00165 if (pd + l > dest_end)
00166 return ps - src;
00167 memcpy(pd, ps, l);
00168 ps += l;
00169 pd += l;
00170 } else {
00171 if (pd + i > dest_end)
00172 return ps - src;
00173 for (i = 0; i < l; i++) {
00174 *pd++ = ps[0];
00175 *pd++ = ps[1];
00176 }
00177 ps += 2;
00178 }
00179 i += l;
00180 } while (i < src_len);
00181
00182 return ps - src;
00183 }
00184
00185 static void vmd_decode(VmdVideoContext *s)
00186 {
00187 int i;
00188 unsigned int *palette32;
00189 unsigned char r, g, b;
00190
00191
00192 const unsigned char *p = s->buf + 16;
00193
00194 const unsigned char *pb;
00195 unsigned char meth;
00196 unsigned char *dp;
00197 unsigned char *pp;
00198 unsigned char len;
00199 int ofs;
00200
00201 int frame_x, frame_y;
00202 int frame_width, frame_height;
00203 int dp_size;
00204
00205 frame_x = AV_RL16(&s->buf[6]);
00206 frame_y = AV_RL16(&s->buf[8]);
00207 frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
00208 frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
00209
00210 if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
00211 (frame_x || frame_y)) {
00212
00213 s->x_off = frame_x;
00214 s->y_off = frame_y;
00215 }
00216 frame_x -= s->x_off;
00217 frame_y -= s->y_off;
00218
00219
00220
00221 if (frame_x || frame_y || (frame_width != s->avctx->width) ||
00222 (frame_height != s->avctx->height)) {
00223
00224 memcpy(s->frame.data[0], s->prev_frame.data[0],
00225 s->avctx->height * s->frame.linesize[0]);
00226 }
00227
00228
00229 if (s->buf[15] & 0x02) {
00230 p += 2;
00231 palette32 = (unsigned int *)s->palette;
00232 for (i = 0; i < PALETTE_COUNT; i++) {
00233 r = *p++ * 4;
00234 g = *p++ * 4;
00235 b = *p++ * 4;
00236 palette32[i] = (r << 16) | (g << 8) | (b);
00237 }
00238 s->size -= (256 * 3 + 2);
00239 }
00240 if (s->size >= 0) {
00241
00242 pb = p;
00243 meth = *pb++;
00244 if (meth & 0x80) {
00245 lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size);
00246 meth &= 0x7F;
00247 pb = s->unpack_buffer;
00248 }
00249
00250 dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
00251 dp_size = s->frame.linesize[0] * s->avctx->height;
00252 pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x];
00253 switch (meth) {
00254 case 1:
00255 for (i = 0; i < frame_height; i++) {
00256 ofs = 0;
00257 do {
00258 len = *pb++;
00259 if (len & 0x80) {
00260 len = (len & 0x7F) + 1;
00261 if (ofs + len > frame_width)
00262 return;
00263 memcpy(&dp[ofs], pb, len);
00264 pb += len;
00265 ofs += len;
00266 } else {
00267
00268 if (ofs + len + 1 > frame_width)
00269 return;
00270 memcpy(&dp[ofs], &pp[ofs], len + 1);
00271 ofs += len + 1;
00272 }
00273 } while (ofs < frame_width);
00274 if (ofs > frame_width) {
00275 av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
00276 ofs, frame_width);
00277 break;
00278 }
00279 dp += s->frame.linesize[0];
00280 pp += s->prev_frame.linesize[0];
00281 }
00282 break;
00283
00284 case 2:
00285 for (i = 0; i < frame_height; i++) {
00286 memcpy(dp, pb, frame_width);
00287 pb += frame_width;
00288 dp += s->frame.linesize[0];
00289 pp += s->prev_frame.linesize[0];
00290 }
00291 break;
00292
00293 case 3:
00294 for (i = 0; i < frame_height; i++) {
00295 ofs = 0;
00296 do {
00297 len = *pb++;
00298 if (len & 0x80) {
00299 len = (len & 0x7F) + 1;
00300 if (*pb++ == 0xFF)
00301 len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
00302 else
00303 memcpy(&dp[ofs], pb, len);
00304 pb += len;
00305 ofs += len;
00306 } else {
00307
00308 if (ofs + len + 1 > frame_width)
00309 return;
00310 memcpy(&dp[ofs], &pp[ofs], len + 1);
00311 ofs += len + 1;
00312 }
00313 } while (ofs < frame_width);
00314 if (ofs > frame_width) {
00315 av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
00316 ofs, frame_width);
00317 }
00318 dp += s->frame.linesize[0];
00319 pp += s->prev_frame.linesize[0];
00320 }
00321 break;
00322 }
00323 }
00324 }
00325
00326 static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
00327 {
00328 VmdVideoContext *s = avctx->priv_data;
00329 int i;
00330 unsigned int *palette32;
00331 int palette_index = 0;
00332 unsigned char r, g, b;
00333 unsigned char *vmd_header;
00334 unsigned char *raw_palette;
00335
00336 s->avctx = avctx;
00337 avctx->pix_fmt = PIX_FMT_PAL8;
00338
00339
00340 if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
00341 av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
00342 VMD_HEADER_SIZE);
00343 return -1;
00344 }
00345 vmd_header = (unsigned char *)avctx->extradata;
00346
00347 s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
00348 s->unpack_buffer = av_malloc(s->unpack_buffer_size);
00349 if (!s->unpack_buffer)
00350 return -1;
00351
00352
00353 raw_palette = &vmd_header[28];
00354 palette32 = (unsigned int *)s->palette;
00355 for (i = 0; i < PALETTE_COUNT; i++) {
00356 r = raw_palette[palette_index++] * 4;
00357 g = raw_palette[palette_index++] * 4;
00358 b = raw_palette[palette_index++] * 4;
00359 palette32[i] = (r << 16) | (g << 8) | (b);
00360 }
00361
00362 s->frame.data[0] = s->prev_frame.data[0] = NULL;
00363
00364 return 0;
00365 }
00366
00367 static int vmdvideo_decode_frame(AVCodecContext *avctx,
00368 void *data, int *data_size,
00369 const uint8_t *buf, int buf_size)
00370 {
00371 VmdVideoContext *s = avctx->priv_data;
00372
00373 s->buf = buf;
00374 s->size = buf_size;
00375
00376 if (buf_size < 16)
00377 return buf_size;
00378
00379 s->frame.reference = 1;
00380 if (avctx->get_buffer(avctx, &s->frame)) {
00381 av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
00382 return -1;
00383 }
00384
00385 vmd_decode(s);
00386
00387
00388 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
00389
00390
00391 FFSWAP(AVFrame, s->frame, s->prev_frame);
00392 if (s->frame.data[0])
00393 avctx->release_buffer(avctx, &s->frame);
00394
00395 *data_size = sizeof(AVFrame);
00396 *(AVFrame*)data = s->prev_frame;
00397
00398
00399 return buf_size;
00400 }
00401
00402 static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
00403 {
00404 VmdVideoContext *s = avctx->priv_data;
00405
00406 if (s->prev_frame.data[0])
00407 avctx->release_buffer(avctx, &s->prev_frame);
00408 av_free(s->unpack_buffer);
00409
00410 return 0;
00411 }
00412
00413
00414
00415
00416
00417
00418 typedef struct VmdAudioContext {
00419 AVCodecContext *avctx;
00420 int channels;
00421 int bits;
00422 int block_align;
00423 int predictors[2];
00424 } VmdAudioContext;
00425
00426 static const uint16_t vmdaudio_table[128] = {
00427 0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
00428 0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
00429 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
00430 0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
00431 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
00432 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
00433 0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
00434 0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
00435 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
00436 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
00437 0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
00438 0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
00439 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
00440 };
00441
00442 static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
00443 {
00444 VmdAudioContext *s = avctx->priv_data;
00445
00446 s->avctx = avctx;
00447 s->channels = avctx->channels;
00448 s->bits = avctx->bits_per_coded_sample;
00449 s->block_align = avctx->block_align;
00450 avctx->sample_fmt = SAMPLE_FMT_S16;
00451
00452 av_log(s->avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, block align = %d, sample rate = %d\n",
00453 s->channels, s->bits, s->block_align, avctx->sample_rate);
00454
00455 return 0;
00456 }
00457
00458 static void vmdaudio_decode_audio(VmdAudioContext *s, unsigned char *data,
00459 const uint8_t *buf, int buf_size, int stereo)
00460 {
00461 int i;
00462 int chan = 0;
00463 int16_t *out = (int16_t*)data;
00464
00465 for(i = 0; i < buf_size; i++) {
00466 if(buf[i] & 0x80)
00467 s->predictors[chan] -= vmdaudio_table[buf[i] & 0x7F];
00468 else
00469 s->predictors[chan] += vmdaudio_table[buf[i]];
00470 s->predictors[chan] = av_clip_int16(s->predictors[chan]);
00471 out[i] = s->predictors[chan];
00472 chan ^= stereo;
00473 }
00474 }
00475
00476 static int vmdaudio_loadsound(VmdAudioContext *s, unsigned char *data,
00477 const uint8_t *buf, int silence, int data_size)
00478 {
00479 int bytes_decoded = 0;
00480 int i;
00481
00482
00483
00484 if (s->channels == 2) {
00485
00486
00487 if (silence) {
00488 memset(data, 0, data_size * 2);
00489 } else {
00490 if (s->bits == 16)
00491 vmdaudio_decode_audio(s, data, buf, data_size, 1);
00492 else {
00493
00494 for (i = 0; i < data_size; i++){
00495 *data++ = buf[i] + 0x80;
00496 *data++ = buf[i] + 0x80;
00497 }
00498 }
00499 }
00500 } else {
00501 bytes_decoded = data_size * 2;
00502
00503
00504 if (silence) {
00505 memset(data, 0, data_size * 2);
00506 } else {
00507 if (s->bits == 16) {
00508 vmdaudio_decode_audio(s, data, buf, data_size, 0);
00509 } else {
00510
00511 for (i = 0; i < data_size; i++){
00512 *data++ = buf[i] + 0x80;
00513 *data++ = buf[i] + 0x80;
00514 }
00515 }
00516 }
00517 }
00518
00519 return data_size * 2;
00520 }
00521
00522 static int vmdaudio_decode_frame(AVCodecContext *avctx,
00523 void *data, int *data_size,
00524 const uint8_t *buf, int buf_size)
00525 {
00526 VmdAudioContext *s = avctx->priv_data;
00527 unsigned char *output_samples = (unsigned char *)data;
00528
00529
00530 const unsigned char *p = buf + 16;
00531
00532 if (buf_size < 16)
00533 return buf_size;
00534
00535 if (buf[6] == 1) {
00536
00537 *data_size = vmdaudio_loadsound(s, output_samples, p, 0, buf_size - 16);
00538 } else if (buf[6] == 2) {
00539
00540 uint32_t flags = AV_RB32(p);
00541 int raw_block_size = s->block_align * s->bits / 8;
00542 int silent_chunks;
00543 if(flags == 0xFFFFFFFF)
00544 silent_chunks = 32;
00545 else
00546 silent_chunks = av_log2(flags + 1);
00547 if(*data_size < (s->block_align*silent_chunks + buf_size - 20) * 2)
00548 return -1;
00549 *data_size = 0;
00550 memset(output_samples, 0, raw_block_size * silent_chunks);
00551 output_samples += raw_block_size * silent_chunks;
00552 *data_size = raw_block_size * silent_chunks;
00553 *data_size += vmdaudio_loadsound(s, output_samples, p + 4, 0, buf_size - 20);
00554 } else if (buf[6] == 3) {
00555
00556 *data_size = vmdaudio_loadsound(s, output_samples, p, 1, 0);
00557 }
00558
00559 return buf_size;
00560 }
00561
00562
00563
00564
00565
00566
00567 AVCodec vmdvideo_decoder = {
00568 "vmdvideo",
00569 CODEC_TYPE_VIDEO,
00570 CODEC_ID_VMDVIDEO,
00571 sizeof(VmdVideoContext),
00572 vmdvideo_decode_init,
00573 NULL,
00574 vmdvideo_decode_end,
00575 vmdvideo_decode_frame,
00576 CODEC_CAP_DR1,
00577 .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
00578 };
00579
00580 AVCodec vmdaudio_decoder = {
00581 "vmdaudio",
00582 CODEC_TYPE_AUDIO,
00583 CODEC_ID_VMDAUDIO,
00584 sizeof(VmdAudioContext),
00585 vmdaudio_decode_init,
00586 NULL,
00587 NULL,
00588 vmdaudio_decode_frame,
00589 .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
00590 };