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

Generated on Fri Sep 16 2011 17:17:45 for FFmpeg by  doxygen 1.7.1