aboutsummaryrefslogtreecommitdiff
path: root/video/qt_decoder.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2012-03-17 18:15:06 -0400
committerMatthew Hoops2012-03-19 12:04:46 -0400
commitbe8c557645bf73e96a463c60bd0422b39a3edfef (patch)
tree2460844c5a521c7bc25af984938cd8ca095d0211 /video/qt_decoder.cpp
parentee0a05c32ee85c276ba98a1bb1882b618be5ca57 (diff)
downloadscummvm-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.cpp124
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) {