aboutsummaryrefslogtreecommitdiff
path: root/graphics/video
diff options
context:
space:
mode:
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();