aboutsummaryrefslogtreecommitdiff
path: root/graphics/video
diff options
context:
space:
mode:
authorFilippos Karapetis2009-05-17 08:44:20 +0000
committerFilippos Karapetis2009-05-17 08:44:20 +0000
commit6f0b6b5aed63f7a2a186442cc83e928554a4185d (patch)
tree8ee6d2f526315ce2b287f3d62ac50cafecd2a560 /graphics/video
parentdc55a54365f1bb29b02bb8681dc4bcf0e230a63a (diff)
downloadscummvm-rg350-6f0b6b5aed63f7a2a186442cc83e928554a4185d.tar.gz
scummvm-rg350-6f0b6b5aed63f7a2a186442cc83e928554a4185d.tar.bz2
scummvm-rg350-6f0b6b5aed63f7a2a186442cc83e928554a4185d.zip
Changed the FLIC player to the common VideoDecoder interface. Note that currently the double animation in Bud Tucker's intro credits is broken, as the second background animation is not played
svn-id: r40638
Diffstat (limited to 'graphics/video')
-rw-r--r--graphics/video/flic_player.cpp227
-rw-r--r--graphics/video/flic_player.h104
-rw-r--r--graphics/video/smk_player.h6
3 files changed, 124 insertions, 213 deletions
diff --git a/graphics/video/flic_player.cpp b/graphics/video/flic_player.cpp
index f5a4fd4e63..a05368a0ab 100644
--- a/graphics/video/flic_player.cpp
+++ b/graphics/video/flic_player.cpp
@@ -27,123 +27,87 @@
#include "common/archive.h"
#include "common/stream.h"
#include "common/endian.h"
+#include "common/system.h"
namespace Graphics {
-FlicPlayer::FlicPlayer()
- : _paletteDirty(false), _offscreen(0), _currFrame(0), _fileStream(0) {
- memset(&_flicInfo, 0, sizeof(_flicInfo));
+FlicDecoder::FlicDecoder() {
+ _paletteChanged = false;
+ _fileStream = 0;
+ _videoFrameBuffer = 0;
+ memset(&_videoInfo, 0, sizeof(_videoInfo));
}
-FlicPlayer::~FlicPlayer() {
+FlicDecoder::~FlicDecoder() {
closeFile();
}
-int FlicPlayer::getWidth() {
- if (!_fileStream)
- return 0;
- return _flicInfo.width;
-}
-
-int FlicPlayer::getHeight() {
- if (!_fileStream)
- return 0;
- return _flicInfo.height;
-}
-
-int32 FlicPlayer::getCurFrame() {
- if (!_fileStream)
- return -1;
- return _currFrame;
-}
-
-int32 FlicPlayer::getFrameCount() {
- if (!_fileStream)
- return 0;
- return _flicInfo.numFrames;
-}
-
-bool FlicPlayer::loadFile(const char *fileName) {
+bool FlicDecoder::loadFile(const char *fileName) {
closeFile();
_fileStream = SearchMan.createReadStreamForMember(fileName);
if (!_fileStream)
return false;
- _flicInfo.size = _fileStream->readUint32LE();
- _flicInfo.type = _fileStream->readUint16LE();
+ uint32 frameSize = _fileStream->readUint32LE();
+ uint16 frameType = _fileStream->readUint16LE();
// Check FLC magic number
- if (_flicInfo.type != 0xAF12) {
- warning("FlicPlayer::FlicPlayer(): attempted to load non-FLC data (type = 0x%04X)", _flicInfo.type);
+ if (frameType != 0xAF12) {
+ warning("FlicDecoder::FlicDecoder(): attempted to load non-FLC data (type = 0x%04X)", frameType);
delete _fileStream;
_fileStream = 0;
return false;
}
- _flicInfo.numFrames = _fileStream->readUint16LE();
- _flicInfo.width = _fileStream->readUint16LE();
- _flicInfo.height = _fileStream->readUint16LE();
- _fileStream->skip(4);
- _flicInfo.speed = _fileStream->readUint32LE();
+ _videoInfo.frameCount = _fileStream->readUint16LE();
+ _videoInfo.width = _fileStream->readUint16LE();
+ _videoInfo.height = _fileStream->readUint16LE();
+ uint16 colorDepth = _fileStream->readUint16LE();
+ if (colorDepth != 8) {
+ warning("FlicDecoder::FlicDecoder(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", frameType);
+ delete _fileStream;
+ _fileStream = 0;
+ return false;
+ }
+ _fileStream->readUint16LE(); // flags
+ // Note: The normal delay is a 32-bit integer (dword), whereas the overriden delay is a 16-bit integer (word)
+ _videoInfo.frameDelay = _fileStream->readUint32LE() * 1000; // "speed", in milliseconds
+ _videoInfo.frameRate = 1000 / _videoInfo.frameDelay;
_fileStream->seek(80);
- _flicInfo.offsetFrame1 = _fileStream->readUint32LE();
- _flicInfo.offsetFrame2 = _fileStream->readUint32LE();
+ _offsetFrame1 = _fileStream->readUint32LE();
+ _offsetFrame2 = _fileStream->readUint32LE();
- _offscreen = new uint8[_flicInfo.width * _flicInfo.height];
- memset(_palette, 0, sizeof(_palette));
- _paletteDirty = false;
+ _videoFrameBuffer = new byte[_videoInfo.width * _videoInfo.height];
+ _palette = (byte *)malloc(3 * 256);
+ memset(_palette, 0, 3 * 256);
+ _paletteChanged = false;
// Seek to the first frame
- _currFrame = 0;
- _fileStream->seek(_flicInfo.offsetFrame1);
+ _videoInfo.currentFrame = 0;
+ _fileStream->seek(_offsetFrame1);
return true;
}
-void FlicPlayer::closeFile() {
+void FlicDecoder::closeFile() {
if (!_fileStream)
return;
delete _fileStream;
_fileStream = 0;
- delete[] _offscreen;
- _offscreen = 0;
+ delete[] _videoFrameBuffer;
+ _videoFrameBuffer = 0;
- _dirtyRects.clear();
-}
+ free(_palette);
-void FlicPlayer::redraw() {
_dirtyRects.clear();
- _dirtyRects.push_back(Common::Rect(0, 0, _flicInfo.width, _flicInfo.height));
-}
-
-ChunkHeader FlicPlayer::readChunkHeader() {
- ChunkHeader head;
-
- head.size = _fileStream->readUint32LE();
- head.type = _fileStream->readUint16LE();
-
- return head;
-}
-
-FrameTypeChunkHeader FlicPlayer::readFrameTypeChunkHeader(ChunkHeader chunkHead) {
- FrameTypeChunkHeader head;
-
- head.header = chunkHead;
- head.numChunks = _fileStream->readUint16LE();
- head.delay = _fileStream->readUint16LE();
- head.reserved = _fileStream->readUint16LE();
- head.widthOverride = _fileStream->readUint16LE();
- head.heightOverride = _fileStream->readUint16LE();
-
- return head;
}
-void FlicPlayer::decodeByteRun(uint8 *data) {
- uint8 *ptr = (uint8 *)_offscreen;
- while ((ptr - _offscreen) < (_flicInfo.width * _flicInfo.height)) {
+void FlicDecoder::decodeByteRun(uint8 *data) {
+ byte *ptr = (uint8 *)_videoFrameBuffer;
+ while ((uint32)(ptr - _videoFrameBuffer) < (_videoInfo.width * _videoInfo.height)) {
int chunks = *data++;
while (chunks--) {
int count = (int8)*data++;
@@ -158,7 +122,9 @@ void FlicPlayer::decodeByteRun(uint8 *data) {
}
}
- redraw();
+ // Redraw
+ _dirtyRects.clear();
+ _dirtyRects.push_back(Common::Rect(0, 0, _videoInfo.width, _videoInfo.height));
}
#define OP_PACKETCOUNT 0
@@ -166,7 +132,7 @@ void FlicPlayer::decodeByteRun(uint8 *data) {
#define OP_LASTPIXEL 2
#define OP_LINESKIPCOUNT 3
-void FlicPlayer::decodeDeltaFLC(uint8 *data) {
+void FlicDecoder::decodeDeltaFLC(uint8 *data) {
uint16 linesInChunk = READ_LE_UINT16(data); data += 2;
uint16 currentLine = 0;
uint16 packetCount = 0;
@@ -185,8 +151,8 @@ void FlicPlayer::decodeDeltaFLC(uint8 *data) {
case OP_UNDEFINED:
break;
case OP_LASTPIXEL:
- _offscreen[currentLine * _flicInfo.width + _flicInfo.width - 1] = (opcode & 0xFF);
- _dirtyRects.push_back(Common::Rect(_flicInfo.width - 1, currentLine, _flicInfo.width, currentLine + 1));
+ _videoFrameBuffer[currentLine * _videoInfo.width + _videoInfo.width - 1] = (opcode & 0xFF);
+ _dirtyRects.push_back(Common::Rect(_videoInfo.width - 1, currentLine, _videoInfo.width, currentLine + 1));
break;
case OP_LINESKIPCOUNT:
currentLine += -(int16)opcode;
@@ -201,14 +167,14 @@ void FlicPlayer::decodeDeltaFLC(uint8 *data) {
column += *data++;
int rleCount = (int8)*data++;
if (rleCount > 0) {
- memcpy(_offscreen + (currentLine * _flicInfo.width) + column, data, rleCount * 2);
+ memcpy(_videoFrameBuffer + (currentLine * _videoInfo.width) + column, data, rleCount * 2);
data += rleCount * 2;
_dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1));
} else if (rleCount < 0) {
rleCount = -rleCount;
uint16 dataWord = READ_UINT16(data); data += 2;
for (int i = 0; i < rleCount; ++i) {
- WRITE_UINT16(_offscreen + currentLine * _flicInfo.width + column + i * 2, dataWord);
+ WRITE_UINT16(_videoFrameBuffer + currentLine * _videoInfo.width + column + i * 2, dataWord);
}
_dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1));
} else { // End of cutscene ?
@@ -227,31 +193,52 @@ void FlicPlayer::decodeDeltaFLC(uint8 *data) {
#define PSTAMP 18
#define FRAME_TYPE 0xF1FA
-void FlicPlayer::decodeNextFrame() {
- FrameTypeChunkHeader frameHeader;
+bool FlicDecoder::decodeNextFrame() {
+ if (_videoInfo.currentFrame == 0)
+ _videoInfo.startTime = g_system->getMillis();
// Read chunk
- ChunkHeader cHeader = readChunkHeader();
- switch (cHeader.type) {
- case FRAME_TYPE:
- frameHeader = readFrameTypeChunkHeader(cHeader);
- _currFrame++;
+ uint32 frameSize = _fileStream->readUint32LE();
+ uint16 frameType = _fileStream->readUint16LE();
+ uint16 chunkCount = 0;
+
+ switch (frameType) {
+ case FRAME_TYPE: {
+ chunkCount = _fileStream->readUint16LE();
+ // Note: The overriden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
+ uint16 newFrameDelay = _fileStream->readUint16LE() * 1000; // "speed", in milliseconds
+ if (newFrameDelay > 0) {
+ _videoInfo.frameDelay = newFrameDelay;
+ _videoInfo.frameRate = 1000 / _videoInfo.frameDelay;
+ }
+ _fileStream->readUint16LE(); // reserved, always 0
+ uint16 newWidth = _fileStream->readUint16LE();
+ uint16 newHeight = _fileStream->readUint16LE();
+ if (newWidth > 0)
+ _videoInfo.width = newWidth;
+ if (newHeight > 0)
+ _videoInfo.height = newHeight;
+
+ _videoInfo.currentFrame++;
+ }
break;
default:
- error("FlicPlayer::decodeFrame(): unknown main chunk type (type = 0x%02X)", cHeader.type);
+ error("FlicDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType);
break;
}
// Read subchunks
- if (cHeader.type == FRAME_TYPE) {
- for (int i = 0; i < frameHeader.numChunks; ++i) {
- cHeader = readChunkHeader();
- uint8 *data = new uint8[cHeader.size - 6];
- _fileStream->read(data, cHeader.size - 6);
- switch (cHeader.type) {
+ if (frameType == FRAME_TYPE) {
+ for (uint32 i = 0; i < chunkCount; ++i) {
+ frameSize = _fileStream->readUint32LE();
+ frameType = _fileStream->readUint16LE();
+ uint8 *data = new uint8[frameSize - 6];
+ _fileStream->read(data, frameSize - 6);
+ switch (frameType) {
case FLI_SETPAL:
- setPalette(data);
- _paletteDirty = true;
+ unpackPalette(data);
+ setPalette(_palette);
+ _paletteChanged = true;
break;
case FLI_SS2:
decodeDeltaFLC(data);
@@ -263,7 +250,7 @@ void FlicPlayer::decodeNextFrame() {
/* PSTAMP - skip for now */
break;
default:
- error("FlicPlayer::decodeFrame(): unknown subchunk type (type = 0x%02X)", cHeader.type);
+ error("FlicDecoder::decodeFrame(): unknown subchunk type (type = 0x%02X)", frameType);
break;
}
@@ -272,25 +259,26 @@ void FlicPlayer::decodeNextFrame() {
}
// If we just processed the ring frame, set the next frame
- if (_currFrame == _flicInfo.numFrames + 1) {
- _currFrame = 1;
- _fileStream->seek(_flicInfo.offsetFrame2);
+ if (_videoInfo.currentFrame == _videoInfo.frameCount + 1) {
+ _videoInfo.currentFrame = 1;
+ _fileStream->seek(_offsetFrame2);
}
+
+ return _videoInfo.currentFrame < _videoInfo.frameCount;
}
-void FlicPlayer::reset() {
- _currFrame = 0;
- _fileStream->seek(_flicInfo.offsetFrame1);
+void FlicDecoder::reset() {
+ _videoInfo.currentFrame = 0;
+ _fileStream->seek(_offsetFrame1);
}
-void FlicPlayer::setPalette(uint8 *mem) {
+void FlicDecoder::unpackPalette(uint8 *mem) {
uint16 numPackets = READ_LE_UINT16(mem); mem += 2;
if (0 == READ_LE_UINT16(mem)) { //special case
mem += 2;
for (int i = 0; i < 256; ++i) {
- memcpy(_palette + i * 4, mem + i * 3, 3);
- _palette[i * 4 + 3] = 0;
+ memcpy(_palette + i * 3, mem + i * 3, 3);
}
} else {
uint8 palPos = 0;
@@ -300,8 +288,7 @@ void FlicPlayer::setPalette(uint8 *mem) {
uint8 change = *mem++;
for (int i = 0; i < change; ++i) {
- memcpy(_palette + (palPos + i) * 4, mem + i * 3, 3);
- _palette[(palPos + i) * 4 + 3] = 0;
+ memcpy(_palette + (palPos + i) * 3, mem + i * 3, 3);
}
palPos += change;
@@ -310,28 +297,14 @@ void FlicPlayer::setPalette(uint8 *mem) {
}
}
-void FlicPlayer::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
+void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
for (int y = (*it).top; y < (*it).bottom; ++y) {
const int x = (*it).left;
- memcpy(dst + y * pitch + x, _offscreen + y * _flicInfo.width + x, (*it).right - x);
+ memcpy(dst + y * pitch + x, _videoFrameBuffer + y * _videoInfo.width + x, (*it).right - x);
}
}
_dirtyRects.clear();
}
-void FlicPlayer::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
- uint h = _flicInfo.height;
- uint w = _flicInfo.width;
-
- byte *src = (byte *)_offscreen;
- dst += y * pitch + x;
-
- do {
- memcpy(dst, src, w);
- dst += pitch;
- src += w;
- } while (--h);
-}
-
} // End of namespace Graphics
diff --git a/graphics/video/flic_player.h b/graphics/video/flic_player.h
index de65e0c47b..4912c02884 100644
--- a/graphics/video/flic_player.h
+++ b/graphics/video/flic_player.h
@@ -28,10 +28,10 @@
* - tucker
*/
-#ifndef GRAPHICS_VIDEO_FLICPLAYER_H
-#define GRAPHICS_VIDEO_FLICPLAYER_H
+#ifndef GRAPHICS_VIDEO_FlicDecoder_H
+#define GRAPHICS_VIDEO_FlicDecoder_H
-#include "common/scummsys.h"
+#include "graphics/video/video_player.h"
#include "common/list.h"
#include "common/rect.h"
@@ -41,50 +41,10 @@ namespace Common {
namespace Graphics {
-struct ChunkHeader {
- uint32 size;
- uint16 type;
-};
-
-struct FrameTypeChunkHeader {
- ChunkHeader header;
- uint16 numChunks;
- uint16 delay;
- uint16 reserved; // always zero
- uint16 widthOverride;
- uint16 heightOverride;
-};
-
-// TOD: rewrite this based on VideoDecoder & VideoPlayer (this may
-// require improvements to these two classes).
-class FlicPlayer {
+class FlicDecoder : public VideoDecoder {
public:
- FlicPlayer();
- ~FlicPlayer();
-
- /**
- * Returns the width of the video
- * @return the width of the video
- */
- int getWidth();
-
- /**
- * Returns the height of the video
- * @return the height of the video
- */
- int getHeight();
-
- /**
- * Returns the current frame number of the video
- * @return the current frame number of the video
- */
- int32 getCurFrame();
-
- /**
- * Returns the amount of frames in the video
- * @return the amount of frames in the video
- */
- int32 getFrameCount();
+ FlicDecoder();
+ virtual ~FlicDecoder();
/**
* Load a FLIC encoded video file
@@ -100,55 +60,29 @@ public:
/**
* Decode the next frame
*/
- void decodeNextFrame();
+ bool decodeNextFrame();
- bool isLastFrame() const { return _currFrame == _flicInfo.numFrames; }
- uint32 getSpeed() const { return _flicInfo.speed; }
- bool isPaletteDirty() const { return _paletteDirty; }
- const uint8 *getPalette() { _paletteDirty = false; return _palette; }
- const uint8 *getOffscreen() const { return _offscreen; }
const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
void clearDirtyRects() { _dirtyRects.clear(); }
- void redraw();
- void reset();
-
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
- /**
- * Copy current frame into the specified position of the destination
- * buffer.
- * @param dst the buffer
- * @param x the x position of the buffer
- * @param y the y position of the buffer
- * @param pitch the pitch of buffer
- */
- void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch);
+ byte getPixel(int offset) { return _videoFrameBuffer[offset]; }
+ byte* getPalette() { _paletteChanged = false; return _palette; }
+ bool paletteChanged() { return _paletteChanged; }
+ void reset();
private:
- struct FlicHeader {
- uint32 size;
- uint16 type;
- uint16 numFrames;
- uint16 width;
- uint16 height;
- uint32 speed;
- uint16 offsetFrame1;
- uint16 offsetFrame2;
- };
-
- ChunkHeader readChunkHeader();
- FrameTypeChunkHeader readFrameTypeChunkHeader(ChunkHeader chunkHead);
+ uint16 _offsetFrame1;
+ uint16 _offsetFrame2;
+ byte *_palette;
+ bool _paletteChanged;
+
void decodeByteRun(uint8 *data);
void decodeDeltaFLC(uint8 *data);
- void setPalette(uint8 *mem);
-
- Common::SeekableReadStream *_fileStream;
- bool _paletteDirty;
- uint8 *_offscreen;
- uint8 _palette[256 * 4];
- FlicHeader _flicInfo;
- uint16 _currFrame;
+ void unpackPalette(uint8 *mem);
+
Common::List<Common::Rect> _dirtyRects;
+
};
} // End of namespace Graphics
diff --git a/graphics/video/smk_player.h b/graphics/video/smk_player.h
index aa2ee305fc..553575ade3 100644
--- a/graphics/video/smk_player.h
+++ b/graphics/video/smk_player.h
@@ -53,7 +53,7 @@ class BigHuffmanTree;
/**
* Implementation of a Smacker v2/v4 video decoder
*/
-class SmackerDecoder : public Graphics::VideoDecoder {
+class SmackerDecoder : public VideoDecoder {
public:
SmackerDecoder(Audio::Mixer *mixer);
virtual ~SmackerDecoder();
@@ -66,6 +66,10 @@ public:
* @param filename the filename to load
*/
bool loadFile(const char *filename);
+
+ /**
+ * Close an SMK encoded video file
+ */
void closeFile();
bool decodeNextFrame();