ALL: synced with ScummVM

This commit is contained in:
Pawel Kolodziejski 2014-08-18 05:21:52 +02:00
parent e76e3f3b3d
commit 1a07a23294
17 changed files with 260 additions and 43 deletions

View file

@ -98,7 +98,7 @@ LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, uint loops
// TODO: Properly indicate error // TODO: Properly indicate error
_loops = _completeIterations = 1; _loops = _completeIterations = 1;
} }
if (stream->endOfData()) { if (stream->endOfStream()) {
// Apparently this is an empty stream // Apparently this is an empty stream
_loops = _completeIterations = 1; _loops = _completeIterations = 1;
} }
@ -122,7 +122,7 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
_loops = _completeIterations = 1; _loops = _completeIterations = 1;
return samplesRead; return samplesRead;
} }
if (_parent->endOfData()) { if (_parent->endOfStream()) {
// Apparently this is an empty stream // Apparently this is an empty stream
_loops = _completeIterations = 1; _loops = _completeIterations = 1;
} }
@ -134,7 +134,11 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
} }
bool LoopingAudioStream::endOfData() const { bool LoopingAudioStream::endOfData() const {
return (_loops != 0 && (_completeIterations == _loops)); return (_loops != 0 && _completeIterations == _loops) || _parent->endOfData();
}
bool LoopingAudioStream::endOfStream() const {
return _loops != 0 && _completeIterations == _loops;
} }
AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops) { AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops) {
@ -189,7 +193,7 @@ int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
int framesRead = _parent->readBuffer(buffer, framesLeft); int framesRead = _parent->readBuffer(buffer, framesLeft);
_pos = _pos.addFrames(framesRead); _pos = _pos.addFrames(framesRead);
if (framesRead < framesLeft && _parent->endOfData()) { if (framesRead < framesLeft && _parent->endOfStream()) {
// TODO: Proper error indication. // TODO: Proper error indication.
_done = true; _done = true;
return framesRead; return framesRead;
@ -216,6 +220,18 @@ int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
} }
} }
bool SubLoopingAudioStream::endOfData() const {
// We're out of data if this stream is finished or the parent
// has run out of data for now.
return _done || _parent->endOfData();
}
bool SubLoopingAudioStream::endOfStream() const {
// The end of the stream has been reached only when we've gone
// through all the iterations.
return _done;
}
#pragma mark - #pragma mark -
#pragma mark --- SubSeekableAudioStream --- #pragma mark --- SubSeekableAudioStream ---
#pragma mark - #pragma mark -
@ -315,18 +331,27 @@ public:
virtual int readBuffer(int16 *buffer, const int numSamples); virtual int readBuffer(int16 *buffer, const int numSamples);
virtual bool isStereo() const { return _stereo; } virtual bool isStereo() const { return _stereo; }
virtual int getRate() const { return _rate; } virtual int getRate() const { return _rate; }
virtual bool endOfData() const { virtual bool endOfData() const {
//Common::StackLock lock(_mutex); Common::StackLock lock(_mutex);
return _queue.empty(); return _queue.empty() || _queue.front()._stream->endOfData();
}
virtual bool endOfStream() const {
Common::StackLock lock(_mutex);
return _finished && _queue.empty();
} }
virtual bool endOfStream() const { return _finished && _queue.empty(); }
// Implement the QueuingAudioStream API // Implement the QueuingAudioStream API
virtual void queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse); virtual void queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse);
virtual void finish() { _finished = true; }
virtual void finish() {
Common::StackLock lock(_mutex);
_finished = true;
}
uint32 numQueuedStreams() const { uint32 numQueuedStreams() const {
//Common::StackLock lock(_mutex); Common::StackLock lock(_mutex);
return _queue.size(); return _queue.size();
} }
}; };
@ -356,11 +381,17 @@ int QueuingAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
AudioStream *stream = _queue.front()._stream; AudioStream *stream = _queue.front()._stream;
samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
if (stream->endOfData()) { // Done with the stream completely
if (stream->endOfStream()) {
StreamHolder tmp = _queue.pop(); StreamHolder tmp = _queue.pop();
if (tmp._disposeAfterUse == DisposeAfterUse::YES) if (tmp._disposeAfterUse == DisposeAfterUse::YES)
delete stream; delete stream;
continue;
} }
// Done with data but not the stream, bail out
if (stream->endOfData())
break;
} }
return samplesDecoded; return samplesDecoded;
@ -416,12 +447,14 @@ public:
return samplesRead; return samplesRead;
} }
bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } bool endOfData() const { return _parentStream->endOfData() || reachedLimit(); }
bool endOfStream() const { return _parentStream->endOfStream() || reachedLimit(); }
bool isStereo() const { return _parentStream->isStereo(); } bool isStereo() const { return _parentStream->isStereo(); }
int getRate() const { return _parentStream->getRate(); } int getRate() const { return _parentStream->getRate(); }
private: private:
int getChannels() const { return isStereo() ? 2 : 1; } int getChannels() const { return isStereo() ? 2 : 1; }
bool reachedLimit() const { return _samplesRead >= _totalSamples; }
AudioStream *_parentStream; AudioStream *_parentStream;
DisposeAfterUse::Flag _disposeAfterUse; DisposeAfterUse::Flag _disposeAfterUse;

