mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-31 07:53:36 +00:00
VIDEO: Add first draft of the new VideoDecoder API
It is currently named "AdvancedVideoDecoder" until all current VideoDecoders are converted to the new API.
This commit is contained in:
parent
f0304ee0bb
commit
818c16bdd0
@ -22,6 +22,7 @@
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mixer.h" // for kMaxChannelVolume
|
||||
|
||||
#include "common/rational.h"
|
||||
@ -51,26 +52,10 @@ uint32 VideoDecoder::getTime() const {
|
||||
return g_system->getMillis() - _startTime;
|
||||
}
|
||||
|
||||
void VideoDecoder::setSystemPalette() {
|
||||
g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
|
||||
}
|
||||
|
||||
bool VideoDecoder::needsUpdate() const {
|
||||
return !endOfVideo() && getTimeToNextFrame() == 0;
|
||||
}
|
||||
|
||||
void VideoDecoder::reset() {
|
||||
_curFrame = -1;
|
||||
_startTime = 0;
|
||||
_pauseLevel = 0;
|
||||
_audioVolume = Audio::Mixer::kMaxChannelVolume;
|
||||
_audioBalance = 0;
|
||||
}
|
||||
|
||||
bool VideoDecoder::endOfVideo() const {
|
||||
return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
|
||||
}
|
||||
|
||||
void VideoDecoder::pauseVideo(bool pause) {
|
||||
if (pause) {
|
||||
_pauseLevel++;
|
||||
@ -108,6 +93,394 @@ void VideoDecoder::setBalance(int8 balance) {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
AdvancedVideoDecoder::AdvancedVideoDecoder() {
|
||||
_needsRewind = false;
|
||||
_dirtyPalette = false;
|
||||
_palette = 0;
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::close() {
|
||||
if (_isPlaying)
|
||||
stop();
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
delete *it;
|
||||
|
||||
_tracks.clear();
|
||||
_needsRewind = false;
|
||||
_dirtyPalette = false;
|
||||
_palette = 0;
|
||||
_startTime = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::isVideoLoaded() const {
|
||||
return !_tracks.empty();
|
||||
}
|
||||
|
||||
const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() {
|
||||
readNextPacket();
|
||||
VideoTrack *track = findNextVideoTrack();
|
||||
|
||||
if (!track)
|
||||
return 0;
|
||||
|
||||
const Graphics::Surface *frame = track->decodeNextFrame();
|
||||
|
||||
if (track->hasDirtyPalette()) {
|
||||
_palette = track->getPalette();
|
||||
_dirtyPalette = true;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
const byte *AdvancedVideoDecoder::getPalette() {
|
||||
_dirtyPalette = false;
|
||||
return _palette;
|
||||
}
|
||||
|
||||
int AdvancedVideoDecoder::getCurFrame() const {
|
||||
int32 frame = -1;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
|
||||
frame += ((VideoTrack *)*it)->getCurFrame() + 1;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
uint32 AdvancedVideoDecoder::getFrameCount() const {
|
||||
int count = 0;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
|
||||
count += ((VideoTrack *)*it)->getFrameCount();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32 AdvancedVideoDecoder::getTime() const {
|
||||
if (isPaused())
|
||||
return _pauseStartTime - _startTime;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
|
||||
uint32 time = ((const AudioTrack *)*it)->getRunningTime();
|
||||
|
||||
if (time != 0)
|
||||
return time + _audioStartOffset.msecs();
|
||||
}
|
||||
}
|
||||
|
||||
return g_system->getMillis() - _startTime;
|
||||
}
|
||||
|
||||
uint32 AdvancedVideoDecoder::getTimeToNextFrame() const {
|
||||
if (endOfVideo())
|
||||
return 0;
|
||||
|
||||
const VideoTrack *track = findNextVideoTrack();
|
||||
|
||||
if (!track)
|
||||
return 0;
|
||||
|
||||
uint32 elapsedTime = getTime();
|
||||
uint32 nextFrameStartTime = track->getNextFrameStartTime();
|
||||
|
||||
if (nextFrameStartTime <= elapsedTime)
|
||||
return 0;
|
||||
|
||||
return nextFrameStartTime - elapsedTime;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::endOfVideo() const {
|
||||
// TODO: Bring _isPlaying into account?
|
||||
|
||||
if (!isVideoLoaded())
|
||||
return true;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if (!(*it)->endOfTrack())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::isRewindable() const {
|
||||
if (_tracks.empty())
|
||||
return false;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if (!(*it)->isRewindable())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::rewind() {
|
||||
if (!isRewindable())
|
||||
return false;
|
||||
|
||||
_needsRewind = false;
|
||||
|
||||
// TODO: Pause status
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if (!(*it)->rewind())
|
||||
return false;
|
||||
|
||||
_audioStartOffset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::isSeekable() const {
|
||||
if (_tracks.empty())
|
||||
return false;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if (!(*it)->isSeekable())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) {
|
||||
if (!isSeekable())
|
||||
return false;
|
||||
|
||||
_needsRewind = false;
|
||||
|
||||
// TODO: Pause status
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if (!(*it)->seek(time))
|
||||
return false;
|
||||
|
||||
_audioStartOffset = time;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::start() {
|
||||
if (_isPlaying || !isVideoLoaded())
|
||||
return;
|
||||
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_audioStartOffset = 0;
|
||||
|
||||
// If someone previously called stop(), we'll rewind it.
|
||||
if (_needsRewind)
|
||||
rewind();
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
(*it)->start();
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::stop() {
|
||||
if (!_isPlaying)
|
||||
return;
|
||||
|
||||
_isPlaying = false;
|
||||
_startTime = 0;
|
||||
_audioStartOffset = 0;
|
||||
_palette = 0;
|
||||
_dirtyPalette = false;
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
(*it)->stop();
|
||||
|
||||
// Also reset the pause state.
|
||||
_pauseLevel = 0;
|
||||
|
||||
// If this is a rewindable video, don't close it too. We'll just rewind() the video
|
||||
// the next time someone calls start(). Otherwise, since it can't be rewound, we
|
||||
// just close it.
|
||||
if (isRewindable())
|
||||
_needsRewind = true;
|
||||
else
|
||||
close();
|
||||
}
|
||||
|
||||
Audio::Timestamp AdvancedVideoDecoder::getDuration() const {
|
||||
return Audio::Timestamp(0, 1000);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::pauseVideoIntern(bool pause) {
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
(*it)->pause(pause);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::updateVolume() {
|
||||
// For API compatibility only
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
|
||||
((AudioTrack *)*it)->setVolume(_audioVolume);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::updateBalance() {
|
||||
// For API compatibility only
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
|
||||
((AudioTrack *)*it)->setBalance(_audioBalance);
|
||||
}
|
||||
|
||||
AdvancedVideoDecoder::Track::Track() {
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::Track::isRewindable() const {
|
||||
return isSeekable();
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::Track::rewind() {
|
||||
return seek(Audio::Timestamp(0, 1000));
|
||||
}
|
||||
|
||||
uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const {
|
||||
if (endOfTrack() || getCurFrame() < 0)
|
||||
return 0;
|
||||
|
||||
Common::Rational time = (getCurFrame() + 1) * 1000;
|
||||
time /= getFrameRate();
|
||||
return time.toInt();
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::FixedLengthVideoTrack::endOfTrack() const {
|
||||
return getCurFrame() >= (getFrameCount() - 1);
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const {
|
||||
Audio::AudioStream *stream = getAudioStream();
|
||||
return !stream || (!g_system->getMixer()->isSoundHandleActive(_handle) && stream->endOfData());
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::AudioTrack::setVolume(byte volume) {
|
||||
_volume = volume;
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->setChannelVolume(_handle, _volume);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::AudioTrack::setBalance(int8 balance) {
|
||||
_balance = balance;
|
||||
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->setChannelBalance(_handle, _balance);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::AudioTrack::start() {
|
||||
stop();
|
||||
|
||||
Audio::AudioStream *stream = getAudioStream();
|
||||
assert(stream);
|
||||
|
||||
g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::NO);
|
||||
|
||||
// Pause the audio again if we're still paused
|
||||
if (isPaused())
|
||||
g_system->getMixer()->pauseHandle(_handle, true);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::AudioTrack::stop() {
|
||||
g_system->getMixer()->stopHandle(_handle);
|
||||
}
|
||||
|
||||
uint32 AdvancedVideoDecoder::AudioTrack::getRunningTime() const {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
return g_system->getMixer()->getSoundElapsedTime(_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::AudioTrack::pauseIntern(bool shouldPause) {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_handle))
|
||||
g_system->getMixer()->pauseHandle(_handle, shouldPause);
|
||||
}
|
||||
|
||||
Audio::AudioStream *AdvancedVideoDecoder::RewindableAudioTrack::getAudioStream() const {
|
||||
return getRewindableAudioStream();
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::RewindableAudioTrack::rewind() {
|
||||
Audio::RewindableAudioStream *stream = getRewindableAudioStream();
|
||||
assert(stream);
|
||||
return stream->rewind();
|
||||
}
|
||||
|
||||
Audio::AudioStream *AdvancedVideoDecoder::SeekableAudioTrack::getAudioStream() const {
|
||||
return getSeekableAudioStream();
|
||||
}
|
||||
|
||||
bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) {
|
||||
Audio::SeekableAudioStream *stream = getSeekableAudioStream();
|
||||
assert(stream);
|
||||
return stream->seek(time);
|
||||
}
|
||||
|
||||
void AdvancedVideoDecoder::addTrack(Track *track) {
|
||||
_tracks.push_back(track);
|
||||
}
|
||||
|
||||
AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() {
|
||||
VideoTrack *bestTrack = 0;
|
||||
uint32 bestTime = 0xFFFFFFFF;
|
||||
|
||||
for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
|
||||
VideoTrack *track = (VideoTrack *)*it;
|
||||
uint32 time = track->getNextFrameStartTime();
|
||||
|
||||
if (time < bestTime) {
|
||||
bestTime = time;
|
||||
bestTrack = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestTrack;
|
||||
}
|
||||
|
||||
const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() const {
|
||||
const VideoTrack *bestTrack = 0;
|
||||
uint32 bestTime = 0xFFFFFFFF;
|
||||
|
||||
for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
|
||||
const VideoTrack *track = (const VideoTrack *)*it;
|
||||
uint32 time = track->getNextFrameStartTime();
|
||||
|
||||
if (time < bestTime) {
|
||||
bestTime = time;
|
||||
bestTrack = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestTrack;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
///////////////// DEPRECATED /////////////////
|
||||
//////////////////////////////////////////////
|
||||
|
||||
void VideoDecoder::reset() {
|
||||
_curFrame = -1;
|
||||
_startTime = 0;
|
||||
_pauseLevel = 0;
|
||||
_audioVolume = Audio::Mixer::kMaxChannelVolume;
|
||||
_audioBalance = 0;
|
||||
}
|
||||
|
||||
bool VideoDecoder::endOfVideo() const {
|
||||
return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
|
||||
}
|
||||
|
||||
void VideoDecoder::setSystemPalette() {
|
||||
g_system->getPaletteManager()->setPalette(getPalette(), 0, 256);
|
||||
}
|
||||
|
||||
uint32 FixedRateVideoDecoder::getTimeToNextFrame() const {
|
||||
if (endOfVideo() || _curFrame < 0)
|
||||
return 0;
|
||||
|
@ -23,10 +23,16 @@
|
||||
#ifndef VIDEO_DECODER_H
|
||||
#define VIDEO_DECODER_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/timestamp.h" // TODO: Move this to common/ ?
|
||||
#include "common/list.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "audio/timestamp.h" // TODO: Move this to common/ ?
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class RewindableAudioStream;
|
||||
class SeekableAudioStream;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class Rational;
|
||||
@ -42,6 +48,7 @@ namespace Video {
|
||||
|
||||
/**
|
||||
* Generic interface for video decoder classes.
|
||||
* @note This class is now deprecated in favor of AdvancedVideoDecoder.
|
||||
*/
|
||||
class VideoDecoder {
|
||||
public:
|
||||
@ -109,6 +116,7 @@ public:
|
||||
/**
|
||||
* Set the system palette to the palette returned by getPalette.
|
||||
* @see getPalette
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
void setSystemPalette();
|
||||
|
||||
@ -222,47 +230,389 @@ public:
|
||||
protected:
|
||||
/**
|
||||
* Resets _curFrame and _startTime. Should be called from every close() function.
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Actual implementation of pause by subclasses. See pause()
|
||||
* for details.
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
virtual void pauseVideoIntern(bool pause) {}
|
||||
|
||||
/**
|
||||
* Add the time the video has been paused to maintain sync
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
virtual void addPauseTime(uint32 ms) { _startTime += ms; }
|
||||
|
||||
/**
|
||||
* Reset the pause start time (which should be called when seeking)
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
void resetPauseStartTime();
|
||||
|
||||
/**
|
||||
* Update currently playing audio tracks with the new volume setting
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
virtual void updateVolume() {}
|
||||
|
||||
/**
|
||||
* Update currently playing audio tracks with the new balance setting
|
||||
* @note This function is now deprecated. There is no replacement.
|
||||
*/
|
||||
virtual void updateBalance() {}
|
||||
|
||||
int32 _curFrame;
|
||||
int32 _startTime;
|
||||
|
||||
private:
|
||||
// FIXME: These are protected until the new API takes over this one
|
||||
//private:
|
||||
uint32 _pauseLevel;
|
||||
uint32 _pauseStartTime;
|
||||
byte _audioVolume;
|
||||
int8 _audioBalance;
|
||||
};
|
||||
|
||||
/**
|
||||
* Improved interface for video decoder classes.
|
||||
*/
|
||||
class AdvancedVideoDecoder : public VideoDecoder {
|
||||
public:
|
||||
AdvancedVideoDecoder();
|
||||
virtual ~AdvancedVideoDecoder() {}
|
||||
|
||||
// Old API Non-changing
|
||||
// loadFile()
|
||||
// loadStream()
|
||||
// getWidth()
|
||||
// getHeight()
|
||||
// needsUpdate()
|
||||
|
||||
// Old API Changing
|
||||
virtual void close();
|
||||
bool isVideoLoaded() const;
|
||||
virtual const Graphics::Surface *decodeNextFrame();
|
||||
const byte *getPalette();
|
||||
bool hasDirtyPalette() const { return _dirtyPalette; }
|
||||
int getCurFrame() const;
|
||||
uint32 getFrameCount() const;
|
||||
uint32 getTime() const;
|
||||
uint32 getTimeToNextFrame() const;
|
||||
bool endOfVideo() const;
|
||||
|
||||
// New API
|
||||
/**
|
||||
* Returns if a video is rewindable or not.
|
||||
*/
|
||||
bool isRewindable() const;
|
||||
|
||||
/**
|
||||
* Rewind a video to its beginning.
|
||||
*
|
||||
* If the video is playing, it will continue to play.
|
||||
*
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool rewind();
|
||||
|
||||
/**
|
||||
* Returns if a video is seekable or not.
|
||||
*/
|
||||
bool isSeekable() const;
|
||||
|
||||
/**
|
||||
* Seek to a given time in the video.
|
||||
*
|
||||
* If the video is playing, it will continue to play.
|
||||
*
|
||||
* @param time The time to seek to
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool seek(const Audio::Timestamp &time);
|
||||
|
||||
/**
|
||||
* Begin playback of the video.
|
||||
*
|
||||
* @note This has no effect is the video is already playing.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stop playback of the video.
|
||||
*
|
||||
* @note This will close() the video if it is not rewindable.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Returns if the video is currently playing or not.
|
||||
* @todo Differentiate this function from endOfVideo()
|
||||
*/
|
||||
bool isPlaying() const { return _isPlaying; }
|
||||
|
||||
/**
|
||||
* Get the duration of the video.
|
||||
*
|
||||
* If the duration is unknown, this will return 0.
|
||||
*/
|
||||
virtual Audio::Timestamp getDuration() const;
|
||||
|
||||
// Future API
|
||||
//void setRate(const Common::Rational &rate);
|
||||
//Common::Rational getRate() const;
|
||||
//void setStartTime(const Audio::Timestamp &startTime);
|
||||
//Audio::Timestamp getStartTime() const;
|
||||
//void setStopTime(const Audio::Timestamp &stopTime);
|
||||
//Audio::Timestamp getStopTime() const;
|
||||
//void setSegment(const Audio::Timestamp &startTime, const Audio::Timestamp &stopTime);
|
||||
|
||||
protected:
|
||||
// Old API
|
||||
void pauseVideoIntern(bool pause);
|
||||
void updateVolume();
|
||||
void updateBalance();
|
||||
|
||||
// New API
|
||||
|
||||
/**
|
||||
* An abstract representation of a track in a movie.
|
||||
*/
|
||||
class Track {
|
||||
public:
|
||||
Track();
|
||||
virtual ~Track() {}
|
||||
|
||||
/**
|
||||
* The types of tracks this class can be.
|
||||
*/
|
||||
enum TrackType {
|
||||
kTrackTypeNone,
|
||||
kTrackTypeVideo,
|
||||
kTrackTypeAudio
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the type of track.
|
||||
*/
|
||||
virtual TrackType getTrackType() const = 0;
|
||||
|
||||
/**
|
||||
* Return if the track has finished.
|
||||
*/
|
||||
virtual bool endOfTrack() const = 0;
|
||||
|
||||
/**
|
||||
* Return if the track is rewindable.
|
||||
*/
|
||||
virtual bool isRewindable() const;
|
||||
|
||||
/**
|
||||
* Rewind the video to the beginning.
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
virtual bool rewind();
|
||||
|
||||
/**
|
||||
* Return if the track is seekable.
|
||||
*/
|
||||
virtual bool isSeekable() const { return false; }
|
||||
|
||||
/**
|
||||
* Seek to the given time.
|
||||
* @param time The time to seek to.
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
virtual bool seek(const Audio::Timestamp &time) { return false; }
|
||||
|
||||
/**
|
||||
* Start playback of the track.
|
||||
*/
|
||||
virtual void start() {}
|
||||
|
||||
/**
|
||||
* Stop playback of the track.
|
||||
*/
|
||||
virtual void stop() {}
|
||||
|
||||
/**
|
||||
* Set the pause status of the track.
|
||||
*/
|
||||
void pause(bool shouldPause) {}
|
||||
|
||||
/**
|
||||
* Return if the track is paused.
|
||||
*/
|
||||
bool isPaused() const { return _paused; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Function called by pause() for subclasses to implement.
|
||||
*/
|
||||
void pauseIntern(bool pause);
|
||||
|
||||
private:
|
||||
bool _paused;
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract representation of a video track.
|
||||
*/
|
||||
class VideoTrack : public Track {
|
||||
public:
|
||||
VideoTrack() {}
|
||||
virtual ~VideoTrack() {}
|
||||
|
||||
TrackType getTrackType() const { return kTrackTypeVideo; }
|
||||
|
||||
// TODO: Document
|
||||
virtual int getCurFrame() const = 0;
|
||||
virtual int getFrameCount() const { return 0; }
|
||||
virtual uint32 getNextFrameStartTime() const = 0;
|
||||
virtual const Graphics::Surface *decodeNextFrame() = 0;
|
||||
virtual const byte *getPalette() const { return 0; }
|
||||
virtual bool hasDirtyPalette() const { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
* A VideoTrack that is played at a constant rate.
|
||||
*/
|
||||
class FixedRateVideoTrack : public virtual VideoTrack {
|
||||
public:
|
||||
FixedRateVideoTrack() {}
|
||||
virtual ~FixedRateVideoTrack() {}
|
||||
|
||||
uint32 getNextFrameStartTime() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Get the rate at which this track is played.
|
||||
*/
|
||||
virtual Common::Rational getFrameRate() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A VideoTrack with a known frame count that can be reliably
|
||||
* used to figure out if the track has finished.
|
||||
*/
|
||||
class FixedLengthVideoTrack : public virtual VideoTrack {
|
||||
public:
|
||||
FixedLengthVideoTrack() {}
|
||||
virtual ~FixedLengthVideoTrack() {}
|
||||
|
||||
bool endOfTrack() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract representation of an audio track.
|
||||
*/
|
||||
class AudioTrack : public Track {
|
||||
public:
|
||||
AudioTrack() {}
|
||||
virtual ~AudioTrack() {}
|
||||
|
||||
TrackType getTrackType() const { return kTrackTypeAudio; }
|
||||
|
||||
virtual bool endOfTrack() const;
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
// TODO: Document
|
||||
byte getVolume() const { return _volume; }
|
||||
void setVolume(byte volume);
|
||||
int8 getBalance() const { return _balance; }
|
||||
void setBalance(int8 balance);
|
||||
uint32 getRunningTime() const;
|
||||
|
||||
virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; }
|
||||
|
||||
protected:
|
||||
void pauseIntern(bool pause);
|
||||
|
||||
// TODO: Document
|
||||
virtual Audio::AudioStream *getAudioStream() const = 0;
|
||||
|
||||
private:
|
||||
Audio::SoundHandle _handle;
|
||||
byte _volume;
|
||||
int8 _balance;
|
||||
};
|
||||
|
||||
/**
|
||||
* An AudioTrack that implements isRewindable() and rewind() using
|
||||
* the RewindableAudioStream API.
|
||||
*/
|
||||
class RewindableAudioTrack : public AudioTrack {
|
||||
public:
|
||||
RewindableAudioTrack() {}
|
||||
virtual ~RewindableAudioTrack() {}
|
||||
|
||||
bool isRewindable() const { return true; }
|
||||
bool rewind();
|
||||
|
||||
protected:
|
||||
Audio::AudioStream *getAudioStream() const;
|
||||
|
||||
// TODO: Document
|
||||
virtual Audio::RewindableAudioStream *getRewindableAudioStream() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An AudioTrack that implements isSeekable() and seek() using
|
||||
* the SeekableAudioStream API.
|
||||
*/
|
||||
class SeekableAudioTrack : public AudioTrack {
|
||||
public:
|
||||
SeekableAudioTrack() {}
|
||||
virtual ~SeekableAudioTrack() {}
|
||||
|
||||
bool isSeekable() const { return true; }
|
||||
bool seek(const Audio::Timestamp &time);
|
||||
|
||||
protected:
|
||||
Audio::AudioStream *getAudioStream() const;
|
||||
|
||||
// TODO: Document
|
||||
virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode enough data for the next frame and enough audio to last that long.
|
||||
*
|
||||
* This function is used by the default decodeNextFrame() function. A subclass
|
||||
* of a Track may decide to just have its decodeNextFrame() function read
|
||||
* and decode the frame.
|
||||
*/
|
||||
virtual void readNextPacket() {}
|
||||
|
||||
/**
|
||||
* Define a track to be used by this class.
|
||||
*
|
||||
* The pointer is then owned by this base class.
|
||||
*/
|
||||
void addTrack(Track *track);
|
||||
|
||||
private:
|
||||
// Tracks owned by this AdvancedVideoDecoder
|
||||
typedef Common::List<Track *> TrackList;
|
||||
TrackList _tracks;
|
||||
VideoTrack *findNextVideoTrack();
|
||||
const VideoTrack *findNextVideoTrack() const;
|
||||
|
||||
// Current playback status
|
||||
bool _isPlaying, _needsRewind;
|
||||
Audio::Timestamp _audioStartOffset;
|
||||
|
||||
// Palette settings from individual tracks
|
||||
mutable bool _dirtyPalette;
|
||||
const byte *_palette;
|
||||
};
|
||||
|
||||
/**
|
||||
* A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate().
|
||||
* @note This class is now deprecated. Use AdvancedVideoDecoder instead.
|
||||
*/
|
||||
class FixedRateVideoDecoder : public virtual VideoDecoder {
|
||||
public:
|
||||
@ -282,6 +632,7 @@ private:
|
||||
|
||||
/**
|
||||
* A VideoDecoder that can be rewound back to the beginning.
|
||||
* @note This class is now deprecated. Use AdvancedVideoDecoder instead.
|
||||
*/
|
||||
class RewindableVideoDecoder : public virtual VideoDecoder {
|
||||
public:
|
||||
@ -293,6 +644,7 @@ public:
|
||||
|
||||
/**
|
||||
* A VideoDecoder that can seek to a frame or point in time.
|
||||
* @note This class is now deprecated. Use AdvancedVideoDecoder instead.
|
||||
*/
|
||||
class SeekableVideoDecoder : public virtual RewindableVideoDecoder {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user