Statistics
| Branch: | Revision:

ffmpeg / libavcodec / vmdav.c @ 1e898e7d

History | View | Annotate | Download (16.8 KB)

1 fafa0b75 Mike Melanson
/*
2
 * Sierra VMD Audio & Video Decoders
3
 * Copyright (C) 2004 the ffmpeg project
4
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 fafa0b75 Mike Melanson
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 fafa0b75 Mike Melanson
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 fafa0b75 Mike Melanson
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 fafa0b75 Mike Melanson
 */
21
22
/**
23 ba87f080 Diego Biurrun
 * @file
24 fafa0b75 Mike Melanson
 * Sierra VMD audio & video decoders
25
 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
26 23fe14bb Mike Melanson
 * for more information on the Sierra VMD format, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28 fafa0b75 Mike Melanson
 *
29
 * The video decoder outputs PAL8 colorspace data. The decoder expects
30
 * a 0x330-byte VMD file header to be transmitted via extradata during
31
 * codec initialization. Each encoded frame that is sent to this decoder
32 115329f1 Diego Biurrun
 * is expected to be prepended with the appropriate 16-byte frame
33 fafa0b75 Mike Melanson
 * information record from the VMD file.
34
 *
35
 * The audio decoder, like the video decoder, expects each encoded data
36 23fe14bb Mike Melanson
 * chunk to be prepended with the appropriate 16-byte frame information
37 fafa0b75 Mike Melanson
 * record from the VMD file. It does not require the 0x330-byte VMD file
38
 * header, but it does need the audio setup parameters passed in through
39
 * normal libavcodec API means.
40
 */
41
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
46 6a5d31ac Diego Biurrun
#include "libavutil/intreadwrite.h"
47 fafa0b75 Mike Melanson
#include "avcodec.h"
48
49
#define VMD_HEADER_SIZE 0x330
50
#define PALETTE_COUNT 256
51
52
/*
53
 * Video Decoder
54
 */
55
56
typedef struct VmdVideoContext {
57
58
    AVCodecContext *avctx;
59
    AVFrame frame;
60
    AVFrame prev_frame;
61
62 e37e5335 Michael Niedermayer
    const unsigned char *buf;
63 fafa0b75 Mike Melanson
    int size;
64
65
    unsigned char palette[PALETTE_COUNT * 4];
66
    unsigned char *unpack_buffer;
67 8458dab1 Mike Melanson
    int unpack_buffer_size;
68 fafa0b75 Mike Melanson
69 ac140479 Kostya Shishkov
    int x_off, y_off;
70 fafa0b75 Mike Melanson
} VmdVideoContext;
71
72
#define QUEUE_SIZE 0x1000
73
#define QUEUE_MASK 0x0FFF
74
75 e37e5335 Michael Niedermayer
static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_len)
76 fafa0b75 Mike Melanson
{
77 e37e5335 Michael Niedermayer
    const unsigned char *s;
78 fafa0b75 Mike Melanson
    unsigned char *d;
79 8458dab1 Mike Melanson
    unsigned char *d_end;
80 fafa0b75 Mike Melanson
    unsigned char queue[QUEUE_SIZE];
81
    unsigned int qpos;
82
    unsigned int dataleft;
83
    unsigned int chainofs;
84
    unsigned int chainlen;
85
    unsigned int speclen;
86
    unsigned char tag;
87
    unsigned int i, j;
88
89
    s = src;
90
    d = dest;
91 8458dab1 Mike Melanson
    d_end = d + dest_len;
92 fead30d4 Alex Beregszaszi
    dataleft = AV_RL32(s);
93 fafa0b75 Mike Melanson
    s += 4;
94 e38f34fd Panagiotis Issaris
    memset(queue, 0x20, QUEUE_SIZE);
95 fead30d4 Alex Beregszaszi
    if (AV_RL32(s) == 0x56781234) {
96 fafa0b75 Mike Melanson
        s += 4;
97
        qpos = 0x111;
98
        speclen = 0xF + 3;
99
    } else {
100
        qpos = 0xFEE;
101
        speclen = 100;  /* no speclen */
102
    }
103
104
    while (dataleft > 0) {
105
        tag = *s++;
106
        if ((tag == 0xFF) && (dataleft > 8)) {
107 8458dab1 Mike Melanson
            if (d + 8 > d_end)
108
                return;
109 fafa0b75 Mike Melanson
            for (i = 0; i < 8; i++) {
110
                queue[qpos++] = *d++ = *s++;
111
                qpos &= QUEUE_MASK;
112
            }
113
            dataleft -= 8;
114
        } else {
115
            for (i = 0; i < 8; i++) {
116
                if (dataleft == 0)
117
                    break;
118
                if (tag & 0x01) {
119 8458dab1 Mike Melanson
                    if (d + 1 > d_end)
120
                        return;
121 fafa0b75 Mike Melanson
                    queue[qpos++] = *d++ = *s++;
122
                    qpos &= QUEUE_MASK;
123
                    dataleft--;
124
                } else {
125
                    chainofs = *s++;
126
                    chainofs |= ((*s & 0xF0) << 4);
127
                    chainlen = (*s++ & 0x0F) + 3;
128
                    if (chainlen == speclen)
129
                        chainlen = *s++ + 0xF + 3;
130 8458dab1 Mike Melanson
                    if (d + chainlen > d_end)
131
                        return;
132 fafa0b75 Mike Melanson
                    for (j = 0; j < chainlen; j++) {
133
                        *d = queue[chainofs++ & QUEUE_MASK];
134
                        queue[qpos++] = *d++;
135
                        qpos &= QUEUE_MASK;
136
                    }
137
                    dataleft -= chainlen;
138
                }
139
                tag >>= 1;
140
            }
141
        }
142
    }
143
}
144
145 e37e5335 Michael Niedermayer
static int rle_unpack(const unsigned char *src, unsigned char *dest,
146 8458dab1 Mike Melanson
    int src_len, int dest_len)