View file

@ -118,6 +118,7 @@ public:
int readBuffer(int16 *buffer, const int numSamples); int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const; bool endOfData() const;
bool endOfStream() const;
bool isStereo() const { return _parent->isStereo(); } bool isStereo() const { return _parent->isStereo(); }
int getRate() const { return _parent->getRate(); } int getRate() const { return _parent->getRate(); }
@ -247,7 +248,8 @@ public:
DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
int readBuffer(int16 *buffer, const int numSamples); int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const { return _done; } bool endOfData() const;
bool endOfStream() const;
bool isStereo() const { return _parent->isStereo(); } bool isStereo() const { return _parent->isStereo(); }
int getRate() const { return _parent->getRate(); } int getRate() const { return _parent->getRate(); }
@ -287,7 +289,8 @@ public:
int getRate() const { return _parent->getRate(); } int getRate() const { return _parent->getRate(); }
bool endOfData() const { return (_pos >= _length) || _parent->endOfStream(); } bool endOfData() const { return (_pos >= _length) || _parent->endOfData(); }
bool endOfStream() const { return (_pos >= _length) || _parent->endOfStream(); }
bool seek(const Timestamp &where); bool seek(const Timestamp &where);

View file

@ -117,6 +117,7 @@ AudioStream *AACDecoder::decodeFrame(Common::SeekableReadStream &stream) {
inBufferPos += frameInfo.bytesconsumed; inBufferPos += frameInfo.bytesconsumed;
} }
audioStream->finish();
return audioStream; return audioStream;
} }

View file

@ -2607,6 +2607,7 @@ AudioStream *QDM2Stream::decodeFrame(Common::SeekableReadStream &stream) {
while (qdm2_decodeFrame(stream, audioStream)) while (qdm2_decodeFrame(stream, audioStream))
; ;
audioStream->finish();
return audioStream; return audioStream;
} }

View file

@ -414,8 +414,15 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &le
} }
void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) { void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) {
for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1 && position > Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++) // Go through the edits look for where we find out we need to be. As long
; // as the position is >= to the edit's start time, it is considered to be in that
// edit. seek() already figured out if we reached the last edit, so we don't need
// to handle that case here.
for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1; _curEdit++) {
Timestamp nextEditTime(0, _parentTrack->editList[_curEdit + 1].timeOffset, _decoder->_timeScale);
if (position < nextEditTime)
break;
}
enterNewEdit(position); enterNewEdit(position);
} }

View file

@ -30,6 +30,9 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Set up a stack cookie to avoid crashes due to too few stack set by users
static const char *stack_cookie __attribute__((used)) = "$STACK: 600000";
// Create our OSystem instance // Create our OSystem instance
g_system = new OSystem_AmigaOS(); g_system = new OSystem_AmigaOS();
assert(g_system); assert(g_system);

View file

