libavcodec/dpcm.c
3ef8be2b
 /*
  * Assorted DPCM codecs
41ed7ab4
  * Copyright (c) 2003 The FFmpeg project
3ef8be2b
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
3ef8be2b
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
b78e7197
  * version 2.1 of the License, or (at your option) any later version.
3ef8be2b
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
3ef8be2b
  * 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
b78e7197
  * License along with FFmpeg; if not, write to the Free Software
5509bffa
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3ef8be2b
  */
 
 /**
33edd31f
  * @file
3ef8be2b
  * Assorted DPCM (differential pulse code modulation) audio codecs
  * by Mike Melanson (melanson@pcisys.net)
9937e686
  * Xan DPCM decoder by Mario Brito (mbrito@student.dei.uc.pt)
3ef8be2b
  * for more information on the specific data formats, visit:
  *   http://www.pcisys.net/~melanson/codecs/simpleaudio.html
d08d7142
  * SOL DPCMs implemented by Konstantin Shishkov
9937e686
  *
  * Note about using the Xan DPCM decoder: Xan DPCM is used in AVI files
  * found in the Wing Commander IV computer game. These AVI files contain
  * WAVEFORMAT headers which report the audio format as 0x01: raw PCM.
  * Clearly incorrect. To detect Xan DPCM, you will probably have to
  * special-case your AVI demuxer to use Xan DPCM if the file uses 'Xxan'
  * (Xan video) for its video codec. Alternately, such AVI files also contain
  * the fourcc 'Axan' in the 'auds' chunk of the AVI header.
3ef8be2b
  */
 
6a5d31ac
 #include "libavutil/intreadwrite.h"
3ef8be2b
 #include "avcodec.h"
1de8401c
 #include "bytestream.h"
594d4d5d
 #include "internal.h"
3a3f06b0
 #include "mathops.h"
3ef8be2b
 
 typedef struct DPCMContext {
29bdcf58
     int16_t array[256];
04b24cf9
     int sample[2];                  ///< previous sample (for SOL_DPCM)
0354fb7e
     const int8_t *sol_table;        ///< delta table for SOL_DPCM
3ef8be2b
 } DPCMContext;
 
0354fb7e
 static const int16_t interplay_delta_table[] = {
3ef8be2b
          0,      1,      2,      3,      4,      5,      6,      7,
          8,      9,     10,     11,     12,     13,     14,     15,
         16,     17,     18,     19,     20,     21,     22,     23,
         24,     25,     26,     27,     28,     29,     30,     31,
         32,     33,     34,     35,     36,     37,     38,     39,
         40,     41,     42,     43,     47,     51,     56,     61,
         66,     72,     79,     86,     94,    102,    112,    122,
        133,    145,    158,    173,    189,    206,    225,    245,
        267,    292,    318,    348,    379,    414,    452,    493,
        538,    587,    640,    699,    763,    832,    908,    991,
       1081,   1180,   1288,   1405,   1534,   1673,   1826,   1993,
       2175,   2373,   2590,   2826,   3084,   3365,   3672,   4008,
       4373,   4772,   5208,   5683,   6202,   6767,   7385,   8059,
       8794,   9597,  10472,  11428,  12471,  13609,  14851,  16206,
      17685,  19298,  21060,  22981,  25078,  27367,  29864,  32589,
     -29973, -26728, -23186, -19322, -15105, -10503,  -5481,     -1,
          1,      1,   5481,  10503,  15105,  19322,  23186,  26728,
      29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298,
     -17685, -16206, -14851, -13609, -12471, -11428, -10472,  -9597,
      -8794,  -8059,  -7385,  -6767,  -6202,  -5683,  -5208,  -4772,
      -4373,  -4008,  -3672,  -3365,  -3084,  -2826,  -2590,  -2373,
      -2175,  -1993,  -1826,  -1673,  -1534,  -1405,  -1288,  -1180,
      -1081,   -991,   -908,   -832,   -763,   -699,   -640,   -587,
       -538,   -493,   -452,   -414,   -379,   -348,   -318,   -292,
       -267,   -245,   -225,   -206,   -189,   -173,   -158,   -145,
       -133,   -122,   -112,   -102,    -94,    -86,    -79,    -72,
        -66,    -61,    -56,    -51,    -47,    -43,    -42,    -41,
        -40,    -39,    -38,    -37,    -36,    -35,    -34,    -33,
        -32,    -31,    -30,    -29,    -28,    -27,    -26,    -25,
        -24,    -23,    -22,    -21,    -20,    -19,    -18,    -17,
        -16,    -15,    -14,    -13,    -12,    -11,    -10,     -9,
         -8,     -7,     -6,     -5,     -4,     -3,     -2,     -1
 
 };
 
