PCM format AUD files are found in Westwood's Blade Runner game. --- libavformat/westwood_aud.c | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-)
diff --git a/libavformat/westwood_aud.c b/libavformat/westwood_aud.c index 9c2d35cb8a..5d7e827bc1 100644 --- a/libavformat/westwood_aud.c +++ b/libavformat/westwood_aud.c @@ -41,6 +41,12 @@ #define AUD_HEADER_SIZE 12 #define AUD_CHUNK_PREAMBLE_SIZE 8 #define AUD_CHUNK_SIGNATURE 0x0000DEAF +#define AUD_PCM_CHUNK_SIZE 2048 /* arbitrary size to pull out of PCM data*/ + +typedef struct AUDDemuxContext { + int size; + int pos; +} AUDDemuxContext; static int wsaud_probe(AVProbeData *p) { @@ -50,10 +56,10 @@ static int wsaud_probe(AVProbeData *p) * so perform sanity checks on various header parameters: * 8000 <= sample rate (16 bits) <= 48000 ==> 40001 acceptable numbers * flags <= 0x03 (2 LSBs are used) ==> 4 acceptable numbers - * compression type (8 bits) = 1 or 99 ==> 2 acceptable numbers + * compression type (8 bits) = 0, 1 or 99 ==> 3 acceptable numbers * first audio chunk signature (32 bits) ==> 1 acceptable number - * The number space contains 2^64 numbers. There are 40001 * 4 * 2 * 1 = - * 320008 acceptable number combinations. + * The number space contains 2^64 numbers. There are 40001 * 4 * 3 * 1 = + * 480012 acceptable number combinations. */ if (p->buf_size < AUD_HEADER_SIZE + AUD_CHUNK_PREAMBLE_SIZE) @@ -69,13 +75,22 @@ static int wsaud_probe(AVProbeData *p) if (p->buf[10] & 0xFC) return 0; - if (p->buf[11] != 99 && p->buf[11] != 1) + /* valid format values are 99 == adpcm, 1 == snd1 and 0 == pcm */ + if (p->buf[11] != 99 && p->buf[11] != 1 && p->buf[11] != 0) return 0; - /* read ahead to the first audio chunk and validate the first header signature */ - if (AV_RL32(&p->buf[16]) != AUD_CHUNK_SIGNATURE) + /* read ahead to the first audio chunk and validate the first header + * signature pcm format does not use a chunk format, so don't check + * for that codec */ + if (p->buf[11] != 0 && AV_RL32(&p->buf[16]) != AUD_CHUNK_SIGNATURE) return 0; + /* if we have pcm format then compressed size should equal + * uncompressed size */ + if (p->buf[11] == 0 && AV_RL32(&p->buf[2]) != AV_RL32(&p->buf[6])) { + return 0; + } + /* return 1/2 certainty since this file check is a little sketchy */ return AVPROBE_SCORE_EXTENSION; } @@ -83,16 +98,20 @@ static int wsaud_probe(AVProbeData *p) static int wsaud_read_header(AVFormatContext *s) { AVIOContext *pb = s->pb; + AUDDemuxContext *aud = s->priv_data; AVStream *st; unsigned char header[AUD_HEADER_SIZE]; - int sample_rate, channels, codec; + int sample_rate, channels, codec, bits_per_sample; if (avio_read(pb, header, AUD_HEADER_SIZE) != AUD_HEADER_SIZE) return AVERROR(EIO); sample_rate = AV_RL16(&header[0]); channels = (header[10] & 0x1) + 1; + bits_per_sample = (header[10] & 0x2) ? 16 : 8; codec = header[11]; + aud->size = AV_RL32(&header[2]); + aud->pos = 0; /* used to track position in a PCM stream */ /* initialize the audio decoder stream */ st = avformat_new_stream(s, NULL); @@ -100,6 +119,15 @@ static int wsaud_read_header(AVFormatContext *s) return AVERROR(ENOMEM); switch (codec) { + case 0: + if (bits_per_sample == 8) { + st->codecpar->codec_id = AV_CODEC_ID_PCM_U8; + } else { + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + } + st->codecpar->bits_per_coded_sample = bits_per_sample; + st->codecpar->bit_rate = channels * sample_rate * bits_per_sample; + break; case 1: if (channels != 1) { avpriv_request_sample(s, "Stereo WS-SND1"); @@ -130,20 +158,24 @@ static int wsaud_read_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; + AUDDemuxContext *aud = s->priv_data; unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE]; - unsigned int chunk_size; + unsigned int chunk_size, bytes_per_sample; int ret = 0; AVStream *st = s->streams[0]; - if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) != - AUD_CHUNK_PREAMBLE_SIZE) - return AVERROR(EIO); + /* AUD files don't store PCM audio in chunks */ + if (st->codecpar->codec_id != AV_CODEC_ID_PCM_S16LE) { + if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) != + AUD_CHUNK_PREAMBLE_SIZE) + return AVERROR(EIO); - /* validate the chunk */ - if (AV_RL32(&preamble[4]) != AUD_CHUNK_SIGNATURE) - return AVERROR_INVALIDDATA; + /* validate the chunk */ + if (AV_RL32(&preamble[4]) != AUD_CHUNK_SIGNATURE) + return AVERROR_INVALIDDATA; - chunk_size = AV_RL16(&preamble[0]); + chunk_size = AV_RL16(&preamble[0]); + } if (st->codecpar->codec_id == AV_CODEC_ID_WESTWOOD_SND1) { /* For Westwood SND1 audio we need to add the output size and input @@ -159,7 +191,7 @@ static int wsaud_read_packet(AVFormatContext *s, AV_WL16(&pkt->data[2], chunk_size); pkt->duration = out_size; - } else { + } else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WS) { ret = av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) return AVERROR(EIO); @@ -172,7 +204,20 @@ static int wsaud_read_packet(AVFormatContext *s, /* 2 samples/byte, 1 or 2 samples per frame depending on stereo */ pkt->duration = (chunk_size * 2) / st->codecpar->channels; - } + } else { + chunk_size = FFMIN(aud->size - aud->pos, AUD_PCM_CHUNK_SIZE); + if(chunk_size <= 0) + return AVERROR_EOF; + + aud->pos += chunk_size; + ret = av_get_packet(pb, pkt, chunk_size); + if (ret != chunk_size) + return AVERROR(EIO); + + bytes_per_sample = st->codecpar->bits_per_coded_sample / 8; + pkt->duration = (chunk_size / bytes_per_sample) / + st->codecpar->channels; + } pkt->stream_index = st->index; return ret; @@ -181,6 +226,7 @@ static int wsaud_read_packet(AVFormatContext *s, AVInputFormat ff_wsaud_demuxer = { .name = "wsaud", .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios audio"), + .priv_data_size = sizeof(AUDDemuxContext), .read_probe = wsaud_probe, .read_header = wsaud_read_header, .read_packet = wsaud_read_packet, -- 2.16.1.windows.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel