vmdav.c 20.2 KB
Newer Older
1 2 3 4
/*
 * Sierra VMD Audio & Video Decoders
 * Copyright (C) 2004 the ffmpeg project
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 21 22
 */

/**
23
 * @file
24 25
 * Sierra VMD audio & video decoders
 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
26 27
 * for more information on the Sierra VMD format, visit:
 *   http://www.pcisys.net/~melanson/codecs/
28 29 30 31
 *
 * The video decoder outputs PAL8 colorspace data. The decoder expects
 * a 0x330-byte VMD file header to be transmitted via extradata during
 * codec initialization. Each encoded frame that is sent to this decoder
32
 * is expected to be prepended with the appropriate 16-byte frame
33 34 35
 * information record from the VMD file.
 *
 * The audio decoder, like the video decoder, expects each encoded data
36
 * chunk to be prepended with the appropriate 16-byte frame information
37 38 39 40 41 42 43 44 45
 * record from the VMD file. It does not require the 0x330-byte VMD file
 * header, but it does need the audio setup parameters passed in through
 * normal libavcodec API means.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

46
#include "libavutil/intreadwrite.h"
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#include "avcodec.h"

#define VMD_HEADER_SIZE 0x330
#define PALETTE_COUNT 256

/*
 * Video Decoder
 */

typedef struct VmdVideoContext {

    AVCodecContext *avctx;
    AVFrame frame;
    AVFrame prev_frame;

Michael Niedermayer's avatar
Michael Niedermayer committed
62
    const unsigned char *buf;
63 64 65 66
    int size;

    unsigned char palette[PALETTE_COUNT * 4];
    unsigned char *unpack_buffer;
67
    int unpack_buffer_size;
68

69
    int x_off, y_off;
70 71 72 73 74
} VmdVideoContext;

#define QUEUE_SIZE 0x1000
#define QUEUE_MASK 0x0FFF

75 76
static void lz_unpack(const unsigned char *src, int src_len,
                      unsigned char *dest, int dest_len)
77
{
Michael Niedermayer's avatar
Michael Niedermayer committed
78
    const unsigned char *s;
79
    const unsigned char *s_end;
80
    unsigned char *d;
81
    unsigned char *d_end;
82 83 84 85 86 87 88 89 90 91
    unsigned char queue[QUEUE_SIZE];
    unsigned int qpos;
    unsigned int dataleft;
    unsigned int chainofs;
    unsigned int chainlen;
    unsigned int speclen;
    unsigned char tag;
    unsigned int i, j;

    s = src;
92
    s_end = src + src_len;
93
    d = dest;
94
    d_end = d + dest_len;
95 96 97

    if (s_end - s < 8)
        return;
98
    dataleft = AV_RL32(s);
99
    s += 4;
100
    memset(queue, 0x20, QUEUE_SIZE);
101
    if (AV_RL32(s) == 0x56781234) {
102 103 104 105 106 107 108 109
        s += 4;
        qpos = 0x111;
        speclen = 0xF + 3;
    } else {
        qpos = 0xFEE;
        speclen = 100;  /* no speclen */
    }

110
    while (s_end - s > 0 && dataleft > 0) {
111 112
        tag = *s++;
        if ((tag == 0xFF) && (dataleft > 8)) {
113
            if (d_end - d < 8 || s_end - s < 8)
114
                return;
115 116 117 118 119 120 121 122 123 124
            for (i = 0; i < 8; i++) {
                queue[qpos++] = *d++ = *s++;
                qpos &= QUEUE_MASK;
            }
            dataleft -= 8;
        } else {
            for (i = 0; i < 8; i++) {
                if (dataleft == 0)
                    break;
                if (tag & 0x01) {
125
                    if (d_end - d < 1 || s_end - s < 1)
126
                        return;
127 128 129 130
                    queue[qpos++] = *d++ = *s++;
                    qpos &= QUEUE_MASK;
                    dataleft--;
                } else {
131 132
                    if (s_end - s < 2)
                        return;
133 134 135
                    chainofs = *s++;
                    chainofs |= ((*s & 0xF0) << 4);
                    chainlen = (*s++ & 0x0F) + 3;
136 137 138
                    if (chainlen == speclen) {
                        if (s_end - s < 1)
                            return;
139
                        chainlen = *s++ + 0xF + 3;
140
                    }
141
                    if (d_end - d < chainlen)
142
                        return;
143 144 145 146 147 148 149 150 151 152 153 154 155
                    for (j = 0; j < chainlen; j++) {
                        *d = queue[chainofs++ & QUEUE_MASK];
                        queue[qpos++] = *d++;
                        qpos &= QUEUE_MASK;
                    }
                    dataleft -= chainlen;
                }
                tag >>= 1;
            }
        }
    }
}