0354fb7e
 static const int8_t sol_table_old[16] = {
4bad464e
       0x0,  0x1,  0x2,  0x3,  0x6,  0xA,  0xF, 0x15,
     -0x15, -0xF, -0xA, -0x6, -0x3, -0x2, -0x1,  0x0
 };
d08d7142
 
0354fb7e
 static const int8_t sol_table_new[16] = {
4bad464e
     0x0,  0x1,  0x2,  0x3,  0x6,  0xA,  0xF,  0x15,
     0x0, -0x1, -0x2, -0x3, -0x6, -0xA, -0xF, -0x15
 };
115329f1
 
0354fb7e
 static const int16_t sol_table_16[128] = {
d08d7142
     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
 };
 
 
98a6fff9
 static av_cold int dpcm_decode_init(AVCodecContext *avctx)
3ef8be2b
 {
     DPCMContext *s = avctx->priv_data;
     int i;
 
8d77d12a
     if (avctx->channels < 1 || avctx->channels > 2) {
8d889205
         av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
8d77d12a
         return AVERROR(EINVAL);
     }
3ef8be2b
 
d08d7142
     s->sample[0] = s->sample[1] = 0;
3ef8be2b
 
     switch(avctx->codec->id) {
 
36ef5369
     case AV_CODEC_ID_ROQ_DPCM:
3ef8be2b
         /* initialize square table */
         for (i = 0; i < 128; i++) {
f47f7efd
             int16_t square = i * i;
29bdcf58
             s->array[i      ] =  square;
             s->array[i + 128] = -square;
3ef8be2b
         }
         break;
 
36ef5369
     case AV_CODEC_ID_SOL_DPCM:
d08d7142
         switch(avctx->codec_tag){
         case 1:
4bad464e
             s->sol_table = sol_table_old;
d08d7142
             s->sample[0] = s->sample[1] = 0x80;
             break;
         case 2:
4bad464e
             s->sol_table = sol_table_new;
d08d7142
             s->sample[0] = s->sample[1] = 0x80;
             break;
         case 3:
             break;
         default:
             av_log(avctx, AV_LOG_ERROR, "Unknown SOL subcodec\n");
             return -1;
         }
         break;
115329f1
 
035ae3c0
     case AV_CODEC_ID_SDX2_DPCM:
         for (i = -128; i < 128; i++) {
             int16_t square = i * i * 2;
29bdcf58
             s->array[i+128] = i < 0 ? -square: square;
         }
         break;
 
     case AV_CODEC_ID_GREMLIN_DPCM: {
         int delta = 0;
         int code = 64;
         int step = 45;
 
         s->array[0] = 0;
         for (i = 0; i < 127; i++) {
             delta += (code >> 5);
             code  += step;
             step  += 2;
 
             s->array[i*2 + 1] =  delta;
             s->array[i*2 + 2] = -delta;
         }
         s->array[255] = delta + (code >> 5);
035ae3c0
         }
         break;
 
3ef8be2b
     default:
         break;
     }
 
36ef5369
     if (avctx->codec->id == AV_CODEC_ID_SOL_DPCM && avctx->codec_tag != 3)
04b24cf9
         avctx->sample_fmt = AV_SAMPLE_FMT_U8;
     else
         avctx->sample_fmt = AV_SAMPLE_FMT_S16;
 
3ef8be2b
     return 0;
 }
 
4bad464e
 
0eea2129
 static int dpcm_decode_frame(AVCodecContext *avctx, void *data,
                              int *got_frame_ptr, AVPacket *avpkt)
