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