147 fafa0b75 Mike Melanson
{
148 e37e5335 Michael Niedermayer
    const unsigned char *ps;
149 fafa0b75 Mike Melanson
    unsigned char *pd;
150
    int i, l;
151 8458dab1 Mike Melanson
    unsigned char *dest_end = dest + dest_len;
152 fafa0b75 Mike Melanson
153
    ps = src;
154
    pd = dest;
155 8458dab1 Mike Melanson
    if (src_len & 1)
156 fafa0b75 Mike Melanson
        *pd++ = *ps++;
157
158 8458dab1 Mike Melanson
    src_len >>= 1;
159 fafa0b75 Mike Melanson
    i = 0;
160
    do {
161
        l = *ps++;
162
        if (l & 0x80) {
163
            l = (l & 0x7F) * 2;
164 8458dab1 Mike Melanson
            if (pd + l > dest_end)
165 ccd425e7 Diego Biurrun
                return ps - src;
166 fafa0b75 Mike Melanson
            memcpy(pd, ps, l);
167
            ps += l;
168
            pd += l;
169
        } else {
170 8458dab1 Mike Melanson
            if (pd + i > dest_end)
171 ccd425e7 Diego Biurrun
                return ps - src;
172 fafa0b75 Mike Melanson
            for (i = 0; i < l; i++) {
173
                *pd++ = ps[0];
174
                *pd++ = ps[1];
175
            }
176
            ps += 2;
177
        }
178
        i += l;
179 8458dab1 Mike Melanson
    } while (i < src_len);
180 fafa0b75 Mike Melanson
181 ccd425e7 Diego Biurrun
    return ps - src;
182 fafa0b75 Mike Melanson
}
183
184
static void vmd_decode(VmdVideoContext *s)
185
{
186
    int i;
187
    unsigned int *palette32;
188
    unsigned char r, g, b;
189
190
    /* point to the start of the encoded data */
191 e37e5335 Michael Niedermayer
    const unsigned char *p = s->buf + 16;
192 fafa0b75 Mike Melanson
193 e37e5335 Michael Niedermayer
    const unsigned char *pb;
194 fafa0b75 Mike Melanson
    unsigned char meth;
195
    unsigned char *dp;   /* pointer to current frame */
196
    unsigned char *pp;   /* pointer to previous frame */
197
    unsigned char len;
198
    int ofs;
199
200
    int frame_x, frame_y;
201
    int frame_width, frame_height;
202 8458dab1 Mike Melanson
    int dp_size;
203 fafa0b75 Mike Melanson
204 fead30d4 Alex Beregszaszi
    frame_x = AV_RL16(&s->buf[6]);
205
    frame_y = AV_RL16(&s->buf[8]);
206
    frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
207
    frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
208 fafa0b75 Mike Melanson
209 ac140479 Kostya Shishkov
    if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
210
        (frame_x || frame_y)) {
211
212
        s->x_off = frame_x;
213
        s->y_off = frame_y;
214
    }
