Statistics
| Branch: | Revision:

ffmpeg / libavcodec / vmdav.c @ 99ed41a8

History | View | Annotate | Download (17.4 KB)

1
/*
2
 * Sierra VMD Audio & Video Decoders
3
 * Copyright (C) 2004 the ffmpeg project
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * 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
 * 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
 * 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 vmdav.c
24
 * Sierra VMD audio & video decoders
25
 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
26
 * for more information on the Sierra VMD format, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28
 *
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
 * is expected to be prepended with the appropriate 16-byte frame
33
 * information record from the VMD file.
34
 *
35
 * The audio decoder, like the video decoder, expects each encoded data
36
 * chunk to be prepended with the appropriate 16-byte frame information
37
 * 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
#include <unistd.h>
46

    
47
#include "libavutil/intreadwrite.h"
48
#include "avcodec.h"
49

    
50
#define VMD_HEADER_SIZE 0x330
51
#define PALETTE_COUNT 256
52

    
53
/*
54
 * Video Decoder
55
 */
56

    
57
typedef struct VmdVideoContext {
58

    
59
    AVCodecContext *avctx;
60
    AVFrame frame;
61
    AVFrame prev_frame;
62

    
63
    const unsigned char *buf;
64
    int size;
65

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

    
70
    int x_off, y_off;
71
} VmdVideoContext;
72

    
73
#define QUEUE_SIZE 0x1000
74
#define QUEUE_MASK 0x0FFF
75

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

    
90
    s = src;
91
    d = dest;
92
    d_end = d + dest_len;
93
    dataleft = AV_RL32(s);
94
    s += 4;
95
    memset(queue, 0x20, QUEUE_SIZE);
96
    if (AV_RL32(s) == 0x56781234) {
97
        s += 4;
98
        qpos = 0x111;
99
        speclen = 0xF + 3;
100
    } else {
101
        qpos = 0xFEE;
102
        speclen = 100;  /* no speclen */
103
    }
104

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

    
146
static int rle_unpack(const unsigned char *src, unsigned char *dest,
147
    int src_len, int dest_len)
148
{
149
    const unsigned char *ps;
150
    unsigned char *pd;
151
    int i, l;
152
    unsigned char *dest_end = dest + dest_len;
153

    
154
    ps = src;
155
    pd = dest;
156
    if (src_len & 1)
157
        *pd++ = *ps++;
158

    
159
    src_len >>= 1;
160
    i = 0;
161
    do {
162
        l = *ps++;
163
        if (l & 0x80) {
164
            l = (l & 0x7F) * 2;
165
            if (pd + l > dest_end)
166
                return ps - src;
167
            memcpy(pd, ps, l);
168
            ps += l;
169
            pd += l;
170
        } else {
171
            if (pd + i > dest_end)
172
                return ps - src;
173
            for (i = 0; i < l; i++) {
174
                *pd++ = ps[0];
175
                *pd++ = ps[1];
176
            }
177
            ps += 2;
178
        }
179
        i += l;
180
    } while (i < src_len);
181

    
182
    return ps - src;
183
}
184

    
185
static void vmd_decode(VmdVideoContext *s)
186
{
187
    int i;
188
    unsigned int *palette32;
189
    unsigned char r, g, b;
190

    
191
    /* point to the start of the encoded data */
192
    const unsigned char *p = s->buf + 16;
193

    
194
    const unsigned char *pb;
195
    unsigned char meth;
196
    unsigned char *dp;   /* pointer to current frame */
197
    unsigned char *pp;   /* pointer to previous frame */
198
    unsigned char len;
199
    int ofs;
200

    
201
    int frame_x, frame_y;
202
    int frame_width, frame_height;
203
    int dp_size;
204

    
205
    frame_x = AV_RL16(&s->buf[6]);
206
    frame_y = AV_RL16(&s->buf[8]);
207
    frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
208
    frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
209

    
210
    if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
211
        (frame_x || frame_y)) {
212

    
213
        s->x_off = frame_x;
214
        s->y_off = frame_y;
215
    }
