Matthew Hoops a1d41da096 Merge remote branch 'upstream/master' into t7g-ios
Conflicts:
	audio/decoders/qdm2.h
	common/util.cpp
	engines/groovie/music.cpp
	engines/groovie/resource.h
	video/qt_decoder.cpp
	video/qt_decoder.h
2011-05-11 00:30:28 -04:00

178 lines
5.3 KiB
C++

/* 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/textconsole.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 && !_remainingSamples; }
bool isStereo() const { return _channels == 2; }
int getRate() const { return _rate; }
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) {
// 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);
// Dip into our remaining samples pool if it's available
if (_remainingSamples) {
samples = MIN<int>(numSamples, _remainingSamplesSize - _remainingSamplesPos);
memcpy(buffer, _remainingSamples + _remainingSamplesPos, samples * 2);
_remainingSamplesPos += samples;
if (_remainingSamplesPos == _remainingSamplesSize) {
delete[] _remainingSamples;
_remainingSamples = 0;
}
}
// Decode until we have enough samples (or there's no more left)
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;
// 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);
}
_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