• 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, 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] = 0xFF << 24 | r << 16 | g << 8 | b;
00268             palette32[i] |= palette32[i] >> 6 & 0x30303;
00269         }
00270     }
00271     if (p < p_end) {
00272         /* originally UnpackFrame in VAG's code */
00273         pb = p;
00274         pb_end = p_end;
00275         meth = *pb++;
00276         if (meth & 0x80) {
00277             lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
00278             meth &= 0x7F;
00279             pb = s->unpack_buffer;
00280             pb_end = s->unpack_buffer + s->unpack_buffer_size;
00281         }
00282 
00283         dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
00284         pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x];
00285         switch (meth) {
00286         case 1:
00287             for (i = 0; i < frame_height; i++) {
00288                 ofs = 0;
00289                 do {
00290                     if (pb_end - pb < 1)
00291                         return;
00292                     len = *pb++;
00293                     if (len & 0x80) {
00294                         len = (len & 0x7F) + 1;
00295                         if (ofs + len > frame_width || pb_end - pb < len)
00296                             return;
00297                         memcpy(&dp[ofs], pb, len);
00298                         pb += len;
00299                         ofs += len;
00300                     } else {
00301                         /* interframe pixel copy */
00302                         if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
00303                             return;
00304                         memcpy(&dp[ofs], &pp[ofs], len + 1);
00305                         ofs += len + 1;
00306                     }
00307                 } while (ofs < frame_width);
00308                 if (ofs > frame_width) {
00309                     av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
00310                         ofs, frame_width);
00311                     break;
00312                 }
00313                 dp += s->frame.linesize[0];
00314                 pp += s->prev_frame.linesize[0];
00315             }
00316             break;
00317 
00318         case 2:
00319             for (i = 0; i < frame_height; i++) {
00320                 if (pb_end -pb < frame_width)
00321                     return;
00322                 memcpy(dp, pb, frame_width);
00323                 pb += frame_width;
00324                 dp += s->frame.linesize[0];
00325                 pp += s->prev_frame.linesize[0];
00326             }
00327             break;
00328 
00329         case 3:
00330             for (i = 0; i < frame_height; i++) {
00331                 ofs = 0;
00332                 do {
00333                     if (pb_end - pb < 1)
00334                         return;
00335                     len = *pb++;
00336                     if (len & 0x80) {
00337                         len = (len & 0x7F) + 1;
00338                         if (pb_end - pb < 1)
00339                             return;
00340                         if (*pb++ == 0xFF)
00341                             len = rle_unpack(pb, pb_end - pb, len, &dp[ofs], frame_width - ofs);
00342                         else {
00343                         if (pb_end - pb < len)
00344                             return;
00345                             memcpy(&dp[ofs], pb, len);
00346                         }
00347                         pb += len;
00348                         ofs += len;
00349                     } else {
00350                         /* interframe pixel copy */
00351                         if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
00352                             return;
00353                         memcpy(&dp[ofs], &pp[ofs], len + 1);
00354                         ofs += len + 1;
00355                     }
00356                 } while (ofs < frame_width);
00357                 if (ofs > frame_width) {
00358                     av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
00359                         ofs, frame_width);
00360                 }
00361                 dp += s->frame.linesize[0];
00362                 pp += s->prev_frame.linesize[0];
00363             }
00364             break;
00365         }
00366     }
00367 }
00368 
00369 static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
00370 {
00371     VmdVideoContext *s = avctx->priv_data;
00372     int i;
00373     unsigned int *palette32;
00374     int palette_index = 0;
00375     unsigned char r, g, b;
00376     unsigned char *vmd_header;
00377     unsigned char *raw_palette;
00378 
00379     s->avctx = avctx;
00380     avctx->pix_fmt = PIX_FMT_PAL8;
00381 
00382     /* make sure the VMD header made it */
00383     if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
00384         av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
00385             VMD_HEADER_SIZE);
00386         return -1;
00387     }
00388     vmd_header = (unsigned char *)avctx->extradata;
00389 
00390     s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
00391     s->unpack_buffer = av_malloc(s->unpack_buffer_size);
00392     if (!s->unpack_buffer)
00393         return -1;
00394 
00395     /* load up the initial palette */
00396     raw_palette = &vmd_header[28];
00397     palette32 = (unsigned int *)s->palette;
00398     for (i = 0; i < PALETTE_COUNT; i++) {
00399         r = raw_palette[palette_index++] * 4;
00400         g = raw_palette[palette_index++] * 4;
00401         b = raw_palette[palette_index++] * 4;
00402         palette32[i] = (r << 16) | (g << 8) | (b);
00403     }
00404 
00405     avcodec_get_frame_defaults(&s->frame);
00406     avcodec_get_frame_defaults(&s->prev_frame);
00407 
00408     return 0;
00409 }
00410 
00411 static int vmdvideo_decode_frame(AVCodecContext *avctx,
00412                                  void *data, int *data_size,
00413                                  AVPacket *avpkt)
00414 {
00415     const uint8_t *buf = avpkt->data;
00416     int buf_size = avpkt->size;
00417     VmdVideoContext *s = avctx->priv_data;
00418 
00419     s->buf = buf;
00420     s->size = buf_size;
00421 
00422     if (buf_size < 16)
00423         return buf_size;
00424 
00425     s->frame.reference = 3;
00426     if (avctx->get_buffer(avctx, &s->frame)) {
00427         av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
00428         return -1;
00429     }
00430 
00431     vmd_decode(s);
00432 
00433     /* make the palette available on the way out */
00434     memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
00435 
00436     /* shuffle frames */
00437     FFSWAP(AVFrame, s->frame, s->prev_frame);
00438     if (s->frame.data[0])
00439         avctx->release_buffer(avctx, &s->frame);
00440 
00441     *data_size = sizeof(AVFrame);
00442     *(AVFrame*)data = s->prev_frame;
00443 
00444     /* report that the buffer was completely consumed */
00445     return buf_size;
00446 }
00447 
00448 static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
00449 {
00450     VmdVideoContext *s = avctx->priv_data;
00451 
00452     if (s->prev_frame.data[0])
00453         avctx->release_buffer(avctx, &s->prev_frame);
00454     av_free(s->unpack_buffer);
00455 
00456     return 0;
00457 }
00458 
00459 
00460 /*
00461  * Audio Decoder
00462  */
00463 
00464 #define BLOCK_TYPE_AUDIO    1
00465 #define BLOCK_TYPE_INITIAL  2
00466 #define BLOCK_TYPE_SILENCE  3
00467 
00468 typedef struct VmdAudioContext {
00469     AVFrame frame;
00470     int out_bps;
00471     int chunk_size;
00472 } VmdAudioContext;
00473 
00474 static const uint16_t vmdaudio_table[128] = {
00475     0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
00476     0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
00477     0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
00478     0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
00479     0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
00480     0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
00481     0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
00482     0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
00483     0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
00484     0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
00485     0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
00486     0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
00487     0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
00488 };
00489 
00490 static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
00491 {
00492     VmdAudioContext *s = avctx->priv_data;
00493 
00494     if (avctx->channels < 1 || avctx->channels > 2) {
00495         av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
00496         return AVERROR(EINVAL);
00497     }
00498     if (avctx->block_align < 1) {
00499         av_log(avctx, AV_LOG_ERROR, "invalid block align\n");
00500         return AVERROR(EINVAL);
00501     }
00502 
00503     if (avctx->bits_per_coded_sample == 16)
00504         avctx->sample_fmt = AV_SAMPLE_FMT_S16;
00505     else
00506         avctx->sample_fmt = AV_SAMPLE_FMT_U8;
00507     s->out_bps = av_get_bytes_per_sample(avctx->sample_fmt);
00508 
00509     s->chunk_size = avctx->block_align + avctx->channels * (s->out_bps == 2);
00510 
00511     avcodec_get_frame_defaults(&s->frame);
00512     avctx->coded_frame = &s->frame;
00513 
00514     av_log(avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, "
00515            "block align = %d, sample rate = %d\n",
00516            avctx->channels, avctx->bits_per_coded_sample, avctx->block_align,
00517            avctx->sample_rate);
00518 
00519     return 0;
00520 }
00521 
00522 static void decode_audio_s16(int16_t *out, const uint8_t *buf, int buf_size,
00523                              int channels)
00524 {
00525     int ch;
00526     const uint8_t *buf_end = buf + buf_size;
00527     int predictor[2];
00528     int st = channels - 1;
00529 
00530     /* decode initial raw sample */
00531     for (ch = 0; ch < channels; ch++) {
00532         predictor[ch] = (int16_t)AV_RL16(buf);
00533         buf += 2;
00534         *out++ = predictor[ch];
00535     }
00536 
00537     /* decode DPCM samples */
00538     ch = 0;
00539     while (buf < buf_end) {
00540         uint8_t b = *buf++;
00541         if (b & 0x80)
00542             predictor[ch] -= vmdaudio_table[b & 0x7F];
00543         else
00544             predictor[ch] += vmdaudio_table[b];
00545         predictor[ch] = av_clip_int16(predictor[ch]);
00546         *out++ = predictor[ch];
00547         ch ^= st;
00548     }
00549 }
00550 
00551 static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
00552                                  int *got_frame_ptr, AVPacket *avpkt)
00553 {
00554     const uint8_t *buf = avpkt->data;
00555     const uint8_t *buf_end;
00556     int buf_size = avpkt->size;
00557     VmdAudioContext *s = avctx->priv_data;
00558     int block_type, silent_chunks, audio_chunks;
00559     int ret;
00560     uint8_t *output_samples_u8;
00561     int16_t *output_samples_s16;
00562 
00563     if (buf_size < 16) {
00564         av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
00565         *got_frame_ptr = 0;
00566         return buf_size;
00567     }
00568 
00569     block_type = buf[6];
00570     if (block_type < BLOCK_TYPE_AUDIO || block_type > BLOCK_TYPE_SILENCE) {
00571         av_log(avctx, AV_LOG_ERROR, "unknown block type: %d\n", block_type);
00572         return AVERROR(EINVAL);
00573     }
00574     buf      += 16;
00575     buf_size -= 16;
00576 
00577     /* get number of silent chunks */
00578     silent_chunks = 0;
00579     if (block_type == BLOCK_TYPE_INITIAL) {
00580         uint32_t flags;
00581         if (buf_size < 4) {
00582             av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
00583             return AVERROR(EINVAL);
00584         }
00585         flags         = AV_RB32(buf);
00586         silent_chunks = av_popcount(flags);
00587         buf      += 4;
00588         buf_size -= 4;
00589     } else if (block_type == BLOCK_TYPE_SILENCE) {
00590         silent_chunks = 1;
00591         buf_size = 0; // should already be zero but set it just to be sure
00592     }
00593 
00594     /* ensure output buffer is large enough */
00595     audio_chunks = buf_size / s->chunk_size;
00596 
00597     /* get output buffer */
00598     s->frame.nb_samples = ((silent_chunks + audio_chunks) * avctx->block_align) / avctx->channels;
00599     if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) {
00600         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00601         return ret;
00602     }
00603     output_samples_u8  = s->frame.data[0];
00604     output_samples_s16 = (int16_t *)s->frame.data[0];
00605 
00606     /* decode silent chunks */
00607     if (silent_chunks > 0) {
00608         int silent_size = avctx->block_align * silent_chunks;
00609         if (s->out_bps == 2) {
00610             memset(output_samples_s16, 0x00, silent_size * 2);
00611             output_samples_s16 += silent_size;
00612         } else {
00613             memset(output_samples_u8,  0x80, silent_size);
00614             output_samples_u8 += silent_size;
00615         }
00616     }
00617 
00618     /* decode audio chunks */
00619     if (audio_chunks > 0) {
00620         buf_end = buf + buf_size;
00621         while ( buf_end - buf >= s->chunk_size) {
00622             if (s->out_bps == 2) {
00623                 decode_audio_s16(output_samples_s16, buf, s->chunk_size,
00624                                  avctx->channels);
00625                 output_samples_s16 += avctx->block_align;
00626             } else {
00627                 memcpy(output_samples_u8, buf, s->chunk_size);
00628                 output_samples_u8  += avctx->block_align;
00629             }
00630             buf += s->chunk_size;
00631         }
00632     }
00633 
00634     *got_frame_ptr   = 1;
00635     *(AVFrame *)data = s->frame;
00636 
00637     return avpkt->size;
00638 }
00639 
00640 
00641 /*
00642  * Public Data Structures
00643  */
00644 
00645 AVCodec ff_vmdvideo_decoder = {
00646     .name           = "vmdvideo",
00647     .type           = AVMEDIA_TYPE_VIDEO,
00648     .id             = CODEC_ID_VMDVIDEO,
00649     .priv_data_size = sizeof(VmdVideoContext),
00650     .init           = vmdvideo_decode_init,
00651     .close          = vmdvideo_decode_end,
00652     .decode         = vmdvideo_decode_frame,
00653     .capabilities   = CODEC_CAP_DR1,
00654     .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
00655 };
00656 
00657 AVCodec ff_vmdaudio_decoder = {
00658     .name           = "vmdaudio",
00659     .type           = AVMEDIA_TYPE_AUDIO,
00660     .id             = CODEC_ID_VMDAUDIO,
00661     .priv_data_size = sizeof(VmdAudioContext),
00662     .init           = vmdaudio_decode_init,
00663     .decode         = vmdaudio_decode_frame,
00664     .capabilities   = CODEC_CAP_DR1,
00665     .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
00666 };
Generated on Fri Feb 1 2013 14:34:45 for FFmpeg by doxygen 1.7.1