aud: support Westwood SND1 audio in AUD files.

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
This commit is contained in:
Justin Ruggles 2012-01-24 11:09:05 -05:00
parent 02e7dbf5ad
commit d481227c54

View 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 /* note: only check for WS IMA (type 99) right now since there is no
* support for type 1 */ * support for type 1 */
if (p->buf[11] != 99) if (p->buf[11] != 99 && p->buf[11] != 1)
return 0; return 0;
/* read ahead to the first audio chunk and validate the first header signature */ /* 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]); wsaud->audio_samplerate = AV_RL16(&header[0]);
if (header[11] == 99) if (header[11] == 99)
wsaud->audio_type = CODEC_ID_ADPCM_IMA_WS; wsaud->audio_type = CODEC_ID_ADPCM_IMA_WS;
else if (header[11] == 1)
wsaud->audio_type = CODEC_ID_WESTWOOD_SND1;
else else
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
@ -121,10 +123,10 @@ static int wsaud_read_header(AVFormatContext *s,
st->codec->codec_tag = 0; /* no tag */ st->codec->codec_tag = 0; /* no tag */
st->codec->channels = wsaud->audio_channels; st->codec->channels = wsaud->audio_channels;
st->codec->sample_rate = wsaud->audio_samplerate; st->codec->sample_rate = wsaud->audio_samplerate;
st->codec->bits_per_coded_sample = wsaud->audio_bits; if (st->codec->codec_id == CODEC_ID_ADPCM_IMA_WS) {
st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample = 4;
st->codec->bits_per_coded_sample / 4; st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 4;
st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; }
wsaud->audio_stream_index = st->index; wsaud->audio_stream_index = st->index;
wsaud->audio_frame_counter = 0; wsaud->audio_frame_counter = 0;
@ -140,6 +142,7 @@ static int wsaud_read_packet(AVFormatContext *s,
unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE]; unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE];
unsigned int chunk_size; unsigned int chunk_size;
int ret = 0; int ret = 0;
AVStream *st = s->streams[wsaud->audio_stream_index];
if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) != if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) !=
AUD_CHUNK_PREAMBLE_SIZE) AUD_CHUNK_PREAMBLE_SIZE)
@ -150,15 +153,32 @@ static int wsaud_read_packet(AVFormatContext *s,
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
chunk_size = AV_RL16(&preamble[0]); 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); ret= av_get_packet(pb, pkt, chunk_size);
if (ret != chunk_size) if (ret != chunk_size)
return AVERROR(EIO); return AVERROR(EIO);
pkt->stream_index = wsaud->audio_stream_index;
pkt->pts = wsaud->audio_frame_counter; pkt->pts = wsaud->audio_frame_counter;
pkt->pts /= wsaud->audio_samplerate; pkt->pts /= wsaud->audio_samplerate;
/* 2 samples/byte, 1 or 2 samples per frame depending on stereo */ /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
wsaud->audio_frame_counter += (chunk_size * 2) / wsaud->audio_channels; wsaud->audio_frame_counter += (chunk_size * 2) / wsaud->audio_channels;
}
pkt->stream_index = st->index;
return ret; return ret;
} }