From 5db42076b87766d29cbcdd153446992bc661aa73 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 08:43:32 -0400 Subject: VIDEO: Convert FlicDecoder to the new AdvancedVideoDecoder API The video no longer automatically loops (unused in-tree) and must have rewind() called manually --- engines/tucker/sequences.cpp | 4 +- video/flic_decoder.cpp | 299 ++++++++++++++++++++++++------------------- video/flic_decoder.h | 101 ++++++++------- 3 files changed, 226 insertions(+), 178 deletions(-) diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 775fd6f1a0..16c4f4f6f0 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -28,6 +28,7 @@ #include "audio/decoders/wave.h" #include "graphics/palette.h" +#include "graphics/surface.h" #include "tucker/tucker.h" #include "tucker/graphics.h" @@ -749,6 +750,7 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) { _seqNum = 1; return; } + _flicPlayer[index].start(); _flicPlayer[index].decodeNextFrame(); if (index == 0) { getRGBPalette(index); @@ -801,7 +803,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { if (_flicPlayer[0].getCurFrame() >= 115) { surface = _flicPlayer[1].decodeNextFrame(); if (_flicPlayer[1].endOfVideo()) - _flicPlayer[1].reset(); + _flicPlayer[1].rewind(); } bool framesLeft = decodeNextAnimationFrame(0, false); diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index bdcdedc142..564d73a9d7 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -26,13 +26,11 @@ #include "common/stream.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/surface.h" namespace Video { FlicDecoder::FlicDecoder() { - _paletteChanged = false; - _fileStream = 0; - _surface = 0; } FlicDecoder::~FlicDecoder() { @@ -42,35 +40,59 @@ FlicDecoder::~FlicDecoder() { bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _fileStream = stream; - - /* uint32 frameSize = */ _fileStream->readUint32LE(); - uint16 frameType = _fileStream->readUint16LE(); + /* uint32 frameSize = */ stream->readUint32LE(); + uint16 frameType = stream->readUint16LE(); // Check FLC magic number if (frameType != 0xAF12) { - warning("FlicDecoder::FlicDecoder(): attempted to load non-FLC data (type = 0x%04X)", frameType); - delete _fileStream; - _fileStream = 0; + warning("FlicDecoder::loadStream(): attempted to load non-FLC data (type = 0x%04X)", frameType); return false; } - - _frameCount = _fileStream->readUint16LE(); - uint16 width = _fileStream->readUint16LE(); - uint16 height = _fileStream->readUint16LE(); - uint16 colorDepth = _fileStream->readUint16LE(); + uint16 frameCount = stream->readUint16LE(); + uint16 width = stream->readUint16LE(); + uint16 height = stream->readUint16LE(); + uint16 colorDepth = stream->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; + warning("FlicDecoder::loadStream(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", colorDepth); return false; } + addTrack(new FlicVideoTrack(stream, frameCount, width, height)); + return true; +} + +const Common::List *FlicDecoder::getDirtyRects() const { + const Track *track = getTrack(0); + + if (track) + return ((const FlicVideoTrack *)track)->getDirtyRects(); + + return 0; +} + +void FlicDecoder::clearDirtyRects() { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->clearDirtyRects(); +} + +void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch); +} + +FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height) { + _fileStream = stream; + _frameCount = frameCount; + _fileStream->readUint16LE(); // flags // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word) // the frame delay is the FLIC "speed", in milliseconds. - _frameRate = Common::Rational(1000, _fileStream->readUint32LE()); + _frameDelay = _startFrameDelay = _fileStream->readUint32LE(); _fileStream->seek(80); _offsetFrame1 = _fileStream->readUint32LE(); @@ -78,112 +100,53 @@ bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { _surface = new Graphics::Surface(); _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - _palette = (byte *)malloc(3 * 256); + _palette = new byte[3 * 256]; memset(_palette, 0, 3 * 256); - _paletteChanged = false; + _dirtyPalette = false; + + _curFrame = -1; + _nextFrameStartTime = 0; + _atRingFrame = false; // Seek to the first frame _fileStream->seek(_offsetFrame1); - return true; } -void FlicDecoder::close() { - if (!_fileStream) - return; - +FlicDecoder::FlicVideoTrack::~FlicVideoTrack() { delete _fileStream; - _fileStream = 0; + delete[] _palette; _surface->free(); delete _surface; - _surface = 0; - - free(_palette); - _dirtyRects.clear(); - - reset(); } -void FlicDecoder::decodeByteRun(uint8 *data) { - byte *ptr = (byte *)_surface->pixels; - while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { - int chunks = *data++; - while (chunks--) { - int count = (int8)*data++; - if (count > 0) { - memset(ptr, *data++, count); - } else { - count = -count; - memcpy(ptr, data, count); - data += count; - } - ptr += count; - } - } - - // Redraw - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +bool FlicDecoder::FlicVideoTrack::endOfTrack() const { + return getCurFrame() >= getFrameCount() - 1; } -#define OP_PACKETCOUNT 0 -#define OP_UNDEFINED 1 -#define OP_LASTPIXEL 2 -#define OP_LINESKIPCOUNT 3 +bool FlicDecoder::FlicVideoTrack::rewind() { + _curFrame = -1; + _nextFrameStartTime = 0; -void FlicDecoder::decodeDeltaFLC(uint8 *data) { - uint16 linesInChunk = READ_LE_UINT16(data); data += 2; - uint16 currentLine = 0; - uint16 packetCount = 0; - - while (linesInChunk--) { - uint16 opcode; - - // First process all the opcodes. - do { - opcode = READ_LE_UINT16(data); data += 2; + if (endOfTrack() && _fileStream->pos() < _fileStream->size()) + _atRingFrame = true; + else + _fileStream->seek(_offsetFrame1); - switch ((opcode >> 14) & 3) { - case OP_PACKETCOUNT: - packetCount = opcode; - break; - case OP_UNDEFINED: - break; - case OP_LASTPIXEL: - *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); - _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); - break; - case OP_LINESKIPCOUNT: - currentLine += -(int16)opcode; - break; - } - } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + _frameDelay = _startFrameDelay; + return true; +} - uint16 column = 0; +uint16 FlicDecoder::FlicVideoTrack::getWidth() const { + return _surface->w; +} - // Now interpret the RLE data - while (packetCount--) { - column += *data++; - int rleCount = (int8)*data++; - if (rleCount > 0) { - memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + 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((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); - } - _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); - } else { // End of cutscene ? - return; - } - column += rleCount * 2; - } +uint16 FlicDecoder::FlicVideoTrack::getHeight() const { + return _surface->h; +} - currentLine++; - } +Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const { + return _surface->format; } #define FLI_SETPAL 4 @@ -192,7 +155,7 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) { #define PSTAMP 18 #define FRAME_TYPE 0xF1FA -const Graphics::Surface *FlicDecoder::decodeNextFrame() { +const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() { // Read chunk uint32 frameSize = _fileStream->readUint32LE(); uint16 frameType = _fileStream->readUint16LE(); @@ -209,7 +172,7 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { // the frame delay is the FLIC "speed", in milliseconds. uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds if (newFrameDelay > 0) - _frameRate = Common::Rational(1000, newFrameDelay); + _frameDelay = newFrameDelay; _fileStream->readUint16LE(); // reserved, always 0 uint16 newWidth = _fileStream->readUint16LE(); @@ -240,10 +203,11 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { frameType = _fileStream->readUint16LE(); uint8 *data = new uint8[frameSize - 6]; _fileStream->read(data, frameSize - 6); + switch (frameType) { case FLI_SETPAL: unpackPalette(data); - _paletteChanged = true; + _dirtyPalette = true; break; case FLI_SS2: decodeDeltaFLC(data); @@ -264,26 +228,111 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { } _curFrame++; + _nextFrameStartTime += _frameDelay; - // If we just processed the ring frame, set the next frame - if (_curFrame == (int32)_frameCount) { - _curFrame = 0; + if (_atRingFrame) { + // If we decoded the ring frame, seek to the second frame + _atRingFrame = false; _fileStream->seek(_offsetFrame2); } - if (_curFrame == 0) - _startTime = g_system->getMillis(); - return _surface; } -void FlicDecoder::reset() { - FixedRateVideoDecoder::reset(); - if (_fileStream) - _fileStream->seek(_offsetFrame1); +void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + for (Common::List::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, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); + } + } + + clearDirtyRects(); } -void FlicDecoder::unpackPalette(uint8 *data) { +void FlicDecoder::FlicVideoTrack::decodeByteRun(uint8 *data) { + byte *ptr = (byte *)_surface->pixels; + while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { + int chunks = *data++; + while (chunks--) { + int count = (int8)*data++; + if (count > 0) { + memset(ptr, *data++, count); + } else { + count = -count; + memcpy(ptr, data, count); + data += count; + } + ptr += count; + } + } + + // Redraw + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +} + +#define OP_PACKETCOUNT 0 +#define OP_UNDEFINED 1 +#define OP_LASTPIXEL 2 +#define OP_LINESKIPCOUNT 3 + +void FlicDecoder::FlicVideoTrack::decodeDeltaFLC(uint8 *data) { + uint16 linesInChunk = READ_LE_UINT16(data); data += 2; + uint16 currentLine = 0; + uint16 packetCount = 0; + + while (linesInChunk--) { + uint16 opcode; + + // First process all the opcodes. + do { + opcode = READ_LE_UINT16(data); data += 2; + + switch ((opcode >> 14) & 3) { + case OP_PACKETCOUNT: + packetCount = opcode; + break; + case OP_UNDEFINED: + break; + case OP_LASTPIXEL: + *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); + _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); + break; + case OP_LINESKIPCOUNT: + currentLine += -(int16)opcode; + break; + } + } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + + uint16 column = 0; + + // Now interpret the RLE data + while (packetCount--) { + column += *data++; + int rleCount = (int8)*data++; + if (rleCount > 0) { + memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + 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((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); + } + _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); + } else { // End of cutscene ? + return; + } + column += rleCount * 2; + } + + currentLine++; + } +} + +void FlicDecoder::FlicVideoTrack::unpackPalette(uint8 *data) { uint16 numPackets = READ_LE_UINT16(data); data += 2; if (0 == READ_LE_UINT16(data)) { //special case @@ -308,14 +357,4 @@ void FlicDecoder::unpackPalette(uint8 *data) { } } -void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { - for (Common::List::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, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); - } - } - _dirtyRects.clear(); -} - } // End of namespace Video diff --git a/video/flic_decoder.h b/video/flic_decoder.h index 9badc3da2e..9b82161ca5 100644 --- a/video/flic_decoder.h +++ b/video/flic_decoder.h @@ -25,15 +25,17 @@ #include "video/video_decoder.h" #include "common/list.h" -#include "common/rational.h" #include "common/rect.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" namespace Common { class SeekableReadStream; } +namespace Graphics { +struct PixelFormat; +struct Surface; +} + namespace Video { /** @@ -42,58 +44,63 @@ namespace Video { * Video decoder used in engines: * - tucker */ -class FlicDecoder : public FixedRateVideoDecoder { +class FlicDecoder : public AdvancedVideoDecoder { public: FlicDecoder(); virtual ~FlicDecoder(); - /** - * Load a video file - * @param stream the stream to load - */ bool loadStream(Common::SeekableReadStream *stream); - void close(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - - const Common::List *getDirtyRects() const { return &_dirtyRects; } - void clearDirtyRects() { _dirtyRects.clear(); } - void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); - - const byte *getPalette() { _paletteChanged = false; return _palette; } - bool hasDirtyPalette() const { return _paletteChanged; } - void reset(); -protected: - Common::Rational getFrameRate() const { return _frameRate; } + const Common::List *getDirtyRects() const; + void clearDirtyRects(); + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); private: - uint16 _offsetFrame1; - uint16 _offsetFrame2; - byte *_palette; - bool _paletteChanged; - - void decodeByteRun(uint8 *data); - void decodeDeltaFLC(uint8 *data); - void unpackPalette(uint8 *mem); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface *_surface; - uint32 _frameCount; - Common::Rational _frameRate; - - Common::List _dirtyRects; + class FlicVideoTrack : public VideoTrack { + public: + FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height); + ~FlicVideoTrack(); + + bool endOfTrack() const; + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + uint32 getNextFrameStartTime() const { return _nextFrameStartTime; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + const Common::List *getDirtyRects() const { return &_dirtyRects; } + void clearDirtyRects() { _dirtyRects.clear(); } + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + + private: + Common::SeekableReadStream *_fileStream; + Graphics::Surface *_surface; + + int _curFrame; + bool _atRingFrame; + + uint16 _offsetFrame1; + uint16 _offsetFrame2; + byte *_palette; + mutable bool _dirtyPalette; + + uint32 _frameCount; + uint32 _frameDelay, _startFrameDelay; + uint32 _nextFrameStartTime; + + Common::List _dirtyRects; + + void decodeByteRun(uint8 *data); + void decodeDeltaFLC(uint8 *data); + void unpackPalette(uint8 *mem); + }; }; } // End of namespace Video -- cgit v1.2.3