diff dpcm.c @ 1443:47f4c8a5a7fc libavcodec

New fringe codecs: WC3/Xan video, Xan DPCM, DK3 & DK4 ADPCM
author tmmm
date Mon, 08 Sep 2003 04:10:59 +0000
parents a4d00b1f0271
children afc7baa19b62
line wrap: on
line diff
--- a/dpcm.c	Fri Sep 05 14:41:53 2003 +0000
+++ b/dpcm.c	Mon Sep 08 04:10:59 2003 +0000
@@ -21,8 +21,17 @@
  * @file: dpcm.c
  * Assorted DPCM (differential pulse code modulation) audio codecs
  * by Mike Melanson (melanson@pcisys.net)
+ * Xan DPCM decoder by Mario Brito (mbrito@student.dei.uc.pt)
  * for more information on the specific data formats, visit:
  *   http://www.pcisys.net/~melanson/codecs/simpleaudio.html
+ *
+ * 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.
  */
 
 #include "avcodec.h"
@@ -115,6 +124,9 @@
     int channel_number = 0;
     short *output_samples = data;
     int sequence_number;
+    int shift[2];
+    unsigned char byte;
+    short diff;
 
     switch(avctx->codec->id) {
 
@@ -171,6 +183,40 @@
             s->last_delta[i] = predictor[i];
 
         break;
+
+    case CODEC_ID_XAN_DPCM:
+        in = 0;
+        shift[0] = shift[1] = 4;
+        predictor[0] = LE_16(&buf[in]);
+        in += 2;
+        SE_16BIT(predictor[0]);
+        if (s->channels == 2) {
+            predictor[1] = LE_16(&buf[in]);
+            in += 2;
+            SE_16BIT(predictor[1]);
+        }
+
+        while (in < buf_size) {
+            byte = buf[in++];
+            diff = (byte & 0xFC) << 8;
+            if ((byte & 0x03) == 3)
+                shift[channel_number]++;
+            else
+                shift[channel_number] -= (2 * (byte & 3));
+            /* saturate the shifter to a lower limit of 0 */
+            if (shift[channel_number] < 0)
+                shift[channel_number] = 0;
+
+            diff >>= shift[channel_number];
+            predictor[channel_number] += diff;
+
+            SATURATE_S16(predictor[channel_number]);
+            output_samples[out++] = predictor[channel_number];
+
+            /* toggle channel */
+            channel_number ^= s->channels - 1;
+        }
+        break;
     }
 
     *data_size = out * sizeof(short);
@@ -198,3 +244,14 @@
     NULL,
     dpcm_decode_frame,
 };
+
+AVCodec xan_dpcm_decoder = {
+    "xan_dpcm",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_XAN_DPCM,
+    sizeof(DPCMContext),
+    dpcm_decode_init,
+    NULL,
+    NULL,
+    dpcm_decode_frame,
+};