diff options
Diffstat (limited to 'video')
-rw-r--r-- | video/avi_decoder.cpp | 40 | ||||
-rw-r--r-- | video/avi_decoder.h | 7 | ||||
-rw-r--r-- | video/bink_decoder.cpp | 10 | ||||
-rw-r--r-- | video/bink_decoder.h | 2 | ||||
-rw-r--r-- | video/smk_decoder.cpp | 25 | ||||
-rw-r--r-- | video/smk_decoder.h | 2 | ||||
-rw-r--r-- | video/video_decoder.cpp | 60 | ||||
-rw-r--r-- | video/video_decoder.h | 44 |
8 files changed, 160 insertions, 30 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 7f5a557474..a3b45995a1 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -441,12 +441,10 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { if (time > getDuration()) return false; - // Track down our video track (optionally audio too). - // We only support seeking with one track right now. + // Track down our video track. + // We only support seeking with one video track right now. AVIVideoTrack *videoTrack = 0; - AVIAudioTrack *audioTrack = 0; int videoIndex = -1; - int audioIndex = -1; uint trackID = 0; for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, trackID++) { @@ -459,15 +457,6 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { videoTrack = (AVIVideoTrack *)*it; videoIndex = trackID; - } else if ((*it)->getTrackType() == Track::kTrackTypeAudio) { - if (audioTrack) { - // Already have one - // -> Not supported - return false; - } - - audioTrack = (AVIAudioTrack *)*it; - audioIndex = trackID; } } @@ -480,8 +469,9 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { if (time == getDuration()) { videoTrack->setCurFrame(videoTrack->getFrameCount() - 1); - if (audioTrack) - audioTrack->resetStream(); + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AVIAudioTrack *)*it)->resetStream(); return true; } @@ -542,7 +532,15 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { if (frameIndex < 0) // This shouldn't happen. return false; - if (audioTrack) { + // Update all the audio tracks + uint audioIndex = 0; + + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, audioIndex++) { + if ((*it)->getTrackType() != Track::kTrackTypeAudio) + continue; + + AVIAudioTrack *audioTrack = (AVIAudioTrack *)*it; + // We need to find where the start of audio should be. // Which is exactly 'initialFrames' audio chunks back from where // our found frame is. @@ -683,6 +681,16 @@ void AVIDecoder::forceVideoEnd() { ((AVIVideoTrack *)*it)->forceTrackEnd(); } +VideoDecoder::AudioTrack *AVIDecoder::getAudioTrack(int index) { + // AVI audio track indexes are relative to the first track + Track *track = getTrack(index); + + if (!track || track->getTrackType() != Track::kTrackTypeAudio) + return 0; + + return (AudioTrack *)track; +} + AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette) : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) { _videoCodec = createCodec(); diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 882cce30de..811f7f82f7 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -72,8 +72,11 @@ public: bool isSeekable() const; protected: - void readNextPacket(); - bool seekIntern(const Audio::Timestamp &time); + // VideoDecoder API + void readNextPacket(); + bool seekIntern(const Audio::Timestamp &time); + bool supportsAudioTrackSwitching() const { return true; } + AudioTrack *getAudioTrack(int index); struct BitmapInfoHeader { uint32 size; diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 45dec0887b..bad34e8373 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -214,6 +214,16 @@ void BinkDecoder::readNextPacket() { frame.bits = 0; } +VideoDecoder::AudioTrack *BinkDecoder::getAudioTrack(int index) { + // Bink audio track indexes are relative to the first audio track + Track *track = getTrack(index + 1); + + if (!track || track->getTrackType() != Track::kTrackTypeAudio) + return 0; + + return (AudioTrack *)track; +} + BinkDecoder::VideoFrame::VideoFrame() : bits(0) { } diff --git a/video/bink_decoder.h b/video/bink_decoder.h index 08800c2223..fb2998fb6e 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -74,6 +74,8 @@ public: protected: void readNextPacket(); + bool supportsAudioTrackSwitching() const { return true; } + AudioTrack *getAudioTrack(int index); private: static const int kAudioChannelsMax = 2; diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index 0247fe5dc9..b31ad109ad 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -369,8 +369,7 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT) warning("Unhandled Smacker v2 audio compression"); - if (i == 0) - addTrack(new SmackerAudioTrack(_header.audioInfo[i], _soundType)); + addTrack(new SmackerAudioTrack(_header.audioInfo[i], _soundType)); } } @@ -477,7 +476,10 @@ void SmackerDecoder::readNextPacket() { } void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { - if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { + if (chunkSize == 0) + return; + + if (_header.audioInfo[track].hasAudio) { // Get the audio track, which start at offset 1 (first track is video) SmackerAudioTrack *audioTrack = (SmackerAudioTrack *)getTrack(track + 1); @@ -501,14 +503,21 @@ void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpac audioTrack->queuePCM(soundBuffer, chunkSize); } } else { - // Ignore the rest of the audio tracks, if they exist - // TODO: Are there any Smacker videos with more than one audio stream? - // If yes, we should play the rest of the audio streams as well - if (chunkSize > 0) - _fileStream->skip(chunkSize); + // Ignore possibly unused data + _fileStream->skip(chunkSize); } } +VideoDecoder::AudioTrack *SmackerDecoder::getAudioTrack(int index) { + // Smacker audio track indexes are relative to the first audio track + Track *track = getTrack(index + 1); + + if (!track || track->getTrackType() != Track::kTrackTypeAudio) + return 0; + + return (AudioTrack *)track; +} + SmackerDecoder::SmackerVideoTrack::SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) { _surface = new Graphics::Surface(); _surface->create(width, height * (flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8()); diff --git a/video/smk_decoder.h b/video/smk_decoder.h index e4bc9bab42..5298158833 100644 --- a/video/smk_decoder.h +++ b/video/smk_decoder.h @@ -69,6 +69,8 @@ public: protected: void readNextPacket(); + bool supportsAudioTrackSwitching() const { return true; } + AudioTrack *getAudioTrack(int index); virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 0ab1478727..931bde20d0 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -46,6 +46,7 @@ VideoDecoder::VideoDecoder() { _endTime = 0; _endTimeSet = false; _nextVideoTrack = 0; + _mainAudioTrack = 0; // Find the best format for output _defaultHighColorFormat = g_system->getScreenFormat(); @@ -75,6 +76,7 @@ void VideoDecoder::close() { _endTime = 0; _endTimeSet = false; _nextVideoTrack = 0; + _mainAudioTrack = 0; } bool VideoDecoder::loadFile(const Common::String &filename) { @@ -553,6 +555,9 @@ Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { return getFrameTime(getFrameCount()); } +VideoDecoder::AudioTrack::AudioTrack() : _volume(Audio::Mixer::kMaxChannelVolume), _balance(0), _muted(false) { +} + bool VideoDecoder::AudioTrack::endOfTrack() const { Audio::AudioStream *stream = getAudioStream(); return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData(); @@ -562,7 +567,7 @@ void VideoDecoder::AudioTrack::setVolume(byte volume) { _volume = volume; if (g_system->getMixer()->isSoundHandleActive(_handle)) - g_system->getMixer()->setChannelVolume(_handle, _volume); + g_system->getMixer()->setChannelVolume(_handle, _muted ? 0 : _volume); } void VideoDecoder::AudioTrack::setBalance(int8 balance) { @@ -578,7 +583,7 @@ void VideoDecoder::AudioTrack::start() { Audio::AudioStream *stream = getAudioStream(); assert(stream); - g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::NO); + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::NO); // Pause the audio again if we're still paused if (isPaused()) @@ -597,7 +602,7 @@ void VideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { stream = Audio::makeLimitingAudioStream(stream, limit, DisposeAfterUse::NO); - g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::YES); + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::YES); // Pause the audio again if we're still paused if (isPaused()) @@ -611,6 +616,16 @@ uint32 VideoDecoder::AudioTrack::getRunningTime() const { return 0; } +void VideoDecoder::AudioTrack::setMute(bool mute) { + // Update the mute settings, if required + if (_muted != mute) { + _muted = mute; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelVolume(_handle, mute ? 0 : _volume); + } +} + void VideoDecoder::AudioTrack::pauseIntern(bool shouldPause) { if (g_system->getMixer()->isSoundHandleActive(_handle)) g_system->getMixer()->pauseHandle(_handle, shouldPause); @@ -669,6 +684,17 @@ void VideoDecoder::addTrack(Track *track, bool isExternal) { // Update volume settings if it's an audio track ((AudioTrack *)track)->setVolume(_audioVolume); ((AudioTrack *)track)->setBalance(_audioBalance); + + if (!isExternal && supportsAudioTrackSwitching()) { + if (_mainAudioTrack) { + // The main audio track has already been found + ((AudioTrack *)track)->setMute(true); + } else { + // First audio track found -> now the main one + _mainAudioTrack = (AudioTrack *)track; + _mainAudioTrack->setMute(false); + } + } } else if (track->getTrackType() == Track::kTrackTypeVideo) { // If this track has a better time, update _nextVideoTrack if (!_nextVideoTrack || ((VideoTrack *)track)->getNextFrameStartTime() < _nextVideoTrack->getNextFrameStartTime()) @@ -701,6 +727,34 @@ bool VideoDecoder::addStreamFileTrack(const Common::String &baseName) { return result; } +bool VideoDecoder::setAudioTrack(int index) { + if (!supportsAudioTrackSwitching()) + return false; + + AudioTrack *audioTrack = getAudioTrack(index); + + if (!audioTrack) + return false; + + if (_mainAudioTrack == audioTrack) + return true; + + _mainAudioTrack->setMute(true); + audioTrack->setMute(false); + _mainAudioTrack = audioTrack; + return true; +} + +uint VideoDecoder::getAudioTrackCount() const { + uint count = 0; + + for (TrackList::const_iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + count++; + + return count; +} + void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { Audio::Timestamp startTime = 0; diff --git a/video/video_decoder.h b/video/video_decoder.h index ac6586d8dd..99161d6f97 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -407,6 +407,21 @@ public: */ bool addStreamFileTrack(const Common::String &baseName); + /** + * Set the internal audio track. + * + * Has no effect if the container does not support this. + * @see supportsAudioTrackSwitching() + * + * @param index The index of the track, whose meaning is dependent on the container + */ + bool setAudioTrack(int index); + + /** + * Get the number of internal audio tracks. + */ + uint getAudioTrackCount() const; + protected: /** * An abstract representation of a track in a movie. Since tracks here are designed @@ -612,7 +627,7 @@ protected: */ class AudioTrack : public Track { public: - AudioTrack() {} + AudioTrack(); virtual ~AudioTrack() {} TrackType getTrackType() const { return kTrackTypeAudio; } @@ -662,6 +677,11 @@ protected: */ virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; } + /** + * Mute the track + */ + void setMute(bool mute); + protected: void pauseIntern(bool shouldPause); @@ -674,6 +694,7 @@ protected: Audio::SoundHandle _handle; byte _volume; int8 _balance; + bool _muted; }; /** @@ -833,6 +854,25 @@ protected: */ virtual bool seekIntern(const Audio::Timestamp &time); + /** + * Does this video format support switching between audio tracks? + * + * Returning true implies this format supports multiple audio tracks, + * can switch tracks, and defaults to playing the first found audio + * track. + */ + virtual bool supportsAudioTrackSwitching() const { return false; } + + /** + * Get the audio track for the given index. + * + * This is used only if supportsAudioTrackSwitching() returns true. + * + * @param index The index of the track, whose meaning is dependent on the container + * @return The audio track for the index, or 0 if not found + */ + virtual AudioTrack *getAudioTrack(int index) { return 0; } + private: // Tracks owned by this VideoDecoder TrackList _tracks; @@ -865,6 +905,8 @@ private: uint32 _pauseStartTime; byte _audioVolume; int8 _audioBalance; + + AudioTrack *_mainAudioTrack; }; } // End of namespace Video |