GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/dpcm.c Lines: 105 175 60.0 %
Date: 2019-11-22 03:34:36 Branches: 44 80 55.0 %

Line Branch Exec Source
1
/*
2
 * Assorted DPCM codecs
3
 * Copyright (c) 2003 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
24
 * Assorted DPCM (differential pulse code modulation) audio codecs
25
 * by Mike Melanson (melanson@pcisys.net)
26
 * Xan DPCM decoder by Mario Brito (mbrito@student.dei.uc.pt)
27
 * for more information on the specific data formats, visit:
28
 *   http://www.pcisys.net/~melanson/codecs/simpleaudio.html
29
 * SOL DPCMs implemented by Konstantin Shishkov
30
 *
31
 * Note about using the Xan DPCM decoder: Xan DPCM is used in AVI files
32
 * found in the Wing Commander IV computer game. These AVI files contain
33
 * WAVEFORMAT headers which report the audio format as 0x01: raw PCM.
34
 * Clearly incorrect. To detect Xan DPCM, you will probably have to
35
 * special-case your AVI demuxer to use Xan DPCM if the file uses 'Xxan'
36
 * (Xan video) for its video codec. Alternately, such AVI files also contain
37
 * the fourcc 'Axan' in the 'auds' chunk of the AVI header.
38
 */
