• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavcodec/vmdav.c

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

Generated on Wed Apr 11 2012 07:31:35 for FFmpeg by  doxygen 1.7.1