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