aboutsummaryrefslogtreecommitdiff
path: root/graphics/video/smk_decoder.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2010-05-18 14:17:24 +0000
committerMatthew Hoops2010-05-18 14:17:24 +0000
commit11cbdd03180a655b2b23ee4a13f1a00a1d782b3c (patch)
tree5b0d84211308ea37a2fa2f7017d6f96314f3c6fb /graphics/video/smk_decoder.cpp
parentf3892a506b2f935bae0be6319394c503c786d368 (diff)
downloadscummvm-rg350-11cbdd03180a655b2b23ee4a13f1a00a1d782b3c.tar.gz
scummvm-rg350-11cbdd03180a655b2b23ee4a13f1a00a1d782b3c.tar.bz2
scummvm-rg350-11cbdd03180a655b2b23ee4a13f1a00a1d782b3c.zip
Committing the rest of the VideoDecoder Rewrite from patch #2963496.
svn-id: r49079
Diffstat (limited to 'graphics/video/smk_decoder.cpp')
-rw-r--r--graphics/video/smk_decoder.cpp152
1 files changed, 62 insertions, 90 deletions
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 2f796c4a65..68fac32aae 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -351,52 +351,28 @@ uint32 BigHuffmanTree::getCode(BitStream &bs) {
SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType)
: _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) {
+ _surface = 0;
+ _fileStream = 0;
+ _dirtyPalette = false;
}
SmackerDecoder::~SmackerDecoder() {
- closeFile();
+ close();
}
-int SmackerDecoder::getHeight() {
- if (!_fileStream)
- return 0;
- return (_header.flags ? 2 : 1) * _videoInfo.height;
-}
-
-int32 SmackerDecoder::getAudioLag() {
- if (!_fileStream)
- return 0;
+uint32 SmackerDecoder::getElapsedTime() const {
+ if (_audioStream)
+ return _mixer->getSoundElapsedTime(_audioHandle);
- int32 frameDelay = getFrameDelay();
- int32 videoTime = (_videoInfo.currentFrame + 1) * frameDelay;
- int32 audioTime;
-
- if (!_audioStream) {
- /* No audio.
- Calculate the lag by how much time has gone by since the first frame
- and how much time *should* have passed.
- */
-
- audioTime = (g_system->getMillis() - _videoInfo.startTime) * 100;
- } else {
- const Audio::Timestamp ts = _mixer->getElapsedTime(_audioHandle);
- audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
- }
-
- return videoTime - audioTime;
+ return VideoDecoder::getElapsedTime();
}
-bool SmackerDecoder::loadFile(const char *fileName) {
- int32 frameRate;
-
- closeFile();
+bool SmackerDecoder::load(Common::SeekableReadStream &stream) {
+ close();
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
+ _fileStream = &stream;
// Seek to the first frame
- _videoInfo.currentFrame = -1;
_header.signature = _fileStream->readUint32BE();
// No BINK support available
@@ -408,21 +384,17 @@ bool SmackerDecoder::loadFile(const char *fileName) {
assert(_header.signature == MKID_BE('SMK2') || _header.signature == MKID_BE('SMK4'));
- _videoInfo.width = _fileStream->readUint32LE();
- _videoInfo.height = _fileStream->readUint32LE();
- _videoInfo.frameCount = _fileStream->readUint32LE();
- frameRate = _fileStream->readSint32LE();
-
- if (frameRate > 0) {
- _videoInfo.frameRate = 1000 / frameRate;
- _videoInfo.frameDelay = frameRate * 100;
- } else if (frameRate < 0) {
- _videoInfo.frameRate = 100000 / (-frameRate);
- _videoInfo.frameDelay = -frameRate;
- } else {
- _videoInfo.frameRate = 10;
- _videoInfo.frameDelay = 10000;
- }
+ uint32 width = _fileStream->readUint32LE();
+ uint32 height = _fileStream->readUint32LE();
+ _frameCount = _fileStream->readUint32LE();
+ int32 frameRate = _fileStream->readSint32LE();
+
+ if (frameRate > 0)
+ _frameRate = 1000 / frameRate;
+ else if (frameRate < 0)
+ _frameRate = 100000 / (-frameRate);
+ else
+ _frameRate = 10;
// Flags are determined by which bit is set, which can be one of the following:
// 0 - set to 1 if file contains a ring frame.
@@ -447,7 +419,6 @@ bool SmackerDecoder::loadFile(const char *fileName) {
_header.fullSize = _fileStream->readUint32LE();
_header.typeSize = _fileStream->readUint32LE();
- uint32 audioInfo;
for (i = 0; i < 7; ++i) {
// AudioRate - Frequency and format information for each sound track, up to 7 audio tracks.
// The 32 constituent bits have the following meaning:
@@ -458,7 +429,7 @@ bool SmackerDecoder::loadFile(const char *fileName) {
// * bits 27-26 - if both set to zero - use v2 sound decompression
// * bits 25-24 - unused
// * bits 23-0 - audio sample rate
- audioInfo = _fileStream->readUint32LE();
+ uint32 audioInfo = _fileStream->readUint32LE();
_header.audioInfo[i].isCompressed = audioInfo & 0x80000000;
_header.audioInfo[i].hasAudio = audioInfo & 0x40000000;
_header.audioInfo[i].is16Bits = audioInfo & 0x20000000;
@@ -467,19 +438,18 @@ bool SmackerDecoder::loadFile(const char *fileName) {
!(audioInfo & 0x4000000);
_header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF;
- if (_header.audioInfo[i].hasAudio && i == 0) {
+ if (_header.audioInfo[i].hasAudio && i == 0)
_audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo);
- }
}
_header.dummy = _fileStream->readUint32LE();
- _frameSizes = (uint32 *)malloc(_videoInfo.frameCount * sizeof(uint32));
- for (i = 0; i < _videoInfo.frameCount; ++i)
+ _frameSizes = new uint32[_frameCount];
+ for (i = 0; i < _frameCount; ++i)
_frameSizes[i] = _fileStream->readUint32LE();
- _frameTypes = (byte *)malloc(_videoInfo.frameCount);
- for (i = 0; i < _videoInfo.frameCount; ++i)
+ _frameTypes = new byte[_frameCount];
+ for (i = 0; i < _frameCount; ++i)
_frameTypes[i] = _fileStream->readByte();
byte *huffmanTrees = new byte[_header.treesSize];
@@ -494,17 +464,17 @@ bool SmackerDecoder::loadFile(const char *fileName) {
delete[] huffmanTrees;
- _videoFrameBuffer = (byte *)malloc(2 * _videoInfo.width * _videoInfo.height);
- memset(_videoFrameBuffer, 0, 2 * _videoInfo.width * _videoInfo.height);
- _palette = (byte *)malloc(3 * 256);
- memset(_palette, 0, 3 * 256);
+ _surface = new Graphics::Surface();
- _videoInfo.firstframeOffset = _fileStream->pos();
+ // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
+ _surface->create(width, height * (_header.flags ? 2 : 1), 1);
+ _palette = (byte *)malloc(3 * 256);
+ memset(_palette, 0, 3 * 256);
return true;
}
-void SmackerDecoder::closeFile() {
+void SmackerDecoder::close() {
if (!_fileStream)
return;
@@ -517,40 +487,42 @@ void SmackerDecoder::closeFile() {
delete _fileStream;
_fileStream = 0;
+ _surface->free();
+ delete _surface;
+ _surface = 0;
+
delete _MMapTree;
delete _MClrTree;
delete _FullTree;
delete _TypeTree;
- free(_frameSizes);
- free(_frameTypes);
- free(_videoFrameBuffer);
+ delete[] _frameSizes;
+ delete[] _frameTypes;
free(_palette);
+
+ reset();
}
-bool SmackerDecoder::decodeNextFrame() {
+Surface *SmackerDecoder::decodeNextFrame() {
uint i;
uint32 chunkSize = 0;
uint32 dataSizeUnpacked = 0;
uint32 startPos = _fileStream->pos();
- _videoInfo.currentFrame++;
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
+ _curFrame++;
// Check if we got a frame with palette data, and
// call back the virtual setPalette function to set
// the current palette
- if (_frameTypes[_videoInfo.currentFrame] & 1) {
+ if (_frameTypes[_curFrame] & 1) {
unpackPalette();
- setPalette(_palette);
+ _dirtyPalette = true;
}
// Load audio tracks
for (i = 0; i < 7; ++i) {
- if (!(_frameTypes[_videoInfo.currentFrame] & (2 << i)))
+ if (!(_frameTypes[_curFrame] & (2 << i)))
continue;
chunkSize = _fileStream->readUint32LE();
@@ -598,10 +570,10 @@ bool SmackerDecoder::decodeNextFrame() {
}
}
- uint32 frameSize = _frameSizes[_videoInfo.currentFrame] & ~3;
+ uint32 frameSize = _frameSizes[_curFrame] & ~3;
if (_fileStream->pos() - startPos > frameSize)
- exit(1);
+ error("Smacker actual frame size exceeds recorded frame size");
uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos);
@@ -615,13 +587,14 @@ bool SmackerDecoder::decodeNextFrame() {
_FullTree->reset();
_TypeTree->reset();
- uint bw = _videoInfo.width / 4;
- uint bh = _videoInfo.height / 4;
- uint stride = _videoInfo.width;
- uint block = 0, blocks = bw*bh;
-
+ // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
uint doubleY = _header.flags ? 2 : 1;
+ uint bw = getWidth() / 4;
+ uint bh = getHeight() / doubleY / 4;
+ uint stride = getWidth();
+ uint block = 0, blocks = bw*bh;
+
byte *out;
uint type, run, j, mode;
uint32 p1, p2, clr, map;
@@ -636,7 +609,7 @@ bool SmackerDecoder::decodeNextFrame() {
while (run-- && block < blocks) {
clr = _MClrTree->getCode(bs);
map = _MMapTree->getCode(bs);
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
hi = clr >> 8;
lo = clr & 0xff;
for (i = 0; i < 4; i++) {
@@ -669,7 +642,7 @@ bool SmackerDecoder::decodeNextFrame() {
}
while (run-- && block < blocks) {
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
switch (mode) {
case 0:
for (i = 0; i < 4; ++i) {
@@ -735,7 +708,7 @@ bool SmackerDecoder::decodeNextFrame() {
uint32 col;
mode = type >> 8;
while (run-- && block < blocks) {
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
col = mode * 0x01010101;
for (i = 0; i < 4 * doubleY; ++i) {
out[0] = out[1] = out[2] = out[3] = col;
@@ -751,7 +724,10 @@ bool SmackerDecoder::decodeNextFrame() {
free(_frameData);
- return !endOfVideo();
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
+
+ return _surface;
}
void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
@@ -806,15 +782,12 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
// If the sample is stereo, the data is stored for the left and right channel, respectively
// (the exact opposite to the base values)
if (!is16Bits) {
-
for (int k = 0; k < (isStereo ? 2 : 1); k++) {
bases[k] += (int8) ((int16) audioTrees[k]->getCode(audioBS));
*curPointer++ = CLIP<int>(bases[k], 0, 255) ^ 0x80;
curPos++;
}
-
} else {
-
for (int k = 0; k < (isStereo ? 2 : 1); k++) {
bases[k] += (int16) (audioTrees[k * 2]->getCode(audioBS) |
(audioTrees[k * 2 + 1]->getCode(audioBS) << 8));
@@ -887,7 +860,6 @@ void SmackerDecoder::unpackPalette() {
}
_fileStream->seek(startPos + len);
-
free(chunk);
}