diff options
author | Matthew Hoops | 2012-03-17 18:15:06 -0400 |
---|---|---|
committer | Matthew Hoops | 2012-03-19 12:04:46 -0400 |
commit | be8c557645bf73e96a463c60bd0422b39a3edfef (patch) | |
tree | 2460844c5a521c7bc25af984938cd8ca095d0211 /video/qt_decoder.cpp | |
parent | ee0a05c32ee85c276ba98a1bb1882b618be5ca57 (diff) | |
download | scummvm-rg350-be8c557645bf73e96a463c60bd0422b39a3edfef.tar.gz scummvm-rg350-be8c557645bf73e96a463c60bd0422b39a3edfef.tar.bz2 scummvm-rg350-be8c557645bf73e96a463c60bd0422b39a3edfef.zip |
AUDIO: Add support for multiple QuickTime audio tracks
This also cleans up the QuickTime audio code to make it a bit more manageable too
Diffstat (limited to 'video/qt_decoder.cpp')
-rw-r--r-- | video/qt_decoder.cpp | 124 |
1 files changed, 46 insertions, 78 deletions
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index 959e3c4fc7..7557222b13 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -57,7 +57,6 @@ namespace Video { QuickTimeDecoder::QuickTimeDecoder() { _setStartTime = false; - _audHandle = Audio::SoundHandle(); _scaledSurface = 0; _dirtyPalette = false; _palette = 0; @@ -95,20 +94,25 @@ uint32 QuickTimeDecoder::getFrameCount() const { } void QuickTimeDecoder::startAudio() { - if (_audStream) { - updateAudioBuffer(); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); - } // else no audio or the audio compression is not supported + updateAudioBuffer(); + + for (uint32 i = 0; i < _audioTracks.size(); i++) { + g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandles[i], _audioTracks[i], -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); + + // Pause the audio again if we're still paused + if (isPaused()) + g_system->getMixer()->pauseHandle(_audioHandles[i], true); + } } void QuickTimeDecoder::stopAudio() { - if (_audStream) - g_system->getMixer()->stopHandle(_audHandle); + for (uint32 i = 0; i < _audioHandles.size(); i++) + g_system->getMixer()->stopHandle(_audioHandles[i]); } void QuickTimeDecoder::pauseVideoIntern(bool pause) { - if (_audStream) - g_system->getMixer()->pauseHandle(_audHandle, pause); + for (uint32 i = 0; i < _audioHandles.size(); i++) + g_system->getMixer()->pauseHandle(_audioHandles[i], pause); } QuickTimeDecoder::VideoTrackHandler *QuickTimeDecoder::findNextVideoTrack() const { @@ -146,9 +150,7 @@ const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { // Update audio buffers too // (needs to be done after we find the next track) - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio) - ((AudioTrackHandler *)_handlers[i])->updateBuffer(); + updateAudioBuffer(); if (_scaledSurface) { scaleSurface(frame, _scaledSurface, _scaleFactorX, _scaleFactorY); @@ -178,15 +180,13 @@ bool QuickTimeDecoder::endOfVideo() const { } uint32 QuickTimeDecoder::getElapsedTime() const { - // TODO: Convert to multi-track - if (_audStream) { - // Use the audio time if present and the audio track's time is less than the - // total length of the audio track. The audio track can end before the video - // track, so we need to fall back on the getMillis() time tracking in that - // case. - uint32 time = g_system->getMixer()->getSoundElapsedTime(_audHandle) + _audioStartOffset.msecs(); - if (time < _tracks[_audioTrackIndex]->mediaDuration * 1000 / _tracks[_audioTrackIndex]->timeScale) - return time; + // Try to base sync off an active audio track + for (uint32 i = 0; i < _audioHandles.size(); i++) { + if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) { + uint32 time = g_system->getMixer()->getSoundElapsedTime(_audioHandles[i]) + _audioStartOffset.msecs(); + if (Audio::Timestamp(time, 1000) < _audioTracks[i]->getLength()) + return time; + } } // Just use time elapsed since the beginning @@ -236,14 +236,12 @@ void QuickTimeDecoder::init() { _startTime = 0; _setStartTime = false; - // Start the audio codec if we've got one that we can handle - if (_audStream) { - startAudio(); - _audioStartOffset = Audio::Timestamp(0); + // Initialize all the audio tracks + if (!_audioTracks.empty()) { + _audioHandles.resize(_audioTracks.size()); - // TODO: Support multiple audio tracks - // For now, just push back a handler for the first audio track - _handlers.push_back(new AudioTrackHandler(this, _tracks[_audioTrackIndex])); + for (uint32 i = 0; i < _audioTracks.size(); i++) + _handlers.push_back(new AudioTrackHandler(this, _audioTracks[i])); } // Initialize all the video tracks @@ -277,6 +275,12 @@ void QuickTimeDecoder::init() { } else { _needUpdate = false; } + + // Now start any audio + if (!_audioTracks.empty()) { + startAudio(); + _audioStartOffset = Audio::Timestamp(0); + } } Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *track, uint32 format) { @@ -401,10 +405,15 @@ void QuickTimeDecoder::freeAllTrackHandlers() { } void QuickTimeDecoder::seekToTime(Audio::Timestamp time) { + stopAudio(); + _audioStartOffset = time; + // Sets all tracks to this time for (uint32 i = 0; i < _handlers.size(); i++) _handlers[i]->seekToTime(time); + startAudio(); + // Reset our start time _startTime = g_system->getMillis() - time.msecs(); _setStartTime = true; @@ -483,7 +492,7 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() { bool QuickTimeDecoder::endOfVideoTracks() const { for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) + if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) return false; return true; @@ -498,64 +507,23 @@ bool QuickTimeDecoder::TrackHandler::endOfTrack() { return _curEdit == _parent->editCount; } -QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, Track *parent) : TrackHandler(decoder, parent) { +QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack) + : TrackHandler(decoder, audioTrack->getParent()), _audioTrack(audioTrack) { } void QuickTimeDecoder::AudioTrackHandler::updateBuffer() { - if (!_decoder->_audStream) - return; - - uint32 numberOfChunksNeeded = 0; - - if (_decoder->endOfVideoTracks()) { - // If we have no video left (or no video), there's nothing to base our buffer against - numberOfChunksNeeded = _parent->chunkCount; - } else { - Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_parent->sampleDescs[0]; - - // Calculate the amount of chunks we need in memory until the next frame - uint32 timeToNextFrame = _decoder->getTimeToNextFrame(); - uint32 timeFilled = 0; - uint32 curAudioChunk = _decoder->_curAudioChunk - _decoder->_audStream->numQueuedStreams(); - - for (; timeFilled < timeToNextFrame && curAudioChunk < _parent->chunkCount; numberOfChunksNeeded++, curAudioChunk++) { - uint32 sampleCount = entry->getAudioChunkSampleCount(curAudioChunk); - assert(sampleCount); - - timeFilled += sampleCount * 1000 / entry->_sampleRate; - } - - // Add a couple extra to ensure we don't underrun - numberOfChunksNeeded += 3; - } - - // Keep three streams in buffer so that if/when the first two end, it goes right into the next - while (_decoder->_audStream->numQueuedStreams() < numberOfChunksNeeded && _decoder->_curAudioChunk < _parent->chunkCount) - _decoder->queueNextAudioChunk(); + if (_decoder->endOfVideoTracks()) // If we have no video left (or no video), there's nothing to base our buffer against + _audioTrack->queueRemainingAudio(); + else // Otherwise, queue enough to get us to the next frame plus another half second spare + _audioTrack->queueAudio(Audio::Timestamp(_decoder->getTimeToNextFrame() + 500, 1000)); } bool QuickTimeDecoder::AudioTrackHandler::endOfTrack() { - // TODO: Handle edits - return (_decoder->_curAudioChunk == _parent->chunkCount) && _decoder->_audStream->endOfData(); + return _audioTrack->endOfData(); } void QuickTimeDecoder::AudioTrackHandler::seekToTime(Audio::Timestamp time) { - if (_decoder->_audStream) { - // Stop all audio - _decoder->stopAudio(); - - _decoder->_audioStartOffset = time; - - // Seek to the new audio location - _decoder->setAudioStreamPos(_decoder->_audioStartOffset); - - // Restart the audio - _decoder->startAudio(); - - // Pause the audio again if we're still paused - if (_decoder->isPaused() && _decoder->_audStream) - g_system->getMixer()->pauseHandle(_decoder->_audHandle, true); - } + _audioTrack->seek(time); } QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : TrackHandler(decoder, parent) { |