3ef8be2b
 {
7a00bbad
     int buf_size = avpkt->size;
3ef8be2b
     DPCMContext *s = avctx->priv_data;
b8788671
     AVFrame *frame = data;
0eea2129
     int out = 0, ret;
3ef8be2b
     int predictor[2];
b09c7eef
     int ch = 0;
0fd1ddf1
     int stereo = avctx->channels - 1;
3a3f06b0
     int16_t *output_samples, *samples_end;
     GetByteContext gb;
3ef8be2b
 
3a3f06b0
     if (stereo && (buf_size & 1))
ce7aee9b
         buf_size--;
3a3f06b0
     bytestream2_init(&gb, avpkt->data, buf_size);
ce7aee9b
 
76db17dc
     /* calculate output size */
     switch(avctx->codec->id) {
36ef5369
     case AV_CODEC_ID_ROQ_DPCM:
76db17dc
         out = buf_size - 8;
         break;
36ef5369
     case AV_CODEC_ID_INTERPLAY_DPCM:
0fd1ddf1
         out = buf_size - 6 - avctx->channels;
76db17dc
         break;
36ef5369
     case AV_CODEC_ID_XAN_DPCM:
0fd1ddf1
         out = buf_size - 2 * avctx->channels;
76db17dc
         break;
36ef5369
     case AV_CODEC_ID_SOL_DPCM:
76db17dc
         if (avctx->codec_tag != 3)
             out = buf_size * 2;
         else
             out = buf_size;
         break;
29bdcf58
     case AV_CODEC_ID_GREMLIN_DPCM:
035ae3c0
     case AV_CODEC_ID_SDX2_DPCM:
         out = buf_size;
         break;
76db17dc
     }
8dbc6d03
     if (out <= 0) {
08bd22a6
         av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
         return AVERROR(EINVAL);
     }
67883502
     if (out % avctx->channels) {
92115bb6
         av_log(avctx, AV_LOG_WARNING, "channels have differing number of samples\n");
     }
0eea2129
 
     /* get output buffer */
5459cf41
     frame->nb_samples = (out + avctx->channels - 1) / avctx->channels;
1ec94b0f
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
0eea2129
         return ret;
b8788671
     output_samples = (int16_t *)frame->data[0];
3a3f06b0
     samples_end = output_samples + out;
a2085a7e
 
3ef8be2b
     switch(avctx->codec->id) {
 
36ef5369
     case AV_CODEC_ID_ROQ_DPCM:
3a3f06b0
         bytestream2_skipu(&gb, 6);
1de8401c
 
3db8db40
         if (stereo) {
3a3f06b0
             predictor[1] = sign_extend(bytestream2_get_byteu(&gb) << 8, 16);
             predictor[0] = sign_extend(bytestream2_get_byteu(&gb) << 8, 16);
3db8db40
         } else {
3a3f06b0
             predictor[0] = sign_extend(bytestream2_get_le16u(&gb), 16);
3ef8be2b
         }
 
         /* decode the samples */
3a3f06b0
         while (output_samples < samples_end) {
29bdcf58
             predictor[ch] += s->array[bytestream2_get_byteu(&gb)];
4bad464e
             predictor[ch]  = av_clip_int16(predictor[ch]);
76db17dc
             *output_samples++ = predictor[ch];
3ef8be2b
 
             /* toggle channel */
3db8db40
             ch ^= stereo;
3ef8be2b
         }
         break;
 
36ef5369
     case AV_CODEC_ID_INTERPLAY_DPCM:
3a3f06b0
         bytestream2_skipu(&gb, 6);  /* skip over the stream mask and stream length */
1de8401c
 
0fd1ddf1
         for (ch = 0; ch < avctx->channels; ch++) {
3a3f06b0
             predictor[ch] = sign_extend(bytestream2_get_le16u(&gb), 16);
1de8401c
             *output_samples++ = predictor[ch];
3ef8be2b
         }
 
1de8401c
         ch = 0;
3a3f06b0
         while (output_samples < samples_end) {
             predictor[ch] += interplay_delta_table[bytestream2_get_byteu(&gb)];
4bad464e
             predictor[ch]  = av_clip_int16(predictor[ch]);
76db17dc
             *output_samples++ = predictor[ch];
3ef8be2b
 
             /* toggle channel */
3db8db40
             ch ^= stereo;
3ef8be2b
         }
         break;
9937e686
 
36ef5369
     case AV_CODEC_ID_XAN_DPCM:
fc6faee0
     {
         int shift[2] = { 4, 4 };
9937e686
 
0fd1ddf1
         for (ch = 0; ch < avctx->channels; ch++)
3a3f06b0
             predictor[ch] = sign_extend(bytestream2_get_le16u(&gb), 16);
1de8401c
 
         ch = 0;
3a3f06b0
         while (output_samples < samples_end) {
             int diff = bytestream2_get_byteu(&gb);
             int n    = diff & 3;
 
             if (n == 3)
b09c7eef
                 shift[ch]++;
9937e686
             else
3a3f06b0
                 shift[ch] -= (2 * n);
             diff = sign_extend((diff &~ 3) << 8, 16);
 
9937e686
             /* saturate the shifter to a lower limit of 0 */
b09c7eef
             if (shift[ch] < 0)
                 shift[ch] = 0;
9937e686
 
b09c7eef
             diff >>= shift[ch];
             predictor[ch] += diff;
9937e686
 
b09c7eef
             predictor[ch] = av_clip_int16(predictor[ch]);
76db17dc
             *output_samples++ = predictor[ch];
9937e686
 
             /* toggle channel */
3db8db40
             ch ^= stereo;
9937e686
         }
         break;
fc6faee0
     }
36ef5369
     case AV_CODEC_ID_SOL_DPCM:
d08d7142
         if (avctx->codec_tag != 3) {
b8788671
             uint8_t *output_samples_u8 = frame->data[0],
3a3f06b0
                     *samples_end_u8 = output_samples_u8 + out;
             while (output_samples_u8 < samples_end_u8) {
                 int n = bytestream2_get_byteu(&gb);
04b24cf9
 
                 s->sample[0] += s->sol_table[n >> 4];
                 s->sample[0]  = av_clip_uint8(s->sample[0]);
                 *output_samples_u8++ = s->sample[0];
 
                 s->sample[stereo] += s->sol_table[n & 0x0F];
                 s->sample[stereo]  = av_clip_uint8(s->sample[stereo]);
                 *output_samples_u8++ = s->sample[stereo];
d08d7142
             }
         } else {
3a3f06b0
             while (output_samples < samples_end) {
                 int n = bytestream2_get_byteu(&gb);
5a54d510
                 if (n & 0x80) s->sample[ch] -= sol_table_16[n & 0x7F];
                 else          s->sample[ch] += sol_table_16[n & 0x7F];
b09c7eef
                 s->sample[ch] = av_clip_int16(s->sample[ch]);
76db17dc
                 *output_samples++ = s->sample[ch];
d08d7142
                 /* toggle channel */
3db8db40
                 ch ^= stereo;
d08d7142
             }
         }
         break;
035ae3c0
 
     case AV_CODEC_ID_SDX2_DPCM:
         while (output_samples < samples_end) {
             int8_t n = bytestream2_get_byteu(&gb);
 
             if (!(n & 1))
                 s->sample[ch] = 0;
29bdcf58
             s->sample[ch] += s->array[n + 128];
035ae3c0
             s->sample[ch]  = av_clip_int16(s->sample[ch]);
             *output_samples++ = s->sample[ch];
             ch ^= stereo;
         }
         break;
29bdcf58
 
     case AV_CODEC_ID_GREMLIN_DPCM: {
         int idx = 0;
 
         while (output_samples < samples_end) {
             uint8_t n = bytestream2_get_byteu(&gb);
 
             *output_samples++ = s->sample[idx] += s->array[n];
             idx ^= 1;
         }
         }
         break;
3ef8be2b
     }
 
b8788671
     *got_frame_ptr = 1;
0eea2129
 
ce7aee9b
     return avpkt->size;
3ef8be2b
 }
 
