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