ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

video_decoder.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "video/video_decoder.h"
00024 
00025 #include "audio/audiostream.h"
00026 #include "audio/mixer.h" // for kMaxChannelVolume
00027 
00028 #include "common/rational.h"
00029 #include "common/file.h"
00030 #include "common/system.h"
00031 
00032 #include "graphics/palette.h"
00033 
00034 namespace Video {
00035 
00036 VideoDecoder::VideoDecoder() {
00037     _startTime = 0;
00038     _dirtyPalette = false;
00039     _palette = 0;
00040     _playbackRate = 0;
00041     _audioVolume = Audio::Mixer::kMaxChannelVolume;
00042     _audioBalance = 0;
00043     _soundType = Audio::Mixer::kPlainSoundType;
00044     _pauseLevel = 0;
00045     _needsUpdate = false;
00046     _lastTimeChange = 0;
00047     _endTime = 0;
00048     _endTimeSet = false;
00049     _nextVideoTrack = 0;
00050     _mainAudioTrack = 0;
00051     _canSetDither = true;
00052 
00053     // Find the best format for output
00054     _defaultHighColorFormat = g_system->getScreenFormat();
00055 
00056     if (_defaultHighColorFormat.bytesPerPixel == 1)
00057         _defaultHighColorFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0);
00058 }
00059 
00060 void VideoDecoder::close() {
00061     if (isPlaying())
00062         stop();
00063 
00064     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00065         delete *it;
00066 
00067     _tracks.clear();
00068     _internalTracks.clear();
00069     _externalTracks.clear();
00070     _dirtyPalette = false;
00071     _palette = 0;
00072     _startTime = 0;
00073     _audioVolume = Audio::Mixer::kMaxChannelVolume;
00074     _audioBalance = 0;
00075     _pauseLevel = 0;
00076     _needsUpdate = false;
00077     _lastTimeChange = 0;
00078     _endTime = 0;
00079     _endTimeSet = false;
00080     _nextVideoTrack = 0;
00081     _mainAudioTrack = 0;
00082     _canSetDither = true;
00083 }
00084 
00085 bool VideoDecoder::loadFile(const Common::String &filename) {
00086     Common::File *file = new Common::File();
00087 
00088     if (!file->open(filename)) {
00089         delete file;
00090         return false;
00091     }
00092 
00093     return loadStream(file);
00094 }
00095 
00096 bool VideoDecoder::needsUpdate() const {
00097     return hasFramesLeft() && getTimeToNextFrame() == 0;
00098 }
00099 
00100 void VideoDecoder::pauseVideo(bool pause) {
00101     if (pause) {
00102         _pauseLevel++;
00103 
00104     // We can't go negative
00105     } else if (_pauseLevel) {
00106         _pauseLevel--;
00107 
00108     // Do nothing
00109     } else {
00110         return;
00111     }
00112 
00113     if (_pauseLevel == 1 && pause) {
00114         _pauseStartTime = g_system->getMillis(); // Store the starting time from pausing to keep it for later
00115 
00116         for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00117             (*it)->pause(true);
00118     } else if (_pauseLevel == 0) {
00119         for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00120             (*it)->pause(false);
00121 
00122         _startTime += (g_system->getMillis() - _pauseStartTime);
00123     }
00124 }
00125 
00126 void VideoDecoder::resetPauseStartTime() {
00127     if (isPaused())
00128         _pauseStartTime = g_system->getMillis();
00129 }
00130 
00131 void VideoDecoder::setVolume(byte volume) {
00132     _audioVolume = volume;
00133 
00134     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00135         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00136             ((AudioTrack *)*it)->setVolume(_audioVolume);
00137 }
00138 
00139 void VideoDecoder::setBalance(int8 balance) {
00140     _audioBalance = balance;
00141 
00142     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00143         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00144             ((AudioTrack *)*it)->setBalance(_audioBalance);
00145 }
00146 
00147 Audio::Mixer::SoundType VideoDecoder::getSoundType() const {
00148     return _soundType;
00149 }
00150 
00151 void VideoDecoder::setSoundType(Audio::Mixer::SoundType soundType) {
00152     assert(!isVideoLoaded());
00153     _soundType = soundType;
00154 }
00155 
00156 bool VideoDecoder::isVideoLoaded() const {
00157     return !_tracks.empty();
00158 }
00159 
00160 uint16 VideoDecoder::getWidth() const {
00161     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00162         if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00163             return ((VideoTrack *)*it)->getWidth();
00164 
00165     return 0;
00166 }
00167 
00168 uint16 VideoDecoder::getHeight() const {
00169     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00170         if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00171             return ((VideoTrack *)*it)->getHeight();
00172 
00173     return 0;
00174 }
00175 
00176 Graphics::PixelFormat VideoDecoder::getPixelFormat() const {
00177     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00178         if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00179             return ((VideoTrack *)*it)->getPixelFormat();
00180 
00181     return Graphics::PixelFormat();
00182 }
00183 
00184 const Graphics::Surface *VideoDecoder::decodeNextFrame() {
00185     _needsUpdate = false;
00186     _canSetDither = false;
00187 
00188     readNextPacket();
00189 
00190     // If we have no next video track at this point, there shouldn't be
00191     // any frame available for us to display.
00192     if (!_nextVideoTrack)
00193         return 0;
00194 
00195     const Graphics::Surface *frame = _nextVideoTrack->decodeNextFrame();
00196 
00197     if (_nextVideoTrack->hasDirtyPalette()) {
00198         _palette = _nextVideoTrack->getPalette();
00199         _dirtyPalette = true;
00200     }
00201 
00202     // Look for the next video track here for the next decode.
00203     findNextVideoTrack();
00204 
00205     return frame;
00206 }
00207 
00208 bool VideoDecoder::setReverse(bool reverse) {
00209     // Can only reverse video-only videos
00210     if (reverse && hasAudio())
00211         return false;
00212 
00213     // Attempt to make sure all the tracks are in the requested direction
00214     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00215         if ((*it)->getTrackType() == Track::kTrackTypeVideo && ((VideoTrack *)*it)->isReversed() != reverse) {
00216             if (!((VideoTrack *)*it)->setReverse(reverse))
00217                 return false;
00218 
00219             _needsUpdate = true; // force an update
00220         }
00221     }
00222 
00223     findNextVideoTrack();
00224     return true;
00225 }
00226 
00227 const byte *VideoDecoder::getPalette() {
00228     _dirtyPalette = false;
00229     return _palette;
00230 }
00231 
00232 int VideoDecoder::getCurFrame() const {
00233     int32 frame = -1;
00234 
00235     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00236         if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00237             frame += ((VideoTrack *)*it)->getCurFrame() + 1;
00238 
00239     return frame;
00240 }
00241 
00242 uint32 VideoDecoder::getFrameCount() const {
00243     int count = 0;
00244 
00245     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00246         if ((*it)->getTrackType() == Track::kTrackTypeVideo)
00247             count += ((VideoTrack *)*it)->getFrameCount();
00248 
00249     return count;
00250 }
00251 
00252 uint32 VideoDecoder::getTime() const {
00253     if (!isPlaying())
00254         return _lastTimeChange.msecs();
00255 
00256     if (isPaused())
00257         return MAX<int>((_playbackRate * (_pauseStartTime - _startTime)).toInt(), 0);
00258 
00259     if (useAudioSync()) {
00260         for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00261             if ((*it)->getTrackType() == Track::kTrackTypeAudio && !(*it)->endOfTrack()) {
00262                 uint32 time = ((const AudioTrack *)*it)->getRunningTime();
00263 
00264                 if (time != 0)
00265                     return time + _lastTimeChange.msecs();
00266             }
00267         }
00268     }
00269 
00270     return MAX<int>((_playbackRate * (g_system->getMillis() - _startTime)).toInt(), 0);
00271 }
00272 
00273 uint32 VideoDecoder::getTimeToNextFrame() const {
00274     if (endOfVideo() || _needsUpdate || !_nextVideoTrack)
00275         return 0;
00276 
00277     uint32 currentTime = getTime();
00278     uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime();
00279 
00280     if (_nextVideoTrack->isReversed()) {
00281         // For reversed videos, we need to handle the time difference the opposite way.
00282         if (nextFrameStartTime >= currentTime)
00283             return 0;
00284 
00285         return currentTime - nextFrameStartTime;
00286     }
00287 
00288     // Otherwise, handle it normally.
00289     if (nextFrameStartTime <= currentTime)
00290         return 0;
00291 
00292     return nextFrameStartTime - currentTime;
00293 }
00294 
00295 bool VideoDecoder::endOfVideo() const {
00296     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00297         const Track *track = *it;
00298 
00299         bool videoEndTimeReached = _endTimeSet && track->getTrackType() == Track::kTrackTypeVideo && ((const VideoTrack *)track)->getNextFrameStartTime() >= (uint)_endTime.msecs();
00300         bool endReached = track->endOfTrack() || (isPlaying() && videoEndTimeReached);
00301         if (!endReached)
00302             return false;
00303     }
00304 
00305     return true;
00306 }
00307 
00308 bool VideoDecoder::isRewindable() const {
00309     if (!isVideoLoaded())
00310         return false;
00311 
00312     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00313         if (!(*it)->isRewindable())
00314             return false;
00315 
00316     return true;
00317 }
00318 
00319 bool VideoDecoder::rewind() {
00320     if (!isRewindable())
00321         return false;
00322 
00323     // Stop all tracks so they can be rewound
00324     if (isPlaying())
00325         stopAudio();
00326 
00327     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00328         if (!(*it)->rewind())
00329             return false;
00330 
00331     // Now that we've rewound, start all tracks again
00332     if (isPlaying())
00333         startAudio();
00334 
00335     _lastTimeChange = 0;
00336     _startTime = g_system->getMillis();
00337     resetPauseStartTime();
00338     findNextVideoTrack();
00339     return true;
00340 }
00341 
00342 bool VideoDecoder::isSeekable() const {
00343     if (!isVideoLoaded())
00344         return false;
00345 
00346     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00347         if (!(*it)->isSeekable())
00348             return false;
00349 
00350     return true;
00351 }
00352 
00353 bool VideoDecoder::seek(const Audio::Timestamp &time) {
00354     if (!isSeekable())
00355         return false;
00356 
00357     // Stop all tracks so they can be seeked
00358     if (isPlaying())
00359         stopAudio();
00360 
00361     // Do the actual seeking
00362     if (!seekIntern(time))
00363         return false;
00364 
00365     // Seek any external track too
00366     for (TrackListIterator it = _externalTracks.begin(); it != _externalTracks.end(); it++)
00367         if (!(*it)->seek(time))
00368             return false;
00369 
00370     _lastTimeChange = time;
00371 
00372     // Now that we've seeked, start all tracks again
00373     // Also reset our start time
00374     if (isPlaying()) {
00375         startAudio();
00376         _startTime = g_system->getMillis() - (time.msecs() / _playbackRate).toInt();
00377     }
00378 
00379     resetPauseStartTime();
00380     findNextVideoTrack();
00381     _needsUpdate = true;
00382     return true;
00383 }
00384 
00385 bool VideoDecoder::seekToFrame(uint frame) {
00386     if (!isSeekable())
00387         return false;
00388 
00389     VideoTrack *track = 0;
00390 
00391     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00392         if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
00393             // We only allow seeking by frame when one video track
00394             // is present
00395             if (track)
00396                 return false;
00397 
00398             track = (VideoTrack *)*it;
00399         }
00400     }
00401 
00402     // If we didn't find a video track, we can't seek by frame (of course)
00403     if (!track)
00404         return false;
00405 
00406     Audio::Timestamp time = track->getFrameTime(frame);
00407 
00408     if (time < 0)
00409         return false;
00410 
00411     return seek(time);
00412 }
00413 
00414 void VideoDecoder::start() {
00415     if (!isPlaying())
00416         setRate(1);
00417 }
00418 
00419 void VideoDecoder::stop() {
00420     if (!isPlaying())
00421         return;
00422 
00423     // Stop audio here so we don't have it affect getTime()
00424     stopAudio();
00425 
00426     // Keep the time marked down in case we start up again
00427     // We do this before _playbackRate is set so we don't get
00428     // _lastTimeChange returned, but before _pauseLevel is
00429     // reset.
00430     _lastTimeChange = getTime();
00431 
00432     _playbackRate = 0;
00433     _startTime = 0;
00434     _palette = 0;
00435     _dirtyPalette = false;
00436     _needsUpdate = false;
00437 
00438     // Also reset the pause state.
00439     _pauseLevel = 0;
00440 
00441     // Reset the pause state of the tracks too
00442     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00443         (*it)->pause(false);
00444 }
00445 
00446 void VideoDecoder::setRate(const Common::Rational &rate) {
00447     if (!isVideoLoaded() || _playbackRate == rate)
00448         return;
00449 
00450     if (rate == 0) {
00451         stop();
00452         return;
00453     } else if (rate != 1 && hasAudio()) {
00454         warning("Cannot set custom rate in videos with audio");
00455         return;
00456     }
00457 
00458     Common::Rational targetRate = rate;
00459 
00460     // Attempt to set the reverse
00461     if (!setReverse(rate < 0)) {
00462         assert(rate < 0); // We shouldn't fail for forward.
00463         warning("Cannot set custom rate to backwards");
00464         setReverse(false);
00465         targetRate = 1;
00466 
00467         if (_playbackRate == targetRate)
00468             return;
00469     }
00470 
00471     if (_playbackRate != 0)
00472         _lastTimeChange = getTime();
00473 
00474     _playbackRate = targetRate;
00475     _startTime = g_system->getMillis();
00476 
00477     // Adjust start time if we've seeked to something besides zero time
00478     if (_lastTimeChange != 0)
00479         _startTime -= (_lastTimeChange.msecs() / _playbackRate).toInt();
00480 
00481     startAudio();
00482 }
00483 
00484 bool VideoDecoder::isPlaying() const {
00485     return _playbackRate != 0;
00486 }
00487 
00488 Audio::Timestamp VideoDecoder::getDuration() const {
00489     Audio::Timestamp maxDuration(0, 1000);
00490 
00491     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00492         Audio::Timestamp duration = (*it)->getDuration();
00493 
00494         if (duration > maxDuration)
00495             maxDuration = duration;
00496     }
00497 
00498     return maxDuration;
00499 }
00500 
00501 bool VideoDecoder::seekIntern(const Audio::Timestamp &time) {
00502     for (TrackList::iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++)
00503         if (!(*it)->seek(time))
00504             return false;
00505 
00506     return true;
00507 }
00508 
00509 bool VideoDecoder::setDitheringPalette(const byte *palette) {
00510     // If a frame was already decoded, we can't set it now.
00511     if (!_canSetDither)
00512         return false;
00513 
00514     bool result = false;
00515 
00516     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00517         if ((*it)->getTrackType() == Track::kTrackTypeVideo && ((VideoTrack *)*it)->canDither()) {
00518             ((VideoTrack *)*it)->setDither(palette);
00519             result = true;
00520         }
00521     }
00522 
00523     return result;
00524 }
00525 
00526 VideoDecoder::Track::Track() {
00527     _paused = false;
00528 }
00529 
00530 bool VideoDecoder::Track::isRewindable() const {
00531     return isSeekable();
00532 }
00533 
00534 bool VideoDecoder::Track::rewind() {
00535     return seek(Audio::Timestamp(0, 1000));
00536 }
00537 
00538 void VideoDecoder::Track::pause(bool shouldPause) {
00539     _paused = shouldPause;
00540     pauseIntern(shouldPause);
00541 }
00542 
00543 Audio::Timestamp VideoDecoder::Track::getDuration() const {
00544     return Audio::Timestamp(0, 1000);
00545 }
00546 
00547 bool VideoDecoder::VideoTrack::endOfTrack() const {
00548     return getCurFrame() >= (getFrameCount() - 1);
00549 }
00550 
00551 Audio::Timestamp VideoDecoder::VideoTrack::getFrameTime(uint frame) const {
00552     // Default implementation: Return an invalid (negative) number
00553     return Audio::Timestamp().addFrames(-1);
00554 }
00555 
00556 uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const {
00557     if (endOfTrack() || getCurFrame() < 0)
00558         return 0;
00559 
00560     return getFrameTime(getCurFrame() + 1).msecs();
00561 }
00562 
00563 Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getFrameTime(uint frame) const {
00564     // Try to get as accurate as possible, considering we have a fractional frame rate
00565     // (which Audio::Timestamp doesn't support).
00566     Common::Rational frameRate = getFrameRate();
00567 
00568     // Try to keep it in terms of the frame rate, if the frame rate is a whole
00569     // number.
00570     if (frameRate.getDenominator() == 1)
00571         return Audio::Timestamp(0, frame, frameRate.toInt());
00572 
00573     // Convert as best as possible
00574     Common::Rational time = frameRate.getInverse() * frame;
00575     return Audio::Timestamp(0, time.getNumerator(), time.getDenominator());
00576 }
00577 
00578 uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &time) const {
00579     Common::Rational frameRate = getFrameRate();
00580 
00581     // Easy conversion
00582     if (frameRate == time.framerate())
00583         return time.totalNumberOfFrames();
00584 
00585     // Create the rational based on the time first to hopefully cancel out
00586     // *something* when multiplying by the frameRate (which can be large in
00587     // some AVI videos).
00588     return (Common::Rational(time.totalNumberOfFrames(), time.framerate()) * frameRate).toInt();
00589 }
00590 
00591 Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const {
00592     return getFrameTime(getFrameCount());
00593 }
00594 
00595 VideoDecoder::AudioTrack::AudioTrack(Audio::Mixer::SoundType soundType) :
00596         _volume(Audio::Mixer::kMaxChannelVolume),
00597         _soundType(soundType),
00598         _balance(0),
00599         _muted(false) {
00600 }
00601 
00602 bool VideoDecoder::AudioTrack::endOfTrack() const {
00603     Audio::AudioStream *stream = getAudioStream();
00604     return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData();
00605 }
00606 
00607 void VideoDecoder::AudioTrack::setVolume(byte volume) {
00608     _volume = volume;
00609 
00610     if (g_system->getMixer()->isSoundHandleActive(_handle))
00611         g_system->getMixer()->setChannelVolume(_handle, _muted ? 0 : _volume);
00612 }
00613 
00614 void VideoDecoder::AudioTrack::setBalance(int8 balance) {
00615     _balance = balance;
00616 
00617     if (g_system->getMixer()->isSoundHandleActive(_handle))
00618         g_system->getMixer()->setChannelBalance(_handle, _balance);
00619 }
00620 
00621 void VideoDecoder::AudioTrack::start() {
00622     stop();
00623 
00624     Audio::AudioStream *stream = getAudioStream();
00625     assert(stream);
00626 
00627     g_system->getMixer()->playStream(_soundType, &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::NO);
00628 
00629     // Pause the audio again if we're still paused
00630     if (isPaused())
00631         g_system->getMixer()->pauseHandle(_handle, true);
00632 }
00633 
00634 void VideoDecoder::AudioTrack::stop() {
00635     g_system->getMixer()->stopHandle(_handle);
00636 }
00637 
00638 void VideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) {
00639     stop();
00640 
00641     Audio::AudioStream *stream = getAudioStream();
00642     assert(stream);
00643 
00644     stream = Audio::makeLimitingAudioStream(stream, limit, DisposeAfterUse::NO);
00645 
00646     g_system->getMixer()->playStream(_soundType, &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::YES);
00647 
00648     // Pause the audio again if we're still paused
00649     if (isPaused())
00650         g_system->getMixer()->pauseHandle(_handle, true);
00651 }
00652 
00653 uint32 VideoDecoder::AudioTrack::getRunningTime() const {
00654     if (g_system->getMixer()->isSoundHandleActive(_handle))
00655         return g_system->getMixer()->getSoundElapsedTime(_handle);
00656 
00657     return 0;
00658 }
00659 
00660 void VideoDecoder::AudioTrack::setMute(bool mute) {
00661     // Update the mute settings, if required
00662     if (_muted != mute) {
00663         _muted = mute;
00664 
00665         if (g_system->getMixer()->isSoundHandleActive(_handle))
00666             g_system->getMixer()->setChannelVolume(_handle, mute ? 0 : _volume);
00667     }
00668 }
00669 
00670 void VideoDecoder::AudioTrack::pauseIntern(bool shouldPause) {
00671     if (g_system->getMixer()->isSoundHandleActive(_handle))
00672         g_system->getMixer()->pauseHandle(_handle, shouldPause);
00673 }
00674 
00675 Audio::AudioStream *VideoDecoder::RewindableAudioTrack::getAudioStream() const {
00676     return getRewindableAudioStream();
00677 }
00678 
00679 bool VideoDecoder::RewindableAudioTrack::rewind() {
00680     Audio::RewindableAudioStream *stream = getRewindableAudioStream();
00681     assert(stream);
00682     return stream->rewind();
00683 }
00684 
00685 Audio::Timestamp VideoDecoder::SeekableAudioTrack::getDuration() const {
00686     Audio::SeekableAudioStream *stream = getSeekableAudioStream();
00687     assert(stream);
00688     return stream->getLength();
00689 }
00690 
00691 Audio::AudioStream *VideoDecoder::SeekableAudioTrack::getAudioStream() const {
00692     return getSeekableAudioStream();
00693 }
00694 
00695 bool VideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) {
00696     Audio::SeekableAudioStream *stream = getSeekableAudioStream();
00697     assert(stream);
00698     return stream->seek(time);
00699 }
00700 
00701 VideoDecoder::StreamFileAudioTrack::StreamFileAudioTrack(Audio::Mixer::SoundType soundType) :
00702         SeekableAudioTrack(soundType) {
00703     _stream = 0;
00704 }
00705 
00706 VideoDecoder::StreamFileAudioTrack::~StreamFileAudioTrack() {
00707     delete _stream;
00708 }
00709 
00710 bool VideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &baseName) {
00711     // TODO: Make sure the stream isn't being played
00712     delete _stream;
00713     _stream = Audio::SeekableAudioStream::openStreamFile(baseName);
00714     return _stream != 0;
00715 }
00716 
00717 void VideoDecoder::addTrack(Track *track, bool isExternal) {
00718     _tracks.push_back(track);
00719 
00720     if (isExternal)
00721         _externalTracks.push_back(track);
00722     else
00723         _internalTracks.push_back(track);
00724 
00725     if (track->getTrackType() == Track::kTrackTypeAudio) {
00726         // Update volume settings if it's an audio track
00727         ((AudioTrack *)track)->setVolume(_audioVolume);
00728         ((AudioTrack *)track)->setBalance(_audioBalance);
00729 
00730         if (!isExternal && supportsAudioTrackSwitching()) {
00731             if (_mainAudioTrack) {
00732                 // The main audio track has already been found
00733                 ((AudioTrack *)track)->setMute(true);
00734             } else {
00735                 // First audio track found -> now the main one
00736                 _mainAudioTrack = (AudioTrack *)track;
00737                 _mainAudioTrack->setMute(false);
00738             }
00739         }
00740     } else if (track->getTrackType() == Track::kTrackTypeVideo) {
00741         // If this track has a better time, update _nextVideoTrack
00742         if (!_nextVideoTrack || ((VideoTrack *)track)->getNextFrameStartTime() < _nextVideoTrack->getNextFrameStartTime())
00743             _nextVideoTrack = (VideoTrack *)track;
00744     }
00745 
00746     // Keep the track paused if we're paused
00747     if (isPaused())
00748         track->pause(true);
00749 
00750     // Start the track if we're playing
00751     if (isPlaying() && track->getTrackType() == Track::kTrackTypeAudio)
00752         ((AudioTrack *)track)->start();
00753 }
00754 
00755 bool VideoDecoder::addStreamFileTrack(const Common::String &baseName) {
00756     // Only allow adding external tracks if a video is already loaded
00757     if (!isVideoLoaded())
00758         return false;
00759 
00760     StreamFileAudioTrack *track = new StreamFileAudioTrack(getSoundType());
00761 
00762     bool result = track->loadFromFile(baseName);
00763 
00764     if (result)
00765         addTrack(track, true);
00766     else
00767         delete track;
00768 
00769     return result;
00770 }
00771 
00772 bool VideoDecoder::setAudioTrack(int index) {
00773     if (!supportsAudioTrackSwitching())
00774         return false;
00775 
00776     AudioTrack *audioTrack = getAudioTrack(index);
00777 
00778     if (!audioTrack)
00779         return false;
00780 
00781     if (_mainAudioTrack == audioTrack)
00782         return true;
00783 
00784     _mainAudioTrack->setMute(true);
00785     audioTrack->setMute(false);
00786     _mainAudioTrack = audioTrack;
00787     return true;
00788 }
00789 
00790 uint VideoDecoder::getAudioTrackCount() const {
00791     uint count = 0;
00792 
00793     for (TrackList::const_iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++)
00794         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00795             count++;
00796 
00797     return count;
00798 }
00799 
00800 void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) {
00801     Audio::Timestamp startTime = 0;
00802 
00803     if (isPlaying()) {
00804         startTime = getTime();
00805         stopAudio();
00806     }
00807 
00808     _endTime = endTime;
00809     _endTimeSet = true;
00810 
00811     if (startTime > endTime)
00812         return;
00813 
00814     if (isPlaying()) {
00815         // We'll assume the audio track is going to start up at the same time it just was
00816         // and therefore not do any seeking.
00817         // Might want to set it anyway if we're seekable.
00818         startAudioLimit(_endTime.msecs() - startTime.msecs());
00819         _lastTimeChange = startTime;
00820     }
00821 }
00822 
00823 void VideoDecoder::setEndFrame(uint frame) {
00824     VideoTrack *track = 0;
00825 
00826     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00827         if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
00828             // We only allow this when one video track is present
00829             if (track)
00830                 return;
00831 
00832             track = (VideoTrack *)*it;
00833         }
00834     }
00835 
00836     // If we didn't find a video track, we can't set the final frame (of course)
00837     if (!track)
00838         return;
00839 
00840     Audio::Timestamp time = track->getFrameTime(frame + 1);
00841 
00842     if (time < 0)
00843         return;
00844 
00845     setEndTime(time);
00846 }
00847 
00848 VideoDecoder::Track *VideoDecoder::getTrack(uint track) {
00849     if (track >= _internalTracks.size())
00850         return 0;
00851 
00852     return _internalTracks[track];
00853 }
00854 
00855 const VideoDecoder::Track *VideoDecoder::getTrack(uint track) const {
00856     if (track >= _internalTracks.size())
00857         return 0;
00858 
00859     return _internalTracks[track];
00860 }
00861 
00862 bool VideoDecoder::endOfVideoTracks() const {
00863     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00864         if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack())
00865             return false;
00866 
00867     return true;
00868 }
00869 
00870 VideoDecoder::VideoTrack *VideoDecoder::findNextVideoTrack() {
00871     _nextVideoTrack = 0;
00872     uint32 bestTime = 0xFFFFFFFF;
00873 
00874     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00875         if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) {
00876             VideoTrack *track = (VideoTrack *)*it;
00877             uint32 time = track->getNextFrameStartTime();
00878 
00879             if (time < bestTime) {
00880                 bestTime = time;
00881                 _nextVideoTrack = track;
00882             }
00883         }
00884     }
00885 
00886     return _nextVideoTrack;
00887 }
00888 
00889 void VideoDecoder::startAudio() {
00890     if (_endTimeSet) {
00891         // HACK: Timestamp's subtraction asserts out when subtracting two times
00892         // with different rates.
00893         startAudioLimit(_endTime - _lastTimeChange.convertToFramerate(_endTime.framerate()));
00894         return;
00895     }
00896 
00897     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00898         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00899             ((AudioTrack *)*it)->start();
00900 }
00901 
00902 void VideoDecoder::stopAudio() {
00903     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00904         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00905             ((AudioTrack *)*it)->stop();
00906 }
00907 
00908 void VideoDecoder::startAudioLimit(const Audio::Timestamp &limit) {
00909     for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
00910         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00911             ((AudioTrack *)*it)->start(limit);
00912 }
00913 
00914 bool VideoDecoder::hasFramesLeft() const {
00915     // This is similar to endOfVideo(), except it doesn't take Audio into account (and returns true if not the end of the video)
00916     // This is only used for needsUpdate() atm so that setEndTime() works properly
00917     // And unlike endOfVideoTracks(), this takes into account _endTime
00918     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
00919         if ((*it)->getTrackType() != Track::kTrackTypeVideo)
00920             continue;
00921 
00922         const VideoTrack *track = (const VideoTrack *)*it;
00923 
00924         bool videoEndTimeReached = _endTimeSet && track->getNextFrameStartTime() >= (uint)_endTime.msecs();
00925         bool endReached = track->endOfTrack() || (isPlaying() && videoEndTimeReached);
00926         if (!endReached)
00927             return true;
00928     }
00929 
00930     return false;
00931 }
00932 
00933 bool VideoDecoder::hasAudio() const {
00934     for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
00935         if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00936             return true;
00937 
00938     return false;
00939 }
00940 
00941 void VideoDecoder::eraseTrack(Track *track) {
00942     for (uint idx = 0; idx < _externalTracks.size(); ++idx) {
00943         if (_externalTracks[idx] == track)
00944             _externalTracks.remove_at(idx);
00945     }
00946 
00947     for (uint idx = 0; idx < _internalTracks.size(); ++idx) {
00948         if (_internalTracks[idx] == track)
00949             _internalTracks.remove_at(idx);
00950     }
00951 
00952     for (uint idx = 0; idx < _tracks.size(); ++idx) {
00953         if (_tracks[idx] == track)
00954             _tracks.remove_at(idx);
00955     }
00956 }
00957 
00958 } // End of namespace Video


Generated on Sat Feb 16 2019 05:01:10 for ResidualVM by doxygen 1.7.1
curved edge   curved edge