86714887
 #define DPCM_DECODER(id_, name_, long_name_)                \
 AVCodec ff_ ## name_ ## _decoder = {                        \
     .name           = #name_,                               \
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL(long_name_),     \
86714887
     .type           = AVMEDIA_TYPE_AUDIO,                   \
     .id             = id_,                                  \
     .priv_data_size = sizeof(DPCMContext),                  \
     .init           = dpcm_decode_init,                     \
     .decode         = dpcm_decode_frame,                    \
def97856
     .capabilities   = AV_CODEC_CAP_DR1,                     \
98ec8287
 }
3ef8be2b
 
29bdcf58
 DPCM_DECODER(AV_CODEC_ID_GREMLIN_DPCM,   gremlin_dpcm,   "DPCM Gremlin");
36ef5369
 DPCM_DECODER(AV_CODEC_ID_INTERPLAY_DPCM, interplay_dpcm, "DPCM Interplay");
 DPCM_DECODER(AV_CODEC_ID_ROQ_DPCM,       roq_dpcm,       "DPCM id RoQ");
035ae3c0
 DPCM_DECODER(AV_CODEC_ID_SDX2_DPCM,      sdx2_dpcm,      "DPCM Squareroot-Delta-Exact");
36ef5369
 DPCM_DECODER(AV_CODEC_ID_SOL_DPCM,       sol_dpcm,       "DPCM Sol");
 DPCM_DECODER(AV_CODEC_ID_XAN_DPCM,       xan_dpcm,       "DPCM Xan");