diff options
author | Matthew Hoops | 2011-07-10 15:20:33 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-07-10 15:50:47 -0400 |
commit | c46aa548d6d8a1eabb968bfd0152215490bf746c (patch) | |
tree | 2d69f3ce5415f13a1b55af1f7efc5a5b43b1c4f4 /audio/decoders | |
parent | 0d02cc0ef5efe1ed3d16904f6622fa9cd520be1d (diff) | |
download | scummvm-rg350-c46aa548d6d8a1eabb968bfd0152215490bf746c.tar.gz scummvm-rg350-c46aa548d6d8a1eabb968bfd0152215490bf746c.tar.bz2 scummvm-rg350-c46aa548d6d8a1eabb968bfd0152215490bf746c.zip |
AUDIO: Fix remaining AAC bugs by decoding with the same AAC context
This introduces a new Audio::Codec class, based on DrMcCoy's solution for WMA in eos.
Diffstat (limited to 'audio/decoders')
-rw-r--r-- | audio/decoders/aac.cpp | 120 | ||||
-rw-r--r-- | audio/decoders/aac.h | 12 | ||||
-rw-r--r-- | audio/decoders/codec.h | 47 | ||||
-rw-r--r-- | audio/decoders/quicktime.cpp | 41 | ||||
-rw-r--r-- | audio/decoders/quicktime_intern.h | 5 |
5 files changed, 127 insertions, 98 deletions
diff --git a/audio/decoders/aac.cpp b/audio/decoders/aac.cpp index 874062a702..50325dc9f0 100644 --- a/audio/decoders/aac.cpp +++ b/audio/decoders/aac.cpp @@ -28,74 +28,34 @@ #ifdef USE_FAAD #include "common/debug.h" +#include "common/memstream.h" #include "common/stream.h" #include "common/textconsole.h" #include "common/util.h" #include "audio/audiostream.h" +#include "audio/decoders/codec.h" +#include "audio/decoders/raw.h" #include <neaacdec.h> namespace Audio { -class AACStream : public AudioStream { +class AACDecoder : public Codec { public: - AACStream(Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeStream, - Common::SeekableReadStream *extraData, + AACDecoder(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData); - ~AACStream(); + ~AACDecoder(); - int readBuffer(int16 *buffer, const int numSamples); - - bool endOfData() const { return _inBufferPos >= _inBufferSize && !_remainingSamples; } - bool isStereo() const { return _channels == 2; } - int getRate() const { return _rate; } + AudioStream *decodeFrame(Common::SeekableReadStream &stream); private: 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) { - - _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) { +AACDecoder::AACDecoder(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) { // Open the library _handle = NeAACDecOpen(); @@ -117,59 +77,55 @@ void AACStream::init(Common::SeekableReadStream *extraData) { 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 (disposeExtraData == DisposeAfterUse::YES) + delete extraData; +} - // Dip into our remaining samples pool if it's available - if (_remainingSamples) { - samples = MIN<int>(numSamples, _remainingSamplesSize - _remainingSamplesPos); +AACDecoder::~AACDecoder() { + NeAACDecClose(_handle); +} - memcpy(buffer, _remainingSamples + _remainingSamplesPos, samples * 2); - _remainingSamplesPos += samples; +AudioStream *AACDecoder::decodeFrame(Common::SeekableReadStream &stream) { + // read everything into a buffer + uint32 inBufferPos = 0; + uint32 inBufferSize = stream.size(); + byte *inBuffer = new byte[inBufferSize]; + stream.read(inBuffer, inBufferSize); - if (_remainingSamplesPos == _remainingSamplesSize) { - delete[] _remainingSamples; - _remainingSamples = 0; - } - } + QueuingAudioStream *audioStream = makeQueuingAudioStream(_rate, _channels == 2); // Decode until we have enough samples (or there's no more left) - while (samples < numSamples && !endOfData()) { + while (inBufferPos < inBufferSize) { NeAACDecFrameInfo frameInfo; - uint16 *decodedSamples = (uint16 *)NeAACDecDecode(_handle, &frameInfo, _inBuffer + _inBufferPos, _inBufferSize - _inBufferPos); + void *decodedSamples = 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; + byte *buffer = (byte *)malloc(frameInfo.samples * 2); + memcpy(buffer, decodedSamples, frameInfo.samples * 2); - memcpy(buffer + samples, decodedSamples, copySamples * 2); - samples += copySamples; + byte flags = FLAG_16BITS; - // Copy leftover samples for use in a later readBuffer() call - if (copySamples != decodedSampleSize) { - _remainingSamplesSize = decodedSampleSize - copySamples; - _remainingSamples = new int16[_remainingSamplesSize]; - _remainingSamplesPos = 0; - memcpy(_remainingSamples, decodedSamples + copySamples, _remainingSamplesSize * 2); - } + if (_channels == 2) + flags |= FLAG_STEREO; - _inBufferPos += frameInfo.bytesconsumed; +#ifdef SCUMM_LITTLE_ENDIAN + flags |= FLAG_LITTLE_ENDIAN; +#endif + + audioStream->queueBuffer(buffer, frameInfo.samples * 2, DisposeAfterUse::YES, flags); + + inBufferPos += frameInfo.bytesconsumed; } - return samples; + return audioStream; } // Factory function -AudioStream *makeAACStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeStream, - Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) { - - return new AACStream(stream, disposeStream, extraData, disposeExtraData); +Codec *makeAACDecoder(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) { + return new AACDecoder(extraData, disposeExtraData); } } // End of namespace Audio diff --git a/audio/decoders/aac.h b/audio/decoders/aac.h index efcbcc6f42..c5085fadaa 100644 --- a/audio/decoders/aac.h +++ b/audio/decoders/aac.h @@ -43,23 +43,19 @@ namespace Common { namespace Audio { -class AudioStream; +class Codec; /** - * Create a new AudioStream from the AAC data of an MPEG-4 file in the given stream. + * Create a new Codec for decoding AAC data of an MPEG-4 file in the given stream. * * @note This should *only* be called by our QuickTime/MPEG-4 decoder since it relies * on the MPEG-4 extra data. If you want to decode a file using AAC, go use * makeQuickTimeStream() instead! - * @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 + * @return a new Codec, or NULL, if an error occurred */ -AudioStream *makeAACStream( - Common::SeekableReadStream *stream, - DisposeAfterUse::Flag disposeStream, +Codec *makeAACDecoder( Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData = DisposeAfterUse::NO); diff --git a/audio/decoders/codec.h b/audio/decoders/codec.h new file mode 100644 index 0000000000..fde7e59f54 --- /dev/null +++ b/audio/decoders/codec.h @@ -0,0 +1,47 @@ +/* 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$ + * + */ + +#ifndef AUDIO_DECODERS_CODEC_H +#define AUDIO_DECODERS_CODEC_H + +namespace Common { + class SeekableReadStream; +} + +namespace Audio { + +class AudioStream; + +class Codec { +public: + Codec() {} + virtual ~Codec() {} + + virtual AudioStream *decodeFrame(Common::SeekableReadStream &data) = 0; +}; + +} // End of namespace Audio + +#endif diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 0ad2821cd5..4531ccee19 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -30,6 +30,7 @@ #include "common/textconsole.h" #include "audio/audiostream.h" +#include "audio/decoders/codec.h" #include "audio/decoders/quicktime.h" #include "audio/decoders/quicktime_intern.h" @@ -86,6 +87,9 @@ void QuickTimeAudioDecoder::init() { // Make sure the bits per sample transfers to the sample size if (entry->getCodecTag() == MKTAG('r', 'a', 'w', ' ') || entry->getCodecTag() == MKTAG('t', 'w', 'o', 's')) _tracks[_audioTrackIndex]->sampleSize = (entry->_bitsPerSample / 8) * entry->_channels; + + // Initialize the codec (if necessary) + entry->initCodec(); } } } @@ -217,6 +221,9 @@ void QuickTimeAudioDecoder::setAudioStreamPos(const Timestamp &where) { Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_tracks[_audioTrackIndex]->sampleDescs[0]; _audStream = Audio::makeQueuingAudioStream(entry->_sampleRate, entry->_channels == 2); + // Reinitialize the codec + entry->initCodec(); + // First, we need to track down what audio sample we need Audio::Timestamp curAudioTime = where.convertToFramerate(_tracks[_audioTrackIndex]->timeScale); uint32 sample = curAudioTime.totalNumberOfFrames(); @@ -266,6 +273,11 @@ QuickTimeAudioDecoder::AudioSampleDesc::AudioSampleDesc(Common::QuickTimeParser: _samplesPerFrame = 0; _bytesPerFrame = 0; _bitsPerSample = 0; + _codec = 0; +} + +QuickTimeAudioDecoder::AudioSampleDesc::~AudioSampleDesc() { + delete _codec; } bool QuickTimeAudioDecoder::AudioSampleDesc::isAudioCodecSupported() const { @@ -313,7 +325,12 @@ AudioStream *QuickTimeAudioDecoder::AudioSampleDesc::createAudioStream(Common::S if (!stream) return 0; - if (_codecTag == MKTAG('t', 'w', 'o', 's') || _codecTag == MKTAG('r', 'a', 'w', ' ')) { + if (_codec) { + // If we've loaded a codec, make sure we use first + AudioStream *audioStream = _codec->decodeFrame(*stream); + delete stream; + return audioStream; + } else if (_codecTag == MKTAG('t', 'w', 'o', 's') || _codecTag == MKTAG('r', 'a', 'w', ' ')) { // Fortunately, most of the audio used in Myst videos is raw... uint16 flags = 0; if (_codecTag == MKTAG('r', 'a', 'w', ' ')) @@ -330,12 +347,6 @@ AudioStream *QuickTimeAudioDecoder::AudioSampleDesc::createAudioStream(Common::S } else if (_codecTag == MKTAG('i', 'm', 'a', '4')) { // Riven uses this codec (as do some Myst ME videos) return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, _sampleRate, _channels, 34); - } else if (_codecTag == MKTAG('m', 'p', '4', 'a')) { - // The 7th Guest iOS uses an MPEG-4 codec -#ifdef USE_FAAD - if (_parentTrack->objectTypeMP4 == 0x40) - return makeAACStream(stream, DisposeAfterUse::YES, _parentTrack->extraData); -#endif #ifdef AUDIO_QDM2_H } else if (_codecTag == MKTAG('Q', 'D', 'M', '2')) { // Myst ME uses this codec for many videos @@ -344,10 +355,24 @@ AudioStream *QuickTimeAudioDecoder::AudioSampleDesc::createAudioStream(Common::S } error("Unsupported audio codec"); - return NULL; } +void QuickTimeAudioDecoder::AudioSampleDesc::initCodec() { + delete _codec; _codec = 0; + + switch (_codecTag) { + case MKTAG('m', 'p', '4', 'a'): +#ifdef USE_FAAD + if (_parentTrack->objectTypeMP4 == 0x40) + _codec = makeAACDecoder(_parentTrack->extraData); +#endif + break; + default: + break; + } +} + /** * A wrapper around QuickTimeAudioDecoder that implements the RewindableAudioStream API */ diff --git a/audio/decoders/quicktime_intern.h b/audio/decoders/quicktime_intern.h index f288d5604b..7ce06b85fe 100644 --- a/audio/decoders/quicktime_intern.h +++ b/audio/decoders/quicktime_intern.h @@ -45,6 +45,7 @@ namespace Common { namespace Audio { class AudioStream; +class Codec; class QueuingAudioStream; class QuickTimeAudioDecoder : public Common::QuickTimeParser { @@ -68,10 +69,12 @@ protected: class AudioSampleDesc : public Common::QuickTimeParser::SampleDesc { public: AudioSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag); + ~AudioSampleDesc(); bool isAudioCodecSupported() const; uint32 getAudioChunkSampleCount(uint chunk) const; AudioStream *createAudioStream(Common::SeekableReadStream *stream) const; + void initCodec(); // TODO: Make private in the long run uint16 _bitsPerSample; @@ -79,6 +82,8 @@ protected: uint32 _sampleRate; uint32 _samplesPerFrame; uint32 _bytesPerFrame; + + Codec *_codec; }; // Common::QuickTimeParser API |