39
40
#include "libavutil/intreadwrite.h"
41
#include "avcodec.h"
42
#include "bytestream.h"
43
#include "internal.h"
44
#include "mathops.h"
45
46
typedef struct DPCMContext {
47
    int16_t array[256];
48
    int sample[2];                  ///< previous sample (for SOL_DPCM)
49
    const int8_t *sol_table;        ///< delta table for SOL_DPCM
50
} DPCMContext;
51
52
static const int16_t interplay_delta_table[] = {
53
         0,      1,      2,      3,      4,      5,      6,      7,
54
         8,      9,     10,     11,     12,     13,     14,     15,
55
        16,     17,     18,     19,     20,     21,     22,     23,
56
        24,     25,     26,     27,     28,     29,     30,     31,
57
        32,     33,     34,     35,     36,     37,     38,     39,
58
        40,     41,     42,     43,     47,     51,     56,     61,
59
        66,     72,     79,     86,     94,    102,    112,    122,
60
       133,    145,    158,    173,    189,    206,    225,    245,
61
       267,    292,    318,    348,    379,    414,    452,    493,
62
       538,    587,    640,    699,    763,    832,    908,    991,
63
      1081,   1180,   1288,   1405,   1534,   1673,   1826,   1993,
64
      2175,   2373,   2590,   2826,   3084,   3365,   3672,   4008,
65
      4373,   4772,   5208,   5683,   6202,   6767,   7385,   8059,
66
      8794,   9597,  10472,  11428,  12471,  13609,  14851,  16206,
67
     17685,  19298,  21060,  22981,  25078,  27367,  29864,  32589,
68
    -29973, -26728, -23186, -19322, -15105, -10503,  -5481,     -1,
69
         1,      1,   5481,  10503,  15105,  19322,  23186,  26728,
70
     29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298,
71
    -17685, -16206, -14851, -13609, -12471, -11428, -10472,  -9597,
72
     -8794,  -8059,  -7385,  -6767,  -6202,  -5683,  -5208,  -4772,
73
     -4373,  -4008,  -3672,  -3365,  -3084,  -2826,  -2590,  -2373,
74
     -2175,  -1993,  -1826,  -1673,  -1534,  -1405,  -1288,  -1180,
75
     -1081,   -991,   -908,   -832,   -763,   -699,   -640,   -587,
76
      -538,   -493,   -452,   -414,   -379,   -348,   -318,   -292,
77
      -267,   -245,   -225,   -206,   -189,   -173,   -158,   -145,
78
      -133,   -122,   -112,   -102,    -94,    -86,    -79,    -72,
79
       -66,    -61,    -56,    -51,    -47,    -43,    -42,    -41,
80
       -40,    -39,    -38,    -37,    -36,    -35,    -34,    -33,
81
       -32,    -31,    -30,    -29,    -28,    -27,    -26,    -25,
82
       -24,    -23,    -22,    -21,    -20,    -19,    -18,    -17,
83
       -16,    -15,    -14,    -13,    -12,    -11,    -10,     -9,
84
        -8,     -7,     -6,     -5,     -4,     -3,     -2,     -1
85
86
};
87
88
static const int8_t sol_table_old[16] = {
89
      0x0,  0x1,  0x2,  0x3,  0x6,  0xA,  0xF, 0x15,
90
    -0x15, -0xF, -0xA, -0x6, -0x3, -0x2, -0x1,  0x0
91
};
92
93
static const int8_t sol_table_new[16] = {
94
    0x0,  0x1,  0x2,  0x3,  0x6,  0xA,  0xF,  0x15,
95
    0x0, -0x1, -0x2, -0x3, -0x6, -0xA, -0xF, -0x15
96
};
97
98
static const int16_t sol_table_16[128] = {
99
    0x000, 0x008, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070, 0x080,
100
    0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0, 0x100, 0x110, 0x120,
101
    0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0,
102
    0x1D0, 0x1E0, 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
103
    0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, 0x278, 0x280,
104
    0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8, 0x2C0, 0x2C8, 0x2D0,
105
    0x2D8, 0x2E0, 0x2E8, 0x2F0, 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320,
106
    0x328, 0x330, 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
107
    0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0, 0x3B8, 0x3C0,
108
    0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0, 0x3F8, 0x400, 0x440, 0x480,
109
    0x4C0, 0x500, 0x540, 0x580, 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700,
110
    0x740, 0x780, 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
111
    0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
112
};
113
114
115
14
static av_cold int dpcm_decode_init(AVCodecContext *avctx)
116
{
117
14
    DPCMContext *s = avctx->priv_data;
118
    int i;
119
120

14
    if (avctx->channels < 1 || avctx->channels > 2) {
121
        av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
122
        return AVERROR(EINVAL);
123
    }
124
125
14
    s->sample[0] = s->sample[1] = 0;
126
127

14
    switch(avctx->codec->id) {
128
129
5
    case AV_CODEC_ID_ROQ_DPCM:
130
        /* initialize square table */
131
645
        for (i = 0; i < 128; i++) {
132
640
            int16_t square = i * i;
133
640
            s->array[i      ] =  square;
134
640
            s->array[i + 128] = -square;
135
        }
136
5
        break;
137
138
2
    case AV_CODEC_ID_SOL_DPCM:
139

2
        switch(avctx->codec_tag){
140
        case 1:
141
            s->sol_table = sol_table_old;
142
            s->sample[0] = s->sample[1] = 0x80;
143
            break;
144
        case 2:
145
            s->sol_table = sol_table_new;
146
            s->sample[0] = s->sample[1] = 0x80;
147
            break;
148
2
        case 3:
149
2
            break;
150
        default:
151
            av_log(avctx, AV_LOG_ERROR, "Unknown SOL subcodec\n");
152
            return -1;
153
        }
154
2
        break;
155
156
    case AV_CODEC_ID_SDX2_DPCM:
157
        for (i = -128; i < 128; i++) {
158
            int16_t square = i * i * 2;
159
            s->array[i+128] = i < 0 ? -square: square;
160
        }
161
        break;
162
163
    case AV_CODEC_ID_GREMLIN_DPCM: {
164
        int delta = 0;
165
        int code = 64;
166
        int step = 45;
167
168
        s->array[0] = 0;
169
        for (i = 0; i < 127; i++) {
170
            delta += (code >> 5);
171
            code  += step;
172
            step  += 2;
173
174
            s->array[i*2 + 1] =  delta;
175
            s->array[i*2 + 2] = -delta;
176
        }
177
        s->array[255] = delta + (code >> 5);
178
        }
179
        break;
180
181
7
    default:
182
7
        break;
183
    }
184
185

14
    if (avctx->codec->id == AV_CODEC_ID_SOL_DPCM && avctx->codec_tag != 3)
186
        avctx->sample_fmt = AV_SAMPLE_FMT_U8;
187
    else
188
14
        avctx->sample_fmt = AV_SAMPLE_FMT_S16;
189
190
14
    return 0;
191
}
192
193
194
649
static int dpcm_decode_frame(AVCodecContext *avctx, void *data,
195
                             int *got_frame_ptr, AVPacket *avpkt)
