vmdav.c 19.9 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 267 268 269
        p += 2;
        palette32 = (unsigned int *)s->palette;
        for (i = 0; i < PALETTE_COUNT; i++) {
            r = *p++ * 4;
            g = *p++ * 4;
            b = *p++ * 4;
            palette32[i] = (r << 16) | (g << 8) | (b);
        }
    }
270
    if (p < p_end) {
271 272
        /* originally UnpackFrame in VAG's code */
        pb = p;
273
        pb_end = p_end;
274 275
        meth = *pb++;
        if (meth & 0x80) {
276
            lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
277 278
            meth &= 0x7F;
            pb = s->unpack_buffer;
279
            pb_end = s->unpack_buffer + s->unpack_buffer_size;
280 281 282 283 284 285 286 287 288
        }

        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 {
289 290
                    if (pb_end - pb < 1)
                        return;
291 292 293
                    len = *pb++;
                    if (len & 0x80) {
                        len = (len & 0x7F) + 1;
294
                        if (ofs + len > frame_width || pb_end - pb < len)
295
                            return;
296 297 298 299 300
                        memcpy(&dp[ofs], pb, len);
                        pb += len;
                        ofs += len;
                    } else {
                        /* interframe pixel copy */
301
                        if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
302
                            return;
303 304 305 306 307
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
                        ofs += len + 1;
                    }
                } while (ofs < frame_width);
                if (ofs > frame_width) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
308
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
309 310 311 312 313 314 315 316 317 318
                        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++) {
319 320
                if (pb_end -pb < frame_width)
                    return;
321 322 323 324 325 326 327 328 329 330 331
                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 {
332 333
                    if (pb_end - pb < 1)
                        return;
334 335 336
                    len = *pb++;
                    if (len & 0x80) {
                        len = (len & 0x7F) + 1;
337 338
                        if (pb_end - pb < 1)
                            return;
339
                        if (*pb++ == 0xFF)
340
                            len = rle_unpack(pb, pb_end - pb, len, &dp[ofs], frame_width - ofs);
341 342 343
                        else {
                        if (pb_end - pb < len)
                            return;
344
                            memcpy(&dp[ofs], pb, len);
345
                        }
346 347 348 349
                        pb += len;
                        ofs += len;
                    } else {
                        /* interframe pixel copy */
350
                        if (ofs + len + 1 > frame_width || !s->prev_frame.data[0])
351
                            return;
352 353 354 355 356
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
                        ofs += len + 1;
                    }
                } while (ofs < frame_width);
                if (ofs > frame_width) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
357
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
358 359 360 361 362 363 364 365 366 367
                        ofs, frame_width);
                }
                dp += s->frame.linesize[0];
                pp += s->prev_frame.linesize[0];
            }
            break;
        }
    }
}

368
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
369
{
370
    VmdVideoContext *s = avctx->priv_data;
371 372 373 374 375 376 377 378 379 380 381 382
    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) {
383
        av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
384 385 386 387 388
            VMD_HEADER_SIZE);
        return -1;
    }
    vmd_header = (unsigned char *)avctx->extradata;

389
    s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
390
    s->unpack_buffer = av_malloc(s->unpack_buffer_size);
391 392 393 394 395 396 397 398 399 400 401 402 403
    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);
    }

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

407 408 409 410 411
    return 0;
}

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

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

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

424 425
    s->frame.reference = 1;
    if (avctx->get_buffer(avctx, &s->frame)) {
Alex Beregszaszi's avatar
Alex Beregszaszi committed
426
        av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
427 428 429 430 431 432 433 434 435
        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 */
436 437 438
    FFSWAP(AVFrame, s->frame, s->prev_frame);
    if (s->frame.data[0])
        avctx->release_buffer(avctx, &s->frame);
439 440

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

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

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

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

    return 0;
}


/*
 * Audio Decoder
 */

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

467
typedef struct VmdAudioContext {
468
    int out_bps;
469
    int chunk_size;
470 471
} VmdAudioContext;

472
static const uint16_t vmdaudio_table[128] = {
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
    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
};

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

492 493 494 495 496 497 498 499 500
    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);
    }

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

507 508
    s->chunk_size = avctx->block_align + avctx->channels * (s->out_bps == 2);

509 510 511 512
    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);
513 514 515 516

    return 0;
}

517 518
static void decode_audio_s16(int16_t *out, const uint8_t *buf, int buf_size,
                             int channels)
519
{
520 521 522 523 524 525 526 527 528 529
    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];
530
    }
531

532 533 534 535 536 537 538 539 540 541 542
    /* 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;
543
    }
544 545 546 547
}

static int vmdaudio_decode_frame(AVCodecContext *avctx,
                                 void *data, int *data_size,
548
                                 AVPacket *avpkt)
549
{
550
    const uint8_t *buf = avpkt->data;
551
    const uint8_t *buf_end;
552
    int buf_size = avpkt->size;
553
    VmdAudioContext *s = avctx->priv_data;
554 555 556 557
    int block_type, silent_chunks, audio_chunks;
    int nb_samples, out_size;
    uint8_t *output_samples_u8  = data;
    int16_t *output_samples_s16 = data;
558

559 560 561
    if (buf_size < 16) {
        av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
        *data_size = 0;
562
        return buf_size;
563
    }
564

565
    block_type = buf[6];
566 567 568 569
    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);
    }
570 571
    buf      += 16;
    buf_size -= 16;
572

573
    /* get number of silent chunks */
574 575
    silent_chunks = 0;
    if (block_type == BLOCK_TYPE_INITIAL) {
576
        uint32_t flags;
577 578 579 580 581 582
        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);
583 584
        buf      += 4;
        buf_size -= 4;
585
    } else if (block_type == BLOCK_TYPE_SILENCE) {
586 587
        silent_chunks = 1;
        buf_size = 0; // should already be zero but set it just to be sure
588 589
    }

590
    /* ensure output buffer is large enough */
591 592 593 594
    audio_chunks = buf_size / s->chunk_size;
    nb_samples   = ((silent_chunks + audio_chunks) * avctx->block_align) / avctx->channels;
    out_size     = nb_samples * avctx->channels * s->out_bps;
    if (*data_size < out_size)
595 596
        return -1;

597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
    /* 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;
        while (buf < buf_end) {
            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;
        }
    }
624

625
    *data_size = out_size;
626
    return avpkt->size;
627 628 629 630 631 632 633
}


/*
 * Public Data Structures
 */

634
AVCodec ff_vmdvideo_decoder = {
635 636 637 638 639 640 641 642
    .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,
643
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
644 645
};

646
AVCodec ff_vmdaudio_decoder = {
647 648 649 650 651 652
    .name           = "vmdaudio",
    .type           = AVMEDIA_TYPE_AUDIO,
    .id             = CODEC_ID_VMDAUDIO,
    .priv_data_size = sizeof(VmdAudioContext),
    .init           = vmdaudio_decode_init,
    .decode         = vmdaudio_decode_frame,
653
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
654
};