aboutsummaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/avi_decoder.cpp40
-rw-r--r--video/avi_decoder.h7
-rw-r--r--video/bink_decoder.cpp10
-rw-r--r--video/bink_decoder.h2
-rw-r--r--video/smk_decoder.cpp25
-rw-r--r--video/smk_decoder.h2
-rw-r--r--video/video_decoder.cpp60
-rw-r--r--video/video_decoder.h44
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