diff options
author | Matthew Hoops | 2011-04-10 14:51:24 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-04-10 14:51:24 -0400 |
commit | f9413e4dc26081f59247fa7eae62f50258e92fa4 (patch) | |
tree | 5d5a22adf1a402133480a0c7b018db1869ce48b1 /audio/decoders | |
parent | 13a6f40dbba1ae389b967b97b9c1cf83685af5e6 (diff) | |
download | scummvm-rg350-f9413e4dc26081f59247fa7eae62f50258e92fa4.tar.gz scummvm-rg350-f9413e4dc26081f59247fa7eae62f50258e92fa4.tar.bz2 scummvm-rg350-f9413e4dc26081f59247fa7eae62f50258e92fa4.zip |
AUDIO: Add support for AAC audio
Diffstat (limited to 'audio/decoders')
-rw-r--r-- | audio/decoders/aac.cpp | 178 | ||||
-rw-r--r-- | audio/decoders/aac.h | 66 | ||||
-rw-r--r-- | audio/decoders/quicktime.cpp | 72 |
3 files changed, 296 insertions, 20 deletions
diff --git a/audio/decoders/aac.cpp b/audio/decoders/aac.cpp new file mode 100644 index 0000000000..fb867250b7 --- /dev/null +++ b/audio/decoders/aac.cpp @@ -0,0 +1,178 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "audio/decoders/aac.h" + +#ifdef USE_FAAD + +#include "common/debug.h" +#include "common/stream.h" +#include "common/util.h" + +#include "audio/audiostream.h" + +#include <neaacdec.h> + +namespace Audio { + +class AACStream : public AudioStream { +public: + AACStream(Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeStream, + Common::SeekableReadStream *extraData, + DisposeAfterUse::Flag disposeExtraData); + ~AACStream(); + + int readBuffer(int16 *buffer, const int numSamples); + + bool endOfData() const { return _inBufferPos >= _inBufferSize; } + bool isStereo() const { return _channels == 2; } + int getRate() const { return _rate; } + +private: + Common::SeekableReadStream *_stream; + DisposeAfterUse::Flag _disposeAfterUse; + + NeAACDecHandle _handle; + byte _channels; + unsigned long _rate; + + byte *_inBuffer; + uint32 _inBufferSize; + uint32 _inBufferPos; + + int16 *_remainingSamples; + uint32 _remainingSamplesSize; + uint32 _remainingSamplesPos; + + void init(Common::SeekableReadStream *extraData); +}; + +AACStream::AACStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeStream, + Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) { + + _stream = stream; + _disposeAfterUse = disposeStream; + _remainingSamples = 0; + _inBufferPos = 0; + + init(extraData); + + // Copy all the data to a pointer so it can be passed through + // (At least MPEG-4 chunks shouldn't be large) + _inBufferSize = stream->size(); + _inBuffer = new byte[_inBufferSize]; + stream->read(_inBuffer, _inBufferSize); + + if (disposeStream == DisposeAfterUse::YES) + delete stream; + + if (disposeExtraData == DisposeAfterUse::YES) + delete extraData; +} + +AACStream::~AACStream() { + NeAACDecClose(_handle); + delete[] _inBuffer; + delete[] _remainingSamples; +} + +void AACStream::init(Common::SeekableReadStream *extraData) { + // Open the library + _handle = NeAACDecOpen(); + + // Configure the library to our needs + NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(_handle); + conf->outputFormat = FAAD_FMT_16BIT; // We only support 16bit audio + conf->downMatrix = 1; // Convert from 5.1 to stereo if required + NeAACDecSetConfiguration(_handle, conf); + + // Copy the extra data to a buffer + extraData->seek(0); + byte *extraDataBuf = new byte[extraData->size()]; + extraData->read(extraDataBuf, extraData->size()); + + // Initialize with our extra data + // NOTE: This code assumes the extra data is coming from an MPEG-4 file! + int err = NeAACDecInit2(_handle, extraDataBuf, extraData->size(), &_rate, &_channels); + delete[] extraDataBuf; + + if (err < 0) + error("Could not initialize AAC decoder: %s", NeAACDecGetErrorMessage(err)); +} + +int AACStream::readBuffer(int16 *buffer, const int numSamples) { + int samples = 0; + + assert((numSamples % _channels) == 0); + + if (_remainingSamples) { + samples = MIN<int>(numSamples, _remainingSamplesSize - _remainingSamplesPos); + + memcpy(buffer, _remainingSamples + _remainingSamplesPos, samples * 2); + _remainingSamplesPos += samples; + + if (_remainingSamplesPos == _remainingSamplesSize) { + delete[] _remainingSamples; + _remainingSamples = 0; + } + } + + while (samples < numSamples && !endOfData()) { + NeAACDecFrameInfo frameInfo; + uint16 *decodedSamples = (uint16 *)NeAACDecDecode(_handle, &frameInfo, _inBuffer + _inBufferPos, _inBufferSize - _inBufferPos); + + if (frameInfo.error != 0) + error("Failed to decode AAC frame: %s", NeAACDecGetErrorMessage(frameInfo.error)); + + int decodedSampleSize = frameInfo.samples; + int copySamples = (decodedSampleSize > (numSamples - samples)) ? (numSamples - samples) : decodedSampleSize; + + memcpy(buffer + samples, decodedSamples, copySamples * 2); + samples += copySamples; + + if (copySamples != decodedSampleSize) { + _remainingSamplesSize = decodedSampleSize - copySamples; + _remainingSamples = new int16[_remainingSamplesSize]; + _remainingSamplesPos = 0; + memcpy(_remainingSamples, decodedSamples + copySamples, _remainingSamplesSize * 2); + } + + _inBufferPos += frameInfo.bytesconsumed; + } + + return samples; +} + +// Factory function +AudioStream *makeAACStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeStream, + Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) { + + return new AACStream(stream, disposeStream, extraData, disposeExtraData); +} + +} // End of namespace Audio + +#endif // #ifdef USE_FAAD diff --git a/audio/decoders/aac.h b/audio/decoders/aac.h new file mode 100644 index 0000000000..f14fa9488b --- /dev/null +++ b/audio/decoders/aac.h @@ -0,0 +1,66 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/** + * @file + * Sound decoder used in engines: + * - groovie + */ + +#ifndef SOUND_AAC_H +#define SOUND_AAC_H + +#include "common/scummsys.h" +#include "common/types.h" + +#ifdef USE_FAAD + +namespace Common { + class SeekableReadStream; +} + +namespace Audio { + +class AudioStream; + +/** + * Create a new AudioStream from the AAC data in the given stream. + * + * @param stream the SeekableReadStream from which to read the AAC data + * @param disposeStream whether to delete the stream after use + * @param extraData the SeekableReadStream from which to read the AAC extra data + * @param disposeExtraData whether to delete the extra data stream after use + * @return a new AudioStream, or NULL, if an error occurred + */ +AudioStream *makeAACStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeStream, + Common::SeekableReadStream *extraData, + DisposeAfterUse::Flag disposeExtraData = DisposeAfterUse::NO); + +} // End of namespace Audio + +#endif // #ifdef USE_FAAD +#endif // #ifndef SOUND_AAC_H diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index e18ba7c480..9b69012c7a 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -32,6 +32,7 @@ #include "audio/decoders/quicktime.h" // Codecs +#include "audio/decoders/aac.h" #include "audio/decoders/adpcm.h" #include "audio/decoders/qdm2.h" #include "audio/decoders/raw.h" @@ -153,9 +154,13 @@ bool QuickTimeAudioDecoder::checkAudioCodecSupport(uint32 tag, byte objectTypeMP if (tag == MKID_BE('mp4a')) { Common::String audioType; switch (objectTypeMP4) { - case 0x40: + case 0x40: // AAC +#ifdef USE_FAAD + return true; +#else audioType = "AAC"; break; +#endif default: audioType = "Unknown"; break; @@ -190,6 +195,12 @@ AudioStream *QuickTimeAudioDecoder::createAudioStream(Common::SeekableReadStream } else if (entry->codecTag == MKID_BE('ima4')) { // Riven uses this codec (as do some Myst ME videos) return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, entry->sampleRate, entry->channels, 34); + } else if (entry->codecTag == MKID_BE('mp4a')) { + // The 7th Guest iOS uses an MPEG-4 codec +#ifdef USE_FAAD + if (_streams[_audioStreamIndex]->objectTypeMP4 == 0x40) + return makeAACStream(stream, DisposeAfterUse::YES, _streams[_audioStreamIndex]->extradata); +#endif #ifdef AUDIO_QDM2_H } else if (entry->codecTag == MKID_BE('QDM2')) { // Myst ME uses this codec for many videos @@ -225,27 +236,48 @@ void QuickTimeAudioDecoder::queueNextAudioChunk() { uint32 sampleCount = getAudioChunkSampleCount(_curAudioChunk); assert(sampleCount); - // Then calculate the right sizes - while (sampleCount > 0) { - uint32 samples = 0, size = 0; + if (_streams[_audioStreamIndex]->stts_count == 1 && _streams[_audioStreamIndex]->stts_data[0].duration == 1) { + // Old-style audio demuxing + + // Then calculate the right sizes + while (sampleCount > 0) { + uint32 samples = 0, size = 0; + + if (entry->samplesPerFrame >= 160) { + samples = entry->samplesPerFrame; + size = entry->bytesPerFrame; + } else if (entry->samplesPerFrame > 1) { + samples = MIN<uint32>((1024 / entry->samplesPerFrame) * entry->samplesPerFrame, sampleCount); + size = (samples / entry->samplesPerFrame) * entry->bytesPerFrame; + } else { + samples = MIN<uint32>(1024, sampleCount); + size = samples * _streams[_audioStreamIndex]->sample_size; + } - if (entry->samplesPerFrame >= 160) { - samples = entry->samplesPerFrame; - size = entry->bytesPerFrame; - } else if (entry->samplesPerFrame > 1) { - samples = MIN<uint32>((1024 / entry->samplesPerFrame) * entry->samplesPerFrame, sampleCount); - size = (samples / entry->samplesPerFrame) * entry->bytesPerFrame; - } else { - samples = MIN<uint32>(1024, sampleCount); - size = samples * _streams[_audioStreamIndex]->sample_size; + // Now, we read in the data for this data and output it + byte *data = (byte *)malloc(size); + _fd->read(data, size); + wStream->write(data, size); + free(data); + sampleCount -= samples; + } + } else { + // New-style audio demuxing + + // Find our starting sample + uint32 startSample = 0; + for (uint32 i = 0; i < _curAudioChunk; i++) + startSample += getAudioChunkSampleCount(i); + + for (uint32 i = 0; i < sampleCount; i++) { + uint32 size = (_streams[_audioStreamIndex]->sample_size != 0) ? _streams[_audioStreamIndex]->sample_size : _streams[_audioStreamIndex]->sample_sizes[i + startSample]; + + // Now, we read in the data for this data and output it + byte *data = (byte *)malloc(size); + _fd->read(data, size); + wStream->write(data, size); + free(data); } - - // Now, we read in the data for this data and output it - byte *data = (byte *)malloc(size); - _fd->read(data, size); - wStream->write(data, size); - free(data); - sampleCount -= samples; } // Now queue the buffer |