156 157
static int rle_unpack(const unsigned char *src, int src_len, int src_count,
                      unsigned char *dest, int dest_len)
158
{
Michael Niedermayer's avatar
Michael Niedermayer committed
159
    const unsigned char *ps;
160
    const unsigned char *ps_end;
161 162
    unsigned char *pd;
    int i, l;
163
    unsigned char *dest_end = dest + dest_len;
164 165

    ps = src;
166
    ps_end = src + src_len;
167
    pd = dest;
168 169 170
    if (src_count & 1) {
        if (ps_end - ps < 1)
            return 0;
171
        *pd++ = *ps++;
172
    }
173

174
    src_count >>= 1;
175 176
    i = 0;
    do {
177 178
        if (ps_end - ps < 1)
            break;
179 180 181
        l = *ps++;
        if (l & 0x80) {
            l = (l & 0x7F) * 2;
182
            if (dest_end - pd < l || ps_end - ps < l)
183
                return ps - src;
184 185 186 187
            memcpy(pd, ps, l);
            ps += l;
            pd += l;
        } else {
188
            if (dest_end - pd < i || ps_end - ps < 2)
189
                return ps - src;
190 191 192 193 194 195 196
            for (i = 0; i < l; i++) {
                *pd++ = ps[0];
                *pd++ = ps[1];
            }
            ps += 2;
        }
        i += l;
197
    } while (i < src_count);
198

199
    return ps - src;
200 201 202 203 204 205 206 207 208
}

static void vmd_decode(VmdVideoContext *s)
{
    int i;
    unsigned int *palette32;
    unsigned char r, g, b;

    /* point to the start of the encoded data */
Michael Niedermayer's avatar
Michael Niedermayer committed
209
    const unsigned char *p = s->buf + 16;
210
    const unsigned char *p_end = s->buf + s->size;
211

Michael Niedermayer's avatar
Michael Niedermayer committed
212
    const unsigned char *pb;
213
    const unsigned char *pb_end;
214 215 216 217 218 219 220 221 222
    unsigned char meth;
    unsigned char *dp;   /* pointer to current frame */
    unsigned char *pp;   /* pointer to previous frame */
    unsigned char len;
    int ofs;

    int frame_x, frame_y;
    int frame_width, frame_height;

223 224 225 226
    frame_x = AV_RL16(&s->buf[6]);
    frame_y = AV_RL16(&s->buf[8]);
    frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
    frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
227 228 229 230 231 232 233 234 235 236
    if (frame_x < 0 || frame_width < 0 ||
        frame_x >= s->avctx->width ||
        frame_width > s->avctx->width ||
        frame_x + frame_width > s->avctx->width)
        return;
    if (frame_y < 0 || frame_height < 0 ||
        frame_y >= s->avctx->height ||
        frame_height > s->avctx->height ||
        frame_y + frame_height > s->avctx->height)
        return;
237

238 239 240 241 242 243 244 245 246
    if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
        (frame_x || frame_y)) {

        s->x_off = frame_x;
        s->y_off = frame_y;
    }
    frame_x -= s->x_off;
    frame_y -= s->y_off;

247 248
    /* if only a certain region will be updated, copy the entire previous
     * frame before the decode */
249 250 251
    if (s->prev_frame.data[0] &&
        (frame_x || frame_y || (frame_width != s->avctx->width) ||
        (frame_height != s->avctx->height))) {
252

253
        memcpy(s->frame.data[0], s->prev_frame.data[0],
254 255 256 257 258
            s->avctx->height * s->frame.linesize[0]);
    }

    /* check if there is a new palette */
    if (s->buf[15] & 0x02) {
259 260
        if (p_end - p < 2 + 3 * PALETTE_COUNT)
            return;
261 262 263 264 265 266
        p += 2;
        palette32 = (unsigned int *)s->palette;
        for (i = 0; i < PALETTE_COUNT; i++) {
            r = *p++ * 4;
            g = *p++ * 4;
            b = *p++ * 4;
267
            palette32[i] = 0xFF << 24 | r << 16 | g << 8 | b;
268
            palette32[i] |= palette32[i] >> 6 & 0x30303;
269 270
        }
    }
