Statistics
| Branch: | Revision:

ffmpeg / libavcodec / vmdav.c @ 1e86d685

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 dd1af513 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 1e86d685 Justin Ruggles
    int out_bps;
424 fafa0b75 Mike Melanson
    int channels;
425
    int bits;
426
    int block_align;
427 79d15fd4 Kostya Shishkov
    int predictors[2];
428 fafa0b75 Mike Melanson
} VmdAudioContext;
429
430 cf2baeb3 Stefan Gehrer
static const uint16_t vmdaudio_table[128] = {
431 79d15fd4 Kostya Shishkov
    0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
432
    0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
433
    0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
434
    0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
435
    0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
436
    0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
437
    0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
438
    0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
439
    0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
440
    0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
441
    0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
442
    0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
443
    0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
444
};
445
446 98a6fff9 Zuxy Meng
static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
447 fafa0b75 Mike Melanson
{
448 e4141433 Nicholas Tung
    VmdAudioContext *s = avctx->priv_data;
449 fafa0b75 Mike Melanson
450 fd146758 Alex Beregszaszi
    s->avctx = avctx;
451 fafa0b75 Mike Melanson
    s->channels = avctx->channels;
452 dd1c8f3e Luca Abeni
    s->bits = avctx->bits_per_coded_sample;
453 fafa0b75 Mike Melanson
    s->block_align = avctx->block_align;
454 5d6e4c16 Stefano Sabatini
    avctx->sample_fmt = AV_SAMPLE_FMT_S16;
455 1e86d685 Justin Ruggles
    s->out_bps = av_get_bits_per_sample_fmt(avctx->sample_fmt) >> 3;
456 fafa0b75 Mike Melanson
457 fd146758 Alex Beregszaszi
    av_log(s->avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, block align = %d, sample rate = %d\n",
458 bb270c08 Diego Biurrun
            s->channels, s->bits, s->block_align, avctx->sample_rate);
459 fafa0b75 Mike Melanson
460
    return 0;
461
}
462
463
static void vmdaudio_decode_audio(VmdAudioContext *s, unsigned char *data,
464 716ba2d0 Kostya Shishkov
    const uint8_t *buf, int buf_size, int stereo)
465 79d15fd4 Kostya Shishkov
{
466
    int i;
467
    int chan = 0;
468
    int16_t *out = (int16_t*)data;
469 fafa0b75 Mike Melanson
470 716ba2d0 Kostya Shishkov
    for(i = 0; i < buf_size; i++) {
471 79d15fd4 Kostya Shishkov
        if(buf[i] & 0x80)
472
            s->predictors[chan] -= vmdaudio_table[buf[i] & 0x7F];
473
        else
474
            s->predictors[chan] += vmdaudio_table[buf[i]];
475 aee481ce Aurelien Jacobs
        s->predictors[chan] = av_clip_int16(s->predictors[chan]);
476 79d15fd4 Kostya Shishkov
        out[i] = s->predictors[chan];
477
        chan ^= stereo;
478
    }
479 fafa0b75 Mike Melanson
}
480
481 23fe14bb Mike Melanson
static int vmdaudio_loadsound(VmdAudioContext *s, unsigned char *data,
482 762b386e Justin Ruggles
    const uint8_t *buf, int silent_chunks, int data_size)
483 fafa0b75 Mike Melanson
{
484 23fe14bb Mike Melanson
    int i;
485 1e86d685 Justin Ruggles
    int silent_size = s->block_align * silent_chunks * s->out_bps;
486 23fe14bb Mike Melanson
487 762b386e Justin Ruggles
    if (silent_chunks) {
488
        memset(data, 0, silent_size);
489
        data += silent_size;
490
    }
491 ba9516cc Justin Ruggles
    if (s->bits == 16)
492
        vmdaudio_decode_audio(s, data, buf, data_size, s->channels == 2);
493
    else {
494
        /* copy the data but convert it to signed */
495
        for (i = 0; i < data_size; i++){
496
            *data++ = buf[i] + 0x80;
497
            *data++ = buf[i] + 0x80;
498 fafa0b75 Mike Melanson
        }
499 ba9516cc Justin Ruggles
    }
500 23fe14bb Mike Melanson
501 1e86d685 Justin Ruggles
    return silent_size + data_size * s->out_bps;
502 fafa0b75 Mike Melanson
}
503
504
static int vmdaudio_decode_frame(AVCodecContext *avctx,
505
                                 void *data, int *data_size,
506 7a00bbad Thilo Borgmann
                                 AVPacket *avpkt)
