aboutsummaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/avi_decoder.cpp115
-rw-r--r--video/avi_decoder.h27
-rw-r--r--video/video_decoder.h2
3 files changed, 111 insertions, 33 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp
index 980ce3a3ea..7041f428ab 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -76,13 +76,13 @@ enum {
};
-AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType, SelectTrackFn trackFn) :
- _frameRateOverride(0), _soundType(soundType), _selectTrackFn(trackFn) {
+AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) :
+ _frameRateOverride(0), _soundType(soundType) {
initCommon();
}
-AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType,
- SelectTrackFn trackFn) : _frameRateOverride(frameRateOverride), _soundType(soundType), _selectTrackFn(trackFn) {
+AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) :
+ _frameRateOverride(frameRateOverride), _soundType(soundType) {
initCommon();
}
@@ -94,6 +94,23 @@ AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader,
return new AVIAudioTrack(sHeader, wvInfo, _soundType);
}
+bool AVIDecoder::seekToFrame(uint frame) {
+ if (!isSeekable())
+ return false;
+
+ // If we didn't find a video track, we can't seek by frame (of course)
+ if (_videoTracks.empty())
+ return false;
+
+ AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks.front().track);
+ Audio::Timestamp time = track->getFrameTime(frame);
+
+ if (time < 0)
+ return false;
+
+ return seek(time);
+}
+
void AVIDecoder::initCommon() {
_decodedHeader = false;
_foundMovieList = false;
@@ -111,6 +128,14 @@ bool AVIDecoder::isSeekable() const {
return isVideoLoaded() && !_indexEntries.empty();
}
+const Graphics::Surface *AVIDecoder::decodeNextTransparency() {
+ if (_videoTracks.size() != 2)
+ return nullptr;
+
+ AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[1].track);
+ return track->decodeNextFrame();
+}
+
bool AVIDecoder::parseNextChunk() {
uint32 tag = _fileStream->readUint32BE();
uint32 size = _fileStream->readUint32LE();
@@ -293,14 +318,8 @@ void AVIDecoder::handleStreamHeader(uint32 size) {
}
void AVIDecoder::addTrack(Track *track, bool isExternal) {
- if (!_selectTrackFn ||
- (dynamic_cast<AVIVideoTrack *>(track) && _selectTrackFn(true, _videoTrackCounter++)) ||
- (dynamic_cast<AVIAudioTrack *>(track) && _selectTrackFn(false, _audioTrackCounter++))) {
- VideoDecoder::addTrack(track, isExternal);
- _lastAddedTrack = track;
- } else {
- _lastAddedTrack = nullptr;
- }
+ VideoDecoder::addTrack(track, isExternal);
+ _lastAddedTrack = track;
}
void AVIDecoder::readStreamName(uint32 size) {
@@ -368,15 +387,19 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
status.index = index;
status.chunkSearchOffset = _movieListStart;
- if ((*it)->getTrackType() == Track::kTrackTypeVideo)
- _videoTracks.push_back(status);
- else
+ if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
_audioTracks.push_back(status);
- }
+ } else if (_videoTracks.empty()) {
+ _videoTracks.push_back(status);
+ } else {
+ // Secondary video track
+ assert(_videoTracks.size() == 1);
+ status.chunkSearchOffset = getVideoTrackOffset(index);
+ assert(status.chunkSearchOffset != 0);
- if (_videoTracks.size() != 1) {
- close();
- return false;
+ // Add the video track to the list
+ _videoTracks.push_back(status);
+ }
}
// Check if this is a special Duck Truemotion video
@@ -407,12 +430,13 @@ void AVIDecoder::readNextPacket() {
if (_videoTracks.empty())
return;
- // Get the video frame first
- handleNextPacket(_videoTracks[0]);
+ // Handle the video first
+ for (uint idx = 0; idx < _videoTracks.size(); ++idx)
+ handleNextPacket(_videoTracks[idx]);
// Handle audio tracks next
- for (uint32 i = 0; i < _audioTracks.size(); i++)
- handleNextPacket(_audioTracks[i]);
+ for (uint idx = 0; idx < _audioTracks.size(); ++idx)
+ handleNextPacket(_audioTracks[idx]);
}
void AVIDecoder::handleNextPacket(TrackStatus &status) {
@@ -524,7 +548,7 @@ bool AVIDecoder::rewind() {
return false;
for (uint32 i = 0; i < _videoTracks.size(); i++)
- _videoTracks[i].chunkSearchOffset = _movieListStart;
+ _videoTracks[i].chunkSearchOffset = getVideoTrackOffset(_videoTracks[i].index);
for (uint32 i = 0; i < _audioTracks.size(); i++)
_audioTracks[i].chunkSearchOffset = _movieListStart;
@@ -532,6 +556,15 @@ bool AVIDecoder::rewind() {
return true;
}
+uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) {
+ if (trackIndex == _videoTracks.front().index && frameNumber == 0)
+ return _movieListStart;
+
+ OldIndex *entry = _indexEntries.find(trackIndex, frameNumber);
+ assert(entry);
+ return entry->offset;
+}
+
bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
// Can't seek beyond the end
if (time > getDuration())
@@ -666,6 +699,26 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
videoTrack->decodeFrame(chunk);
}
+ // Update any secondary video track for transparencies
+ if (_videoTracks.size() == 2) {
+ // Set it's frame number
+ AVIVideoTrack *videoTrack2 = static_cast<AVIVideoTrack *>(_videoTracks.back().track);
+ videoTrack2->setCurFrame((int)frame - 1);
+
+ // Find the index entry for the frame and read it in
+ OldIndex *entry = _indexEntries.find(_videoTracks.back().index, frame);
+ assert(entry);
+
+ Common::SeekableReadStream *chunk = nullptr;
+ _fileStream->seek(entry->offset + 8);
+ _videoTracks.back().chunkSearchOffset = entry->offset;
+
+ if (entry->size != 0)
+ chunk = _fileStream->readStream(entry->size);
+
+ videoTrack2->decodeFrame(chunk);
+ }
+
// Set the video track's frame
videoTrack->setCurFrame((int)frame - 1);
@@ -674,7 +727,7 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
return true;
}
-byte AVIDecoder::getStreamIndex(uint32 tag) const {
+byte AVIDecoder::getStreamIndex(uint32 tag) {
char string[3];
WRITE_BE_UINT16(string, tag >> 16);
string[2] = 0;
@@ -975,4 +1028,16 @@ void AVIDecoder::AVIAudioTrack::createAudioStream() {
AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
}
+AVIDecoder::OldIndex *AVIDecoder::IndexEntries::find(uint index, uint frameNumber) {
+ for (uint idx = 0, frameCtr = 0; idx < size(); ++idx) {
+ if ((*this)[idx].id != ID_REC &&
+ AVIDecoder::getStreamIndex((*this)[idx].id) == index) {
+ if (frameCtr++ == frameNumber)
+ return &(*this)[idx];
+ }
+ }
+
+ return nullptr;
+}
+
} // End of namespace Video
diff --git a/video/avi_decoder.h b/video/avi_decoder.h
index a3733b579c..4bba07e98f 100644
--- a/video/avi_decoder.h
+++ b/video/avi_decoder.h
@@ -62,10 +62,8 @@ namespace Video {
*/
class AVIDecoder : public VideoDecoder {
public:
- typedef bool(*SelectTrackFn)(bool isVideo, int trackNumber);
- AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType, SelectTrackFn trackFn = nullptr);
- AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
- SelectTrackFn trackFn = nullptr);
+ AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
+ AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
virtual ~AVIDecoder();
bool loadStream(Common::SeekableReadStream *stream);
@@ -77,6 +75,7 @@ public:
bool isRewindable() const { return true; }
bool isSeekable() const;
+ const Graphics::Surface *decodeNextTransparency();
protected:
// VideoDecoder API
void readNextPacket();
@@ -190,6 +189,7 @@ protected:
uint16 getWidth() const { return _bmInfo.width; }
uint16 getHeight() const { return _bmInfo.height; }
+ uint16 getBitCount() const { return _bmInfo.bitCount; }
Graphics::PixelFormat getPixelFormat() const;
int getCurFrame() const { return _curFrame; }
int getFrameCount() const { return _frameCount; }
@@ -272,10 +272,15 @@ protected:
uint32 chunkSearchOffset;
};
+ class IndexEntries : public Common::Array<OldIndex> {
+ public:
+ OldIndex *find(uint index, uint frameNumber);
+ };
+
AVIHeader _header;
void readOldIndex(uint32 size);
- Common::Array<OldIndex> _indexEntries;
+ IndexEntries _indexEntries;
Common::SeekableReadStream *_fileStream;
bool _decodedHeader;
@@ -287,7 +292,6 @@ protected:
int _videoTrackCounter, _audioTrackCounter;
Track *_lastAddedTrack;
- SelectTrackFn _selectTrackFn;
void initCommon();
@@ -297,8 +301,9 @@ protected:
void handleStreamHeader(uint32 size);
void readStreamName(uint32 size);
uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; }
- byte getStreamIndex(uint32 tag) const;
+ static byte getStreamIndex(uint32 tag);
void checkTruemotion1();
+ uint getVideoTrackOffset(uint trackIndex, uint frameNumber = 0);
void handleNextPacket(TrackStatus& status);
bool shouldQueueAudio(TrackStatus& status);
@@ -306,6 +311,14 @@ protected:
public:
virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo);
+
+ /**
+ * Seek to a given frame.
+ *
+ * This only works when the video track(s) supports getFrameTime().
+ * This calls seek() internally.
+ */
+ virtual bool seekToFrame(uint frame);
};
} // End of namespace Video
diff --git a/video/video_decoder.h b/video/video_decoder.h
index eca15e7265..a415a70724 100644
--- a/video/video_decoder.h
+++ b/video/video_decoder.h
@@ -184,7 +184,7 @@ public:
* This only works when one video track is present, and that track
* supports getFrameTime(). This calls seek() internally.
*/
- bool seekToFrame(uint frame);
+ virtual bool seekToFrame(uint frame);
/**
* Pause or resume the video. This should stop/resume any audio playback