aud: support Westwood SND1 audio in AUD files.
authorJustin Ruggles <justin.ruggles@gmail.com>
Tue, 24 Jan 2012 16:09:05 +0000 (11:09 -0500)
committerJustin Ruggles <justin.ruggles@gmail.com>
Tue, 24 Jan 2012 19:13:46 +0000 (14:13 -0500)
Fixes decoding of the handful of "death scream" samples from
"Command and Conquer" that use SND1. e.g.
http://samples.libav.org/game-formats/westwood-aud/nuyell1.aud
http://samples.libav.org/game-formats/westwood-aud/nuyell7.aud

libavformat/westwood_aud.c

index b1eb768..652045f 100644 (file)
@@ -79,7 +79,7 @@ static int wsaud_probe(AVProbeData *p)
 
     /* note: only check for WS IMA (type 99) right now since there is no
      * support for type 1 */
-    if (p->buf[11] != 99)
+    if (p->buf[11] != 99 && p->buf[11] != 1)
         return 0;
 
     /* read ahead to the first audio chunk and validate the first header signature */
@@ -103,6 +103,8 @@ static int wsaud_read_header(AVFormatContext *s,
     wsaud->audio_samplerate = AV_RL16(&header[0]);
     if (header[11] == 99)
         wsaud->audio_type = CODEC_ID_ADPCM_IMA_WS;
+    else if (header[11] == 1)
+        wsaud->audio_type = CODEC_ID_WESTWOOD_SND1;
     else
         return AVERROR_INVALIDDATA;
 
@@ -121,10 +123,10 @@ static int wsaud_read_header(AVFormatContext *s,
     st->codec->codec_tag = 0;  /* no tag */
     st->codec->channels = wsaud->audio_channels;
     st->codec->sample_rate = wsaud->audio_samplerate;
-    st->codec->bits_per_coded_sample = wsaud->audio_bits;
-    st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
-        st->codec->bits_per_coded_sample / 4;
-    st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
+    if (st->codec->codec_id == CODEC_ID_ADPCM_IMA_WS) {
+        st->codec->bits_per_coded_sample = 4;
+        st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 4;
+    }
 
     wsaud->audio_stream_index = st->index;
     wsaud->audio_frame_counter = 0;
@@ -140,6 +142,7 @@ static int wsaud_read_packet(AVFormatContext *s,
     unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE];
     unsigned int chunk_size;
     int ret = 0;
+    AVStream *st = s->streams[wsaud->audio_stream_index];
 
     if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) !=
         AUD_CHUNK_PREAMBLE_SIZE)
@@ -150,15 +153,32 @@ static int wsaud_read_packet(AVFormatContext *s,
         return AVERROR_INVALIDDATA;
 
     chunk_size = AV_RL16(&preamble[0]);
+
+    if (st->codec->codec_id == CODEC_ID_WESTWOOD_SND1) {
+        /* For Westwood SND1 audio we need to add the output size and input
+           size to the start of the packet to match what is in VQA.
+           Specifically, this is needed to signal when a packet should be
+           decoding as raw 8-bit pcm or variable-size ADPCM. */
+        int out_size = AV_RL16(&preamble[2]);
+        if ((ret = av_new_packet(pkt, chunk_size + 4)))
+            return ret;
+        if ((ret = avio_read(pb, &pkt->data[4], chunk_size)) != chunk_size)
+            return ret < 0 ? ret : AVERROR(EIO);
+        AV_WL16(&pkt->data[0], out_size);
+        AV_WL16(&pkt->data[2], chunk_size);
+
+        pkt->duration = out_size;
+    } else {
     ret= av_get_packet(pb, pkt, chunk_size);
     if (ret != chunk_size)
         return AVERROR(EIO);
-    pkt->stream_index = wsaud->audio_stream_index;
     pkt->pts = wsaud->audio_frame_counter;
     pkt->pts /= wsaud->audio_samplerate;
 
     /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
     wsaud->audio_frame_counter += (chunk_size * 2) / wsaud->audio_channels;
+    }
+    pkt->stream_index = st->index;
 
     return ret;
 }