215
    frame_x -= s->x_off;
216
    frame_y -= s->y_off;
217
218 fafa0b75 Mike Melanson
    /* if only a certain region will be updated, copy the entire previous
219
     * frame before the decode */
220
    if (frame_x || frame_y || (frame_width != s->avctx->width) ||
221
        (frame_height != s->avctx->height)) {
222
223 115329f1 Diego Biurrun
        memcpy(s->frame.data[0], s->prev_frame.data[0],
224 fafa0b75 Mike Melanson
            s->avctx->height * s->frame.linesize[0]);
225
    }
226
227
    /* check if there is a new palette */
228
    if (s->buf[15] & 0x02) {
229
        p += 2;
230
        palette32 = (unsigned int *)s->palette;
231
        for (i = 0; i < PALETTE_COUNT; i++) {
232
            r = *p++ * 4;
233
            g = *p++ * 4;
234
            b = *p++ * 4;
235
            palette32[i] = (r << 16) | (g << 8) | (b);
236
        }
237
        s->size -= (256 * 3 + 2);
238
    }
239
    if (s->size >= 0) {
240
        /* originally UnpackFrame in VAG's code */
241
        pb = p;
242
        meth = *pb++;
243
        if (meth & 0x80) {
244 8458dab1 Mike Melanson
            lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size);
245 fafa0b75 Mike Melanson
            meth &= 0x7F;
246
            pb = s->unpack_buffer;
247
        }
248
249
        dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
250 8458dab1 Mike Melanson
        dp_size = s->frame.linesize[0] * s->avctx->height;
251 fafa0b75 Mike Melanson
        pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x];
252
        switch (meth) {
253
        case 1:
254
            for (i = 0; i < frame_height; i++) {
255
                ofs = 0;
256
                do {
257
                    len = *pb++;
258
                    if (len & 0x80) {
259
                        len = (len & 0x7F) + 1;
260 8458dab1 Mike Melanson
                        if (ofs + len > frame_width)
261
                            return;
262 fafa0b75 Mike Melanson
                        memcpy(&dp[ofs], pb, len);
263
                        pb += len;
264
                        ofs += len;
265
                    } else {
266
                        /* interframe pixel copy */
267 8458dab1 Mike Melanson
                        if (ofs + len + 1 > frame_width)
268
                            return;
269 fafa0b75 Mike Melanson
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
270
                        ofs += len + 1;
271
                    }
272
                } while (ofs < frame_width);
273
                if (ofs > frame_width) {
274 fd146758 Alex Beregszaszi
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
275 fafa0b75 Mike Melanson
                        ofs, frame_width);
276
                    break;
277
                }
278
                dp += s->frame.linesize[0];
279
                pp += s->prev_frame.linesize[0];
280
            }
281
            break;
282
283
        case 2:
284
            for (i = 0; i < frame_height; i++) {
285
                memcpy(dp, pb, frame_width);
286
                pb += frame_width;
287
                dp += s->frame.linesize[0];
288
                pp += s->prev_frame.linesize[0];
289
            }
290
            break;
291
292
        case 3:
293
            for (i = 0; i < frame_height; i++) {
294
                ofs = 0;
295
                do {
296
                    len = *pb++;
297
                    if (len & 0x80) {
298
                        len = (len & 0x7F) + 1;
299
                        if (*pb++ == 0xFF)
300 8458dab1 Mike Melanson
                            len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
301 fafa0b75 Mike Melanson
                        else
302
                            memcpy(&dp[ofs], pb, len);
303
                        pb += len;
304
                        ofs += len;
305
                    } else {
306
                        /* interframe pixel copy */
307 8458dab1 Mike Melanson
                        if (ofs + len + 1 > frame_width)
308
                            return;
309 fafa0b75 Mike Melanson
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
310
                        ofs += len + 1;
311
                    }
312
                } while (ofs < frame_width);
313
                if (ofs > frame_width) {
314 fd146758 Alex Beregszaszi
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
315 fafa0b75 Mike Melanson
                        ofs, frame_width);
316
                }
