ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

quicktime.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/debug.h"
00024 #include "common/util.h"
00025 #include "common/memstream.h"
00026 #include "common/stream.h"
00027 #include "common/textconsole.h"
00028 
00029 #include "audio/decoders/codec.h"
00030 #include "audio/decoders/quicktime.h"
00031 #include "audio/decoders/quicktime_intern.h"
00032 
00033 // Codecs
00034 #include "audio/decoders/aac.h"
00035 #include "audio/decoders/adpcm.h"
00036 #include "audio/decoders/qdm2.h"
00037 #include "audio/decoders/raw.h"
00038 
00039 namespace Audio {
00040 
00046 class SilentAudioStream : public AudioStream {
00047 public:
00048     SilentAudioStream(int rate, bool stereo) : _rate(rate), _isStereo(stereo) {}
00049 
00050     int readBuffer(int16 *buffer, const int numSamples) {
00051         memset(buffer, 0, numSamples * 2);
00052         return numSamples;
00053     }
00054 
00055     bool endOfData() const { return false; } // it never ends!
00056     bool isStereo() const { return _isStereo; }
00057     int getRate() const { return _rate; }
00058 
00059 private:
00060     int _rate;
00061     bool _isStereo;
00062 };
00063 
00068 class ForcedMonoAudioStream : public AudioStream {
00069 public:
00070     ForcedMonoAudioStream(AudioStream *parentStream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) :
00071             _parentStream(parentStream), _disposeAfterUse(disposeAfterUse) {}
00072 
00073     ~ForcedMonoAudioStream() {
00074         if (_disposeAfterUse == DisposeAfterUse::YES)
00075                 delete _parentStream;
00076     }
00077 
00078     int readBuffer(int16 *buffer, const int numSamples) {
00079         if (!_parentStream->isStereo())
00080             return _parentStream->readBuffer(buffer, numSamples);
00081 
00082         int16 temp[2];
00083         int samples = 0;
00084 
00085         while (samples < numSamples && !endOfData()) {
00086             _parentStream->readBuffer(temp, 2);
00087             *buffer++ = temp[0];
00088             samples++;
00089         }
00090 
00091         return samples;
00092     }
00093 
00094     bool endOfData() const { return _parentStream->endOfData(); }
00095     bool isStereo() const { return false; }
00096     int getRate() const { return _parentStream->getRate(); }
00097 
00098 private:
00099     AudioStream *_parentStream;
00100     DisposeAfterUse::Flag _disposeAfterUse;
00101 };
00102 
00103 QuickTimeAudioDecoder::QuickTimeAudioDecoder() : Common::QuickTimeParser() {
00104 }
00105 
00106 QuickTimeAudioDecoder::~QuickTimeAudioDecoder() {
00107     for (uint32 i = 0; i < _audioTracks.size(); i++)
00108         delete _audioTracks[i];
00109 }
00110 
00111 bool QuickTimeAudioDecoder::loadAudioFile(const Common::String &filename) {
00112     if (!Common::QuickTimeParser::parseFile(filename))
00113         return false;
00114 
00115     init();
00116     return true;
00117 }
00118 
00119 bool QuickTimeAudioDecoder::loadAudioStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeFileHandle) {
00120     if (!Common::QuickTimeParser::parseStream(stream, disposeFileHandle))
00121         return false;
00122 
00123     init();
00124     return true;
00125 }
00126 
00127 void QuickTimeAudioDecoder::init() {
00128     Common::QuickTimeParser::init();
00129 
00130     // Initialize all the audio streams
00131     // But ignore any streams we don't support
00132     for (uint32 i = 0; i < _tracks.size(); i++)
00133         if (_tracks[i]->codecType == CODEC_TYPE_AUDIO && ((AudioSampleDesc *)_tracks[i]->sampleDescs[0])->isAudioCodecSupported())
00134             _audioTracks.push_back(new QuickTimeAudioTrack(this, _tracks[i]));
00135 }
00136 
00137 Common::QuickTimeParser::SampleDesc *QuickTimeAudioDecoder::readSampleDesc(Track *track, uint32 format, uint32 descSize) {
00138     if (track->codecType == CODEC_TYPE_AUDIO) {
00139         debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
00140 
00141         AudioSampleDesc *entry = new AudioSampleDesc(track, format);
00142 
00143         uint16 stsdVersion = _fd->readUint16BE();
00144         _fd->readUint16BE(); // revision level
00145         _fd->readUint32BE(); // vendor
00146 
00147         entry->_channels = _fd->readUint16BE();          // channel count
00148         entry->_bitsPerSample = _fd->readUint16BE();      // sample size
00149 
00150         _fd->readUint16BE(); // compression id = 0
00151         _fd->readUint16BE(); // packet size = 0
00152 
00153         entry->_sampleRate = (_fd->readUint32BE() >> 16);
00154 
00155         debug(0, "stsd version =%d", stsdVersion);
00156         if (stsdVersion == 0) {
00157             // Not used, except in special cases. See below.
00158             entry->_samplesPerFrame = entry->_bytesPerFrame = 0;
00159         } else if (stsdVersion == 1) {
00160             // Read QT version 1 fields. In version 0 these dont exist.
00161             entry->_samplesPerFrame = _fd->readUint32BE();
00162             debug(0, "stsd samples_per_frame =%d",entry->_samplesPerFrame);
00163             _fd->readUint32BE(); // bytes per packet
00164             entry->_bytesPerFrame = _fd->readUint32BE();
00165             debug(0, "stsd bytes_per_frame =%d", entry->_bytesPerFrame);
00166             _fd->readUint32BE(); // bytes per sample
00167         } else {
00168             warning("Unsupported QuickTime STSD audio version %d", stsdVersion);
00169             delete entry;
00170             return 0;
00171         }
00172 
00173         // Version 0 files don't have some variables set, so we'll do that here
00174         if (format == MKTAG('i', 'm', 'a', '4')) {
00175             entry->_samplesPerFrame = 64;
00176             entry->_bytesPerFrame = 34 * entry->_channels;
00177         }
00178 
00179         if (entry->_sampleRate == 0 && track->timeScale > 1)
00180             entry->_sampleRate = track->timeScale;
00181 
00182         return entry;
00183     }
00184 
00185     return 0;
00186 }
00187 
00188 QuickTimeAudioDecoder::QuickTimeAudioTrack::QuickTimeAudioTrack(QuickTimeAudioDecoder *decoder, Common::QuickTimeParser::Track *parentTrack) {
00189     _decoder = decoder;
00190     _parentTrack = parentTrack;
00191     _queue = createStream();
00192     _samplesQueued = 0;
00193 
00194     AudioSampleDesc *entry = (AudioSampleDesc *)_parentTrack->sampleDescs[0];
00195 
00196     if (entry->getCodecTag() == MKTAG('r', 'a', 'w', ' ') || entry->getCodecTag() == MKTAG('t', 'w', 'o', 's'))
00197         _parentTrack->sampleSize = (entry->_bitsPerSample / 8) * entry->_channels;
00198 
00199     // Initialize our edit parser too
00200     _curEdit = 0;
00201     enterNewEdit(Timestamp());
00202 
00203     // If the edit doesn't start on a nice boundary, set us up to skip some samples
00204     Timestamp editStartTime(0, _parentTrack->editList[_curEdit].mediaTime, _parentTrack->timeScale);
00205     Timestamp trackPosition = getCurrentTrackTime();
00206     if (_parentTrack->editList[_curEdit].mediaTime != -1 && trackPosition != editStartTime)
00207         _skipSamples = editStartTime.convertToFramerate(getRate()) - trackPosition;
00208 }
00209 
00210 QuickTimeAudioDecoder::QuickTimeAudioTrack::~QuickTimeAudioTrack() {
00211     delete _queue;
00212 }
00213 
00214 void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &length) {
00215     if (allDataRead() || (length.totalNumberOfFrames() != 0 && Timestamp(0, _samplesQueued, getRate()) >= length))
00216         return;
00217 
00218     do {
00219         Timestamp nextEditTime(0, _parentTrack->editList[_curEdit].timeOffset + _parentTrack->editList[_curEdit].trackDuration, _decoder->_timeScale);
00220 
00221         if (_parentTrack->editList[_curEdit].mediaTime == -1) {
00222             // We've got an empty edit, so fill it with silence
00223             Timestamp editLength(0, _parentTrack->editList[_curEdit].trackDuration, _decoder->_timeScale);
00224 
00225             // If we seek into the middle of an empty edit, we need to adjust
00226             if (_skipSamples != Timestamp()) {
00227                 editLength = editLength - _skipSamples;
00228                 _skipSamples = Timestamp();
00229             }
00230 
00231             queueStream(makeLimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength);
00232             _curEdit++;
00233             enterNewEdit(nextEditTime);
00234         } else {
00235             // Normal audio
00236             AudioStream *stream = readAudioChunk(_curChunk);
00237             Timestamp chunkLength = getChunkLength(_curChunk, _skipAACPrimer);
00238             _skipAACPrimer = false;
00239             _curChunk++;
00240 
00241             // If we have any samples that we need to skip (ie. we seeked into
00242             // the middle of a chunk), skip them here.
00243             if (_skipSamples != Timestamp()) {
00244                 if (_skipSamples > chunkLength) {
00245                     // If the amount we need to skip is greater than the size
00246                     // of the chunk, just skip it altogether.
00247                     _curMediaPos = _curMediaPos + chunkLength;
00248                     _skipSamples = _skipSamples - chunkLength;
00249                     delete stream;
00250                     continue;
00251                 }
00252 
00253                 skipSamples(_skipSamples, stream);
00254                 _curMediaPos = _curMediaPos + _skipSamples;
00255                 chunkLength = chunkLength - _skipSamples;
00256                 _skipSamples = Timestamp();
00257             }
00258 
00259             // Calculate our overall position within the media
00260             Timestamp trackPosition = getCurrentTrackTime() + chunkLength;
00261 
00262             // If we have reached the end of this edit (or have no more media to read),
00263             // we move on to the next edit
00264             if (trackPosition >= nextEditTime || _curChunk >= _parentTrack->chunkCount) {
00265                 chunkLength = nextEditTime.convertToFramerate(getRate()) - getCurrentTrackTime();
00266                 stream = makeLimitingAudioStream(stream, chunkLength);
00267                 _curEdit++;
00268                 enterNewEdit(nextEditTime);
00269 
00270                 // Next time around, we'll know how much to skip
00271                 trackPosition = getCurrentTrackTime();
00272                 if (!allDataRead() && _parentTrack->editList[_curEdit].mediaTime != -1 && nextEditTime != trackPosition)
00273                     _skipSamples = nextEditTime.convertToFramerate(getRate()) - trackPosition;
00274             } else {
00275                 _curMediaPos = _curMediaPos + chunkLength.convertToFramerate(_curMediaPos.framerate());
00276             }
00277 
00278             queueStream(stream, chunkLength);
00279         }
00280     } while (!allDataRead() && Timestamp(0, _samplesQueued, getRate()) < length);
00281 }
00282 
00283 Timestamp QuickTimeAudioDecoder::QuickTimeAudioTrack::getCurrentTrackTime() const {
00284     if (allDataRead())
00285         return getLength().convertToFramerate(getRate());
00286 
00287     return Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale).convertToFramerate(getRate())
00288             + _curMediaPos - Timestamp(0, _parentTrack->editList[_curEdit].mediaTime, _parentTrack->timeScale).convertToFramerate(getRate());
00289 }
00290 
00291 void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueRemainingAudio() {
00292     queueAudio(getLength());
00293 }
00294 
00295 int QuickTimeAudioDecoder::QuickTimeAudioTrack::readBuffer(int16 *buffer, const int numSamples) {
00296     int samplesRead = _queue->readBuffer(buffer, numSamples);
00297     _samplesQueued -= samplesRead / (isStereo() ? 2 : 1);
00298     return samplesRead;
00299 }
00300 
00301 bool QuickTimeAudioDecoder::QuickTimeAudioTrack::allDataRead() const {
00302     return _curEdit == _parentTrack->editList.size();
00303 }
00304 
00305 bool QuickTimeAudioDecoder::QuickTimeAudioTrack::endOfData() const {
00306     return allDataRead() && _queue->endOfData();
00307 }
00308 
00309 bool QuickTimeAudioDecoder::QuickTimeAudioTrack::seek(const Timestamp &where) {
00310     // Recreate the queue
00311     delete _queue;
00312     _queue = createStream();
00313     _samplesQueued = 0;
00314 
00315     if (where >= getLength()) {
00316         // We're done
00317         _curEdit = _parentTrack->editList.size();
00318         return true;
00319     }
00320 
00321     // Find where we are in the stream
00322     findEdit(where);
00323 
00324     // Now queue up some audio and skip whatever we need to skip
00325     Timestamp samplesToSkip = where.convertToFramerate(getRate()) - getCurrentTrackTime();
00326     queueAudio();
00327     skipSamples(samplesToSkip, _queue);
00328 
00329     return true;
00330 }
00331 
00332 Timestamp QuickTimeAudioDecoder::QuickTimeAudioTrack::getLength() const {
00333     return Timestamp(0, _parentTrack->duration, _decoder->_timeScale);
00334 }
00335 
00336 QueuingAudioStream *QuickTimeAudioDecoder::QuickTimeAudioTrack::createStream() const {
00337     AudioSampleDesc *entry = (AudioSampleDesc *)_parentTrack->sampleDescs[0];
00338     return makeQueuingAudioStream(entry->_sampleRate, entry->_channels == 2);
00339 }
00340 
00341 bool QuickTimeAudioDecoder::QuickTimeAudioTrack::isOldDemuxing() const {
00342     return _parentTrack->timeToSampleCount == 1 && _parentTrack->timeToSample[0].duration == 1;
00343 }
00344 
00345 AudioStream *QuickTimeAudioDecoder::QuickTimeAudioTrack::readAudioChunk(uint chunk) {
00346     AudioSampleDesc *entry = (AudioSampleDesc *)_parentTrack->sampleDescs[0];
00347     Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::NO);
00348 
00349     _decoder->_fd->seek(_parentTrack->chunkOffsets[chunk]);
00350 
00351     // First, we have to get the sample count
00352     uint32 sampleCount = getAudioChunkSampleCount(chunk);
00353     assert(sampleCount != 0);
00354 
00355     if (isOldDemuxing()) {
00356         // Old-style audio demuxing
00357 
00358         // Then calculate the right sizes
00359         while (sampleCount > 0) {
00360             uint32 samples = 0, size = 0;
00361 
00362             if (entry->_samplesPerFrame >= 160) {
00363                 samples = entry->_samplesPerFrame;
00364                 size = entry->_bytesPerFrame;
00365             } else if (entry->_samplesPerFrame > 1) {
00366                 samples = MIN<uint32>((1024 / entry->_samplesPerFrame) * entry->_samplesPerFrame, sampleCount);
00367                 size = (samples / entry->_samplesPerFrame) * entry->_bytesPerFrame;
00368             } else {
00369                 samples = MIN<uint32>(1024, sampleCount);
00370                 size = samples * _parentTrack->sampleSize;
00371             }
00372 
00373             // Now, we read in the data for this data and output it
00374             byte *data = (byte *)malloc(size);
00375             _decoder->_fd->read(data, size);
00376             wStream->write(data, size);
00377             free(data);
00378             sampleCount -= samples;
00379         }
00380     } else {
00381         // New-style audio demuxing
00382 
00383         // Find our starting sample
00384         uint32 startSample = 0;
00385         for (uint32 i = 0; i < chunk; i++)
00386             startSample += getAudioChunkSampleCount(i);
00387 
00388         for (uint32 i = 0; i < sampleCount; i++) {
00389             uint32 size = (_parentTrack->sampleSize != 0) ? _parentTrack->sampleSize : _parentTrack->sampleSizes[i + startSample];
00390 
00391             // Now, we read in the data for this data and output it
00392             byte *data = (byte *)malloc(size);
00393             _decoder->_fd->read(data, size);
00394             wStream->write(data, size);
00395             free(data);
00396         }
00397     }
00398 
00399     AudioStream *audioStream = entry->createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES));
00400     delete wStream;
00401 
00402     return audioStream;
00403 }
00404 
00405 void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &length, AudioStream *stream) {
00406     int32 sampleCount = length.convertToFramerate(getRate()).totalNumberOfFrames();
00407 
00408     if (sampleCount <= 0)
00409         return;
00410 
00411     if (isStereo())
00412         sampleCount *= 2;
00413 
00414     int16 *tempBuffer = new int16[sampleCount];
00415     uint32 result = stream->readBuffer(tempBuffer, sampleCount);
00416     delete[] tempBuffer;
00417 
00418     // If this is the queue, make sure we subtract this number from the
00419     // amount queued
00420     if (stream == _queue)
00421         _samplesQueued -= result / (isStereo() ? 2 : 1);
00422 }
00423 
00424 void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) {
00425     // Go through the edits look for where we find out we need to be. As long
00426     // as the position is >= to the edit's start time, it is considered to be in that
00427     // edit. seek() already figured out if we reached the last edit, so we don't need
00428     // to handle that case here.
00429     for (_curEdit = 0; _curEdit < _parentTrack->editList.size() - 1; _curEdit++) {
00430         Timestamp nextEditTime(0, _parentTrack->editList[_curEdit + 1].timeOffset, _decoder->_timeScale);
00431         if (position < nextEditTime)
00432             break;
00433     }
00434 
00435     enterNewEdit(position);
00436 }
00437 
00438 void QuickTimeAudioDecoder::QuickTimeAudioTrack::enterNewEdit(const Timestamp &position) {
00439     _skipSamples = Timestamp(); // make sure our skip variable doesn't remain around
00440 
00441     // If we're at the end of the edit list, there's nothing else for us to do here
00442     if (allDataRead())
00443         return;
00444 
00445     // For an empty edit, we may need to adjust the start time
00446     if (_parentTrack->editList[_curEdit].mediaTime == -1) {
00447         // Just invalidate the current media position (and make sure the scale
00448         // is in terms of our rate so it simplifies things later)
00449         _curMediaPos = Timestamp(0, 0, getRate());
00450 
00451         // Also handle shortening of the empty edit if needed
00452         if (position != Timestamp())
00453             _skipSamples = position.convertToFramerate(_decoder->_timeScale) - Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale);
00454         return;
00455     }
00456 
00457     // I really hope I never need to implement this :P
00458     // But, I'll throw in this error just to make sure I catch anything with this...
00459     if (_parentTrack->editList[_curEdit].mediaRate != 1)
00460         error("Unhandled QuickTime audio rate change");
00461 
00462     // Reinitialize the codec
00463     ((AudioSampleDesc *)_parentTrack->sampleDescs[0])->initCodec();
00464     _skipAACPrimer = true;
00465 
00466     // First, we need to track down what audio sample we need
00467     // Convert our variables from the media time (position) and the edit time (based on position)
00468     // and the media time
00469     Timestamp curAudioTime = Timestamp(0, _parentTrack->editList[_curEdit].mediaTime, _parentTrack->timeScale)
00470         + position.convertToFramerate(_parentTrack->timeScale)
00471         - Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale).convertToFramerate(_parentTrack->timeScale);
00472 
00473     uint32 sample = curAudioTime.totalNumberOfFrames();
00474     uint32 seekSample = sample;
00475 
00476     if (!isOldDemuxing()) {
00477         // For MPEG-4 style demuxing, we need to track down the sample based on the time
00478         // The old style demuxing doesn't require this because each "sample"'s duration
00479         // is just 1
00480         uint32 curSample = 0;
00481         seekSample = 0;
00482 
00483         for (int32 i = 0; i < _parentTrack->timeToSampleCount; i++) {
00484             uint32 sampleCount = _parentTrack->timeToSample[i].count * _parentTrack->timeToSample[i].duration;
00485 
00486             if (sample < curSample + sampleCount) {
00487                 seekSample += (sample - curSample) / _parentTrack->timeToSample[i].duration;
00488                 break;
00489             }
00490 
00491             seekSample += _parentTrack->timeToSample[i].count;
00492             curSample += sampleCount;
00493         }
00494     }
00495 
00496     // Now to track down what chunk it's in
00497     uint32 totalSamples = 0;
00498     _curChunk = 0;
00499     for (uint32 i = 0; i < _parentTrack->chunkCount; i++, _curChunk++) {
00500         uint32 chunkSampleCount = getAudioChunkSampleCount(i);
00501 
00502         if (seekSample < totalSamples + chunkSampleCount)
00503             break;
00504 
00505         totalSamples += chunkSampleCount;
00506     }
00507 
00508     // Now we get to have fun and convert *back* to an actual time
00509     // We don't want the sample count to be modified at this point, though
00510     if (!isOldDemuxing())
00511         totalSamples = getAACSampleTime(totalSamples);
00512 
00513     _curMediaPos = Timestamp(0, totalSamples, getRate());
00514 }
00515 
00516 void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueStream(AudioStream *stream, const Timestamp &length) {
00517     // If the samples are stereo and the container is mono, force the samples
00518     // to be mono.
00519     if (stream->isStereo() && !isStereo())
00520         _queue->queueAudioStream(new ForcedMonoAudioStream(stream, DisposeAfterUse::YES), DisposeAfterUse::YES);
00521     else
00522         _queue->queueAudioStream(stream, DisposeAfterUse::YES);
00523 
00524     _samplesQueued += length.convertToFramerate(getRate()).totalNumberOfFrames();
00525 }
00526 
00527 uint32 QuickTimeAudioDecoder::QuickTimeAudioTrack::getAudioChunkSampleCount(uint chunk) const {
00528     uint32 sampleCount = 0;
00529 
00530     for (uint32 i = 0; i < _parentTrack->sampleToChunkCount; i++)
00531         if (chunk >= _parentTrack->sampleToChunk[i].first)
00532             sampleCount = _parentTrack->sampleToChunk[i].count;
00533 
00534     return sampleCount;
00535 }
00536 
00537 Timestamp QuickTimeAudioDecoder::QuickTimeAudioTrack::getChunkLength(uint chunk, bool skipAACPrimer) const {
00538     uint32 chunkSampleCount = getAudioChunkSampleCount(chunk);
00539 
00540     if (isOldDemuxing())
00541         return Timestamp(0, chunkSampleCount, getRate());
00542 
00543     // AAC needs some extra handling, of course
00544     return Timestamp(0, getAACSampleTime(chunkSampleCount, skipAACPrimer), getRate());
00545 }
00546 
00547 uint32 QuickTimeAudioDecoder::QuickTimeAudioTrack::getAACSampleTime(uint32 totalSampleCount, bool skipAACPrimer) const{
00548     uint32 curSample = 0;
00549     uint32 time = 0;
00550 
00551     for (int32 i = 0; i < _parentTrack->timeToSampleCount; i++) {
00552         uint32 sampleCount = _parentTrack->timeToSample[i].count;
00553 
00554         if (totalSampleCount < curSample + sampleCount) {
00555             time += (totalSampleCount - curSample) * _parentTrack->timeToSample[i].duration;
00556             break;
00557         }
00558 
00559         time += _parentTrack->timeToSample[i].count * _parentTrack->timeToSample[i].duration;
00560         curSample += sampleCount;
00561     }
00562 
00563     // The first chunk of AAC contains "duration" samples that are used as a primer
00564     // We need to subtract that number from the duration for the first chunk. See:
00565     // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html#//apple_ref/doc/uid/TP40000939-CH2-SW1
00566     // The skipping of both the primer and the remainder are handled by the AAC code,
00567     // whereas the timing of the remainder are handled by this time-to-sample chunk
00568     // code already.
00569     // We have to do this after each time we reinitialize the codec
00570     if (skipAACPrimer) {
00571         assert(_parentTrack->timeToSampleCount > 0);
00572         time -= _parentTrack->timeToSample[0].duration;
00573     }
00574 
00575     return time;
00576 }
00577 
00578 QuickTimeAudioDecoder::AudioSampleDesc::AudioSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag) : Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) {
00579     _channels = 0;
00580     _sampleRate = 0;
00581     _samplesPerFrame = 0;
00582     _bytesPerFrame = 0;
00583     _bitsPerSample = 0;
00584     _codec = 0;
00585 }
00586 
00587 QuickTimeAudioDecoder::AudioSampleDesc::~AudioSampleDesc() {
00588     delete _codec;
00589 }
00590 
00591 bool QuickTimeAudioDecoder::AudioSampleDesc::isAudioCodecSupported() const {
00592     // Check if the codec is a supported codec
00593     if (_codecTag == MKTAG('t', 'w', 'o', 's') || _codecTag == MKTAG('r', 'a', 'w', ' ') || _codecTag == MKTAG('i', 'm', 'a', '4'))
00594         return true;
00595 
00596 #ifdef AUDIO_QDM2_H
00597     if (_codecTag == MKTAG('Q', 'D', 'M', '2'))
00598         return true;
00599 #endif
00600 
00601     if (_codecTag == MKTAG('m', 'p', '4', 'a')) {
00602         Common::String audioType;
00603         switch (_objectTypeMP4) {
00604         case 0x40: // AAC
00605 #ifdef USE_FAAD
00606             return true;
00607 #else
00608             audioType = "AAC";
00609             break;
00610 #endif
00611         default:
00612             audioType = "Unknown";
00613             break;
00614         }
00615         warning("No MPEG-4 audio (%s) support", audioType.c_str());
00616     } else {
00617         warning("Audio Codec Not Supported: \'%s\'", tag2str(_codecTag));
00618     }
00619 
00620     return false;
00621 }
00622 
00623 AudioStream *QuickTimeAudioDecoder::AudioSampleDesc::createAudioStream(Common::SeekableReadStream *stream) const {
00624     if (!stream)
00625         return 0;
00626 
00627     if (_codec) {
00628         // If we've loaded a codec, make sure we use first
00629         AudioStream *audioStream = _codec->decodeFrame(*stream);
00630         delete stream;
00631         return audioStream;
00632     } else if (_codecTag == MKTAG('t', 'w', 'o', 's') || _codecTag == MKTAG('r', 'a', 'w', ' ')) {
00633         // Fortunately, most of the audio used in Myst videos is raw...
00634         uint16 flags = 0;
00635         if (_codecTag == MKTAG('r', 'a', 'w', ' '))
00636             flags |= FLAG_UNSIGNED;
00637         if (_channels == 2)
00638             flags |= FLAG_STEREO;
00639         if (_bitsPerSample == 16)
00640             flags |= FLAG_16BITS;
00641         uint32 dataSize = stream->size();
00642         byte *data = (byte *)malloc(dataSize);
00643         stream->read(data, dataSize);
00644         delete stream;
00645         return makeRawStream(data, dataSize, _sampleRate, flags);
00646     } else if (_codecTag == MKTAG('i', 'm', 'a', '4')) {
00647         // Riven uses this codec (as do some Myst ME videos)
00648         return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, _sampleRate, _channels, 34);
00649     }
00650 
00651     error("Unsupported audio codec");
00652     return NULL;
00653 }
00654 
00655 void QuickTimeAudioDecoder::AudioSampleDesc::initCodec() {
00656     delete _codec; _codec = 0;
00657 
00658     switch (_codecTag) {
00659     case MKTAG('Q', 'D', 'M', '2'):
00660 #ifdef AUDIO_QDM2_H
00661         _codec = makeQDM2Decoder(_extraData);
00662 #endif
00663         break;
00664     case MKTAG('m', 'p', '4', 'a'):
00665 #ifdef USE_FAAD
00666         if (_objectTypeMP4 == 0x40)
00667             _codec = makeAACDecoder(_extraData);
00668 #endif
00669         break;
00670     default:
00671         break;
00672     }
00673 }
00674 
00678 class QuickTimeAudioStream : public SeekableAudioStream, public QuickTimeAudioDecoder {
00679 public:
00680     QuickTimeAudioStream() {}
00681     ~QuickTimeAudioStream() {}
00682 
00683     bool openFromFile(const Common::String &filename) {
00684         return QuickTimeAudioDecoder::loadAudioFile(filename) && !_audioTracks.empty();
00685     }
00686 
00687     bool openFromStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeFileHandle) {
00688         return QuickTimeAudioDecoder::loadAudioStream(stream, disposeFileHandle) && !_audioTracks.empty();
00689     }
00690 
00691     // AudioStream API
00692     int readBuffer(int16 *buffer, const int numSamples) {
00693         int samples = 0;
00694 
00695         while (samples < numSamples && !endOfData()) {
00696             if (!_audioTracks[0]->hasDataInQueue())
00697                 _audioTracks[0]->queueAudio();
00698             samples += _audioTracks[0]->readBuffer(buffer + samples, numSamples - samples);
00699         }
00700 
00701         return samples;
00702     }
00703 
00704     bool isStereo() const { return _audioTracks[0]->isStereo(); }
00705     int getRate() const { return _audioTracks[0]->getRate(); }
00706     bool endOfData() const { return _audioTracks[0]->endOfData(); }
00707 
00708     // SeekableAudioStream API
00709     bool seek(const Timestamp &where) { return _audioTracks[0]->seek(where); }
00710     Timestamp getLength() const { return _audioTracks[0]->getLength(); }
00711 };
00712 
00713 SeekableAudioStream *makeQuickTimeStream(const Common::String &filename) {
00714     QuickTimeAudioStream *audioStream = new QuickTimeAudioStream();
00715 
00716     if (!audioStream->openFromFile(filename)) {
00717         delete audioStream;
00718         return 0;
00719     }
00720 
00721     return audioStream;
00722 }
00723 
00724 SeekableAudioStream *makeQuickTimeStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
00725     QuickTimeAudioStream *audioStream = new QuickTimeAudioStream();
00726 
00727     if (!audioStream->openFromStream(stream, disposeAfterUse)) {
00728         delete audioStream;
00729         return 0;
00730     }
00731 
00732     return audioStream;
00733 }
00734 
00735 } // End of namespace Audio


Generated on Sat Dec 14 2019 05:00:24 for ResidualVM by doxygen 1.7.1
curved edge   curved edge