216
    frame_x -= s->x_off;
217
    frame_y -= s->y_off;
218

    
219
    /* if only a certain region will be updated, copy the entire previous
220
     * frame before the decode */
221
    if (frame_x || frame_y || (frame_width != s->avctx->width) ||
222
        (frame_height != s->avctx->height)) {
223

    
224
        memcpy(s->frame.data[0], s->prev_frame.data[0],
225
            s->avctx->height * s->frame.linesize[0]);
226
    }
227

    
228
    /* check if there is a new palette */
229
    if (s->buf[15] & 0x02) {
230
        p += 2;
231
        palette32 = (unsigned int *)s->palette;
232
        for (i = 0; i < PALETTE_COUNT; i++) {
233
            r = *p++ * 4;
234
            g = *p++ * 4;
235
            b = *p++ * 4;
236
            palette32[i] = (r << 16) | (g << 8) | (b);
237
        }
238
        s->size -= (256 * 3 + 2);
239
    }
240
    if (s->size >= 0) {
241
        /* originally UnpackFrame in VAG's code */
242
        pb = p;
243
        meth = *pb++;
244
        if (meth & 0x80) {
245
            lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size);
246
            meth &= 0x7F;
247
            pb = s->unpack_buffer;
248
        }
249

    
250
        dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
251
        dp_size = s->frame.linesize[0] * s->avctx->height;
252
        pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x];
253
        switch (meth) {
254
        case 1:
255
            for (i = 0; i < frame_height; i++) {
256
                ofs = 0;
257
                do {
258
                    len = *pb++;
259
                    if (len & 0x80) {
260
                        len = (len & 0x7F) + 1;
261
                        if (ofs + len > frame_width)
262
                            return;
263
                        memcpy(&dp[ofs], pb, len);
264
                        pb += len;
265
                        ofs += len;
266
                    } else {
267
                        /* interframe pixel copy */
268
                        if (ofs + len + 1 > frame_width)
269
                            return;
270
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
271
                        ofs += len + 1;
272
                    }
273
                } while (ofs < frame_width);
274
                if (ofs > frame_width) {
275
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
276
                        ofs, frame_width);
277
                    break;
278
                }
279
                dp += s->frame.linesize[0];
280
                pp += s->prev_frame.linesize[0];
281
            }
282
            break;
283

    
284
        case 2:
285
            for (i = 0; i < frame_height; i++) {
286
                memcpy(dp, pb, frame_width);
287
                pb += frame_width;
288
                dp += s->frame.linesize[0];
289
                pp += s->prev_frame.linesize[0];
290
            }
291
            break;
292

    
293
        case 3:
294
            for (i = 0; i < frame_height; i++) {
295
                ofs = 0;
296
                do {
297
                    len = *pb++;
298
                    if (len & 0x80) {
299
                        len = (len & 0x7F) + 1;
300
                        if (*pb++ == 0xFF)
301
                            len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
302
                        else
303
                            memcpy(&dp[ofs], pb, len);
304
                        pb += len;
305
                        ofs += len;
306
                    } else {
307
                        /* interframe pixel copy */
308
                        if (ofs + len + 1 > frame_width)
309
                            return;
310
                        memcpy(&dp[ofs], &pp[ofs], len + 1);
311
                        ofs += len + 1;
312
                    }
313
                } while (ofs < frame_width);
314
                if (ofs > frame_width) {
315
                    av_log(s->avctx, AV_LOG_ERROR, "VMD video: offset > width (%d > %d)\n",
316
                        ofs, frame_width);
317
                }
318
                dp += s->frame.linesize[0];
319
                pp += s->prev_frame.linesize[0];
320
            }
321
            break;
322
        }
323
    }
324
}
325

    
326
static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
327
{
328
    VmdVideoContext *s = avctx->priv_data;
329
    int i;
330
    unsigned int *palette32;
331
    int palette_index = 0;
332
    unsigned char r, g, b;
333
    unsigned char *vmd_header;
334
    unsigned char *raw_palette;
335

    
336
    s->avctx = avctx;
337
    avctx->pix_fmt = PIX_FMT_PAL8;
338

    
339
    /* make sure the VMD header made it */
340
    if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
341
        av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
342
            VMD_HEADER_SIZE);