317
                dp += s->frame.linesize[0];
318
                pp += s->prev_frame.linesize[0];
319
            }
320
            break;
321
        }
322
    }
323
}
324
325 98a6fff9 Zuxy Meng
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
326 fafa0b75 Mike Melanson
{
327 e4141433 Nicholas Tung
    VmdVideoContext *s = avctx->priv_data;
328 fafa0b75 Mike Melanson
    int i;
329
    unsigned int *palette32;
330
    int palette_index = 0;
331
    unsigned char r, g, b;
332
    unsigned char *vmd_header;
333
    unsigned char *raw_palette;
334
335
    s->avctx = avctx;
336
    avctx->pix_fmt = PIX_FMT_PAL8;
337
338
    /* make sure the VMD header made it */
339
    if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
340 115329f1 Diego Biurrun
        av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
341 fafa0b75 Mike Melanson
            VMD_HEADER_SIZE);
342
        return -1;
343
    }
344
    vmd_header = (unsigned char *)avctx->extradata;
345
346 fead30d4 Alex Beregszaszi
    s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
347 8458dab1 Mike Melanson
    s->unpack_buffer = av_malloc(s->unpack_buffer_size);
348 fafa0b75 Mike Melanson
    if (!s->unpack_buffer)
349
        return -1;
350
351
    /* load up the initial palette */
352
    raw_palette = &vmd_header[28];
353
    palette32 = (unsigned int *)s->palette;
354
    for (i = 0; i < PALETTE_COUNT; i++) {
355
        r = raw_palette[palette_index++] * 4;
356
        g = raw_palette[palette_index++] * 4;
357
        b = raw_palette[palette_index++] * 4;
358
        palette32[i] = (r << 16) | (g << 8) | (b);
359
    }
360
361
    return 0;
362
}
363
364
static int vmdvideo_decode_frame(AVCodecContext *avctx,
365
                                 void *data, int *data_size,
366 7a00bbad Thilo Borgmann
                                 AVPacket *avpkt)
367 fafa0b75 Mike Melanson
{
368 7a00bbad Thilo Borgmann
    const uint8_t *buf = avpkt->data;
369
    int buf_size = avpkt->size;
370 e4141433 Nicholas Tung
    VmdVideoContext *s = avctx->priv_data;
371 fafa0b75 Mike Melanson
372
    s->buf = buf;
373
    s->size = buf_size;
374
375 23fe14bb Mike Melanson
    if (buf_size < 16)
376
        return buf_size;
377
378 fafa0b75 Mike Melanson
    s->frame.reference = 1;
379
    if (avctx->get_buffer(avctx, &s->frame)) {
380 fd146758 Alex Beregszaszi
        av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
381 fafa0b75 Mike Melanson
        return -1;
382
    }
383
384
    vmd_decode(s);
385
386
    /* make the palette available on the way out */
387
    memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
388
389
    /* shuffle frames */
390 3dba31aa Kostya Shishkov
    FFSWAP(AVFrame, s->frame, s->prev_frame);
391
    if (s->frame.data[0])
392
        avctx->release_buffer(avctx, &s->frame);
393 fafa0b75 Mike Melanson
394
    *data_size = sizeof(AVFrame);
395 3dba31aa Kostya Shishkov
    *(AVFrame*)data = s->prev_frame;
396 fafa0b75 Mike Melanson
397
    /* report that the buffer was completely consumed */
398
    return buf_size;
399
}
400
401 98a6fff9 Zuxy Meng
static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
402 fafa0b75 Mike Melanson
{
403 e4141433 Nicholas Tung
    VmdVideoContext *s = avctx->priv_data;
404 fafa0b75 Mike Melanson
405
    if (s->prev_frame.data[0])
406
        avctx->release_buffer(avctx, &s->prev_frame);
407
    av_free(s->unpack_buffer);
408
409
    return 0;
410
}
411
412
413
/*
414
 * Audio Decoder
415
 */
