ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

coktel_decoder.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 #include "common/rect.h"
00025 #include "common/endian.h"
00026 #include "common/stream.h"
00027 #include "common/system.h"
00028 #include "common/textconsole.h"
00029 #include "common/types.h"
00030 #include "common/util.h"
00031 
00032 #include "video/coktel_decoder.h"
00033 
00034 #include "image/codecs/indeo3.h"
00035 
00036 #ifdef VIDEO_COKTELDECODER_H
00037 
00038 #include "audio/audiostream.h"
00039 #include "audio/decoders/raw.h"
00040 #include "audio/decoders/adpcm_intern.h"
00041 #include "common/memstream.h"
00042 
00043 static const uint32 kVideoCodecIndeo3 = MKTAG('i','v','3','2');
00044 
00045 namespace Video {
00046 
00047 CoktelDecoder::State::State() : flags(0), speechId(0) {
00048 }
00049 
00050 
00051 CoktelDecoder::CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) :
00052     _mixer(mixer), _soundType(soundType), _width(0), _height(0), _x(0), _y(0),
00053     _defaultX(0), _defaultY(0), _features(0), _frameCount(0), _paletteDirty(false),
00054     _ownSurface(true), _frameRate(12), _hasSound(false), _soundEnabled(false),
00055     _soundStage(kSoundNone), _audioStream(0), _startTime(0), _pauseStartTime(0),
00056     _isPaused(false) {
00057 
00058     assert(_mixer);
00059 
00060     memset(_palette, 0, 768);
00061 }
00062 
00063 CoktelDecoder::~CoktelDecoder() {
00064 }
00065 
00066 bool CoktelDecoder::evaluateSeekFrame(int32 &frame, int whence) const {
00067     if (!isVideoLoaded())
00068         // Nothing to do
00069         return false;
00070 
00071     // Find the frame to which to seek
00072     if      (whence == SEEK_CUR)
00073         frame += _curFrame;
00074     else if (whence == SEEK_END)
00075         frame = _frameCount - frame - 1;
00076     else if (whence == SEEK_SET)
00077         frame--;
00078     else
00079         return false;
00080 
00081     if ((frame < -1) || (frame >= ((int32) _frameCount)))
00082         // Out of range
00083         return false;
00084 
00085     return true;
00086 }
00087 
00088 void CoktelDecoder::setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp) {
00089     freeSurface();
00090 
00091     if (!hasVideo())
00092         return;
00093 
00094     // Sanity checks
00095     assert((width > 0) && (height > 0));
00096     assert(bpp == getPixelFormat().bytesPerPixel);
00097 
00098     // Create a surface over this memory
00099     // TODO: Check whether it is fine to assume we want the setup PixelFormat.
00100     _surface.init(width, height, width * bpp, mem, getPixelFormat());
00101 
00102     _ownSurface = false;
00103 }
00104 
00105 void CoktelDecoder::setSurfaceMemory() {
00106     freeSurface();
00107     createSurface();
00108 
00109     _ownSurface = true;
00110 }
00111 
00112 const Graphics::Surface *CoktelDecoder::getSurface() const {
00113     if (!isVideoLoaded())
00114         return 0;
00115 
00116     return &_surface;
00117 }
00118 
00119 bool CoktelDecoder::hasSurface() {
00120     return _surface.getPixels();
00121 }
00122 
00123 void CoktelDecoder::createSurface() {
00124     if (hasSurface())
00125         return;
00126 
00127     if (!hasVideo())
00128         return;
00129 
00130     if ((_width > 0) && (_height > 0))
00131         _surface.create(_width, _height, getPixelFormat());
00132 
00133     _ownSurface = true;
00134 }
00135 
00136 void CoktelDecoder::freeSurface() {
00137     if (!_ownSurface) {
00138         _surface.w      = 0;
00139         _surface.h      = 0;
00140         _surface.pitch  = 0;
00141         _surface.setPixels(0);
00142         _surface.format = Graphics::PixelFormat();
00143     } else
00144         _surface.free();
00145 
00146     _ownSurface = true;
00147 }
00148 
00149 void CoktelDecoder::setXY(uint16 x, uint16 y) {
00150     _x = x;
00151     _y = y;
00152 }
00153 
00154 void CoktelDecoder::setXY() {
00155     setXY(_defaultX, _defaultY);
00156 }
00157 
00158 void CoktelDecoder::setFrameRate(Common::Rational frameRate) {
00159     _frameRate = frameRate;
00160 }
00161 
00162 uint16 CoktelDecoder::getDefaultX() const {
00163     return _defaultX;
00164 }
00165 
00166 uint16 CoktelDecoder::getDefaultY() const {
00167     return _defaultY;
00168 }
00169 
00170 const Common::List<Common::Rect> &CoktelDecoder::getDirtyRects() const {
00171     return _dirtyRects;
00172 }
00173 
00174 bool CoktelDecoder::hasPalette() const {
00175     return (_features & kFeaturesPalette) != 0;
00176 }
00177 
00178 bool CoktelDecoder::hasVideo() const {
00179     return true;
00180 }
00181 
00182 bool CoktelDecoder::hasSound() const {
00183     return _hasSound;
00184 }
00185 
00186 bool CoktelDecoder::isSoundEnabled() const {
00187     return _soundEnabled;
00188 }
00189 
00190 bool CoktelDecoder::isSoundPlaying() const {
00191     return _audioStream && _mixer->isSoundHandleActive(_audioHandle);
00192 }
00193 
00194 void CoktelDecoder::enableSound() {
00195     if (!hasSound() || isSoundEnabled())
00196         return;
00197 
00198     // Sanity check
00199     if (_mixer->getOutputRate() == 0)
00200         return;
00201 
00202     // Only possible on the first frame
00203     if (_curFrame > -1)
00204         return;
00205 
00206     _soundEnabled = true;
00207 }
00208 
00209 void CoktelDecoder::disableSound() {
00210     if (_audioStream) {
00211         if ((_soundStage == kSoundPlaying) || (_soundStage == kSoundFinished)) {
00212             _audioStream->finish();
00213             _mixer->stopHandle(_audioHandle);
00214         }
00215 
00216         delete _audioStream;
00217     }
00218 
00219     _soundEnabled = false;
00220     _soundStage   = kSoundNone;
00221 
00222     _audioStream = 0;
00223 }
00224 
00225 void CoktelDecoder::finishSound() {
00226     if (!_audioStream)
00227         return;
00228 
00229     _audioStream->finish();
00230     _soundStage = kSoundFinished;
00231 }
00232 
00233 void CoktelDecoder::colorModeChanged() {
00234 }
00235 
00236 bool CoktelDecoder::getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height) {
00237     return false;
00238 }
00239 
00240 bool CoktelDecoder::hasEmbeddedFiles() const {
00241     return false;
00242 }
00243 
00244 bool CoktelDecoder::hasEmbeddedFile(const Common::String &fileName) const {
00245     return false;
00246 }
00247 
00248 Common::SeekableReadStream *CoktelDecoder::getEmbeddedFile(const Common::String &fileName) const {
00249     return 0;
00250 }
00251 
00252 int32 CoktelDecoder::getSubtitleIndex() const {
00253     return -1;
00254 }
00255 
00256 bool CoktelDecoder::isPaletted() const {
00257     return true;
00258 }
00259 
00260 int CoktelDecoder::getCurFrame() const {
00261     return _curFrame;
00262 }
00263 
00264 void CoktelDecoder::close() {
00265     disableSound();
00266     freeSurface();
00267 
00268     _x = 0;
00269     _y = 0;
00270 
00271     _defaultX = 0;
00272     _defaultY = 0;
00273 
00274     _features = 0;
00275 
00276     _curFrame   = -1;
00277     _frameCount =  0;
00278 
00279     _startTime = 0;
00280 
00281     _hasSound = false;
00282 
00283     _isPaused = false;
00284 }
00285 
00286 Audio::Mixer::SoundType CoktelDecoder::getSoundType() const {
00287     return _soundType;
00288 }
00289 
00290 Audio::AudioStream *CoktelDecoder::getAudioStream() const {
00291     return _audioStream;
00292 }
00293 
00294 uint16 CoktelDecoder::getWidth() const {
00295     return _width;
00296 }
00297 
00298 uint16 CoktelDecoder::getHeight() const {
00299     return _height;
00300 }
00301 
00302 uint32 CoktelDecoder::getFrameCount() const {
00303     return _frameCount;
00304 }
00305 
00306 const byte *CoktelDecoder::getPalette() {
00307     _paletteDirty = false;
00308     return _palette;
00309 }
00310 
00311 bool CoktelDecoder::hasDirtyPalette() const {
00312     return (_features & kFeaturesPalette) && _paletteDirty;
00313 }
00314 
00315 uint32 CoktelDecoder::deLZ77(byte *dest, const byte *src, uint32 srcSize, uint32 destSize) {
00316     uint32 frameLength = READ_LE_UINT32(src);
00317     if (frameLength > destSize) {
00318         warning("CoktelDecoder::deLZ77(): Uncompressed size bigger than buffer size (%d > %d)", frameLength, destSize);
00319         return 0;
00320     }
00321 
00322     assert(srcSize >= 4);
00323 
00324     uint32 realSize = frameLength;
00325 
00326     src     += 4;
00327     srcSize -= 4;
00328 
00329     uint16 bufPos1;
00330     bool mode;
00331     if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) {
00332         assert(srcSize >= 4);
00333 
00334         src     += 4;
00335         srcSize -= 4;
00336 
00337         bufPos1 = 273;
00338         mode    = 1; // 123Ch (cmp al, 12h)
00339     } else {
00340         bufPos1 = 4078;
00341         mode    = 0; // 275h (jnz +2)
00342     }
00343 
00344     byte buf[4370];
00345     memset(buf, 32, bufPos1);
00346 
00347     uint8 chunkCount    = 1;
00348     uint8 chunkBitField = 0;
00349 
00350     while (frameLength > 0) {
00351         chunkCount--;
00352 
00353         if (chunkCount == 0) {
00354             chunkCount    = 8;
00355             chunkBitField = *src++;
00356         }
00357 
00358         if (chunkBitField % 2) {
00359             assert(srcSize >= 1);
00360 
00361             chunkBitField >>= 1;
00362             buf[bufPos1] = *src;
00363             *dest++ = *src++;
00364             bufPos1 = (bufPos1 + 1) % 4096;
00365             frameLength--;
00366             srcSize--;
00367             continue;
00368         }
00369         chunkBitField >>= 1;
00370 
00371         assert(srcSize >= 2);
00372 
00373         uint16 tmp = READ_LE_UINT16(src);
00374         uint16 chunkLength = ((tmp & 0xF00) >> 8) + 3;
00375 
00376         src     += 2;
00377         srcSize -= 2;
00378 
00379         if ((mode && ((chunkLength & 0xFF) == 0x12)) ||
00380                 (!mode && (chunkLength == 0))) {
00381             assert(srcSize >= 1);
00382 
00383             chunkLength = *src++ + 0x12;
00384             srcSize--;
00385         }
00386 
00387         uint16 bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00);
00388         if (((tmp + chunkLength) >= 4096) ||
00389                 ((chunkLength + bufPos1) >= 4096)) {
00390 
00391             for (int i = 0; i < chunkLength; i++, dest++) {
00392                 *dest = buf[bufPos2];
00393                 buf[bufPos1] = buf[bufPos2];
00394                 bufPos1 = (bufPos1 + 1) % 4096;
00395                 bufPos2 = (bufPos2 + 1) % 4096;
00396             }
00397 
00398         } else if (((tmp + chunkLength) < bufPos1) ||
00399                 ((chunkLength + bufPos1) < bufPos2)) {
00400 
00401             memcpy(dest, buf + bufPos2, chunkLength);
00402             memmove(buf + bufPos1, buf + bufPos2, chunkLength);
00403 
00404             dest    += chunkLength;
00405             bufPos1 += chunkLength;
00406             bufPos2 += chunkLength;
00407 
00408         } else {
00409 
00410             for (int i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) {
00411                 *dest = buf[bufPos2];
00412                 buf[bufPos1] = buf[bufPos2];
00413             }
00414 
00415         }
00416         frameLength -= chunkLength;
00417 
00418     }
00419 
00420     return realSize;
00421 }
00422 
00423 void CoktelDecoder::deRLE(byte *&destPtr, const byte *&srcPtr, int16 destLen, int16 srcLen) {
00424     srcPtr++;
00425 
00426     if (srcLen & 1) {
00427         byte data = *srcPtr++;
00428 
00429         if (destLen > 0) {
00430             *destPtr++ = data;
00431             destLen--;
00432         }
00433     }
00434 
00435     srcLen >>= 1;
00436 
00437     while (srcLen > 0) {
00438         uint8 tmp = *srcPtr++;
00439         if (tmp & 0x80) { // Verbatim copy
00440             tmp &= 0x7F;
00441 
00442             int16 copyCount = MAX<int16>(0, MIN<int16>(destLen, tmp * 2));
00443 
00444             memcpy(destPtr, srcPtr, copyCount);
00445 
00446             srcPtr  += tmp * 2;
00447             destPtr += copyCount;
00448             destLen -= copyCount;
00449         } else { // 2 bytes tmp times
00450             for (int i = 0; (i < tmp) && (destLen > 0); i++) {
00451                 for (int j = 0; j < 2; j++) {
00452                     if (destLen <= 0)
00453                         break;
00454 
00455                     *destPtr++ = srcPtr[j];
00456                     destLen--;
00457                 }
00458             }
00459             srcPtr += 2;
00460         }
00461         srcLen -= tmp;
00462     }
00463 }
00464 
00465 // A whole, completely filled block
00466 void CoktelDecoder::renderBlockWhole(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00467     Common::Rect srcRect = rect;
00468 
00469     rect.clip(dstSurf.w, dstSurf.h);
00470 
00471     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00472     for (int i = 0; i < rect.height(); i++) {
00473         memcpy(dst, src, rect.width() * dstSurf.format.bytesPerPixel);
00474 
00475         src += srcRect.width() * dstSurf.format.bytesPerPixel;
00476         dst += dstSurf.pitch;
00477     }
00478 }
00479 
00480 // A quarter-wide whole, completely filled block
00481 void CoktelDecoder::renderBlockWhole4X(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00482     Common::Rect srcRect = rect;
00483 
00484     rect.clip(dstSurf.w, dstSurf.h);
00485 
00486     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00487     for (int i = 0; i < rect.height(); i++) {
00488               byte *dstRow = dst;
00489         const byte *srcRow = src;
00490 
00491         int16 count = rect.width();
00492         while (count >= 0) {
00493             memset(dstRow, *srcRow, MIN<int16>(count, 4));
00494 
00495             count  -= 4;
00496             dstRow += 4;
00497             srcRow += 1;
00498         }
00499 
00500         src += srcRect.width() / 4;
00501         dst += dstSurf.pitch;
00502     }
00503 }
00504 
00505 // A half-high whole, completely filled block
00506 void CoktelDecoder::renderBlockWhole2Y(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00507     Common::Rect srcRect = rect;
00508 
00509     rect.clip(dstSurf.w, dstSurf.h);
00510 
00511     int16 height = rect.height();
00512 
00513     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00514     while (height > 1) {
00515         memcpy(dst                 , src, rect.width());
00516         memcpy(dst + dstSurf.pitch, src, rect.width());
00517 
00518         height -= 2;
00519         src    += srcRect.width();
00520         dst    += 2 * dstSurf.pitch;
00521     }
00522 
00523     if (height == 1)
00524         memcpy(dst, src, rect.width());
00525 }
00526 
00527 // A sparse block
00528 void CoktelDecoder::renderBlockSparse(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00529     Common::Rect srcRect = rect;
00530 
00531     rect.clip(dstSurf.w, dstSurf.h);
00532 
00533     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00534     for (int i = 0; i < rect.height(); i++) {
00535         byte *dstRow = dst;
00536         int16 pixWritten = 0;
00537 
00538         while (pixWritten < srcRect.width()) {
00539             int16 pixCount = *src++;
00540 
00541             if (pixCount & 0x80) { // Data
00542                 int16 copyCount;
00543 
00544                 pixCount  = MIN((pixCount & 0x7F) + 1, srcRect.width() - pixWritten);
00545                 copyCount = CLIP<int16>(rect.width() - pixWritten, 0, pixCount);
00546                 memcpy(dstRow, src, copyCount);
00547 
00548                 pixWritten += pixCount;
00549                 dstRow     += pixCount;
00550                 src        += pixCount;
00551             } else { // "Hole"
00552                 pixWritten += pixCount + 1;
00553                 dstRow     += pixCount + 1;
00554             }
00555 
00556         }
00557 
00558         dst += dstSurf.pitch;
00559     }
00560 }
00561 
00562 // A half-high sparse block
00563 void CoktelDecoder::renderBlockSparse2Y(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00564     warning("renderBlockSparse2Y");
00565 
00566     Common::Rect srcRect = rect;
00567 
00568     rect.clip(dstSurf.w, dstSurf.h);
00569 
00570     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00571     for (int i = 0; i < rect.height(); i += 2) {
00572         byte *dstRow = dst;
00573         int16 pixWritten = 0;
00574 
00575         while (pixWritten < srcRect.width()) {
00576             int16 pixCount = *src++;
00577 
00578             if (pixCount & 0x80) { // Data
00579                 pixCount  = MIN((pixCount & 0x7F) + 1, srcRect.width() - pixWritten);
00580                 memcpy(dstRow                 , src, pixCount);
00581                 memcpy(dstRow + dstSurf.pitch, src, pixCount);
00582 
00583                 pixWritten += pixCount;
00584                 dstRow     += pixCount;
00585                 src        += pixCount;
00586             } else { // "Hole"
00587                 pixWritten += pixCount + 1;
00588                 dstRow     += pixCount + 1;
00589             }
00590 
00591         }
00592 
00593         dst += dstSurf.pitch;
00594     }
00595 }
00596 
00597 void CoktelDecoder::renderBlockRLE(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect) {
00598     Common::Rect srcRect = rect;
00599 
00600     rect.clip(dstSurf.w, dstSurf.h);
00601 
00602     byte *dst = (byte *)dstSurf.getBasePtr(rect.left, rect.top);
00603     for (int i = 0; i < rect.height(); i++) {
00604         byte *dstRow = dst;
00605         int16 pixWritten = 0;
00606 
00607         while (pixWritten < srcRect.width()) {
00608             int16 pixCount = *src++;
00609 
00610             if (pixCount & 0x80) {
00611                 int16 copyCount;
00612 
00613                 pixCount  = MIN((pixCount & 0x7F) + 1, srcRect.width() - pixWritten);
00614                 copyCount = CLIP<int16>(rect.width() - pixWritten, 0, pixCount);
00615 
00616                 if (*src != 0xFF) { // Normal copy
00617 
00618                     memcpy(dstRow, src, copyCount);
00619                     dstRow += copyCount;
00620                     src    += pixCount;
00621                 } else
00622                     deRLE(dstRow, src, copyCount, pixCount);
00623 
00624                 pixWritten += pixCount;
00625             } else { // "Hole"
00626                 int16 copyCount = CLIP<int16>(rect.width() - pixWritten, 0, pixCount + 1);
00627 
00628                 dstRow     += copyCount;
00629                 pixWritten += pixCount + 1;
00630             }
00631 
00632         }
00633 
00634         dst += dstSurf.pitch;
00635     }
00636 }
00637 
00638 Common::Rational CoktelDecoder::getFrameRate() const {
00639     return _frameRate;
00640 }
00641 
00642 uint32 CoktelDecoder::getTimeToNextFrame() const {
00643     if (endOfVideo() || _curFrame < 0)
00644         return 0;
00645 
00646     uint32 elapsedTime        = g_system->getMillis() - _startTime;
00647     uint32 nextFrameStartTime = (Common::Rational((_curFrame + 1) * 1000) / getFrameRate()).toInt();
00648 
00649     if (nextFrameStartTime <= elapsedTime)
00650         return 0;
00651 
00652     return nextFrameStartTime - elapsedTime;
00653 }
00654 
00655 uint32 CoktelDecoder::getStaticTimeToNextFrame() const {
00656     return (1000 / _frameRate).toInt();
00657 }
00658 
00659 void CoktelDecoder::pauseVideo(bool pause) {
00660     if (_isPaused != pause) {
00661         if (_isPaused) {
00662             // Add the time we were paused to the initial starting time
00663             _startTime += g_system->getMillis() - _pauseStartTime;
00664         } else {
00665             // Store the time we paused for use later
00666             _pauseStartTime = g_system->getMillis();
00667         }
00668 
00669         _isPaused = pause;
00670     }
00671 }
00672 
00673 inline void CoktelDecoder::unsignedToSigned(byte *buffer, int length) {
00674     while (length-- > 0) *buffer++ ^= 0x80;
00675 }
00676 
00677 bool CoktelDecoder::endOfVideo() const {
00678     return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
00679 }
00680 
00681 
00682 PreIMDDecoder::PreIMDDecoder(uint16 width, uint16 height,
00683     Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
00684     _stream(0), _videoBuffer(0), _videoBufferSize(0) {
00685 
00686     _width  = width;
00687     _height = height;
00688 }
00689 
00690 PreIMDDecoder::~PreIMDDecoder() {
00691     close();
00692 }
00693 
00694 bool PreIMDDecoder::reloadStream(Common::SeekableReadStream *stream) {
00695     if (!_stream)
00696         return false;
00697 
00698     if (!stream->seek(_stream->pos())) {
00699         close();
00700         return false;
00701     }
00702 
00703     delete _stream;
00704     _stream = stream;
00705 
00706     return true;
00707 }
00708 
00709 bool PreIMDDecoder::seek(int32 frame, int whence, bool restart) {
00710     if (!evaluateSeekFrame(frame, whence))
00711         return false;
00712 
00713     if (frame == _curFrame)
00714         // Nothing to do
00715         return true;
00716 
00717     // Run through the frames
00718     _curFrame = -1;
00719     _stream->seek(2);
00720     while (_curFrame != frame) {
00721         uint16 frameSize = _stream->readUint16LE();
00722 
00723         _stream->skip(frameSize + 2);
00724 
00725         _curFrame++;
00726     }
00727 
00728     return true;
00729 }
00730 
00731 bool PreIMDDecoder::loadStream(Common::SeekableReadStream *stream) {
00732     // Since PreIMDs don't have any width and height values stored,
00733     // we need them to be specified in the constructor
00734     assert((_width > 0) && (_height > 0));
00735 
00736     close();
00737 
00738     _stream = stream;
00739 
00740     _stream->seek(0);
00741 
00742     _frameCount = _stream->readUint16LE();
00743 
00744     _videoBufferSize = _width * _height;
00745     _videoBuffer     = new byte[_videoBufferSize];
00746 
00747     memset(_videoBuffer, 0, _videoBufferSize);
00748 
00749     return true;
00750 }
00751 
00752 void PreIMDDecoder::close() {
00753     CoktelDecoder::close();
00754 
00755     delete _stream;
00756 
00757     delete[] _videoBuffer;
00758 
00759     _stream = 0;
00760 
00761     _videoBuffer     = 0;
00762     _videoBufferSize = 0;
00763 }
00764 
00765 bool PreIMDDecoder::isVideoLoaded() const {
00766     return _stream != 0;
00767 }
00768 
00769 const Graphics::Surface *PreIMDDecoder::decodeNextFrame() {
00770     if (!isVideoLoaded() || endOfVideo())
00771         return 0;
00772 
00773     createSurface();
00774 
00775     processFrame();
00776     renderFrame();
00777 
00778     if (_curFrame == 0)
00779         _startTime = g_system->getMillis();
00780 
00781     return &_surface;
00782 }
00783 
00784 void PreIMDDecoder::processFrame() {
00785     _curFrame++;
00786 
00787     uint16 frameSize = _stream->readUint16LE();
00788     if (_stream->eos() || (frameSize == 0))
00789         return;
00790 
00791     uint32 nextFramePos = _stream->pos() + frameSize + 2;
00792 
00793     byte cmd;
00794 
00795     cmd = _stream->readByte();
00796     frameSize--;
00797 
00798     if (cmd == 0) {
00799         // Palette. Ignored by Fascination, though.
00800 
00801         // NOTE: If we ever find another game using this format,
00802         //       palettes may need to be evaluated.
00803 
00804         _stream->skip(768);
00805 
00806         frameSize -= 769;
00807 
00808         cmd = _stream->readByte();
00809     }
00810 
00811     if (cmd != 2) {
00812         // Partial frame data
00813 
00814         uint32 fSize   = frameSize;
00815         uint32 vidSize = _videoBufferSize;
00816 
00817         byte *vidBuffer = _videoBuffer;
00818 
00819         while ((fSize > 0) && (vidSize > 0)) {
00820             uint32 n = _stream->readByte();
00821             fSize--;
00822 
00823             if ((n & 0x80) != 0) {
00824                 // Data
00825 
00826                 n = MIN<uint32>((n & 0x7F) + 1, MIN(fSize, vidSize));
00827 
00828                 _stream->read(vidBuffer, n);
00829 
00830                 vidBuffer += n;
00831                 vidSize   -= n;
00832                 fSize     -= n;
00833 
00834             } else {
00835                 // Skip
00836 
00837                 n = MIN<uint32>(n + 1, vidSize);
00838 
00839                 vidBuffer += n;
00840                 vidSize   -= n;
00841             }
00842         }
00843 
00844     } else {
00845         // Full direct frame
00846 
00847         uint32 vidSize = MIN<uint32>(_videoBufferSize, frameSize);
00848 
00849         _stream->read(_videoBuffer, vidSize);
00850     }
00851 
00852     _stream->seek(nextFramePos);
00853 }
00854 
00855 // Just a simple blit
00856 void PreIMDDecoder::renderFrame() {
00857     _dirtyRects.clear();
00858 
00859     uint16 w = CLIP<int32>(_surface.w - _x, 0, _width);
00860     uint16 h = CLIP<int32>(_surface.h - _y, 0, _height);
00861 
00862     const byte *src = _videoBuffer;
00863           byte *dst = (byte *)_surface.getBasePtr(_x, _y);
00864 
00865     uint32 frameDataSize = _videoBufferSize;
00866 
00867     while (h-- > 0) {
00868         uint32 n = MIN<uint32>(w, frameDataSize);
00869 
00870         memcpy(dst, src, n);
00871 
00872         src += _width;
00873         dst += _surface.pitch;
00874 
00875         frameDataSize -= n;
00876     }
00877 
00878     _dirtyRects.push_back(Common::Rect(_x, _y, _x + _width, _y + _height));
00879 }
00880 
00881 Graphics::PixelFormat PreIMDDecoder::getPixelFormat() const {
00882     return Graphics::PixelFormat::createFormatCLUT8();
00883 }
00884 
00885 
00886 IMDDecoder::IMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
00887     _stream(0), _version(0), _stdX(-1), _stdY(-1), _stdWidth(-1), _stdHeight(-1),
00888     _flags(0), _firstFramePos(0), _framePos(0), _frameCoords(0), _videoBufferSize(0),
00889     _soundFlags(0), _soundFreq(0), _soundSliceSize(0), _soundSlicesCount(0) {
00890 
00891     _videoBuffer   [0] = 0;
00892     _videoBuffer   [1] = 0;
00893     _videoBufferLen[0] = 0;
00894     _videoBufferLen[1] = 0;
00895 }
00896 
00897 IMDDecoder::~IMDDecoder() {
00898     close();
00899 }
00900 
00901 bool IMDDecoder::reloadStream(Common::SeekableReadStream *stream) {
00902     if (!_stream)
00903         return false;
00904 
00905     if (!stream->seek(_stream->pos())) {
00906         close();
00907         return false;
00908     }
00909 
00910     delete _stream;
00911     _stream = stream;
00912 
00913     return true;
00914 }
00915 
00916 bool IMDDecoder::seek(int32 frame, int whence, bool restart) {
00917     if (!evaluateSeekFrame(frame, whence))
00918         return false;
00919 
00920     if (frame == _curFrame)
00921         // Nothing to do
00922         return true;
00923 
00924     // Try every possible way to find a file offset to that frame
00925     uint32 framePos = 0;
00926     if (frame == -1) {
00927         // First frame, we know that position
00928 
00929         framePos = _firstFramePos;
00930 
00931     } else if (frame == 0) {
00932         // Second frame, can be calculated from the first frame's position
00933 
00934         framePos = _firstFramePos;
00935         _stream->seek(framePos);
00936         framePos += _stream->readUint16LE() + 4;
00937 
00938     } else if (_framePos) {
00939         // If we have an array of frame positions, use that
00940 
00941         framePos = _framePos[frame + 1];
00942 
00943     } else if (restart && (_soundStage == kSoundNone)) {
00944         // If we are asked to restart the video if necessary and have no
00945         // audio to worry about, restart the video and run through the frames
00946 
00947         _curFrame = 0;
00948         _stream->seek(_firstFramePos);
00949 
00950         for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++)
00951             processFrame();
00952 
00953         return true;
00954 
00955     } else {
00956         // Not possible
00957 
00958         warning("IMDDecoder::seek(): Frame %d is not directly accessible", frame + 1);
00959         return false;
00960     }
00961 
00962     // Seek
00963     _stream->seek(framePos);
00964     _curFrame = frame;
00965 
00966     return true;
00967 }
00968 
00969 void IMDDecoder::setXY(uint16 x, uint16 y) {
00970     // Adjusting the standard coordinates
00971     if (_stdX != -1) {
00972         if (x != 0xFFFF)
00973             _stdX = _stdX - _x + x;
00974         if (y != 0xFFFF)
00975             _stdY = _stdY - _y + y;
00976     }
00977 
00978     // Going through the coordinate table as well
00979     if (_frameCoords) {
00980         for (uint32 i = 0; i < _frameCount; i++) {
00981             if (_frameCoords[i].left != -1) {
00982                 if (x != 0xFFFF) {
00983                     _frameCoords[i].left  = _frameCoords[i].left  - _x + x;
00984                     _frameCoords[i].right = _frameCoords[i].right - _x + x;
00985                 }
00986                 if (y != 0xFFFF) {
00987                     _frameCoords[i].top    = _frameCoords[i].top    - _y + y;
00988                     _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y;
00989                 }
00990             }
00991         }
00992     }
00993 
00994     if (x != 0xFFFF)
00995         _x = x;
00996     if (y != 0xFFFF)
00997         _y = y;
00998 }
00999 
01000 bool IMDDecoder::loadStream(Common::SeekableReadStream *stream) {
01001     close();
01002 
01003     _stream = stream;
01004 
01005     uint16 handle;
01006 
01007     handle   = _stream->readUint16LE();
01008     _version = _stream->readByte();
01009 
01010     // Version checking
01011     if ((handle != 0) || (_version < 2)) {
01012         warning("IMDDecoder::loadStream(): Version incorrect (%d, 0x%X)", handle, _version);
01013         close();
01014         return false;
01015     }
01016 
01017     // Rest header
01018     _features      = _stream->readByte();
01019     _frameCount    = _stream->readUint16LE();
01020     _defaultX      = _stream->readSint16LE();
01021     _defaultY      = _stream->readSint16LE();
01022     _width         = _stream->readSint16LE();
01023     _height        = _stream->readSint16LE();
01024     _flags         = _stream->readUint16LE();
01025     _firstFramePos = _stream->readUint16LE();
01026 
01027     _x = _defaultX;
01028     _y = _defaultY;
01029 
01030     // IMDs always have video
01031     _features |= kFeaturesVideo;
01032     // IMDs always have palettes
01033     _features |= kFeaturesPalette;
01034 
01035     // Palette
01036     for (int i = 0; i < 768; i++)
01037         _palette[i] = _stream->readByte() << 2;
01038 
01039     _paletteDirty = true;
01040 
01041     if (!loadCoordinates()) {
01042         close();
01043         return false;
01044     }
01045 
01046     uint32 framePosPos, frameCoordsPos;
01047     if (!loadFrameTableOffsets(framePosPos, frameCoordsPos)) {
01048         close();
01049         return false;
01050     }
01051 
01052     if (!assessAudioProperties()) {
01053         close();
01054         return false;
01055     }
01056 
01057     if (!assessVideoProperties()) {
01058         close();
01059         return false;
01060     }
01061 
01062     if (!loadFrameTables(framePosPos, frameCoordsPos)) {
01063         close();
01064         return false;
01065     }
01066 
01067     // Seek to the first frame
01068     _stream->seek(_firstFramePos);
01069 
01070     return true;
01071 }
01072 
01073 bool IMDDecoder::loadCoordinates() {
01074     // Standard coordinates
01075     if (_version >= 3) {
01076         uint16 count = _stream->readUint16LE();
01077         if (count > 1) {
01078             warning("IMDDecoder::loadCoordinates(): More than one standard coordinate quad found (%d)", count);
01079             return false;
01080         }
01081 
01082         if (count != 0) {
01083             _stdX      = _stream->readSint16LE();
01084             _stdY      = _stream->readSint16LE();
01085             _stdWidth  = _stream->readSint16LE();
01086             _stdHeight = _stream->readSint16LE();
01087             _features |= kFeaturesStdCoords;
01088         } else
01089             _stdX = _stdY = _stdWidth = _stdHeight = -1;
01090 
01091     } else
01092         _stdX = _stdY = _stdWidth = _stdHeight = -1;
01093 
01094     return true;
01095 }
01096 
01097 bool IMDDecoder::loadFrameTableOffsets(uint32 &framePosPos, uint32 &frameCoordsPos) {
01098     framePosPos    = 0;
01099     frameCoordsPos = 0;
01100 
01101     // Frame positions
01102     if (_version >= 4) {
01103         framePosPos = _stream->readUint32LE();
01104         if (framePosPos != 0) {
01105             _framePos  = new uint32[_frameCount];
01106             _features |= kFeaturesFramePos;
01107         }
01108     }
01109 
01110     // Frame coordinates
01111     if (_features & kFeaturesFrameCoords)
01112         frameCoordsPos = _stream->readUint32LE();
01113 
01114     return true;
01115 }
01116 
01117 bool IMDDecoder::assessVideoProperties() {
01118     uint32 suggestedVideoBufferSize = 0;
01119 
01120     // Sizes of the frame data and extra video buffer
01121     if (_features & kFeaturesDataSize) {
01122         uint32 size1, size2;
01123 
01124         size1 = _stream->readUint16LE();
01125         if (size1 == 0) {
01126             size1 = _stream->readUint32LE();
01127             size2 = _stream->readUint32LE();
01128         } else
01129             size2 = _stream->readUint16LE();
01130 
01131         suggestedVideoBufferSize = MAX(size1, size2);
01132     }
01133 
01134     _videoBufferSize = _width * _height + 1000;
01135 
01136     if (suggestedVideoBufferSize > _videoBufferSize) {
01137         warning("Suggested video buffer size greater than what should be needed (%d, %d, %dx%d",
01138             suggestedVideoBufferSize, _videoBufferSize, _width, _height);
01139 
01140         _videoBufferSize = suggestedVideoBufferSize;
01141     }
01142 
01143     for (int i = 0; i < 2; i++) {
01144         _videoBuffer[i] = new byte[_videoBufferSize];
01145         memset(_videoBuffer[i], 0, _videoBufferSize);
01146     }
01147 
01148     return true;
01149 }
01150 
01151 bool IMDDecoder::assessAudioProperties() {
01152     if (_features & kFeaturesSound) {
01153         _soundFreq        = _stream->readSint16LE();
01154         _soundSliceSize   = _stream->readSint16LE();
01155         _soundSlicesCount = _stream->readSint16LE();
01156 
01157         if (_soundFreq < 0)
01158             _soundFreq = -_soundFreq;
01159 
01160         if (_soundSlicesCount < 0)
01161             _soundSlicesCount = -_soundSlicesCount - 1;
01162 
01163         if (_soundSlicesCount > 40) {
01164             warning("IMDDecoder::assessAudioProperties(): More than 40 sound slices found (%d)", _soundSlicesCount);
01165             return false;
01166         }
01167 
01168         _frameRate = Common::Rational(_soundFreq, _soundSliceSize);
01169 
01170         _hasSound     = true;
01171         _soundEnabled = true;
01172         _soundStage   = kSoundLoaded;
01173 
01174         _audioStream = Audio::makeQueuingAudioStream(_soundFreq, false);
01175     }
01176 
01177     return true;
01178 }
01179 
01180 bool IMDDecoder::loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos) {
01181     // Positions table
01182     if (_framePos) {
01183         _stream->seek(framePosPos);
01184         for (uint32 i = 0; i < _frameCount; i++)
01185             _framePos[i] = _stream->readUint32LE();
01186     }
01187 
01188     // Coordinates table
01189     if (_features & kFeaturesFrameCoords) {
01190         _stream->seek(frameCoordsPos);
01191         _frameCoords = new Coord[_frameCount];
01192         assert(_frameCoords);
01193         for (uint32 i = 0; i < _frameCount; i++) {
01194             _frameCoords[i].left   = _stream->readSint16LE();
01195             _frameCoords[i].top    = _stream->readSint16LE();
01196             _frameCoords[i].right  = _stream->readSint16LE();
01197             _frameCoords[i].bottom = _stream->readSint16LE();
01198         }
01199     }
01200 
01201     return true;
01202 }
01203 
01204 void IMDDecoder::close() {
01205     CoktelDecoder::close();
01206 
01207     delete _stream;
01208 
01209     delete[] _framePos;
01210     delete[] _frameCoords;
01211 
01212     delete[] _videoBuffer[0];
01213     delete[] _videoBuffer[1];
01214 
01215     _stream = 0;
01216 
01217     _version = 0;
01218 
01219     _stdX      = -1;
01220     _stdY      = -1;
01221     _stdWidth  = -1;
01222     _stdHeight = -1;
01223 
01224     _flags         = 0;
01225 
01226     _firstFramePos = 0;
01227     _framePos      = 0;
01228     _frameCoords   = 0;
01229 
01230     _videoBufferSize   = 0;
01231     _videoBuffer   [0] = 0;
01232     _videoBuffer   [1] = 0;
01233     _videoBufferLen[0] = 0;
01234     _videoBufferLen[1] = 0;
01235 
01236     _soundFlags       = 0;
01237     _soundFreq        = 0;
01238     _soundSliceSize   = 0;
01239     _soundSlicesCount = 0;
01240 
01241     _hasSound     = false;
01242     _soundEnabled = false;
01243     _soundStage   = kSoundNone;
01244 }
01245 
01246 bool IMDDecoder::isVideoLoaded() const {
01247     return _stream != 0;
01248 }
01249 
01250 const Graphics::Surface *IMDDecoder::decodeNextFrame() {
01251     if (!isVideoLoaded() || endOfVideo())
01252         return 0;
01253 
01254     createSurface();
01255 
01256     processFrame();
01257 
01258     if (_curFrame == 0)
01259         _startTime = g_system->getMillis();
01260 
01261     return &_surface;
01262 }
01263 
01264 void IMDDecoder::processFrame() {
01265     _curFrame++;
01266 
01267     _dirtyRects.clear();
01268 
01269     uint32 cmd = 0;
01270     bool hasNextCmd = false;
01271     bool startSound = false;
01272 
01273     do {
01274         cmd = _stream->readUint16LE();
01275 
01276         if ((cmd & kCommandBreakMask) == kCommandBreak) {
01277             // Flow control
01278 
01279             if (cmd == kCommandBreak) {
01280                 _stream->skip(2);
01281                 cmd = _stream->readUint16LE();
01282             }
01283 
01284             // Break
01285             if (cmd == kCommandBreakSkip0) {
01286                 continue;
01287             } else if (cmd == kCommandBreakSkip16) {
01288                 cmd = _stream->readUint16LE();
01289                 _stream->skip(cmd);
01290                 continue;
01291             } else if (cmd == kCommandBreakSkip32) {
01292                 cmd = _stream->readUint32LE();
01293                 _stream->skip(cmd);
01294                 continue;
01295             }
01296         }
01297 
01298         // Audio
01299         if (cmd == kCommandNextSound) {
01300 
01301             nextSoundSlice(hasNextCmd);
01302             cmd = _stream->readUint16LE();
01303 
01304         } else if (cmd == kCommandStartSound) {
01305 
01306             startSound = initialSoundSlice(hasNextCmd);
01307             cmd = _stream->readUint16LE();
01308 
01309         } else
01310             emptySoundSlice(hasNextCmd);
01311 
01312         // Set palette
01313         if (cmd == kCommandPalette) {
01314             _stream->skip(2);
01315 
01316             _paletteDirty = true;
01317 
01318             for (int i = 0; i < 768; i++)
01319                 _palette[i] = _stream->readByte() << 2;
01320 
01321             cmd = _stream->readUint16LE();
01322         }
01323 
01324         hasNextCmd = false;
01325 
01326         if (cmd == kCommandJump) {
01327             // Jump to frame
01328 
01329             int16 frame = _stream->readSint16LE();
01330             if (_framePos) {
01331                 _curFrame = frame - 1;
01332                 _stream->seek(_framePos[frame]);
01333 
01334                 hasNextCmd = true;
01335             }
01336 
01337         } else if (cmd == kCommandVideoData) {
01338 
01339             _videoBufferLen[0] = _stream->readUint32LE() + 2;
01340             _stream->read(_videoBuffer[0], _videoBufferLen[0]);
01341 
01342             Common::Rect rect = calcFrameCoords(_curFrame);
01343 
01344             if (renderFrame(rect))
01345                 _dirtyRects.push_back(rect);
01346 
01347         } else if (cmd != 0) {
01348 
01349             _videoBufferLen[0] = cmd + 2;
01350             _stream->read(_videoBuffer[0], _videoBufferLen[0]);
01351 
01352             Common::Rect rect = calcFrameCoords(_curFrame);
01353 
01354             if (renderFrame(rect))
01355                 _dirtyRects.push_back(rect);
01356 
01357         }
01358 
01359     } while (hasNextCmd);
01360 
01361     // Start the audio stream if necessary
01362     if (startSound && _soundEnabled) {
01363             _mixer->playStream(_soundType, &_audioHandle, _audioStream,
01364                     -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
01365         _soundStage = kSoundPlaying;
01366     }
01367 
01368     // End the audio stream if necessary
01369     if ((_curFrame >= (int32)(_frameCount - 1)) && (_soundStage == kSoundPlaying)) {
01370         _audioStream->finish();
01371         _soundStage = kSoundFinished;
01372     }
01373 
01374 }
01375 
01376 Common::Rect IMDDecoder::calcFrameCoords(uint32 frame) {
01377     Common::Rect rect;
01378 
01379     if (frame == 0) {
01380         // First frame is always a full "keyframe"
01381 
01382         rect.left   = _x;
01383         rect.top    = _y;
01384         rect.right  = _x + _width;
01385         rect.bottom = _y + _height;
01386     } else if (_frameCoords && ((_frameCoords[frame].left != -1))) {
01387         // We have frame coordinates for that frame
01388 
01389         rect.left   = _frameCoords[frame].left;
01390         rect.top    = _frameCoords[frame].top;
01391         rect.right  = _frameCoords[frame].right  + 1;
01392         rect.bottom = _frameCoords[frame].bottom + 1;
01393     } else if (_stdX != -1) {
01394         // We have standard coordinates
01395 
01396         rect.left   = _stdX;
01397         rect.top    = _stdY;
01398         rect.right  = _stdX + _stdWidth;
01399         rect.bottom = _stdY + _stdHeight;
01400     } else {
01401         // Otherwise, it must be a full "keyframe"
01402 
01403         rect.left   = _x;
01404         rect.top    = _y;
01405         rect.right  = _x + _width;
01406         rect.bottom = _y + _height;
01407     }
01408 
01409     return rect;
01410 }
01411 
01412 bool IMDDecoder::renderFrame(Common::Rect &rect) {
01413     if (!rect.isValidRect())
01414         // Invalid rendering area
01415         return false;
01416 
01417     // Clip the rendering area to the video's visible area
01418     rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height));
01419     if (!rect.isValidRect() || rect.isEmpty())
01420         // Result is empty => nothing to do
01421         return false;
01422 
01423     byte  *dataPtr  = _videoBuffer[0];
01424     uint32 dataSize = _videoBufferLen[0] - 1;
01425 
01426     uint8 type = *dataPtr++;
01427 
01428     if (type & 0x10) {
01429         // Palette data
01430 
01431         // One byte index
01432         int index = *dataPtr++;
01433 
01434         int count = MIN((255 - index) * 3, 48);
01435         for (int i = 0; i < count; i++)
01436             _palette[index * 3 + i] = dataPtr[i] << 2;
01437 
01438         dataPtr  += 48;
01439         dataSize -= 49;
01440         type ^= 0x10;
01441 
01442         _paletteDirty = true;
01443     }
01444 
01445     if (type & 0x80) {
01446         // Frame data is compressed
01447 
01448         type &= 0x7F;
01449 
01450         if ((type == 2) && (rect.width() == _surface.w) && (_x == 0)) {
01451             // Directly uncompress onto the video surface
01452             const int offsetX = rect.left * _surface.format.bytesPerPixel;
01453             const int offsetY = (_y + rect.top) * _surface.pitch;
01454             const int offset  = offsetX + offsetY;
01455 
01456             if (deLZ77((byte *)_surface.getPixels() + offset, dataPtr, dataSize,
01457                        _surface.w * _surface.h * _surface.format.bytesPerPixel - offset))
01458                 return true;
01459         }
01460 
01461         _videoBufferLen[1] = deLZ77(_videoBuffer[1], dataPtr, dataSize, _videoBufferSize);
01462 
01463         dataPtr  = _videoBuffer[1];
01464         dataSize = _videoBufferLen[1];
01465     }
01466 
01467     // Evaluate the block type
01468     if      (type == 0x01)
01469         renderBlockSparse  (_surface, dataPtr, rect);
01470     else if (type == 0x02)
01471         renderBlockWhole   (_surface, dataPtr, rect);
01472     else if (type == 0x42)
01473         renderBlockWhole4X (_surface, dataPtr, rect);
01474     else if ((type & 0x0F) == 0x02)
01475         renderBlockWhole2Y (_surface, dataPtr, rect);
01476     else
01477         renderBlockSparse2Y(_surface, dataPtr, rect);
01478 
01479     return true;
01480 }
01481 
01482 void IMDDecoder::nextSoundSlice(bool hasNextCmd) {
01483     if (hasNextCmd || !_soundEnabled || !_audioStream) {
01484         // Skip sound
01485 
01486         _stream->skip(_soundSliceSize);
01487         return;
01488     }
01489 
01490     // Read, convert, queue
01491 
01492     byte *soundBuf = (byte *)malloc(_soundSliceSize);
01493 
01494     _stream->read(soundBuf, _soundSliceSize);
01495     unsignedToSigned(soundBuf, _soundSliceSize);
01496 
01497     _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0);
01498 }
01499 
01500 bool IMDDecoder::initialSoundSlice(bool hasNextCmd) {
01501     int dataLength = _soundSliceSize * _soundSlicesCount;
01502 
01503     if (hasNextCmd || !_soundEnabled) {
01504         // Skip sound
01505 
01506         _stream->skip(dataLength);
01507         return false;
01508     }
01509 
01510     if (!_audioStream || (_soundStage == kSoundFinished)) {
01511         delete _audioStream;
01512 
01513         _audioStream = Audio::makeQueuingAudioStream(_soundFreq, false);
01514         _soundStage  = kSoundLoaded;
01515     }
01516 
01517     // Read, convert, queue
01518 
01519     byte *soundBuf = (byte *)malloc(dataLength);
01520 
01521     _stream->read(soundBuf, dataLength);
01522     unsignedToSigned(soundBuf, dataLength);
01523 
01524     _audioStream->queueBuffer(soundBuf, dataLength, DisposeAfterUse::YES, 0);
01525 
01526     return _soundStage == kSoundLoaded;
01527 }
01528 
01529 void IMDDecoder::emptySoundSlice(bool hasNextCmd) {
01530     if (hasNextCmd || !_soundEnabled || !_audioStream)
01531         return;
01532 
01533     // Create an empty sound buffer and queue it
01534 
01535     byte *soundBuf = (byte *)malloc(_soundSliceSize);
01536 
01537     memset(soundBuf, 0, _soundSliceSize);
01538 
01539     _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0);
01540 }
01541 
01542 Graphics::PixelFormat IMDDecoder::getPixelFormat() const {
01543     return Graphics::PixelFormat::createFormatCLUT8();
01544 }
01545 
01546 class DPCMStream : public Audio::AudioStream {
01547 public:
01548     DPCMStream(Common::SeekableReadStream *stream, int rate, int channels, bool oldStereo) {
01549         _stream = stream;
01550         _rate = rate;
01551         _channels = channels;
01552         _oldStereo = oldStereo;
01553         if (oldStereo) {
01554             _buffer[0] = _buffer[1] = 0;
01555         }
01556     }
01557 
01558     ~DPCMStream() {
01559         delete _stream;
01560     }
01561 
01562     int readBuffer(int16 *buffer, const int numSamples);
01563     bool isStereo() const { return _channels == 2; }
01564     int getRate() const { return _rate; }
01565     bool endOfData() const { return _stream->pos() >= _stream->size() || _stream->eos() || _stream->err(); }
01566 
01567 private:
01568     Common::SeekableReadStream *_stream;
01569     int _channels;
01570     int _rate;
01571     int _buffer[2];
01572     bool _oldStereo;
01573 };
01574 
01575 int DPCMStream::readBuffer(int16 *buffer, const int numSamples) {
01576     static const uint16 tableDPCM[128] = {
01577         0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
01578         0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
01579         0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
01580         0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
01581         0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
01582         0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
01583         0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
01584         0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
01585         0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
01586         0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
01587         0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
01588         0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
01589         0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
01590     };
01591 
01592     assert((numSamples % _channels) == 0);
01593 
01594     int samples = 0;
01595 
01596     // Our starting position
01597     if (!_oldStereo && _stream->pos() == 0) {
01598         for (int i = 0; i < _channels; i++)
01599             *buffer++ = _buffer[i] = _stream->readSint16LE();
01600 
01601         samples += _channels;
01602     }
01603 
01604     while (!endOfData() && samples < numSamples) {
01605         if (_channels == 2 && _stream->size() == 1) {
01606             warning("Buffer underrun in DPCMStream");
01607             break;
01608         }
01609 
01610         for (int i = 0; i < _channels; i++) {
01611             byte data = _stream->readByte();
01612 
01613             if (data & 0x80)
01614                 _buffer[i] -= tableDPCM[data & 0x7f];
01615             else
01616                 _buffer[i] += tableDPCM[data];
01617 
01618             // Emulating x86 16-bit signed register overflow
01619             if (_buffer[i] > 32767) {
01620                 _buffer[i] -= 65536;
01621             } else if (_buffer[i] < -32768) {
01622                 _buffer[i] += 65536;
01623             }
01624 
01625             *buffer++ = _buffer[i];
01626         }
01627 
01628         samples += _channels;
01629     }
01630 
01631     return samples;
01632 }
01633 
01634 VMDDecoder::File::File() {
01635     offset   = 0;
01636     size     = 0;
01637     realSize = 0;
01638 }
01639 
01640 
01641 VMDDecoder::Part::Part() {
01642     type    = kPartTypeSeparator;
01643     field_1 = 0;
01644     field_E = 0;
01645     size    = 0;
01646     left    = 0;
01647     top     = 0;
01648     right   = 0;
01649     bottom  = 0;
01650     id      = 0;
01651     flags   = 0;
01652 }
01653 
01654 
01655 VMDDecoder::Frame::Frame() {
01656     parts  = 0;
01657     offset = 0;
01658 }
01659 
01660 VMDDecoder::Frame::~Frame() {
01661     delete[] parts;
01662 }
01663 
01664 VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
01665     _stream(0), _version(0), _flags(0), _frameInfoOffset(0), _partsPerFrame(0), _frames(0),
01666     _soundFlags(0), _soundFreq(0), _soundSliceSize(0), _soundSlicesCount(0),
01667     _soundBytesPerSample(0), _soundStereo(0), _soundHeaderSize(0), _soundDataSize(0),
01668     _soundLastFilledFrame(0), _audioFormat(kAudioFormat8bitRaw),
01669     _hasVideo(false), _videoCodec(0), _blitMode(0), _bytesPerPixel(0),
01670     _firstFramePos(0), _videoBufferSize(0), _externalCodec(false), _codec(0),
01671     _subtitle(-1), _isPaletted(true), _autoStartSound(true), _oldStereoBuffer(nullptr) {
01672 
01673     _videoBuffer   [0] = 0;
01674     _videoBuffer   [1] = 0;
01675     _videoBuffer   [2] = 0;
01676     _videoBufferLen[0] = 0;
01677     _videoBufferLen[1] = 0;
01678     _videoBufferLen[2] = 0;
01679 }
01680 
01681 VMDDecoder::~VMDDecoder() {
01682     close();
01683 }
01684 
01685 bool VMDDecoder::reloadStream(Common::SeekableReadStream *stream) {
01686     if (!_stream)
01687         return false;
01688 
01689     if (!stream->seek(_stream->pos())) {
01690         close();
01691         return false;
01692     }
01693 
01694     delete _stream;
01695     _stream = stream;
01696 
01697     return true;
01698 }
01699 
01700 bool VMDDecoder::seek(int32 frame, int whence, bool restart) {
01701     if (!evaluateSeekFrame(frame, whence))
01702         return false;
01703 
01704     if (frame == _curFrame)
01705         // Nothing to do
01706         return true;
01707 
01708     // Restart sound
01709     if (_hasSound && (frame == -1) &&
01710             ((_soundStage == kSoundNone) || (_soundStage == kSoundFinished))) {
01711 
01712         delete _audioStream;
01713 
01714         _soundStage  = kSoundLoaded;
01715         createAudioStream();
01716     }
01717 
01718     _subtitle = -1;
01719 
01720     if ((_blitMode > 0) && (_flags & 0x4000)) {
01721         if (_curFrame > frame) {
01722             _stream->seek(_frames[0].offset);
01723             _curFrame = -1;
01724         }
01725 
01726         while (frame > _curFrame)
01727             decodeNextFrame();
01728 
01729         return true;
01730     }
01731 
01732     // Seek
01733     _stream->seek(_frames[frame + 1].offset);
01734     _curFrame = frame;
01735     _startTime = g_system->getMillis() - ((frame + 2) * getStaticTimeToNextFrame());
01736 
01737 
01738     return true;
01739 }
01740 
01741 void VMDDecoder::setXY(uint16 x, uint16 y) {
01742     uint16 curX = _x;
01743     uint16 setX =  x;
01744 
01745     if ((x != 0xFFFF) && (_blitMode == 1)) {
01746         curX *= _bytesPerPixel;
01747         setX *= _bytesPerPixel;
01748     }
01749 
01750     for (uint32 i = 0; i < _frameCount; i++) {
01751         for (int j = 0; j < _partsPerFrame; j++) {
01752 
01753             if (_frames[i].parts[j].type == kPartTypeVideo) {
01754                 if (x != 0xFFFF) {
01755                     _frames[i].parts[j].left  = _frames[i].parts[j].left  - curX + setX;
01756                     _frames[i].parts[j].right = _frames[i].parts[j].right - curX + setX;
01757                 }
01758                 if (y != 0xFFFF) {
01759                     _frames[i].parts[j].top    = _frames[i].parts[j].top    - _y + y;
01760                     _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y;
01761                 }
01762             }
01763 
01764         }
01765     }
01766 
01767     if (x != 0xFFFF)
01768         _x = x;
01769     if (y != 0xFFFF)
01770         _y = y;
01771 }
01772 
01773 bool VMDDecoder::openExternalCodec() {
01774     delete _codec;
01775     _codec = 0;
01776 
01777     if (_externalCodec) {
01778         if (_videoCodec == kVideoCodecIndeo3) {
01779             _isPaletted = false;
01780 
01781             _codec = new Image::Indeo3Decoder(_width, _height, g_system->getScreenFormat().bpp());
01782 
01783         } else {
01784             warning("VMDDecoder::openExternalCodec(): Unknown video codec FourCC \"%s\"",
01785                     tag2str(_videoCodec));
01786             return false;
01787         }
01788     }
01789 
01790     return true;
01791 }
01792 
01793 void VMDDecoder::colorModeChanged() {
01794     openExternalCodec();
01795 }
01796 
01797 bool VMDDecoder::loadStream(Common::SeekableReadStream *stream) {
01798     close();
01799 
01800     _stream = stream;
01801 
01802     _stream->seek(0);
01803 
01804     uint16 headerLength;
01805     uint16 handle;
01806 
01807     headerLength = _stream->readUint16LE();
01808     handle       = _stream->readUint16LE();
01809     _version     = _stream->readUint16LE();
01810 
01811     // Version checking
01812     if (headerLength == 50) {
01813         // Newer version, used in Addy 5 upwards
01814         warning("VMDDecoder::loadStream(): TODO: Addy 5 videos");
01815     } else if (headerLength == 814) {
01816         // Old version
01817         _features |= kFeaturesPalette;
01818     } else {
01819         warning("VMDDecoder::loadStream(): Version incorrect (%d, %d, %d)", headerLength, handle, _version);
01820         close();
01821         return false;
01822     }
01823 
01824     _frameCount = _stream->readUint16LE();
01825 
01826     _defaultX = _stream->readSint16LE();
01827     _defaultY = _stream->readSint16LE();
01828     _width    = _stream->readSint16LE();
01829     _height   = _stream->readSint16LE();
01830 
01831     _x = _defaultX;
01832     _y = _defaultY;
01833 
01834     if ((_width != 0) && (_height != 0)) {
01835 
01836         _hasVideo = true;
01837         _features |= kFeaturesVideo;
01838 
01839     } else
01840         _hasVideo = false;
01841 
01842     _bytesPerPixel = 1;
01843     if (_version & 4)
01844         _bytesPerPixel = handle + 1;
01845 
01846     if (_bytesPerPixel > 3) {
01847         warning("VMDDecoder::loadStream(): Requested %d bytes per pixel (%d, %d, %d)",
01848                 _bytesPerPixel, headerLength, handle, _version);
01849         close();
01850         return false;
01851     }
01852 
01853     _flags = _stream->readUint16LE();
01854 
01855     _partsPerFrame = _stream->readUint16LE();
01856     _firstFramePos = _stream->readUint32LE();
01857 
01858     _videoCodec = _stream->readUint32BE();
01859 
01860     if (_features & kFeaturesPalette) {
01861         for (int i = 0; i < 768; i++)
01862             _palette[i] = _stream->readByte() << 2;
01863 
01864         _paletteDirty = true;
01865     }
01866 
01867     uint32 videoBufferSize1 = _stream->readUint32LE();
01868     uint32 videoBufferSize2 = _stream->readUint32LE();
01869 
01870     _videoBufferSize = MAX(videoBufferSize1, videoBufferSize2);
01871 
01872     if (_hasVideo) {
01873         if (!assessVideoProperties()) {
01874             close();
01875             return false;
01876         }
01877     }
01878 
01879     _soundFreq        = _stream->readSint16LE();
01880     _soundSliceSize   = _stream->readSint16LE();
01881     _soundSlicesCount = _stream->readSint16LE();
01882     _soundFlags       = _stream->readUint16LE();
01883 
01884     _hasSound = (_soundFreq != 0);
01885 
01886     if (_hasSound) {
01887         if (!assessAudioProperties()) {
01888             close();
01889             return false;
01890         }
01891     } else
01892         _frameRate = 12;
01893 
01894     _frameInfoOffset = _stream->readUint32LE();
01895 
01896     int numFiles;
01897     if (!readFrameTable(numFiles)) {
01898         close();
01899         return false;
01900     }
01901 
01902     _stream->seek(_firstFramePos);
01903 
01904     if (numFiles == 0)
01905         return true;
01906 
01907     _files.reserve(numFiles);
01908     if (!readFiles()) {
01909         close();
01910         return false;
01911     }
01912 
01913     _stream->seek(_firstFramePos);
01914     return true;
01915 }
01916 
01917 bool VMDDecoder::assessVideoProperties() {
01918     _isPaletted = true;
01919 
01920     if ((_version & 2) && !(_version & 8)) {
01921         _externalCodec   = true;
01922         _videoBufferSize = 0;
01923     } else
01924         _externalCodec = false;
01925 
01926     if (!openExternalCodec())
01927         return false;
01928 
01929     if (_externalCodec)
01930         _blitMode = 0;
01931     else if (_bytesPerPixel == 1)
01932         _blitMode = 0;
01933     else if ((_bytesPerPixel == 2) || (_bytesPerPixel == 3)) {
01934         int n = (_flags & 0x80) ? 2 : 3;
01935 
01936         _blitMode      = _bytesPerPixel - 1;
01937         _bytesPerPixel = n;
01938 
01939         _isPaletted = false;
01940     }
01941 
01942     if (_blitMode == 1) {
01943         _width    /= _bytesPerPixel;
01944         _defaultX /= _bytesPerPixel;
01945         _x        /= _bytesPerPixel;
01946     }
01947 
01948     if (_hasVideo) {
01949         uint32 suggestedVideoBufferSize = _videoBufferSize;
01950 
01951         _videoBufferSize = _width * _height * _bytesPerPixel + 1000;
01952 
01953         if ((suggestedVideoBufferSize > _videoBufferSize) && (suggestedVideoBufferSize < 2097152)) {
01954             warning("Suggested video buffer size greater than what should be needed (%d, %d, %dx%d",
01955                 suggestedVideoBufferSize, _videoBufferSize, _width, _height);
01956 
01957             _videoBufferSize = suggestedVideoBufferSize;
01958         }
01959 
01960         for (int i = 0; i < 3; i++) {
01961             _videoBuffer[i] = new byte[_videoBufferSize];
01962             memset(_videoBuffer[i], 0, _videoBufferSize);
01963 
01964             _8bppSurface[i].init(_width * _bytesPerPixel, _height, _width * _bytesPerPixel,
01965                                  _videoBuffer[i], Graphics::PixelFormat::createFormatCLUT8());
01966         }
01967     }
01968 
01969     return true;
01970 }
01971 
01972 bool VMDDecoder::assessAudioProperties() {
01973     bool supportedFormat = true;
01974 
01975     _features |= kFeaturesSound;
01976 
01977     _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0);
01978 
01979     if (_soundSliceSize < 0) {
01980         _soundBytesPerSample = 2;
01981         _soundSliceSize      = -_soundSliceSize;
01982 
01983         if (_soundFlags & 0x10) {
01984             _audioFormat     = kAudioFormat16bitADPCM;
01985             _soundHeaderSize = 3;
01986             _soundDataSize   = _soundSliceSize >> 1;
01987 
01988             if (_soundStereo > 0)
01989                 supportedFormat = false;
01990 
01991         } else {
01992             _audioFormat     = kAudioFormat16bitDPCM;
01993             _soundHeaderSize = 1;
01994             _soundDataSize   = _soundSliceSize;
01995 
01996             if (_soundStereo == 1) {
01997                 supportedFormat = false;
01998             } else if (_soundStereo == 2) {
01999                 _soundDataSize = 2 * _soundDataSize + 2;
02000                 _soundHeaderSize = 4;
02001             }
02002 
02003         }
02004     } else {
02005         if (_soundStereo == 2) {
02006             supportedFormat = false;
02007         }
02008 
02009         _soundBytesPerSample = 1;
02010         _soundHeaderSize     = 0;
02011         _soundDataSize       = _soundSliceSize;
02012 
02013         if (_soundStereo == 1) {
02014             _audioFormat = kAudioFormat16bitDPCM;
02015         } else {
02016             _audioFormat = kAudioFormat8bitRaw;
02017         }
02018     }
02019 
02020     if (!supportedFormat) {
02021         warning("VMDDecoder::assessAudioProperties(): Unsupported audio format: %d bits, encoding %d, stereo %d",
02022                 _soundBytesPerSample * 8, _audioFormat, _soundStereo);
02023         return false;
02024     }
02025 
02026     _frameRate = Common::Rational(_soundFreq, _soundSliceSize / (_soundStereo == 1 ? 2 : 1));
02027 
02028     _hasSound     = true;
02029     _soundEnabled = true;
02030     _soundStage   = kSoundLoaded;
02031     createAudioStream();
02032     return true;
02033 }
02034 
02035 bool VMDDecoder::readFrameTable(int &numFiles) {
02036     numFiles = 0;
02037 
02038     _stream->seek(_frameInfoOffset);
02039     _frames = new Frame[_frameCount];
02040     for (uint16 i = 0; i < _frameCount; i++) {
02041         _frames[i].parts = new Part[_partsPerFrame];
02042         _stream->skip(2); // Unknown
02043         _frames[i].offset = _stream->readUint32LE();
02044     }
02045 
02046     _soundLastFilledFrame = 0;
02047     for (uint16 i = 0; i < _frameCount; i++) {
02048         bool separator = false;
02049 
02050         for (uint16 j = 0; j < _partsPerFrame; j++) {
02051 
02052             _frames[i].parts[j].type    = (PartType) _stream->readByte();
02053             _frames[i].parts[j].field_1 = _stream->readByte();
02054             _frames[i].parts[j].size    = _stream->readUint32LE();
02055 
02056             if (_frames[i].parts[j].type == kPartTypeAudio) {
02057 
02058                 _frames[i].parts[j].flags = _stream->readByte();
02059                 _stream->skip(9); // Unknown
02060 
02061                 if (_frames[i].parts[j].flags != 3)
02062                     _soundLastFilledFrame = i;
02063 
02064             } else if (_frames[i].parts[j].type == kPartTypeVideo) {
02065 
02066                 _frames[i].parts[j].left    = _stream->readUint16LE();
02067                 _frames[i].parts[j].top     = _stream->readUint16LE();
02068                 _frames[i].parts[j].right   = _stream->readUint16LE();
02069                 _frames[i].parts[j].bottom  = _stream->readUint16LE();
02070                 _frames[i].parts[j].field_E = _stream->readByte();
02071                 _frames[i].parts[j].flags   = _stream->readByte();
02072 
02073             } else if (_frames[i].parts[j].type == kPartTypeSubtitle) {
02074                 _frames[i].parts[j].id = _stream->readUint16LE();
02075                 // Speech text file name
02076                 _stream->skip(8);
02077             } else if (_frames[i].parts[j].type == kPartTypeFile) {
02078                 if (!separator)
02079                     numFiles++;
02080                 _stream->skip(10);
02081             } else if (_frames[i].parts[j].type == kPartTypeSeparator) {
02082                 separator = true;
02083                 _stream->skip(10);
02084             } else {
02085                 // Unknown type
02086                 _stream->skip(10);
02087             }
02088 
02089         }
02090     }
02091 
02092     return true;
02093 }
02094 
02095 bool VMDDecoder::readFiles() {
02096     uint32 ssize = _stream->size();
02097     for (uint16 i = 0; i < _frameCount; i++) {
02098         _stream->seek(_frames[i].offset);
02099 
02100         for (uint16 j = 0; j < _partsPerFrame; j++) {
02101             if (_frames[i].parts[j].type == kPartTypeSeparator)
02102                 break;
02103 
02104             if (_frames[i].parts[j].type == kPartTypeFile) {
02105                 File file;
02106 
02107                 file.offset   = _stream->pos() + 20;
02108                 file.size     = _frames[i].parts[j].size;
02109                 file.realSize = _stream->readUint32LE();
02110 
02111                 char name[16];
02112 
02113                 _stream->read(name, 16);
02114                 name[15] = '\0';
02115 
02116                 file.name = name;
02117 
02118                 _stream->skip(_frames[i].parts[j].size - 20);
02119 
02120                 if ((((uint32) file.realSize) >= ssize) || (file.name == ""))
02121                     continue;
02122 
02123                 _files.push_back(file);
02124 
02125             } else
02126                 _stream->skip(_frames[i].parts[j].size);
02127         }
02128     }
02129 
02130     return true;
02131 }
02132 
02133 void VMDDecoder::close() {
02134     CoktelDecoder::close();
02135 
02136     delete _stream;
02137 
02138     delete[] _frames;
02139 
02140     delete[] _videoBuffer[0];
02141     delete[] _videoBuffer[1];
02142     delete[] _videoBuffer[2];
02143 
02144     delete _codec;
02145 
02146     _files.clear();
02147 
02148 
02149     _stream = 0;
02150 
02151     _version = 0;
02152     _flags   = 0;
02153 
02154     _frameInfoOffset = 0;
02155     _partsPerFrame   = 0;
02156     _frames          = 0;
02157 
02158     _soundFlags           = 0;
02159     _soundFreq            = 0;
02160     _soundSliceSize       = 0;
02161     _soundSlicesCount     = 0;
02162     _soundBytesPerSample  = 0;
02163     _soundStereo          = 0;
02164     _soundHeaderSize      = 0;
02165     _soundDataSize        = 0;
02166     _soundLastFilledFrame = 0;
02167     _audioFormat          = kAudioFormat8bitRaw;
02168     _oldStereoBuffer      = nullptr;
02169 
02170     _hasVideo      = false;
02171     _videoCodec    = 0;
02172     _blitMode      = 0;
02173     _bytesPerPixel = 0;
02174 
02175     _firstFramePos = 0;
02176 
02177     _videoBufferSize   = 0;
02178     _videoBuffer   [0] = 0;
02179     _videoBuffer   [1] = 0;
02180     _videoBuffer   [2] = 0;
02181     _videoBufferLen[0] = 0;
02182     _videoBufferLen[1] = 0;
02183     _videoBufferLen[2] = 0;
02184 
02185     _externalCodec = false;
02186     _codec         = 0;
02187 
02188     _isPaletted = true;
02189 }
02190 
02191 bool VMDDecoder::isVideoLoaded() const {
02192     return _stream != 0;
02193 }
02194 
02195 const Graphics::Surface *VMDDecoder::decodeNextFrame() {
02196     if (!isVideoLoaded() || endOfVideo())
02197         return 0;
02198 
02199     createSurface();
02200 
02201     processFrame();
02202 
02203     if (_curFrame == 0)
02204         _startTime = g_system->getMillis();
02205 
02206     return &_surface;
02207 }
02208 
02209 void VMDDecoder::processFrame() {
02210     _curFrame++;
02211 
02212     _dirtyRects.clear();
02213 
02214     _subtitle     = -1;
02215 
02216     bool startSound = false;
02217 
02218     _stream->seek(_frames[_curFrame].offset, SEEK_SET);
02219 
02220     for (uint16 i = 0; i < _partsPerFrame; i++) {
02221         Part &part = _frames[_curFrame].parts[i];
02222 
02223         if (part.type == kPartTypeAudio) {
02224 
02225             if (part.flags == 1) {
02226                 // Next sound slice data
02227 
02228                 if (_soundEnabled) {
02229                     filledSoundSlice(part.size);
02230 
02231                     if (_soundStage == kSoundLoaded)
02232                         startSound = true;
02233 
02234                 } else
02235                     _stream->skip(part.size);
02236 
02237             } else if (part.flags == 2) {
02238                 // Initial sound data (all slices)
02239 
02240                 if (_soundEnabled) {
02241                     uint32 mask = _stream->readUint32LE();
02242                     filledSoundSlices(part.size - /* mask size */ 4, mask);
02243 
02244                     if (_soundStage == kSoundLoaded)
02245                         startSound = true;
02246 
02247                 } else
02248                     _stream->skip(part.size);
02249 
02250             } else if (part.flags == 3) {
02251                 // Empty sound slice
02252 
02253                 if (_soundEnabled) {
02254                     if ((uint32)_curFrame < _soundLastFilledFrame)
02255                         emptySoundSlice(_soundDataSize * _soundBytesPerSample);
02256 
02257                     if (_soundStage == kSoundLoaded)
02258                         startSound = true;
02259                 }
02260 
02261                 _stream->skip(part.size);
02262             } else if (part.flags == 4) {
02263                 warning("VMDDecoder::processFrame(): TODO: Addy 5 sound type 4 (%d)", part.size);
02264                 disableSound();
02265                 _stream->skip(part.size);
02266             } else {
02267                 warning("VMDDecoder::processFrame(): Unknown sound type %d", part.flags);
02268                 _stream->skip(part.size);
02269             }
02270 
02271         } else if ((part.type == kPartTypeVideo) && !_hasVideo) {
02272 
02273             warning("VMDDecoder::processFrame(): Header claims there's no video, but video found (%d)", part.size);
02274             _stream->skip(part.size);
02275 
02276         } else if ((part.type == kPartTypeVideo) && _hasVideo) {
02277 
02278             uint32 size = part.size;
02279 
02280             // New palette
02281             if (part.flags & 2) {
02282                 uint8 index = _stream->readByte();
02283                 uint8 count = _stream->readByte();
02284 
02285                 for (int j = 0; j < ((count + 1) * 3); j++)
02286                     _palette[index * 3 + j] = _stream->readByte() << 2;
02287 
02288                 _stream->skip((255 - count) * 3);
02289 
02290                 _paletteDirty = true;
02291 
02292                 size -= (768 + 2);
02293             }
02294 
02295             _stream->read(_videoBuffer[0], size);
02296             _videoBufferLen[0] = size;
02297 
02298             Common::Rect rect(part.left, part.top, part.right + 1, part.bottom + 1);
02299             if (renderFrame(rect))
02300                 _dirtyRects.push_back(rect);
02301 
02302         } else if (part.type == kPartTypeSeparator) {
02303 
02304             // Ignore
02305 
02306         } else if (part.type == kPartTypeFile) {
02307 
02308             // Ignore
02309             _stream->skip(part.size);
02310 
02311         } else if (part.type == kPartType4) {
02312 
02313             // Unknown, ignore
02314             _stream->skip(part.size);
02315 
02316         } else if (part.type == kPartTypeSubtitle) {
02317 
02318             _subtitle = part.id;
02319             _stream->skip(part.size);
02320 
02321         } else {
02322 
02323             warning("VMDDecoder::processFrame(): Unknown frame part type %d, size %d (%d of %d)",
02324                     part.type, part.size, i + 1, _partsPerFrame);
02325 
02326         }
02327     }
02328 
02329     if (startSound && _soundEnabled) {
02330         if (_hasSound && _audioStream) {
02331             if (_autoStartSound)
02332                 _mixer->playStream(_soundType, &_audioHandle, _audioStream,
02333                         -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
02334             _soundStage = kSoundPlaying;
02335         } else
02336             _soundStage = kSoundNone;
02337     }
02338 
02339     if (((uint32)_curFrame == (_frameCount - 1)) && (_soundStage == 2)) {
02340         _audioStream->finish();
02341         _soundStage = kSoundFinished;
02342     }
02343 }
02344 
02345 bool VMDDecoder::renderFrame(Common::Rect &rect) {
02346     Common::Rect realRect, fakeRect;
02347     if (!getRenderRects(rect, realRect, fakeRect))
02348         return false;
02349 
02350     if (_externalCodec) {
02351         if (!_codec)
02352             return false;
02353 
02354         Common::MemoryReadStream frameStream(_videoBuffer[0], _videoBufferLen[0]);
02355         const Graphics::Surface *codecSurf = _codec->decodeFrame(frameStream);
02356         if (!codecSurf)
02357             return false;
02358 
02359         rect = Common::Rect(_x, _y, _x + codecSurf->w, _y + codecSurf->h);
02360         rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height));
02361 
02362         renderBlockWhole(_surface, (const byte *)codecSurf->getPixels(), rect);
02363         return true;
02364     }
02365 
02366     uint8  srcBuffer = 0;
02367     byte  *dataPtr   = _videoBuffer[srcBuffer];
02368     uint32 dataSize  = _videoBufferLen[srcBuffer] - 1;
02369 
02370     uint8 type = *dataPtr++;
02371 
02372     if (type & 0x80) {
02373         // Frame data is compressed
02374 
02375         type &= 0x7F;
02376 
02377         if ((type == 2) && (rect.width() == _surface.w) && (_x == 0) && (_blitMode == 0)) {
02378             // Directly uncompress onto the video surface
02379             const int offsetX = rect.left * _surface.format.bytesPerPixel;
02380             const int offsetY = (_y + rect.top) * _surface.pitch;
02381             const int offset  = offsetX + offsetY;
02382 
02383             if (deLZ77((byte *)_surface.getPixels() + offset, dataPtr, dataSize,
02384                        _surface.w * _surface.h * _surface.format.bytesPerPixel - offset))
02385                 return true;
02386         }
02387 
02388         srcBuffer = 1;
02389         _videoBufferLen[srcBuffer] =
02390             deLZ77(_videoBuffer[srcBuffer], dataPtr, dataSize, _videoBufferSize);
02391 
02392         dataPtr  = _videoBuffer[srcBuffer];
02393         dataSize = _videoBufferLen[srcBuffer];
02394     }
02395 
02396     Common::Rect      *blockRect = &fakeRect;
02397     Graphics::Surface *surface   = &_surface;
02398     if (_blitMode == 0) {
02399         *blockRect = Common::Rect(blockRect->left  + _x, blockRect->top    + _y,
02400                                   blockRect->right + _x, blockRect->bottom + _y);
02401     } else {
02402         surface = &_8bppSurface[2];
02403     }
02404 
02405     // Evaluate the block type
02406     if      (type == 0x01)
02407         renderBlockSparse  (*surface, dataPtr, *blockRect);
02408     else if (type == 0x02)
02409         renderBlockWhole   (*surface, dataPtr, *blockRect);
02410     else if (type == 0x03)
02411         renderBlockRLE     (*surface, dataPtr, *blockRect);
02412     else if (type == 0x42)
02413         renderBlockWhole4X (*surface, dataPtr, *blockRect);
02414     else if ((type & 0x0F) == 0x02)
02415         renderBlockWhole2Y (*surface, dataPtr, *blockRect);
02416     else
02417         renderBlockSparse2Y(*surface, dataPtr, *blockRect);
02418 
02419     if (_blitMode > 0) {
02420         if      (_bytesPerPixel == 2)
02421             blit16(*surface, *blockRect);
02422         else if (_bytesPerPixel == 3)
02423             blit24(*surface, *blockRect);
02424 
02425         *blockRect = Common::Rect(blockRect->left  + _x, blockRect->top    + _y,
02426                                   blockRect->right + _x, blockRect->bottom + _y);
02427     }
02428 
02429     rect = *blockRect;
02430     return true;
02431 }
02432 
02433 bool VMDDecoder::getRenderRects(const Common::Rect &rect,
02434         Common::Rect &realRect, Common::Rect &fakeRect) {
02435 
02436     realRect = rect;
02437     fakeRect = rect;
02438 
02439     if        (_blitMode == 0) {
02440 
02441         realRect = Common::Rect(realRect.left  - _x, realRect.top    - _y,
02442                                 realRect.right - _x, realRect.bottom - _y);
02443 
02444         fakeRect = Common::Rect(fakeRect.left  - _x, fakeRect.top    - _y,
02445                                 fakeRect.right - _x, fakeRect.bottom - _y);
02446 
02447     } else if (_blitMode == 1) {
02448 
02449         realRect = Common::Rect(rect.left  / _bytesPerPixel, rect.top,
02450                                 rect.right / _bytesPerPixel, rect.bottom);
02451 
02452         realRect = Common::Rect(realRect.left  - _x, realRect.top    - _y,
02453                                 realRect.right - _x, realRect.bottom - _y);
02454 
02455         fakeRect = Common::Rect(fakeRect.left  - _x * _bytesPerPixel, fakeRect.top    - _y,
02456                                 fakeRect.right - _x * _bytesPerPixel, fakeRect.bottom - _y);
02457 
02458     } else if (_blitMode == 2) {
02459 
02460         fakeRect = Common::Rect(rect.left  * _bytesPerPixel, rect.top,
02461                                 rect.right * _bytesPerPixel, rect.bottom);
02462 
02463         realRect = Common::Rect(realRect.left  - _x, realRect.top    - _y,
02464                                 realRect.right - _x, realRect.bottom - _y);
02465 
02466         fakeRect = Common::Rect(fakeRect.left  - _x * _bytesPerPixel, fakeRect.top    - _y,
02467                                 fakeRect.right - _x * _bytesPerPixel, fakeRect.bottom - _y);
02468 
02469     }
02470 
02471     realRect.clip(Common::Rect(_surface.w, _surface.h));
02472     fakeRect.clip(Common::Rect(_surface.w * _bytesPerPixel, _surface.h));
02473 
02474     if (!realRect.isValidRect() || realRect.isEmpty())
02475         return false;
02476     if (!fakeRect.isValidRect() || realRect.isEmpty())
02477         return false;
02478 
02479     return true;
02480 }
02481 
02482 void VMDDecoder::blit16(const Graphics::Surface &srcSurf, Common::Rect &rect) {
02483     rect = Common::Rect(rect.left / 2, rect.top, rect.right / 2, rect.bottom);
02484 
02485     Common::Rect srcRect = rect;
02486 
02487     rect.clip(_surface.w, _surface.h);
02488 
02489     Graphics::PixelFormat pixelFormat = getPixelFormat();
02490 
02491     // We cannot use getBasePtr here because srcSurf.format.bytesPerPixel is
02492     // different from _bytesPerPixel.
02493     const byte *src = (const byte *)srcSurf.getPixels() +
02494         (srcRect.top * srcSurf.pitch) + srcRect.left * _bytesPerPixel;
02495     byte *dst = (byte *)_surface.getBasePtr(_x + rect.left, _y + rect.top);
02496 
02497     for (int i = 0; i < rect.height(); i++) {
02498         const byte *srcRow = src;
02499               byte *dstRow = dst;
02500 
02501         for (int j = 0; j < rect.width(); j++, srcRow += 2, dstRow += _surface.format.bytesPerPixel) {
02502             uint16 data = READ_LE_UINT16(srcRow);
02503 
02504             byte r = ((data & 0x7C00) >> 10) << 3;
02505             byte g = ((data & 0x03E0) >>  5) << 3;
02506             byte b = ((data & 0x001F) >>  0) << 3;
02507 
02508             uint32 c = pixelFormat.RGBToColor(r, g, b);
02509             if ((r == 0) && (g == 0) && (b == 0))
02510                 c = 0;
02511 
02512             if      (_surface.format.bytesPerPixel == 2)
02513                 *((uint16 *)dstRow) = (uint16) c;
02514             else if (_surface.format.bytesPerPixel == 4)
02515                 *((uint32 *)dstRow) = (uint32) c;
02516         }
02517 
02518         src += srcSurf .pitch;
02519         dst += _surface.pitch;
02520     }
02521 }
02522 
02523 void VMDDecoder::blit24(const Graphics::Surface &srcSurf, Common::Rect &rect) {
02524     rect = Common::Rect(rect.left / 3, rect.top, rect.right / 3, rect.bottom);
02525 
02526     Common::Rect srcRect = rect;
02527 
02528     rect.clip(_surface.w, _surface.h);
02529 
02530     Graphics::PixelFormat pixelFormat = getPixelFormat();
02531 
02532     // We cannot use getBasePtr here because srcSurf.format.bytesPerPixel is
02533     // different from _bytesPerPixel.
02534     const byte *src = (const byte *)srcSurf.getPixels() +
02535         (srcRect.top * srcSurf.pitch) + srcRect.left * _bytesPerPixel;
02536     byte *dst = (byte *)_surface.getBasePtr(_x + rect.left, _y + rect.top);
02537 
02538     for (int i = 0; i < rect.height(); i++) {
02539         const byte *srcRow = src;
02540               byte *dstRow = dst;
02541 
02542         for (int j = 0; j < rect.width(); j++, srcRow += 3, dstRow += _surface.format.bytesPerPixel) {
02543             byte r = srcRow[2];
02544             byte g = srcRow[1];
02545             byte b = srcRow[0];
02546 
02547             uint32 c = pixelFormat.RGBToColor(r, g, b);
02548             if ((r == 0) && (g == 0) && (b == 0))
02549                 c = 0;
02550 
02551             if      (_surface.format.bytesPerPixel == 2)
02552                 *((uint16 *)dstRow) = (uint16) c;
02553             else if (_surface.format.bytesPerPixel == 4)
02554                 *((uint32 *)dstRow) = (uint32) c;
02555         }
02556 
02557         src += srcSurf .pitch;
02558         dst += _surface.pitch;
02559     }
02560 }
02561 
02562 void VMDDecoder::emptySoundSlice(uint32 size) {
02563     if (_soundStereo == 1) {
02564         // Technically an empty slice could be used at the very beginning of the
02565         // stream, but anywhere else it would need to dynamically calculate the
02566         // delta between the current sample and zero sample level and the steps
02567         // to get a zero level
02568         error("Old-style stereo cannot be filled with an empty slice");
02569     }
02570 
02571     byte *soundBuf = (byte *)malloc(size);
02572 
02573     if (soundBuf) {
02574         uint32 flags = 0;
02575         memset(soundBuf, 0, size);
02576         flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;
02577         flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0;
02578 
02579         _audioStream->queueBuffer(soundBuf, size, DisposeAfterUse::YES, flags);
02580     }
02581 }
02582 
02583 void VMDDecoder::filledSoundSlice(uint32 size) {
02584     if (!_audioStream) {
02585         _stream->skip(size);
02586         return;
02587     }
02588 
02589     if (_soundStereo == 1) {
02590         void *buf = malloc(size);
02591         assert(buf);
02592         const uint32 numBytesRead = _stream->read(buf, size);
02593         assert(numBytesRead == size);
02594         const uint32 numBytesWritten = _oldStereoBuffer->write(buf, size);
02595         assert(numBytesWritten == size);
02596         free(buf);
02597         return;
02598     }
02599 
02600     Common::SeekableReadStream *data = _stream->readStream(size);
02601     Audio::AudioStream *sliceStream = 0;
02602 
02603     if (_audioFormat == kAudioFormat8bitRaw)
02604         sliceStream = create8bitRaw(data);
02605     else if (_audioFormat == kAudioFormat16bitDPCM)
02606         sliceStream = create16bitDPCM(data);
02607     else if (_audioFormat == kAudioFormat16bitADPCM)
02608         sliceStream = create16bitADPCM(data);
02609 
02610     if (sliceStream)
02611         _audioStream->queueAudioStream(sliceStream);
02612 }
02613 
02614 void VMDDecoder::filledSoundSlices(uint32 size, uint32 mask) {
02615     bool fillInfo[32];
02616 
02617     uint8 max;
02618     uint8 n = evaluateMask(mask, fillInfo, max);
02619 
02620     // extraSize is needed by videos in some games (GK2) or audio data will be
02621     // incomplete
02622     int32 extraSize = size - n * _soundDataSize;
02623 
02624     if (_soundSlicesCount > 32)
02625         extraSize -= (_soundSlicesCount - 32) * _soundDataSize;
02626 
02627     if (n > 0)
02628         extraSize /= n;
02629 
02630     // extraSize cannot be negative or audio data will be incomplete in some
02631     // games (old-style stereo videos in Lighthouse)
02632     if (extraSize < 0)
02633         extraSize = 0;
02634 
02635     for (uint8 i = 0; i < max; i++)
02636         if (fillInfo[i])
02637             filledSoundSlice(_soundDataSize + extraSize);
02638         else
02639             emptySoundSlice(_soundDataSize * _soundBytesPerSample);
02640 
02641     if (_soundSlicesCount > 32)
02642         filledSoundSlice((_soundSlicesCount - 32) * _soundDataSize + _soundHeaderSize);
02643 }
02644 
02645 void VMDDecoder::createAudioStream() {
02646     _audioStream = Audio::makeQueuingAudioStream(_soundFreq, _soundStereo != 0);
02647     if (_soundStereo == 1) {
02648         _oldStereoBuffer = new Common::MemoryReadWriteStream(DisposeAfterUse::YES);
02649         _audioStream->queueAudioStream(new DPCMStream(_oldStereoBuffer, _soundFreq, 2, true));
02650     }
02651 }
02652 
02653 uint8 VMDDecoder::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) {
02654     max = MIN<int>(_soundSlicesCount - 1, 31);
02655 
02656     uint8 n = 0;
02657     for (int i = 0; i < max; i++) {
02658 
02659         if (!(mask & 1)) {
02660             n++;
02661             *fillInfo++ = true;
02662         } else
02663             *fillInfo++ = false;
02664 
02665         mask >>= 1;
02666     }
02667 
02668     return n;
02669 }
02670 
02671 Audio::AudioStream *VMDDecoder::create8bitRaw(Common::SeekableReadStream *stream) {
02672     int flags = Audio::FLAG_UNSIGNED;
02673 
02674     if (_soundStereo != 0)
02675         flags |= Audio::FLAG_STEREO;
02676 
02677     return Audio::makeRawStream(stream, _soundFreq, flags, DisposeAfterUse::YES);
02678 }
02679 
02680 Audio::AudioStream *VMDDecoder::create16bitDPCM(Common::SeekableReadStream *stream) {
02681     // Old-style stereo audio blocks are not self-contained so cannot be played
02682     // using this mechanism
02683     assert(_soundStereo != 1);
02684 
02685     return new DPCMStream(stream, _soundFreq, (_soundStereo == 0) ? 1 : 2, false);
02686 }
02687 
02688 class VMD_ADPCMStream : public Audio::DVI_ADPCMStream {
02689 public:
02690     VMD_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse,
02691             int rate, int channels) : Audio::DVI_ADPCMStream(stream, disposeAfterUse, stream->size(), rate, channels, 0) {
02692         // FIXME: Using the same predictor/index for two channels probably won't work
02693         // properly However, we have no samples of this, so an assert is here for now.
02694         // Also, since the DPCM stereo has a second predictor, I'm lead to believe
02695         // all VMD with ADPCM are mono unless they changed the code in a later
02696         // revision.
02697         assert(channels == 1);
02698         _startPredictorValue = stream->readSint16LE();
02699         _startIndexValue = stream->readByte();
02700         _startpos = 3;
02701         reset();
02702     }
02703 
02704 protected:
02705     virtual void reset() {
02706         Audio::DVI_ADPCMStream::reset();
02707         _status.ima_ch[0].last = _startPredictorValue;
02708         _status.ima_ch[0].stepIndex = _startIndexValue;
02709     }
02710 
02711 private:
02712     int32 _startPredictorValue;
02713     int32 _startIndexValue;
02714 };
02715 
02716 Audio::AudioStream *VMDDecoder::create16bitADPCM(Common::SeekableReadStream *stream) {
02717     return new VMD_ADPCMStream(stream, DisposeAfterUse::YES, _soundFreq, (_soundStereo == 0) ? 1 : 2);
02718 }
02719 
02720 Graphics::PixelFormat VMDDecoder::getPixelFormat() const {
02721     if (_externalCodec) {
02722         if (_codec)
02723             return _codec->getPixelFormat();
02724 
02725         // If we don't have the needed codec, just assume it's in the
02726         // current screen format
02727         return g_system->getScreenFormat();
02728     }
02729 
02730     if (_blitMode > 0)
02731         return g_system->getScreenFormat();
02732 
02733     return Graphics::PixelFormat::createFormatCLUT8();
02734 }
02735 
02736 bool VMDDecoder::getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height) {
02737     if (frame >= ((int32) _frameCount))
02738         return false;
02739 
02740     Frame &f = _frames[frame];
02741 
02742     // Look for a part matching the requested type, stopping at a separator
02743     Part *part = 0;
02744     for (int i = 0; i < _partsPerFrame; i++) {
02745         Part &p = f.parts[i];
02746 
02747         if ((p.type == kPartTypeSeparator) || (p.type == type)) {
02748             part = &p;
02749             break;
02750         }
02751     }
02752 
02753     if (!part)
02754         return false;
02755 
02756     x      = part->left;
02757     y      = part->top;
02758     width  = part->right  - part->left + 1;
02759     height = part->bottom - part->top  + 1;
02760 
02761     return true;
02762 }
02763 
02764 bool VMDDecoder::getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height) {
02765     return getPartCoords(frame, kPartTypeVideo, x, y, width, height);
02766 }
02767 
02768 bool VMDDecoder::hasEmbeddedFiles() const {
02769     return !_files.empty();
02770 }
02771 
02772 bool VMDDecoder::hasEmbeddedFile(const Common::String &fileName) const {
02773     for (Common::Array<File>::const_iterator file = _files.begin(); file != _files.end(); ++file)
02774         if (!file->name.compareToIgnoreCase(fileName))
02775             return true;
02776 
02777     return false;
02778 }
02779 
02780 Common::SeekableReadStream *VMDDecoder::getEmbeddedFile(const Common::String &fileName) const {
02781     const File *file = 0;
02782 
02783     for (Common::Array<File>::const_iterator it = _files.begin(); it != _files.end(); ++it)
02784         if (!it->name.compareToIgnoreCase(fileName)) {
02785             file = &*it;
02786             break;
02787         }
02788 
02789     if (!file)
02790         return 0;
02791 
02792     if ((file->size - 20) != file->realSize) {
02793         warning("VMDDecoder::getEmbeddedFile(): Sizes for \"%s\" differ! (%d, %d)",
02794                 fileName.c_str(), (file->size - 20), file->realSize);
02795         return 0;
02796     }
02797 
02798     if (!_stream->seek(file->offset)) {
02799         warning("VMDDecoder::getEmbeddedFile(): Can't seek to offset %d to (file \"%s\")",
02800                 file->offset, fileName.c_str());
02801         return 0;
02802     }
02803 
02804     byte *data = (byte *) malloc(file->realSize);
02805     if (_stream->read(data, file->realSize) != file->realSize) {
02806         free(data);
02807         warning("VMDDecoder::getEmbeddedFile(): Couldn't read %d bytes (file \"%s\")",
02808                 file->realSize, fileName.c_str());
02809         return 0;
02810     }
02811 
02812     Common::MemoryReadStream *stream =
02813         new Common::MemoryReadStream(data, file->realSize, DisposeAfterUse::YES);
02814 
02815     return stream;
02816 }
02817 
02818 int32 VMDDecoder::getSubtitleIndex() const {
02819     return _subtitle;
02820 }
02821 
02822 bool VMDDecoder::hasVideo() const {
02823     return _hasVideo;
02824 }
02825 
02826 bool VMDDecoder::isPaletted() const {
02827     return _isPaletted;
02828 }
02829 
02830 void VMDDecoder::setAutoStartSound(bool autoStartSound) {
02831     _autoStartSound = autoStartSound;
02832 }
02833 
02834 AdvancedVMDDecoder::AdvancedVMDDecoder(Audio::Mixer::SoundType soundType) {
02835     setSoundType(soundType);
02836     _decoder = new VMDDecoder(g_system->getMixer(), soundType);
02837     _decoder->setAutoStartSound(false);
02838 }
02839 
02840 AdvancedVMDDecoder::~AdvancedVMDDecoder() {
02841     close();
02842     delete _decoder;
02843 }
02844 
02845 bool AdvancedVMDDecoder::loadStream(Common::SeekableReadStream *stream) {
02846     close();
02847 
02848     if (!_decoder->loadStream(stream))
02849         return false;
02850 
02851     if (_decoder->hasVideo()) {
02852         _videoTrack = new VMDVideoTrack(_decoder);
02853         addTrack(_videoTrack);
02854     }
02855 
02856     if (_decoder->hasSound()) {
02857         _audioTrack = new VMDAudioTrack(_decoder);
02858         addTrack(_audioTrack);
02859     }
02860 
02861     return true;
02862 }
02863 
02864 void AdvancedVMDDecoder::close() {
02865     VideoDecoder::close();
02866     _decoder->close();
02867 }
02868 
02869 void AdvancedVMDDecoder::setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp) {
02870     _decoder->setSurfaceMemory(mem, width, height, bpp);
02871 }
02872 
02873 AdvancedVMDDecoder::VMDVideoTrack::VMDVideoTrack(VMDDecoder *decoder) : _decoder(decoder) {
02874 }
02875 
02876 uint16 AdvancedVMDDecoder::VMDVideoTrack::getWidth() const {
02877     return _decoder->getWidth();
02878 }
02879 
02880 uint16 AdvancedVMDDecoder::VMDVideoTrack::getHeight() const {
02881     return _decoder->getHeight();
02882 }
02883 
02884 Graphics::PixelFormat AdvancedVMDDecoder::VMDVideoTrack::getPixelFormat() const {
02885     return _decoder->getPixelFormat();
02886 }
02887 
02888 int AdvancedVMDDecoder::VMDVideoTrack::getCurFrame() const {
02889     return _decoder->getCurFrame();
02890 }
02891 
02892 int AdvancedVMDDecoder::VMDVideoTrack::getFrameCount() const {
02893     return _decoder->getFrameCount();
02894 }
02895 
02896 const Graphics::Surface *AdvancedVMDDecoder::VMDVideoTrack::decodeNextFrame() {
02897     return _decoder->decodeNextFrame();
02898 }
02899 
02900 const byte *AdvancedVMDDecoder::VMDVideoTrack::getPalette() const {
02901     return _decoder->getPalette();
02902 }
02903 
02904 bool AdvancedVMDDecoder::VMDVideoTrack::hasDirtyPalette() const {
02905     return _decoder->hasDirtyPalette();
02906 }
02907 
02908 Common::Rational AdvancedVMDDecoder::VMDVideoTrack::getFrameRate() const {
02909     return _decoder->getFrameRate();
02910 }
02911 
02912 AdvancedVMDDecoder::VMDAudioTrack::VMDAudioTrack(VMDDecoder *decoder) :
02913         AudioTrack(decoder->getSoundType()),
02914         _decoder(decoder) {
02915 }
02916 
02917 Audio::AudioStream *AdvancedVMDDecoder::VMDAudioTrack::getAudioStream() const {
02918     return _decoder->getAudioStream();
02919 }
02920 
02921 } // End of namespace Video
02922 
02923 #endif // VIDEO_COKTELDECODER_H


Generated on Sat Feb 23 2019 05:00:59 for ResidualVM by doxygen 1.7.1
curved edge   curved edge