343
        return -1;
344
    }
345
    vmd_header = (unsigned char *)avctx->extradata;
346

    
347
    s->unpack_buffer_size = AV_RL32(&vmd_header[800]);
348
    s->unpack_buffer = av_malloc(s->unpack_buffer_size);
349
    if (!s->unpack_buffer)
350
        return -1;
351

    
352
    /* load up the initial palette */
353
    raw_palette = &vmd_header[28];
354
    palette32 = (unsigned int *)s->palette;
355
    for (i = 0; i < PALETTE_COUNT; i++) {
356
        r = raw_palette[palette_index++] * 4;
357
        g = raw_palette[palette_index++] * 4;
358
        b = raw_palette[palette_index++] * 4;
359
        palette32[i] = (r << 16) | (g << 8) | (b);
360
    }
361

    
362
    s->frame.data[0] = s->prev_frame.data[0] = NULL;
363

    
364
    return 0;
365
}
366

    
367
static int vmdvideo_decode_frame(AVCodecContext *avctx,
368
                                 void *data, int *data_size,
369
                                 const uint8_t *buf, int buf_size)
370
{
371
    VmdVideoContext *s = avctx->priv_data;
372

    
373
    s->buf = buf;
374
    s->size = buf_size;
375

    
376
    if (buf_size < 16)
377
        return buf_size;
378

    
379
    s->frame.reference = 1;
380
    if (avctx->get_buffer(avctx, &s->frame)) {
381
        av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
382
        return -1;
383
    }
384

    
385
    vmd_decode(s);
386

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

    
390
    /* shuffle frames */
391
    FFSWAP(AVFrame, s->frame, s->prev_frame);
392
    if (s->frame.data[0])
393
        avctx->release_buffer(avctx, &s->frame);
394

    
395
    *data_size = sizeof(AVFrame);
396
    *(AVFrame*)data = s->prev_frame;
397

    
398
    /* report that the buffer was completely consumed */
399
    return buf_size;
400
}
401

    
402
static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
403
{
404
    VmdVideoContext *s = avctx->priv_data;
405

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

    
410
    return 0;
411
}
412

    
413

    
414
/*
415
 * Audio Decoder
416
 */
417

    
418
typedef struct VmdAudioContext {
419
    AVCodecContext *avctx;
420
    int channels;
421
    int bits;
422
    int block_align;
423
    int predictors[2];
424
} VmdAudioContext;
425

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

    
442
static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
443
{
444
    VmdAudioContext *s = avctx->priv_data;
445

    
446
    s->avctx = avctx;
447
    s->channels = avctx->channels;
448
    s->bits = avctx->bits_per_coded_sample;
449
    s->block_align = avctx->block_align;
450
    avctx->sample_fmt = SAMPLE_FMT_S16;
451

    
452
    av_log(s->avctx, AV_LOG_DEBUG, "%d channels, %d bits/sample, block align = %d, sample rate = %d\n",
453
            s->channels, s->bits, s->block_align, avctx->sample_rate);
454

    
455
    return 0;
456
}
457

    
458
static void vmdaudio_decode_audio(VmdAudioContext *s, unsigned char *data,
459
    const uint8_t *buf, int buf_size, int stereo)
460
{
461
    int i;
462
    int chan = 0;
463
    int16_t *out = (int16_t*)data;
464

    
465
    for(i = 0; i < buf_size; i++) {
466
        if(buf[i] & 0x80)
467
            s->predictors[chan] -= vmdaudio_table[buf[i] & 0x7F];
468
        else
469
            s->predictors[chan] += vmdaudio_table[buf[i]];
470
        s->predictors[chan] = av_clip_int16(s->predictors[chan]);
471
        out[i] = s->predictors[chan];
472
        chan ^= stereo;
473
    }
474
}
475

    
476
static int vmdaudio_loadsound(VmdAudioContext *s, unsigned char *data,
477
    const uint8_t *buf, int silence, int data_size)