@ -1,18 +1,18 @@
# Special target to create an AmigaOS snapshot installation # Special target to create an AmigaOS snapshot installation
amigaos4dist: $(EXECUTABLE) amigaosdist: $(EXECUTABLE)
mkdir -p $(AMIGAOS4PATH) mkdir -p $(AMIGAOSPATH)
mkdir -p $(AMIGAOS4PATH)/themes mkdir -p $(AMIGAOSPATH)/themes
mkdir -p $(AMIGAOS4PATH)/extras mkdir -p $(AMIGAOSPATH)/extras
$(STRIP) $(EXECUTABLE) -o $(AMIGAOS4PATH)/$(EXECUTABLE) $(STRIP) $(EXECUTABLE) -o $(AMIGAOSPATH)/$(EXECUTABLE)
cp ${srcdir}/icons/residualvm.info $(AMIGAOS4PATH)/$(EXECUTABLE).info cp ${srcdir}/icons/residualvm.info $(AMIGAOSPATH)/$(EXECUTABLE).info
cp $(DIST_FILES_THEMES) $(AMIGAOS4PATH)/themes/ cp $(DIST_FILES_THEMES) $(AMIGAOSPATH)/themes/
ifdef DIST_FILES_ENGINEDATA ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AMIGAOS4PATH)/extras/ cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/
endif endif
cp $(DIST_FILES_DOCS) $(AMIGAOS4PATH) cp $(DIST_FILES_DOCS) $(AMIGAOSPATH)
# Special target to cross create an AmigaOS snapshot installation # Special target to cross create an AmigaOS snapshot installation
amigaos4cross: $(EXECUTABLE) amigaoscross: $(EXECUTABLE)
mkdir -p ResidualVM mkdir -p ResidualVM
mkdir -p ResidualVM/themes mkdir -p ResidualVM/themes
mkdir -p ResidualVM/extras mkdir -p ResidualVM/extras

View file

@ -56,6 +56,9 @@
* to properly work in exports (i.e. release tar balls etc.). * to properly work in exports (i.e. release tar balls etc.).
*/ */
const char *gScummVMVersion = SCUMMVM_VERSION; const char *gScummVMVersion = SCUMMVM_VERSION;
#ifdef __amigaos4__
static const char *version_cookie __attribute__((used)) = "$VER: ScummVM " SCUMMVM_VERSION " (" __DATE__ ", " __TIME__ ")";
#endif
#ifdef __PLAYSTATION2__ #ifdef __PLAYSTATION2__
const char *gScummVMBuildDate = "Git Master"; /* ScummVM Git Master */ const char *gScummVMBuildDate = "Git Master"; /* ScummVM Git Master */
const char *gScummVMVersionDate = SCUMMVM_VERSION " - PlayStation2"; const char *gScummVMVersionDate = SCUMMVM_VERSION " - PlayStation2";

View file

