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

Generated on Tue Nov 4 2014 12:59:23 for ffmpeg by  doxygen 1.7.1