478
{
479
    int bytes_decoded = 0;
480
    int i;
481

    
482
//    if (silence)
483
//        av_log(s->avctx, AV_LOG_INFO, "silent block!\n");
484
    if (s->channels == 2) {
485

    
486
        /* stereo handling */
487
        if (silence) {
488
            memset(data, 0, data_size * 2);
489
        } else {
490
            if (s->bits == 16)
491
                vmdaudio_decode_audio(s, data, buf, data_size, 1);
492
            else {
493
                /* copy the data but convert it to signed */
494
                for (i = 0; i < data_size; i++){
495
                    *data++ = buf[i] + 0x80;
496
                    *data++ = buf[i] + 0x80;
497
                }
498
            }
499
        }
500
    } else {
501
        bytes_decoded = data_size * 2;
502

    
503
        /* mono handling */
504
        if (silence) {
505
            memset(data, 0, data_size * 2);
506
        } else {
507
            if (s->bits == 16) {
508
                vmdaudio_decode_audio(s, data, buf, data_size, 0);
509
            } else {
510
                /* copy the data but convert it to signed */
511
                for (i = 0; i < data_size; i++){
512
                    *data++ = buf[i] + 0x80;
513
                    *data++ = buf[i] + 0x80;
514
                }
515
            }
516
        }
517
    }
518

    
519
    return data_size * 2;
520
}
521

    
522
static int vmdaudio_decode_frame(AVCodecContext *avctx,
523
                                 void *data, int *data_size,
524
                                 const uint8_t *buf, int buf_size)
525
{
526
    VmdAudioContext *s = avctx->priv_data;
527
    unsigned char *output_samples = (unsigned char *)data;
528

    
529
    /* point to the start of the encoded data */
530
    const unsigned char *p = buf + 16;
531

    
532
    if (buf_size < 16)
533
        return buf_size;
534

    
535
    if (buf[6] == 1) {
536
        /* the chunk contains audio */
537
        *data_size = vmdaudio_loadsound(s, output_samples, p, 0, buf_size - 16);
538
    } else if (buf[6] == 2) {
539
        /* initial chunk, may contain audio and silence */
540
        uint32_t flags = AV_RB32(p);
541
        int raw_block_size = s->block_align * s->bits / 8;
542
        int silent_chunks;
543
        if(flags == 0xFFFFFFFF)
544
            silent_chunks = 32;
545
        else
546
            silent_chunks = av_log2(flags + 1);
547
        if(*data_size < (s->block_align*silent_chunks + buf_size - 20) * 2)
548
            return -1;
549
        *data_size = 0;
550
        memset(output_samples, 0, raw_block_size * silent_chunks);
551
        output_samples += raw_block_size * silent_chunks;
552
        *data_size = raw_block_size * silent_chunks;
553
        *data_size += vmdaudio_loadsound(s, output_samples, p + 4, 0, buf_size - 20);
554
    } else if (buf[6] == 3) {
555
        /* silent chunk */
556
        *data_size = vmdaudio_loadsound(s, output_samples, p, 1, 0);
557
    }
558

    
559
    return buf_size;
560
}
561

    
562

    
563
/*
564
 * Public Data Structures
565
 */
566

    
567
AVCodec vmdvideo_decoder = {
568
    "vmdvideo",
569
    CODEC_TYPE_VIDEO,
570
    CODEC_ID_VMDVIDEO,
571
    sizeof(VmdVideoContext),
572
    vmdvideo_decode_init,
573
    NULL,
574
    vmdvideo_decode_end,
575
    vmdvideo_decode_frame,
576
    CODEC_CAP_DR1,
577
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"),
578
};
579

    
580
AVCodec vmdaudio_decoder = {
581
    "vmdaudio",
582
    CODEC_TYPE_AUDIO,
583
    CODEC_ID_VMDAUDIO,
584
    sizeof(VmdAudioContext),
585
    vmdaudio_decode_init,
586
    NULL,
587
    NULL,
588
    vmdaudio_decode_frame,
589
    .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"),
590
};