196
{
197
649
    int buf_size = avpkt->size;
198
649
    DPCMContext *s = avctx->priv_data;
199
649
    AVFrame *frame = data;
200
649
    int out = 0, ret;
201
    int predictor[2];
202
649
    int ch = 0;
203
649
    int stereo = avctx->channels - 1;
204
    int16_t *output_samples, *samples_end;
205
    GetByteContext gb;
206
207

649
    if (stereo && (buf_size & 1))
208
        buf_size--;
209
649
    bytestream2_init(&gb, avpkt->data, buf_size);
210
211
    /* calculate output size */
212

649
    switch(avctx->codec->id) {
213
340
    case AV_CODEC_ID_ROQ_DPCM:
214
340
        out = buf_size - 8;
215
340
        break;
216
124
    case AV_CODEC_ID_INTERPLAY_DPCM:
217
124
        out = buf_size - 6 - avctx->channels;
218
124
        break;
219
111
    case AV_CODEC_ID_XAN_DPCM:
220
111
        out = buf_size - 2 * avctx->channels;
221
111
        break;
222
74
    case AV_CODEC_ID_SOL_DPCM:
223
74
        if (avctx->codec_tag != 3)
224
            out = buf_size * 2;
225
        else
226
74
            out = buf_size;
227
74
        break;
228
    case AV_CODEC_ID_GREMLIN_DPCM:
229
    case AV_CODEC_ID_SDX2_DPCM:
230
        out = buf_size;
231
        break;
232
    }
233
649
    if (out <= 0) {
234
        av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
235
        return AVERROR(EINVAL);
236
    }
237
649
    if (out % avctx->channels) {
238
        av_log(avctx, AV_LOG_WARNING, "channels have differing number of samples\n");
239
    }
240
241
    /* get output buffer */
242
649
    frame->nb_samples = (out + avctx->channels - 1) / avctx->channels;
243
649
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
244
        return ret;
245
649
    output_samples = (int16_t *)frame->data[0];
246
649
    samples_end = output_samples + out;
247
248

649
    switch(avctx->codec->id) {
249
250
340
    case AV_CODEC_ID_ROQ_DPCM:
251
340
        bytestream2_skipu(&gb, 6);
252
253
340
        if (stereo) {
254
340
            predictor[1] = sign_extend(bytestream2_get_byteu(&gb) << 8, 16);
255
340
            predictor[0] = sign_extend(bytestream2_get_byteu(&gb) << 8, 16);
256
        } else {
257
            predictor[0] = sign_extend(bytestream2_get_le16u(&gb), 16);
258
        }
259
260
        /* decode the samples */
261
523240
        while (output_samples < samples_end) {
262
522900
            predictor[ch] += s->array[bytestream2_get_byteu(&gb)];
263
522900
            predictor[ch]  = av_clip_int16(predictor[ch]);
264
522900
            *output_samples++ = predictor[ch];
265
266
            /* toggle channel */
267
522900
            ch ^= stereo;
268
        }
269
340
        break;
270
271
124
    case AV_CODEC_ID_INTERPLAY_DPCM:
272
124
        bytestream2_skipu(&gb, 6);  /* skip over the stream mask and stream length */
273
274
372
        for (ch = 0; ch < avctx->channels; ch++) {
275
248
            predictor[ch] = sign_extend(bytestream2_get_le16u(&gb), 16);
276
248
            *output_samples++ = predictor[ch];
277
        }
278
279
124
        ch = 0;
280
364752
        while (output_samples < samples_end) {
281
364628
            predictor[ch] += interplay_delta_table[bytestream2_get_byteu(&gb)];
282
364628
            predictor[ch]  = av_clip_int16(predictor[ch]);
283
364628
            *output_samples++ = predictor[ch];
284
285
            /* toggle channel */
286
364628
            ch ^= stereo;
287
        }
288
124
        break;
289
290
111
    case AV_CODEC_ID_XAN_DPCM:
291
    {
292
111
        int shift[2] = { 4, 4 };
293
294
333
        for (ch = 0; ch < avctx->channels; ch++)
295
222
            predictor[ch] = sign_extend(bytestream2_get_le16u(&gb), 16);
296
297
111
        ch = 0;
298
326229
        while (output_samples < samples_end) {
299
326118
            int diff = bytestream2_get_byteu(&gb);
300
326118
            int n    = diff & 3;
301
302
326118
            if (n == 3)
303
134940
                shift[ch]++;
304
            else
305
191178
                shift[ch] -= (2 * n);
306
326118
            diff = sign_extend((diff &~ 3) << 8, 16);
307
308
            /* saturate the shifter to a lower limit of 0 */
309
326118
            if (shift[ch] < 0)
310
                shift[ch] = 0;
311
312
326118
            diff >>= shift[ch];
313
326118
            predictor[ch] += diff;
314
315
326118
            predictor[ch] = av_clip_int16(predictor[ch]);
316
326118
            *output_samples++ = predictor[ch];
317
318
            /* toggle channel */
319
326118
            ch ^= stereo;
320
        }
321
111
        break;
322
    }
323
74
    case AV_CODEC_ID_SOL_DPCM:
324
74
        if (avctx->codec_tag != 3) {
325
            uint8_t *output_samples_u8 = frame->data[0],
326
                    *samples_end_u8 = output_samples_u8 + out;
327
            while (output_samples_u8 < samples_end_u8) {
328
                int n = bytestream2_get_byteu(&gb);
329
330
                s->sample[0] += s->sol_table[n >> 4];
331
                s->sample[0]  = av_clip_uint8(s->sample[0]);
332
                *output_samples_u8++ = s->sample[0];
333
334
                s->sample[stereo] += s->sol_table[n & 0x0F];
335
                s->sample[stereo]  = av_clip_uint8(s->sample[stereo]);
336
                *output_samples_u8++ = s->sample[stereo];
337
            }
338
        } else {
339
299512
            while (output_samples < samples_end) {
340
299438
                int n = bytestream2_get_byteu(&gb);
341
299438
                if (n & 0x80) s->sample[ch] -= sol_table_16[n & 0x7F];
342
150564
                else          s->sample[ch] += sol_table_16[n & 0x7F];
343
299438
                s->sample[ch] = av_clip_int16(s->sample[ch]);
344
299438
                *output_samples++ = s->sample[ch];
345
                /* toggle channel */
346
299438
                ch ^= stereo;
347
            }
348
        }
349
74
        break;
350
351
    case AV_CODEC_ID_SDX2_DPCM:
352
        while (output_samples < samples_end) {
353
            int8_t n = bytestream2_get_byteu(&gb);
354
355
            if (!(n & 1))
356
                s->sample[ch] = 0;
357
            s->sample[ch] += s->array[n + 128];
358
            s->sample[ch]  = av_clip_int16(s->sample[ch]);
359
            *output_samples++ = s->sample[ch];
360
            ch ^= stereo;
361
        }
362
        break;
363
364
    case AV_CODEC_ID_GREMLIN_DPCM: {
365
        int idx = 0;
366
367
        while (output_samples < samples_end) {
368
            uint8_t n = bytestream2_get_byteu(&gb);
369
370
            *output_samples++ = s->sample[idx] += s->array[n];
371
            idx ^= 1;
372
        }
373
        }
374
        break;
375
    }
376
377
649
    *got_frame_ptr = 1;
378
379
649
    return avpkt->size;
380
}
381
382
#define DPCM_DECODER(id_, name_, long_name_)                \
383
AVCodec ff_ ## name_ ## _decoder = {                        \
384
    .name           = #name_,                               \