271
    if (p < p_end) {
272 273
        /* originally UnpackFrame in VAG's code */
        pb = p;
274
        pb_end = p_end;
275 276
        meth = *pb++;
        if (meth & 0x80) {
277
            lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
278 279
            meth &= 0x7F;
            pb = s->unpack_buffer;
280
            pb_end = s->unpack_buffer + s->unpack_buffer_size;
281 282 283 284 285 286 287 288 289
        }

        dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
        pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x];
        switch (meth) {
        case 1:
            for (i = 0; i < frame_height; i++) {
                ofs = 0;
                do {
290 291
                    if (pb_end - pb < 1)
                        return;
292 293 294
                    len = *pb++;
                    if (len & 0x80) {
                        len = (len & 0x7F) + 1;
295
                        if (ofs + len > frame_width || pb_end - pb < len)
296
                            return;
297 298 299 300 301
                        memcpy(&dp[ofs], pb, len);
                        pb += len;
                        ofs += len;
                    } else {
                        /* interframe pixel copy */
302
                        if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
303
                            return;
304 305 306 307 308
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
                        ofs += len + 1;
                    }
                } while (ofs < frame_width);
                if (ofs > frame_width) {
309
                    av_log(s->avctx, AV_LOG_ERROR, "offset > width (%d > %d)\n",
310 311 312 313 314 315 316 317 318 319
                        ofs, frame_width);
                    break;
                }
                dp += s->frame.linesize[0];
                pp += s->prev_frame.linesize[0];
            }
            break;

        case 2:
            for (i = 0; i < frame_height; i++) {
320 321
                if (pb_end -pb < frame_width)
                    return;
322 323 324 325 326 327 328 329 330 331 332
                memcpy(dp, pb, frame_width);
                pb += frame_width;
                dp += s->frame.linesize[0];
                pp += s->prev_frame.linesize[0];
            }
            break;

        case 3:
            for (i = 0; i < frame_height; i++) {
                ofs = 0;
                do {
333 334
                    if (pb_end - pb < 1)
                        return;
335 336 337
                    len = *pb++;
                    if (len & 0x80) {
                        len = (len & 0x7F) + 1;
338 339
                        if (pb_end - pb < 1)
                            return;
340
                        if (*pb++ == 0xFF)
341
                            len = rle_unpack(pb, pb_end - pb, len, &dp[ofs], frame_width - ofs);
342 343 344
                        else {
                        if (pb_end - pb < len)
                            return;
345
                            memcpy(&dp[ofs], pb, len);
346
                        }
347 348 349 350
                        pb += len;
                        ofs += len;
                    } else {
                        /* interframe pixel copy */
351
                        if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
352
                            return;
353 354 355 356 357
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
                        ofs += len + 1;
                    }
                } while (ofs < frame_width);
                if (ofs > frame_width) {
358
                    av_log(s->avctx, AV_LOG_ERROR, "offset > width (%d > %d)\n",
359 360 361 362 363 364 365 366 367 368
                        ofs, frame_width);
                }
                dp += s->frame.linesize[0];
                pp += s->prev_frame.linesize[0];
            }
            break;
        }
    }
}

369
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
370
{
371
    VmdVideoContext *s = avctx->priv_data;
372 373 374 375 376 377 378 379 380 381 382 383
    int i;
    unsigned int *palette32;
    int palette_index = 0;
    unsigned char r, g, b;
    unsigned char *vmd_header;
    unsigned char *raw_palette;

    s->avctx = avctx;
    avctx->pix_fmt = PIX_FMT_PAL8;

    /* make sure the VMD header made it */
    if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
384
        av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n",
385 386 387 388 389
            VMD_HEADER_SIZE);
        return -1;
    }
    vmd_header = (unsigned char *)avctx->extradata;

390
    s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
391
    s->unpack_buffer = av_malloc(s->unpack_buffer_size);
392 393 394 395 396 397 398 399 400 401 402 403 404
    if (!s->unpack_buffer)
        return -1;

    /* load up the initial palette */
    raw_palette = &vmd_header[28];
    palette32 = (unsigned int *)s->palette;
    for (i = 0; i < PALETTE_COUNT; i++) {
        r = raw_palette[palette_index++] * 4;
        g = raw_palette[palette_index++] * 4;
        b = raw_palette[palette_index++] * 4;
        palette32[i] = (r << 16) | (g << 8) | (b);
    }