@ -597,7 +597,7 @@ void ConfigManager::setActiveDomain(const String &domName) {
_activeDomain = 0; _activeDomain = 0;
} else { } else {
assert(isValidDomainName(domName)); assert(isValidDomainName(domName));
_activeDomain = & _gameDomains[domName]; _activeDomain = &_gameDomains[domName];
} }
_activeDomainName = domName; _activeDomainName = domName;
} }
@ -626,6 +626,10 @@ void ConfigManager::addMiscDomain(const String &domName) {
void ConfigManager::removeGameDomain(const String &domName) { void ConfigManager::removeGameDomain(const String &domName) {
assert(!domName.empty()); assert(!domName.empty());
assert(isValidDomainName(domName)); assert(isValidDomainName(domName));
if (domName == _activeDomainName) {
_activeDomainName.clear();
_activeDomain = 0;
}
_gameDomains.erase(domName); _gameDomains.erase(domName);
} }
@ -638,6 +642,10 @@ void ConfigManager::removeMiscDomain(const String &domName) {
void ConfigManager::renameGameDomain(const String &oldName, const String &newName) { void ConfigManager::renameGameDomain(const String &oldName, const String &newName) {
renameDomain(oldName, newName, _gameDomains); renameDomain(oldName, newName, _gameDomains);
if (_activeDomainName == oldName) {
_activeDomainName = newName;
_activeDomain = &_gameDomains[newName];
}
} }
void ConfigManager::renameMiscDomain(const String &oldName, const String &newName) { void ConfigManager::renameMiscDomain(const String &oldName, const String &newName) {

4
configure vendored
View file

@ -175,7 +175,7 @@ _as="as"
_windres=windres _windres=windres
_stagingpath="staging" _stagingpath="staging"
_win32path="C:/residualvm" _win32path="C:/residualvm"
_amigaos4path="Games:ResidualVM" _amigaospath="Games:ResidualVM"
_staticlibpath= _staticlibpath=
_sdlconfig=sdl-config _sdlconfig=sdl-config
_freetypeconfig=freetype-config _freetypeconfig=freetype-config
@ -4572,7 +4572,7 @@ WINDRES := $_windres
WINDRESFLAGS := $WINDRESFLAGS WINDRESFLAGS := $WINDRESFLAGS
STAGINGPATH=$_stagingpath STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path WIN32PATH=$_win32path
AMIGAOS4PATH=$_amigaos4path AMIGAOSPATH=$_amigaospath
STATICLIBPATH=$_staticlibpath STATICLIBPATH=$_staticlibpath
BACKEND := $_backend BACKEND := $_backend

View file

@ -122,7 +122,7 @@ bool cleanupPirated(ADGameDescList &matched) {
// We ruled out all variants and now have nothing // We ruled out all variants and now have nothing
if (matched.empty()) { if (matched.empty()) {
warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size()); warning("Illegitimate game copy detected. We provide no support in such cases");
return true; return true;
} }
} }

View file

@ -27,6 +27,97 @@
namespace Graphics { namespace Graphics {
/** Template to expand from an n-bit component to an 8-bit component */
template<int depth>
struct ColorComponent {
};
template<>
struct ColorComponent<0> {
static inline uint expand(uint value) {
return 0;
}
};
template<>
struct ColorComponent<1> {
static inline uint expand(uint value) {
value &= 1;
return value |
(value << 1) |
(value << 2) |
(value << 3) |
(value << 4) |
(value << 5) |
(value << 6) |
(value << 7);
}
};
template<>
struct ColorComponent<2> {
static inline uint expand(uint value) {
value &= 3;
return value |
(value << 2) |
(value << 4) |
(value << 6);
}
};
template<>
struct ColorComponent<3> {
static inline uint expand(uint value) {
value &= 7;
return (value << 5) |
(value << 2) |
(value >> 1);
}
};
template<>
struct ColorComponent<4> {
static inline uint expand(uint value) {
value &= 15;
return value |
(value << 4);
}
};
template<>
struct ColorComponent<5> {
static inline uint expand(uint value) {
value &= 31;
return (value << 3) |
(value >> 2);
}
};
template<>
struct ColorComponent<6> {
static inline uint expand(uint value) {
value &= 63;
return (value << 2) |
(value >> 4);
}
};
template<>
struct ColorComponent<7> {
static inline uint expand(uint value) {
value &= 127;
return (value << 1) |
(value >> 6);
}
};
template<>
struct ColorComponent<8> {
static inline uint expand(uint value) {
return value & 255;
}
};
/** /**
* A pixel format description. * A pixel format description.
* *
@ -91,16 +182,16 @@ struct PixelFormat {
} }
inline void colorToRGB(uint32 color, uint8 &r, uint8 &g, uint8 &b) const { inline void colorToRGB(uint32 color, uint8 &r, uint8 &g, uint8 &b) const {
r = ((color >> rShift) << rLoss) & 0xFF; r = expand(rBits(), color >> rShift);
g = ((color >> gShift) << gLoss) & 0xFF; g = expand(gBits(), color >> gShift);
b = ((color >> bShift) << bLoss) & 0xFF; b = expand(bBits(), color >> bShift);
} }
inline void colorToARGB(uint32 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const { inline void colorToARGB(uint32 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const {
a = (aBits() == 0) ? 0xFF : (((color >> aShift) << aLoss) & 0xFF); a = (aBits() == 0) ? 0xFF : expand(aBits(), color >> aShift);
r = ((color >> rShift) << rLoss) & 0xFF; r = expand(rBits(), color >> rShift);
g = ((color >> gShift) << gLoss) & 0xFF; g = expand(gBits(), color >> gShift);
b = ((color >> bShift) << bLoss) & 0xFF; b = expand(bBits(), color >> bShift);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -142,6 +233,33 @@ struct PixelFormat {
inline uint aMax() const { inline uint aMax() const {
return (1 << aBits()) - 1; return (1 << aBits()) - 1;
} }
/** Expand a given bit-depth component to a full 8-bit component */
static inline uint expand(uint bits, uint color) {
switch (bits) {
case 0:
return ColorComponent<0>::expand(color);
case 1:
return ColorComponent<1>::expand(color);
case 2:
return ColorComponent<2>::expand(color);
case 3:
return ColorComponent<3>::expand(color);
case 4:
return ColorComponent<4>::expand(color);
case 5:
return ColorComponent<5>::expand(color);
case 6:
return ColorComponent<6>::expand(color);
case 7:
return ColorComponent<7>::expand(color);
case 8:
return ColorComponent<8>::expand(color);
}
// Unsupported
return 0;
}
}; };
} // End of namespace Graphics } // End of namespace Graphics

View file

@ -84,7 +84,7 @@ enum {
static const char *savePeriodLabels[] = { _s("Never"), _s("every 5 mins"), _s("every 10 mins"), _s("every 15 mins"), _s("every 30 mins"), 0 }; static const char *savePeriodLabels[] = { _s("Never"), _s("every 5 mins"), _s("every 10 mins"), _s("every 15 mins"), _s("every 30 mins"), 0 };
static const int savePeriodValues[] = { 0, 5 * 60, 10 * 60, 15 * 60, 30 * 60, -1 }; static const int savePeriodValues[] = { 0, 5 * 60, 10 * 60, 15 * 60, 30 * 60, -1 };
static const char *outputRateLabels[] = { _s("<default>"), _s("8 kHz"), _s("11kHz"), _s("22 kHz"), _s("44 kHz"), _s("48 kHz"), 0 }; static const char *outputRateLabels[] = { _s("<default>"), _s("8 kHz"), _s("11 kHz"), _s("22 kHz"), _s("44 kHz"), _s("48 kHz"), 0 };
static const int outputRateValues[] = { 0, 8000, 11025, 22050, 44100, 48000, -1 }; static const int outputRateValues[] = { 0, 8000, 11025, 22050, 44100, 48000, -1 };
OptionsDialog::OptionsDialog(const Common::String &domain, int x, int y, int w, int h) OptionsDialog::OptionsDialog(const Common::String &domain, int x, int y, int w, int h)
@ -890,10 +890,10 @@ void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefi
// SoundFont // SoundFont
if (g_system->getOverlayWidth() > 320) if (g_system->getOverlayWidth() > 320)
_soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _("SoundFont:"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd); _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _("SoundFont:"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity"), kChooseSoundFontCmd);
else else
_soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _c("SoundFont:", "lowres"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd); _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _c("SoundFont:", "lowres"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity"), kChooseSoundFontCmd);
_soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _c("None", "soundfont"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity")); _soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _c("None", "soundfont"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity"));
_soundFontClearButton = addClearButton(boss, prefix + "mcFontClearButton", kClearSoundFontCmd); _soundFontClearButton = addClearButton(boss, prefix + "mcFontClearButton", kClearSoundFontCmd);

View file

@ -52,11 +52,16 @@ CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec() {
_curFrame.strips = NULL; _curFrame.strips = NULL;
_y = 0; _y = 0;
if (bitsPerPixel == 8) if (bitsPerPixel == 8) {
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); _pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
else } else {
_pixelFormat = g_system->getScreenFormat(); _pixelFormat = g_system->getScreenFormat();
// Default to a 32bpp format, if in 8bpp mode
if (_pixelFormat.bytesPerPixel == 1)
_pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0);
}
// Create a lookup for the clip function // Create a lookup for the clip function
// This dramatically improves the performance of the color conversion // This dramatically improves the performance of the color conversion
_clipTableBuf = new byte[1024]; _clipTableBuf = new byte[1024];

View file

@ -49,7 +49,6 @@ class RenderModeTestSuite : public CxxTest::TestSuite {
* Notably, the output should not be in mixed case. * Notably, the output should not be in mixed case.
*/ */
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns", 7); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns", 7);
TS_ASSERT_DIFFERS(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns");
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("CGA")), "cga", 3); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("CGA")), "cga", 3);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("vga")), "vga", 3); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("vga")), "vga", 3);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("Ega")), "ega", 3); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("Ega")), "ega", 3);

View file

@ -778,6 +778,31 @@ void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) {
} }
} }
void VideoDecoder::setEndFrame(uint frame) {
VideoTrack *track = 0;
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
// We only allow this when one video track is present
if (track)
return;
track = (VideoTrack *)*it;
}
}
// If we didn't find a video track, we can't set the final frame (of course)
if (!track)
return;
Audio::Timestamp time = track->getFrameTime(frame + 1);
if (time < 0)
return;
setEndTime(time);
}
VideoDecoder::Track *VideoDecoder::getTrack(uint track) { VideoDecoder::Track *VideoDecoder::getTrack(uint track) {
if (track > _internalTracks.size()) if (track > _internalTracks.size())
return 0; return 0;

View file

@ -213,6 +213,17 @@ public:
*/ */
void setEndTime(const Audio::Timestamp &endTime); void setEndTime(const Audio::Timestamp &endTime);
/**
* Set the end frame.
*
* The passed frame will be the last frame to show.
*
* Like seekToFrame(), this only works when one video track is present,
* and that track supports getFrameTime(). This calls setEndTime()
* internally.
*/
void setEndFrame(uint frame);
/** /**
* Get the stop time of the video (if not set, zero) * Get the stop time of the video (if not set, zero)
*/ */