416
417 149d3687 Justin Ruggles
#define BLOCK_TYPE_AUDIO    1
418
#define BLOCK_TYPE_INITIAL  2
419
#define BLOCK_TYPE_SILENCE  3
420
421 fafa0b75 Mike Melanson
typedef struct VmdAudioContext {
422 fd146758 Alex Beregszaszi
    AVCodecContext *avctx;
423 5e7c422d Justin Ruggles
    int out_bps;
424 79d15fd4 Kostya Shishkov
    int predictors[2];
425 fafa0b75 Mike Melanson
} VmdAudioContext;
426
427 cf2baeb3 Stefan Gehrer
static const uint16_t vmdaudio_table[128] = {
428 79d15fd4 Kostya Shishkov
    0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
429
    0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
430
    0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
431
    0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
432
    0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
433
    0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
434
    0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
435
    0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
436
    0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
437
    0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
438
    0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
439
    0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
440
    0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
441
};
442
443 98a6fff9 Zuxy Meng
static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
444 fafa0b75 Mike Melanson
{
445 e4141433 Nicholas Tung
    VmdAudioContext *s = avctx->priv_data;
446 fafa0b75 Mike Melanson
447 fd146758 Alex Beregszaszi
    s->avctx = avctx;
448 1e898e7d Justin Ruggles
    if (avctx->bits_per_coded_sample == 16)
449
        avctx->sample_fmt = AV_SAMPLE_FMT_S16;
450
    else
451
        avctx->sample_fmt = AV_SAMPLE_FMT_U8;
452 5e7c422d Justin Ruggles
    s->out_bps = av_get_bits_per_sample_fmt(avctx->sample_fmt) >> 3;
453 fafa0b75 Mike Melanson
454 f3618b01 Justin Ruggles
    av_log(avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, "
455
           "block align = %d, sample rate = %d\n",
456
           avctx->channels, avctx->bits_per_coded_sample, avctx->block_align,
457
           avctx->sample_rate);
458 fafa0b75 Mike Melanson
459
    return 0;
460
}
461
462
static void vmdaudio_decode_audio(VmdAudioContext *s, unsigned char *data,
463 716ba2d0 Kostya Shishkov
    const uint8_t *buf, int buf_size, int stereo)
464 79d15fd4 Kostya Shishkov
{
465
    int i;
466
    int chan = 0;
467
    int16_t *out = (int16_t*)data;
468 fafa0b75 Mike Melanson
469 716ba2d0 Kostya Shishkov
    for(i = 0; i < buf_size; i++) {
470 79d15fd4 Kostya Shishkov
        if(buf[i] & 0x80)
471
            s->predictors[chan] -= vmdaudio_table[buf[i] & 0x7F];
472
        else
473
            s->predictors[chan] += vmdaudio_table[buf[i]];
474 aee481ce Aurelien Jacobs
        s->predictors[chan] = av_clip_int16(s->predictors[chan]);
475 79d15fd4 Kostya Shishkov
        out[i] = s->predictors[chan];
476
        chan ^= stereo;
477
    }
478 fafa0b75 Mike Melanson
}
479
480 23fe14bb Mike Melanson
static int vmdaudio_loadsound(VmdAudioContext *s, unsigned char *data,
481 fb0e3c2b Justin Ruggles
    const uint8_t *buf, int silent_chunks, int data_size)
482 fafa0b75 Mike Melanson
{
483 f3618b01 Justin Ruggles
    int silent_size = s->avctx->block_align * silent_chunks * s->out_bps;
484 23fe14bb Mike Melanson
485 fb0e3c2b Justin Ruggles
    if (silent_chunks) {
486 1e898e7d Justin Ruggles
        memset(data, s->out_bps == 2 ? 0x00 : 0x80, silent_size);
487 fb0e3c2b Justin Ruggles
        data += silent_size;
488
    }
489 f3618b01 Justin Ruggles
    if (s->avctx->bits_per_coded_sample == 16)
490
        vmdaudio_decode_audio(s, data, buf, data_size, s->avctx->channels == 2);
491 83e94d50 Justin Ruggles
    else {
492 1e898e7d Justin Ruggles
        /* just copy the data */
493
        memcpy(data, buf, data_size);
494 83e94d50 Justin Ruggles
    }
495 23fe14bb Mike Melanson
496 5e7c422d Justin Ruggles
    return silent_size + data_size * s->out_bps;
497 fafa0b75 Mike Melanson
}
498
499
static int vmdaudio_decode_frame(AVCodecContext *avctx,
500
                                 void *data, int *data_size,
501 7a00bbad Thilo Borgmann
                                 AVPacket *avpkt)
