734 lines
19 KiB
C++
734 lines
19 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "audio/decoders/aiff.h"
|
|
#include "common/platform.h"
|
|
#include "common/stream.h"
|
|
#include "common/macresman.h"
|
|
|
|
#include "graphics/paletteman.h"
|
|
#include "graphics/surface.h"
|
|
#include "graphics/macgui/macwidget.h"
|
|
|
|
#include "video/video_decoder.h"
|
|
#include "video/avi_decoder.h"
|
|
#include "video/qt_decoder.h"
|
|
|
|
#include "director/director.h"
|
|
#include "director/cast.h"
|
|
#include "director/channel.h"
|
|
#include "director/images.h"
|
|
#include "director/movie.h"
|
|
#include "director/window.h"
|
|
#include "director/castmember/digitalvideo.h"
|
|
#include "director/lingo/lingo-the.h"
|
|
|
|
namespace Director {
|
|
|
|
|
|
class NoVideoAIFFDecoder : public Video::VideoDecoder {
|
|
|
|
protected:
|
|
class AIFFAudioTrack : public Video::VideoDecoder::AudioTrack {
|
|
private:
|
|
Audio::RewindableAudioStream *_audioStream = nullptr;
|
|
public:
|
|
AIFFAudioTrack(Audio::Mixer::SoundType soundType, Audio::RewindableAudioStream *stream) : AudioTrack(soundType) {
|
|
_audioStream = stream;
|
|
}
|
|
|
|
virtual Audio::AudioStream *getAudioStream() const {
|
|
return _audioStream;
|
|
}
|
|
};
|
|
|
|
public:
|
|
bool loadFile(const Common::Path &filename) override {
|
|
Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(filename);
|
|
if (!file) {
|
|
delete file;
|
|
return false;
|
|
}
|
|
|
|
bool result = loadStream(file);
|
|
if (!result)
|
|
delete file;
|
|
return result;
|
|
}
|
|
|
|
virtual bool loadStream(Common::SeekableReadStream *stream) override {
|
|
addTrack(new AIFFAudioTrack(Audio::Mixer::SoundType::kSFXSoundType, Audio::makeAIFFStream(stream, DisposeAfterUse::Flag::NO)));
|
|
return true;
|
|
}
|
|
|
|
};
|
|
|
|
DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId)
|
|
: CastMember(cast, castId) {
|
|
_type = kCastDigitalVideo;
|
|
_video = nullptr;
|
|
_lastFrame = nullptr;
|
|
_channel = nullptr;
|
|
|
|
_getFirstFrame = false;
|
|
_duration = 0;
|
|
|
|
_vflags = 0;
|
|
_frameRate = 0;
|
|
|
|
_frameRateType = kFrameRateDefault;
|
|
_videoType = kDVUnknown;
|
|
_qtmovie = true;
|
|
_avimovie = false;
|
|
_preload = false;
|
|
_enableVideo = true;
|
|
_pausedAtStart = false;
|
|
_showControls = false;
|
|
_directToStage = false;
|
|
_looping = false;
|
|
_enableSound = true;
|
|
_crop = false;
|
|
_center = false;
|
|
_dirty = false;
|
|
_emptyFile = false;
|
|
|
|
memset(_ditheringPalette, 0, 256*3);
|
|
}
|
|
|
|
|
|
|
|
DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version)
|
|
: CastMember(cast, castId, stream) {
|
|
_type = kCastDigitalVideo;
|
|
_video = nullptr;
|
|
_lastFrame = nullptr;
|
|
_channel = nullptr;
|
|
|
|
_getFirstFrame = false;
|
|
_duration = 0;
|
|
|
|
_initialRect = Movie::readRect(stream);
|
|
_vflags = stream.readUint32();
|
|
_frameRate = (_vflags >> 24) & 0xff;
|
|
|
|
_frameRateType = kFrameRateDefault;
|
|
_videoType = kDVUnknown;
|
|
if (_vflags & 0x0800) {
|
|
_frameRateType = (FrameRateType)((_vflags & 0x3000) >> 12);
|
|
}
|
|
_qtmovie = _vflags & 0x8000;
|
|
_avimovie = _vflags & 0x4000;
|
|
_preload = _vflags & 0x0400;
|
|
_enableVideo = !(_vflags & 0x0200);
|
|
_pausedAtStart = _vflags & 0x0100;
|
|
_showControls = _vflags & 0x40;
|
|
_directToStage = _vflags & 0x20;
|
|
_looping = _vflags & 0x10;
|
|
_enableSound = _vflags & 0x08;
|
|
_crop = !(_vflags & 0x02);
|
|
_center = _vflags & 0x01;
|
|
_dirty = false;
|
|
_emptyFile = false;
|
|
|
|
memset(_ditheringPalette, 0, 256*3);
|
|
|
|
if (debugChannelSet(2, kDebugLoading))
|
|
_initialRect.debugPrint(2, "DigitalVideoCastMember(): rect:");
|
|
|
|
debugC(2, kDebugLoading, "DigitalVideoCastMember(): flags: (%d 0x%04x)", _vflags, _vflags);
|
|
|
|
debugC(2, kDebugLoading, "_frameRate: %d", _frameRate);
|
|
debugC(2, kDebugLoading, "_frameRateType: %d, _preload: %d, _enableVideo %d, _pausedAtStart %d",
|
|
_frameRateType, _preload, _enableVideo, _pausedAtStart);
|
|
debugC(2, kDebugLoading, "_showControls: %d, _looping: %d, _enableSound: %d, _crop %d, _center: %d, _directToStage: %d",
|
|
_showControls, _looping, _enableSound, _crop, _center, _directToStage);
|
|
debugC(2, kDebugLoading, "_avimovie: %d, _qtmovie: %d", _avimovie, _qtmovie);
|
|
}
|
|
|
|
DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, DigitalVideoCastMember &source)
|
|
: CastMember(cast, castId) {
|
|
_type = kCastDigitalVideo;
|
|
_loaded = source._loaded;
|
|
|
|
_initialRect = source._initialRect;
|
|
_boundingRect = source._boundingRect;
|
|
if (cast == source._cast)
|
|
_children = source._children;
|
|
|
|
_filename = source._filename;
|
|
|
|
_vflags = source._vflags;
|
|
_looping = source._looping;
|
|
_pausedAtStart = source._pausedAtStart;
|
|
_enableVideo = source._enableVideo;
|
|
_enableSound = source._enableSound;
|
|
_crop = source._crop;
|
|
_center = source._center;
|
|
_preload = source._preload;
|
|
_showControls = source._showControls;
|
|
_directToStage = source._directToStage;
|
|
_avimovie = source._avimovie;
|
|
_qtmovie = source._qtmovie;
|
|
_dirty = source._dirty;
|
|
_frameRateType = source._frameRateType;
|
|
_videoType = source._videoType;
|
|
|
|
_frameRate = source._frameRate;
|
|
_getFirstFrame = source._getFirstFrame;
|
|
_duration = source._duration;
|
|
|
|
_video = nullptr;
|
|
_lastFrame = nullptr;
|
|
|
|
_channel = nullptr;
|
|
}
|
|
|
|
DigitalVideoCastMember::~DigitalVideoCastMember() {
|
|
if (_lastFrame) {
|
|
_lastFrame->free();
|
|
delete _lastFrame;
|
|
}
|
|
|
|
if (_video)
|
|
delete _video;
|
|
}
|
|
|
|
bool DigitalVideoCastMember::loadVideoFromCast() {
|
|
Common::String path = getCast()->getVideoPath(_castId);
|
|
if (!path.empty())
|
|
return loadVideo(path);
|
|
return false;
|
|
}
|
|
|
|
bool DigitalVideoCastMember::loadVideo(Common::String path) {
|
|
if (_filename == path) {
|
|
// we've already loaded this video, or not. no point trying again.
|
|
return _video ? true : false;
|
|
}
|
|
|
|
if (_video) {
|
|
delete _video;
|
|
_video = nullptr;
|
|
}
|
|
|
|
_filename = path;
|
|
|
|
Common::Path location = findPath(path);
|
|
if (location.empty()) {
|
|
warning("DigitalVideoCastMember::loadVideo(): unable to resolve path %s", path.c_str());
|
|
return false;
|
|
}
|
|
|
|
Common::SeekableReadStream *copiedStream = Common::MacResManager::openFileOrDataFork(location);
|
|
if (!copiedStream) {
|
|
warning("DigitalVideoCastMember::loadVideo Failed to open %s", path.c_str());
|
|
return false;
|
|
}
|
|
|
|
uint32 magic1 = copiedStream->readUint32BE();
|
|
uint32 magic2 = copiedStream->readUint32BE();
|
|
uint32 magic3 = copiedStream->readUint32BE();
|
|
delete copiedStream;
|
|
bool result = false;
|
|
|
|
debugC(2, kDebugLoading, "Loading video %s -> %s", path.c_str(), location.toString(Common::Path::kNativeSeparator).c_str());
|
|
if (magic1 == MKTAG('F', 'O', 'R', 'M') &&
|
|
(magic3 == MKTAG('A', 'I', 'F', 'F') || magic3 == MKTAG('A', 'I', 'F', 'C'))) {
|
|
_video = new NoVideoAIFFDecoder();
|
|
result = _video->loadFile(location);
|
|
if (!result) {
|
|
delete _video;
|
|
_video = nullptr;
|
|
return false;
|
|
} else {
|
|
// Pretend that this is our friend QuickTime
|
|
_videoType = kDVQuickTime;
|
|
}
|
|
|
|
} else if (magic2 == MKTAG('m', 'o', 'o', 'v') || magic2 == MKTAG('m', 'd', 'a', 't')) {
|
|
_video = new Video::QuickTimeDecoder();
|
|
result = _video->loadFile(location);
|
|
if (!result) {
|
|
delete _video;
|
|
_video = nullptr;
|
|
|
|
// Probe for empty file
|
|
Common::MacResManager mgr;
|
|
if (mgr.open(location)) {
|
|
if (!mgr.hasDataFork()) {
|
|
debugC(8, kDebugLevelGVideo, "DigitalVideoCastMember::loadVideo(): skipping empty stream");
|
|
_emptyFile = true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} else {
|
|
_videoType = kDVQuickTime;
|
|
}
|
|
} else if (magic1 == MKTAG('R', 'I', 'F', 'F') && (magic3 == MKTAG('A', 'V', 'I', ' '))) {
|
|
_video = new Video::AVIDecoder();
|
|
result = _video->loadFile(location);
|
|
if (!result) {
|
|
warning("DigitalVideoCastMember::loadVideo(): format not supported, skipping video '%s'", path.c_str());
|
|
delete _video;
|
|
_video = nullptr;
|
|
return false;
|
|
} else {
|
|
_videoType = kDVVideoForWindows;
|
|
}
|
|
} else {
|
|
warning("DigitalVideoCastMember::loadVideo: Unknown file format for video '%s', skipping", path.c_str());
|
|
}
|
|
|
|
if (result && g_director->_pixelformat.bytesPerPixel == 1) {
|
|
// Director supports playing back RGB and paletted video in 256 colour mode.
|
|
// In both cases they are dithered to match the Director palette.
|
|
memcpy(_ditheringPalette, g_director->getPalette(), 256*3);
|
|
// In Windows, the first 8 and last 8 colors are reserved for the system palette.
|
|
// Generally you don't want these as part of the video, and Video for Windows
|
|
// seems to deliberately exclude them.
|
|
// Keep colour 0 and 255 as they are pure white and pure black, respectively.
|
|
if (g_director->_vfwPaletteHack && g_director->getPlatform() == Common::kPlatformWindows) {
|
|
for (int i = 1; i < 8; i++) {
|
|
_ditheringPalette[i*3+0] = _ditheringPalette[0];
|
|
_ditheringPalette[i*3+1] = _ditheringPalette[1];
|
|
_ditheringPalette[i*3+2] = _ditheringPalette[2];
|
|
}
|
|
for (int i = 248; i < 255; i++) {
|
|
_ditheringPalette[i*3+0] = _ditheringPalette[0];
|
|
_ditheringPalette[i*3+1] = _ditheringPalette[1];
|
|
_ditheringPalette[i*3+2] = _ditheringPalette[2];
|
|
}
|
|
}
|
|
_video->setDitheringPalette(_ditheringPalette);
|
|
}
|
|
|
|
_duration = getMovieTotalTime();
|
|
|
|
if (_video) {
|
|
// Setting the initial rect to the actual movie dimensions
|
|
_initialRect.setWidth(_video->getWidth());
|
|
_initialRect.setHeight(_video->getHeight());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool DigitalVideoCastMember::isModified() {
|
|
if (!_video || !_video->isVideoLoaded())
|
|
return true;
|
|
|
|
if (_dirty) {
|
|
_dirty = false;
|
|
return true;
|
|
}
|
|
|
|
// Inelegant, but necessary. isModified will get called on
|
|
// every screen update, so use it to keep the playback
|
|
// status up to date.
|
|
if (_video->endOfVideo()) {
|
|
if (_looping) {
|
|
_video->rewind();
|
|
} else if (_channel) {
|
|
_channel->_movieRate = 0.0;
|
|
}
|
|
}
|
|
|
|
if (_getFirstFrame)
|
|
return true;
|
|
|
|
if (_channel && _channel->_movieRate == 0.0)
|
|
return false;
|
|
|
|
return _video->needsUpdate();
|
|
}
|
|
|
|
void DigitalVideoCastMember::startVideo() {
|
|
if (!_video || !_video->isVideoLoaded()) {
|
|
warning("DigitalVideoCastMember::startVideo: No video %s", !_video ? "decoder" : "loaded");
|
|
return;
|
|
}
|
|
|
|
if (_pausedAtStart) {
|
|
_getFirstFrame = true;
|
|
} else {
|
|
if (_channel && _channel->_movieRate == 0.0)
|
|
_channel->_movieRate = 1.0;
|
|
}
|
|
|
|
if (_video->isPlaying())
|
|
_video->rewind();
|
|
else
|
|
_video->start();
|
|
|
|
debugC(2, kDebugImages, "STARTING VIDEO %s", _filename.c_str());
|
|
|
|
if (_channel && _channel->_stopTime == 0)
|
|
_channel->_stopTime = getMovieTotalTime();
|
|
}
|
|
|
|
void DigitalVideoCastMember::stopVideo() {
|
|
if (!_video || !_video->isVideoLoaded()) {
|
|
if (!_emptyFile)
|
|
warning("DigitalVideoCastMember::stopVideo: No video decoder");
|
|
return;
|
|
}
|
|
|
|
_video->stop();
|
|
|
|
debugC(2, kDebugImages, "STOPPING VIDEO %s", _filename.c_str());
|
|
}
|
|
|
|
void DigitalVideoCastMember::rewindVideo() {
|
|
if (!_video || !_video->isVideoLoaded()) {
|
|
if (!_emptyFile)
|
|
warning("DigitalVideoCastMember::rewindVideo: No video decoder");
|
|
return;
|
|
}
|
|
|
|
_video->rewind();
|
|
|
|
debugC(2, kDebugImages, "REWINDING VIDEO %s", _filename.c_str());
|
|
}
|
|
|
|
Graphics::MacWidget *DigitalVideoCastMember::createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) {
|
|
if (_emptyFile)
|
|
return nullptr;
|
|
|
|
if (!_video || !_video->isVideoLoaded()) {
|
|
// try and load the video if not already
|
|
if (!loadVideoFromCast()) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentWindow()->getMacWindow(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, false);
|
|
|
|
_channel = channel;
|
|
|
|
// Do not render stopped videos
|
|
if (_channel->_movieRate == 0.0 && !_getFirstFrame && _lastFrame) {
|
|
widget->getSurface()->blitFrom(*_lastFrame);
|
|
|
|
return widget;
|
|
}
|
|
|
|
const Graphics::Surface *frame = _video->decodeNextFrame();
|
|
|
|
// If the video gets stopped, for whatever reason, _video->getPalette() will not work.
|
|
// Cache it when possible.
|
|
if (g_director->_pixelformat.bytesPerPixel == 4) {
|
|
const byte *videoPalette = _video->getPalette();
|
|
if (videoPalette) {
|
|
memcpy(_ditheringPalette, videoPalette, 256*3);
|
|
}
|
|
}
|
|
|
|
debugC(1, kDebugImages, "Video time: %d rate: %f frame: %p dims: %d x %d", _channel->_movieTime, _channel->_movieRate, (const void *)frame, bbox.width(), bbox.height());
|
|
|
|
if (frame) {
|
|
if (_lastFrame) {
|
|
_lastFrame->free();
|
|
delete _lastFrame;
|
|
_lastFrame = nullptr;
|
|
}
|
|
|
|
if (frame->getPixels()) {
|
|
// Video should have the dithering palette set, decode using whatever palette we have now
|
|
_lastFrame = frame->convertTo(g_director->_pixelformat, _ditheringPalette);
|
|
} else {
|
|
warning("DigitalVideoCastMember::createWidget(): frame has no pixel data");
|
|
}
|
|
}
|
|
if (_lastFrame)
|
|
copyStretchImg(
|
|
_lastFrame,
|
|
widget->getSurface()->surfacePtr(),
|
|
Common::Rect((int16)_video->getWidth(), (int16)_video->getHeight()),
|
|
bbox
|
|
);
|
|
|
|
if (_getFirstFrame) {
|
|
_video->stop();
|
|
_getFirstFrame = false;
|
|
}
|
|
|
|
return widget;
|
|
}
|
|
|
|
uint DigitalVideoCastMember::getDuration() {
|
|
if (!_video || !_video->isVideoLoaded()) {
|
|
loadVideoFromCast();
|
|
}
|
|
return _duration;
|
|
}
|
|
|
|
uint DigitalVideoCastMember::getMovieCurrentTime() {
|
|
if (!_video)
|
|
return 0;
|
|
int ticks = 1 + ((_video->getTime() * 60 - 1)/1000);
|
|
int stamp = MIN<int>(ticks, getMovieTotalTime());
|
|
|
|
return stamp;
|
|
}
|
|
|
|
uint DigitalVideoCastMember::getMovieTotalTime() {
|
|
if (!_video)
|
|
return 0;
|
|
|
|
int ticks = 1 + ((_video->getDuration().msecs() * 60 - 1)/1000);
|
|
return ticks;
|
|
}
|
|
|
|
void DigitalVideoCastMember::seekMovie(int stamp) {
|
|
if (!_video)
|
|
return;
|
|
|
|
_channel->_startTime = stamp;
|
|
|
|
Audio::Timestamp dur = _video->getDuration();
|
|
|
|
_video->seek(Audio::Timestamp(_channel->_startTime * 1000 / 60, dur.framerate()));
|
|
|
|
if (_channel->_movieRate == 0.0) {
|
|
_getFirstFrame = true;
|
|
}
|
|
|
|
_dirty = true;
|
|
}
|
|
|
|
void DigitalVideoCastMember::setStopTime(int stamp) {
|
|
if (!_video)
|
|
return;
|
|
|
|
_channel->_stopTime = stamp;
|
|
|
|
Audio::Timestamp dur = _video->getDuration();
|
|
|
|
_video->setEndTime(Audio::Timestamp(_channel->_stopTime * 1000 / 60, dur.framerate()));
|
|
}
|
|
|
|
void DigitalVideoCastMember::setMovieRate(double rate) {
|
|
if (!_video)
|
|
return;
|
|
|
|
_channel->_movieRate = rate;
|
|
|
|
if (rate < 0.0)
|
|
warning("STUB: DigitalVideoCastMember::setMovieRate(%g)", rate);
|
|
else {
|
|
if (_getFirstFrame && rate != 0.0) {
|
|
// playback got started before we rendered the first
|
|
// frame in pause mode, keep going
|
|
_getFirstFrame = false;
|
|
}
|
|
_video->setRate(Common::Rational((int)(rate * 100.0), 100));
|
|
}
|
|
|
|
if (_video->endOfVideo())
|
|
_video->rewind();
|
|
}
|
|
|
|
void DigitalVideoCastMember::setFrameRate(int rate) {
|
|
if (!_video)
|
|
return;
|
|
|
|
warning("STUB: DigitalVideoCastMember::setFrameRate(%d)", rate);
|
|
}
|
|
|
|
Common::String DigitalVideoCastMember::formatInfo() {
|
|
return Common::String::format(
|
|
"initialRect: %dx%d@%d,%d, boundingRect: %dx%d@%d,%d, filename: \"%s\", duration: %d, enableVideo: %d, enableSound: %d, looping: %d, crop: %d, center: %d, showControls: %d",
|
|
_initialRect.width(), _initialRect.height(),
|
|
_initialRect.left, _initialRect.top,
|
|
_boundingRect.width(), _boundingRect.height(),
|
|
_boundingRect.left, _boundingRect.top,
|
|
_filename.c_str(), _duration,
|
|
_enableVideo, _enableSound,
|
|
_looping, _crop, _center, _showControls
|
|
);
|
|
}
|
|
|
|
Common::Point DigitalVideoCastMember::getRegistrationOffset() {
|
|
return Common::Point(_initialRect.width() / 2, _initialRect.height() / 2);
|
|
}
|
|
|
|
Common::Point DigitalVideoCastMember::getRegistrationOffset(int16 width, int16 height) {
|
|
return Common::Point(width / 2, height / 2);
|
|
}
|
|
|
|
bool DigitalVideoCastMember::hasField(int field) {
|
|
switch (field) {
|
|
case kTheCenter:
|
|
case kTheController:
|
|
case kTheCrop:
|
|
case kTheCuePointNames: // D6
|
|
case kTheCuePointTimes: // D6
|
|
case kTheCurrentTime: // D6
|
|
case kTheDigitalVideoType:
|
|
case kTheDirectToStage:
|
|
case kTheDuration:
|
|
case kTheFrameRate:
|
|
case kTheLoop:
|
|
case kThePausedAtStart:
|
|
case kThePreLoad:
|
|
case kTheSound:
|
|
case kTheTimeScale:
|
|
case kTheVideo:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return CastMember::hasField(field);
|
|
}
|
|
|
|
Datum DigitalVideoCastMember::getField(int field) {
|
|
Datum d;
|
|
|
|
switch (field) {
|
|
case kTheCenter:
|
|
d = _center;
|
|
break;
|
|
case kTheController:
|
|
d = _showControls;
|
|
break;
|
|
case kTheCrop:
|
|
d = _crop;
|
|
break;
|
|
case kTheDigitalVideoType:
|
|
if (_videoType == kDVVideoForWindows) {
|
|
d = Datum("videoForWindows");
|
|
} else {
|
|
// for unknown, just pretend QuickTime
|
|
d = Datum("quickTime");
|
|
}
|
|
d.type = SYMBOL;
|
|
break;
|
|
case kTheDirectToStage:
|
|
d = _directToStage;
|
|
break;
|
|
case kTheDuration:
|
|
// sometimes, we will get duration before we start video.
|
|
// _duration is initialized in startVideo, thus we will not get the correct number.
|
|
d = (int)getDuration();
|
|
break;
|
|
case kTheFrameRate:
|
|
d = _frameRate;
|
|
break;
|
|
case kTheLoop:
|
|
d = _looping;
|
|
break;
|
|
case kThePausedAtStart:
|
|
d = _pausedAtStart;
|
|
break;
|
|
case kThePreLoad:
|
|
d = _preload;
|
|
break;
|
|
case kTheSound:
|
|
d = _enableSound;
|
|
break;
|
|
case kTheTimeScale:
|
|
warning("STUB: DigitalVideoCastMember::getField(): timeScale not implemented");
|
|
d = Datum(600); // quicktime default
|
|
break;
|
|
case kTheVideo:
|
|
d = _enableVideo;
|
|
break;
|
|
default:
|
|
d = CastMember::getField(field);
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
void DigitalVideoCastMember::setField(int field, const Datum &d) {
|
|
switch (field) {
|
|
case kTheCenter:
|
|
_center = (bool)d.asInt();
|
|
return;
|
|
case kTheController:
|
|
_showControls = (bool)d.asInt();
|
|
return;
|
|
case kTheCrop:
|
|
_crop = (bool)d.asInt();
|
|
return;
|
|
case kTheDigitalVideoType:
|
|
warning("DigitalVideoCastMember::setField(): Attempt to set read-only field %s of cast %d", g_lingo->entity2str(field), _castId);
|
|
return;
|
|
case kTheDirectToStage:
|
|
_directToStage = (bool)d.asInt();
|
|
return;
|
|
case kTheDuration:
|
|
warning("DigitalVideoCastMember::setField(): Attempt to set read-only field %s of cast %d", g_lingo->entity2str(field), _castId);
|
|
return;
|
|
case kTheFrameRate:
|
|
_frameRate = d.asInt();
|
|
setFrameRate(d.asInt());
|
|
return;
|
|
case kTheLoop:
|
|
_looping = (bool)d.asInt();
|
|
if (_looping && _channel && _channel->_movieRate == 0.0) {
|
|
setMovieRate(1.0);
|
|
}
|
|
return;
|
|
case kThePausedAtStart:
|
|
_pausedAtStart = (bool)d.asInt();
|
|
return;
|
|
case kThePreLoad:
|
|
_preload = (bool)d.asInt();
|
|
return;
|
|
case kTheSound:
|
|
_enableSound = (bool)d.asInt();
|
|
return;
|
|
case kTheTimeScale:
|
|
warning("DigitalVideoCastMember::setField(): Attempt to set read-only field %s of cast %d", g_lingo->entity2str(field), _castId);
|
|
return;
|
|
case kTheVideo:
|
|
_enableVideo = (bool)d.asInt();
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CastMember::setField(field, d);
|
|
}
|
|
|
|
uint32 DigitalVideoCastMember::getCastDataSize() {
|
|
// We're only reading the _initialRect and _vflags from the Cast Data
|
|
// _initialRect : 8 bytes + _vflags : 4 bytes + castType and flags1 (see Cast::loadCastData() for Director 4 only) 2 byte
|
|
if (_cast->_version >= kFileVer400 && _cast->_version < kFileVer500) {
|
|
// It has been observed that the DigitalVideoCastMember has _flags set to 0x00
|
|
return (_flags1 == 0xFF) ? 13 : 14;
|
|
} else if (_cast->_version >= kFileVer500 && _cast->_version < kFileVer600) {
|
|
return 8 + 4;
|
|
}
|
|
|
|
warning("DigitalVideoCastMember::getCastDataSize(): unhandled or invalid cast version: %d", _cast->_version);
|
|
return 0;
|
|
}
|
|
|
|
void DigitalVideoCastMember::writeCastData(Common::SeekableWriteStream *writeStream) {
|
|
Movie::writeRect(writeStream, _initialRect);
|
|
writeStream->writeUint32BE(_vflags);
|
|
}
|
|
|
|
} // End of namespace Director
|