507 fafa0b75 Mike Melanson
{
508 7a00bbad Thilo Borgmann
    const uint8_t *buf = avpkt->data;
509
    int buf_size = avpkt->size;
510 e4141433 Nicholas Tung
    VmdAudioContext *s = avctx->priv_data;
511 1574eff3 Justin Ruggles
    int block_type, silent_chunks;
512 fafa0b75 Mike Melanson
    unsigned char *output_samples = (unsigned char *)data;
513
514 7a4fb3fd Justin Ruggles
    if (buf_size < 16) {
515
        av_log(avctx, AV_LOG_WARNING, "skipping small junk packet\n");
516
        *data_size = 0;
517 23fe14bb Mike Melanson
        return buf_size;
518 7a4fb3fd Justin Ruggles
    }
519 23fe14bb Mike Melanson
520 dd1af513 Justin Ruggles
    block_type = buf[6];
521 22f893e1 Justin Ruggles
    if (block_type < BLOCK_TYPE_AUDIO || block_type > BLOCK_TYPE_SILENCE) {
522
        av_log(avctx, AV_LOG_ERROR, "unknown block type: %d\n", block_type);
523
        return AVERROR(EINVAL);
524
    }
525 2d213695 Justin Ruggles
    buf      += 16;
526
    buf_size -= 16;
527 dd1af513 Justin Ruggles
528 1574eff3 Justin Ruggles
    silent_chunks = 0;
529
    if (block_type == BLOCK_TYPE_INITIAL) {
530 2d213695 Justin Ruggles
        uint32_t flags = AV_RB32(buf);
531 1574eff3 Justin Ruggles
        silent_chunks  = av_popcount(flags);
532 2d213695 Justin Ruggles
        buf      += 4;
533
        buf_size -= 4;
534 dd1af513 Justin Ruggles
    } else if (block_type == BLOCK_TYPE_SILENCE) {
535 1574eff3 Justin Ruggles
        silent_chunks = 1;
536
        buf_size = 0; // should already be zero but set it just to be sure
537 fafa0b75 Mike Melanson
    }
538
539 1574eff3 Justin Ruggles
    /* ensure output buffer is large enough */
540 1e86d685 Justin Ruggles
    if (*data_size < (s->block_align*silent_chunks + buf_size) * s->out_bps)
541 1574eff3 Justin Ruggles
        return -1;
542
543
    *data_size = vmdaudio_loadsound(s, output_samples, buf, silent_chunks, buf_size);
544
545 2d213695 Justin Ruggles
    return avpkt->size;
546 fafa0b75 Mike Melanson
}
547
548
549
/*
550
 * Public Data Structures
551
 */
552
553 d36beb3f Diego Elio Pettenò
AVCodec ff_vmdvideo_decoder = {
554 fafa0b75 Mike Melanson
    "vmdvideo",
555 72415b2a Stefano Sabatini
    AVMEDIA_TYPE_VIDEO,
556 fafa0b75 Mike Melanson
    CODEC_ID_VMDVIDEO,
557
    sizeof(VmdVideoContext),
558
    vmdvideo_decode_init,
559
    NULL,
560
    vmdvideo_decode_end,
561
    vmdvideo_decode_frame,
562
    CODEC_CAP_DR1,
563 fe4bf374 Stefano Sabatini
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
564 fafa0b75 Mike Melanson
};
565
566 d36beb3f Diego Elio Pettenò
AVCodec ff_vmdaudio_decoder = {
567 fafa0b75 Mike Melanson
    "vmdaudio",
568 72415b2a Stefano Sabatini
    AVMEDIA_TYPE_AUDIO,
569 fafa0b75 Mike Melanson
    CODEC_ID_VMDAUDIO,
570
    sizeof(VmdAudioContext),
571
    vmdaudio_decode_init,
572
    NULL,
573
    NULL,
574
    vmdaudio_decode_frame,
575 fe4bf374 Stefano Sabatini
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
576 fafa0b75 Mike Melanson
};