502 fafa0b75 Mike Melanson
{
503 7a00bbad Thilo Borgmann
    const uint8_t *buf = avpkt->data;
504
    int buf_size = avpkt->size;
505 e4141433 Nicholas Tung
    VmdAudioContext *s = avctx->priv_data;
506 504dff8e Justin Ruggles
    int block_type, silent_chunks;
507 fafa0b75 Mike Melanson
    unsigned char *output_samples = (unsigned char *)data;
508
509 b4b5e922 Justin Ruggles
    if (buf_size < 16) {
510
        av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
511
        *data_size = 0;
512 23fe14bb Mike Melanson
        return buf_size;
513 b4b5e922 Justin Ruggles
    }
514 23fe14bb Mike Melanson
515 149d3687 Justin Ruggles
    block_type = buf[6];
516 ebed7b68 Justin Ruggles
    if (block_type < BLOCK_TYPE_AUDIO || block_type > BLOCK_TYPE_SILENCE) {
517
        av_log(avctx, AV_LOG_ERROR, "unknown block type: %d\n", block_type);
518
        return AVERROR(EINVAL);
519
    }
520 aa236250 Justin Ruggles
    buf      += 16;
521
    buf_size -= 16;
522 149d3687 Justin Ruggles
523 504dff8e Justin Ruggles
    silent_chunks = 0;
524
    if (block_type == BLOCK_TYPE_INITIAL) {
525 aa236250 Justin Ruggles
        uint32_t flags = AV_RB32(buf);
526 504dff8e Justin Ruggles
        silent_chunks  = av_popcount(flags);
527 aa236250 Justin Ruggles
        buf      += 4;
528
        buf_size -= 4;
529 149d3687 Justin Ruggles
    } else if (block_type == BLOCK_TYPE_SILENCE) {
530 504dff8e Justin Ruggles
        silent_chunks = 1;
531
        buf_size = 0; // should already be zero but set it just to be sure
532 fafa0b75 Mike Melanson
    }
533
534 504dff8e Justin Ruggles
    /* ensure output buffer is large enough */
535 f3618b01 Justin Ruggles
    if (*data_size < (avctx->block_align*silent_chunks + buf_size) * s->out_bps)
536 504dff8e Justin Ruggles
        return -1;
537
538
    *data_size = vmdaudio_loadsound(s, output_samples, buf, silent_chunks, buf_size);
539
540 aa236250 Justin Ruggles
    return avpkt->size;
541 fafa0b75 Mike Melanson
}
542
543
544
/*
545
 * Public Data Structures
546
 */
547
548 e7e2df27 Diego Elio Pettenò
AVCodec ff_vmdvideo_decoder = {
549 fafa0b75 Mike Melanson
    "vmdvideo",
550 72415b2a Stefano Sabatini
    AVMEDIA_TYPE_VIDEO,
551 fafa0b75 Mike Melanson
    CODEC_ID_VMDVIDEO,
552
    sizeof(VmdVideoContext),
553
    vmdvideo_decode_init,
554
    NULL,
555
    vmdvideo_decode_end,
556
    vmdvideo_decode_frame,
557
    CODEC_CAP_DR1,
558 fe4bf374 Stefano Sabatini
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
559 fafa0b75 Mike Melanson
};
560
561 e7e2df27 Diego Elio Pettenò
AVCodec ff_vmdaudio_decoder = {
562 fafa0b75 Mike Melanson
    "vmdaudio",
563 72415b2a Stefano Sabatini
    AVMEDIA_TYPE_AUDIO,
564 fafa0b75 Mike Melanson
    CODEC_ID_VMDAUDIO,
565
    sizeof(VmdAudioContext),
566
    vmdaudio_decode_init,
567
    NULL,
568
    NULL,
569
    vmdaudio_decode_frame,
570 fe4bf374 Stefano Sabatini
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
571 fafa0b75 Mike Melanson
};