405 406 407
    avcodec_get_frame_defaults(&s->frame);
    avcodec_get_frame_defaults(&s->prev_frame);

408 409 410 411 412
    return 0;
}

static int vmdvideo_decode_frame(AVCodecContext *avctx,
                                 void *data, int *data_size,
413
                                 AVPacket *avpkt)
414
{
415 416
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
417
    VmdVideoContext *s = avctx->priv_data;
418 419 420 421

    s->buf = buf;
    s->size = buf_size;

422 423 424
    if (buf_size < 16)
        return buf_size;

425
    s->frame.reference = 3;
426
    if (avctx->get_buffer(avctx, &s->frame)) {
427
        av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
428 429 430 431 432 433 434 435 436
        return -1;
    }

    vmd_decode(s);

    /* make the palette available on the way out */
    memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);

    /* shuffle frames */
437 438 439
    FFSWAP(AVFrame, s->frame, s->prev_frame);
    if (s->frame.data[0])
        avctx->release_buffer(avctx, &s->frame);
440 441

    *data_size = sizeof(AVFrame);
442
    *(AVFrame*)data = s->prev_frame;
443 444 445 446 447

    /* report that the buffer was completely consumed */
    return buf_size;
}

448
static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
449
{
450
    VmdVideoContext *s = avctx->priv_data;
451 452 453 454 455 456 457 458 459 460 461 462 463

    if (s->prev_frame.data[0])
        avctx->release_buffer(avctx, &s->prev_frame);
    av_free(s->unpack_buffer);

    return 0;
}


/*
 * Audio Decoder
 */

464 465 466 467
#define BLOCK_TYPE_AUDIO    1
#define BLOCK_TYPE_INITIAL  2
#define BLOCK_TYPE_SILENCE  3

468
typedef struct VmdAudioContext {
469
    AVFrame frame;
470
    int out_bps;
471
    int chunk_size;
472 473
} VmdAudioContext;

474
static const uint16_t vmdaudio_table[128] = {
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
    0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
    0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
    0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
    0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
    0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
    0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
    0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
    0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
    0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
    0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
    0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
    0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
};

490
static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
491
{
492
    VmdAudioContext *s = avctx->priv_data;
493

494 495 496 497 498 499 500 501 502
    if (avctx->channels < 1 || avctx->channels > 2) {
        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
        return AVERROR(EINVAL);
    }
    if (avctx->block_align < 1) {
        av_log(avctx, AV_LOG_ERROR, "invalid block align\n");
        return AVERROR(EINVAL);
    }

503 504 505 506
    if (avctx->bits_per_coded_sample == 16)
        avctx->sample_fmt = AV_SAMPLE_FMT_S16;
    else
        avctx->sample_fmt = AV_SAMPLE_FMT_U8;
507
    s->out_bps = av_get_bytes_per_sample(avctx->sample_fmt);
508

509 510
    s->chunk_size = avctx->block_align + avctx->channels * (s->out_bps == 2);

511 512 513
    avcodec_get_frame_defaults(&s->frame);
    avctx->coded_frame = &s->frame;

514 515 516 517
    av_log(avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, "
           "block align = %d, sample rate = %d\n",
           avctx->channels, avctx->bits_per_coded_sample, avctx->block_align,
           avctx->sample_rate);
518 519 520 521

    return 0;
}

522 523
static void decode_audio_s16(int16_t *out, const uint8_t *buf, int buf_size,
                             int channels)
524
{
525 526 527 528 529 530 531 532 533 534
    int ch;
    const uint8_t *buf_end = buf + buf_size;
    int predictor[2];
    int st = channels - 1;

    /* decode initial raw sample */
    for (ch = 0; ch < channels; ch++) {
        predictor[ch] = (int16_t)AV_RL16(buf);
        buf += 2;
        *out++ = predictor[ch];
535
    }
536

537 538 539 540 541 542 543 544 545 546 547
    /* decode DPCM samples */
    ch = 0;
    while (buf < buf_end) {
        uint8_t b = *buf++;
        if (b & 0x80)
            predictor[ch] -= vmdaudio_table[b & 0x7F];
        else
            predictor[ch] += vmdaudio_table[b];
        predictor[ch] = av_clip_int16(predictor[ch]);
        *out++ = predictor[ch];
        ch ^= st;
548
    }
549 550
}