385
    .long_name      = NULL_IF_CONFIG_SMALL(long_name_),     \
386
    .type           = AVMEDIA_TYPE_AUDIO,                   \
387
    .id             = id_,                                  \
388
    .priv_data_size = sizeof(DPCMContext),                  \
389
    .init           = dpcm_decode_init,                     \
390
    .decode         = dpcm_decode_frame,                    \
391
    .capabilities   = AV_CODEC_CAP_DR1,                     \
392
}
393
394
DPCM_DECODER(AV_CODEC_ID_GREMLIN_DPCM,   gremlin_dpcm,   "DPCM Gremlin");
395
DPCM_DECODER(AV_CODEC_ID_INTERPLAY_DPCM, interplay_dpcm, "DPCM Interplay");
396
DPCM_DECODER(AV_CODEC_ID_ROQ_DPCM,       roq_dpcm,       "DPCM id RoQ");
397
DPCM_DECODER(AV_CODEC_ID_SDX2_DPCM,      sdx2_dpcm,      "DPCM Squareroot-Delta-Exact");
398
DPCM_DECODER(AV_CODEC_ID_SOL_DPCM,       sol_dpcm,       "DPCM Sol");
399
DPCM_DECODER(AV_CODEC_ID_XAN_DPCM,       xan_dpcm,       "DPCM Xan");