551 552
static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
                                 int *got_frame_ptr, AVPacket *avpkt)
553
{
554
    const uint8_t *buf = avpkt->data;
555
    const uint8_t *buf_end;
556
    int buf_size = avpkt->size;
557
    VmdAudioContext *s = avctx->priv_data;
558
    int block_type, silent_chunks, audio_chunks;
559 560 561
    int ret;
    uint8_t *output_samples_u8;
    int16_t *output_samples_s16;
562

563 564
    if (buf_size < 16) {
        av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
565
        *got_frame_ptr = 0;
566
        return buf_size;
567
    }
568

569
    block_type = buf[6];
570 571 572 573
    if (block_type < BLOCK_TYPE_AUDIO || block_type > BLOCK_TYPE_SILENCE) {
        av_log(avctx, AV_LOG_ERROR, "unknown block type: %d\n", block_type);
        return AVERROR(EINVAL);
    }
574 575
    buf      += 16;
    buf_size -= 16;
576

577
    /* get number of silent chunks */
578 579
    silent_chunks = 0;
    if (block_type == BLOCK_TYPE_INITIAL) {
580
        uint32_t flags;
581 582 583 584 585 586
        if (buf_size < 4) {
            av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
            return AVERROR(EINVAL);
        }
        flags         = AV_RB32(buf);
        silent_chunks = av_popcount(flags);
587 588
        buf      += 4;
        buf_size -= 4;
589
    } else if (block_type == BLOCK_TYPE_SILENCE) {
590 591
        silent_chunks = 1;
        buf_size = 0; // should already be zero but set it just to be sure
592 593
    }

594
    /* ensure output buffer is large enough */
595
    audio_chunks = buf_size / s->chunk_size;
596 597 598 599 600 601 602 603 604

    /* get output buffer */
    s->frame.nb_samples = ((silent_chunks + audio_chunks) * avctx->block_align) / avctx->channels;
    if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) {
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return ret;
    }
    output_samples_u8  = s->frame.data[0];
    output_samples_s16 = (int16_t *)s->frame.data[0];
605

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
    /* decode silent chunks */
    if (silent_chunks > 0) {
        int silent_size = avctx->block_align * silent_chunks;
        if (s->out_bps == 2) {
            memset(output_samples_s16, 0x00, silent_size * 2);
            output_samples_s16 += silent_size;
        } else {
            memset(output_samples_u8,  0x80, silent_size);
            output_samples_u8 += silent_size;
        }
    }

    /* decode audio chunks */
    if (audio_chunks > 0) {
        buf_end = buf + buf_size;
621
        while ( buf_end - buf >= s->chunk_size) {
622 623 624 625 626 627 628 629 630 631 632
            if (s->out_bps == 2) {
                decode_audio_s16(output_samples_s16, buf, s->chunk_size,
                                 avctx->channels);
                output_samples_s16 += avctx->block_align;
            } else {
                memcpy(output_samples_u8, buf, s->chunk_size);
                output_samples_u8  += avctx->block_align;
            }
            buf += s->chunk_size;
        }
    }
633

634 635 636
    *got_frame_ptr   = 1;
    *(AVFrame *)data = s->frame;

637
    return avpkt->size;
638 639 640 641 642 643 644
}


/*
 * Public Data Structures
 */

645
AVCodec ff_vmdvideo_decoder = {
646 647 648 649 650 651 652 653
    .name           = "vmdvideo",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = CODEC_ID_VMDVIDEO,
    .priv_data_size = sizeof(VmdVideoContext),
    .init           = vmdvideo_decode_init,
    .close          = vmdvideo_decode_end,
    .decode         = vmdvideo_decode_frame,
    .capabilities   = CODEC_CAP_DR1,
654
    .long_name      = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
655 656
};

657
AVCodec ff_vmdaudio_decoder = {
658 659 660 661 662 663
    .name           = "vmdaudio",
    .type           = AVMEDIA_TYPE_AUDIO,
    .id             = CODEC_ID_VMDAUDIO,
    .priv_data_size = sizeof(VmdAudioContext),
    .init           = vmdaudio_decode_init,
    .decode         = vmdaudio_decode_frame,
664
    .capabilities   = CODEC_CAP_DR1,
665
    .long_name      = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
666
};