Hello, I have an update for the scumm smush_player and chunk class. The old smush player was fairly excelent on fast computers wheere seek / and transfer times are very short. On the other hand if smush player was not fed properly right from the start (mostly happens on platforms where there is no read-ahead file caching, and on platforms where data transfer rate is slow - flash disks etc.) then the playback performace suffer. Another glitch concerned the time-compression on the start of the movie (first 2 or 3 seconds of the movie were missing - or played back at once with stacked voice streams) is also solved. This fix/update adds read-ahead caching to the chunk class (I have created CachedFileChunk from the FileChunk) and slightly modifies the smush_player. I'm sorry that the source is attached here, but I have no other easier way how to contribute. Hope it will be usefull. Ole chunk.h ----------------------------------------------------------- class CachedFileChunk : public BaseChunk { private: ScummFile *_data; uint32 _offset; unsigned char* _cache; //read ahead cache uint32 _cachePos; //position at the start of the cache uint32 _cacheSize;//current size of the cache uint32 _cacheMax; //maximum size of the cache bugger int8 _cacheOwner; //set to 1 if the chunk is cache owner CachedFileChunk* _parent; protected: CachedFileChunk(CachedFileChunk *); public: CachedFileChunk(const char *fname); virtual ~CachedFileChunk(); Chunk *subBlock(); bool read(void *buffer, uint32 size); int8 getChar(); byte getByte(); short getShort(); uint16 getWord(); uint32 getDword(); void reinit(uint32 offset); void setCache(unsigned char* cache, int32 cachePos, int32 cacheSize, int32 cacheMax); void fillCache(); }; chunk.cpp ---------------------------------------------------------- #define DW_LE_BE(x) (((x)&0xFF)<<24) + (((x)&0xFF00) <<8) + (((x)&0xFF0000) >> 8) +(((x)&0xFF000000)>>24) CachedFileChunk::CachedFileChunk(CachedFileChunk * parent) { _data = NULL; _cacheOwner = 0; _parent = parent; } CachedFileChunk::CachedFileChunk(const char *fname) { _data = new ScummFile(); if (!g_scumm->openFile(*_data, fname)) error("FileChunk: Unable to open file %s", fname); _type = _data->readUint32BE(); _size = _data->readUint32BE(); _offset = sizeof(Chunk::type) + sizeof(uint32); _curPos = 0; _cacheOwner = 1; _cachePos = 0; _cacheMax = 64 * 1024; _cache = (unsigned char*) malloc(_cacheMax); if (_cache == NULL) { error("cache malloc failed! "); } memset(_cache, 0, _cacheMax); _data->seek(0); _cacheSize = _data->read(_cache, _cacheMax); _parent = NULL; } CachedFileChunk::~CachedFileChunk() { if (_data) _data->decRef(); if (_parent != NULL) { _parent->setCache(_cache, _cachePos, _cacheSize, _cacheMax); } if (_cacheOwner && _cache) { free(_cache); } } void CachedFileChunk::setCache(unsigned char* cache, int32 cachePos, int32 cacheSize, int32 cacheMax) { _cache = cache; _cachePos = cachePos; _cacheSize = cacheSize; _cacheMax = cacheMax; } Chunk *CachedFileChunk::subBlock() { int dword; CachedFileChunk *ptr = new CachedFileChunk(this); ptr->setCache(_cache, _cachePos, _cacheSize, _cacheMax); ptr->_data = _data; _data->incRef(); dword = getDword(); ptr->_type = DW_LE_BE(dword); dword = getDword(); ptr->_size = DW_LE_BE(dword); _curPos -= 8; ptr->_offset = _offset + _curPos + sizeof(Chunk::type) + sizeof(uint32) ; ptr->_curPos = 0; //seek behind the sub block seek(sizeof(Chunk::type) + sizeof(uint32) + ptr->getSize()); return ptr; } void CachedFileChunk::fillCache() { int position; int cachePoint; int cacheHalf; int size; //cache reached end of file if (_cacheSize < _cacheMax) { return; } cacheHalf = _cacheMax / 2; position = _offset + _curPos; cachePoint = _cachePos + cacheHalf; //current position is beyond the half of the cache //i.e. cache holds a lot of old data if (position > cachePoint) { //copy 2nd half of the cache to 1st half of the cache memcpy(_cache, _cache + cacheHalf, cacheHalf); //read the rest of the cache size = _data->read(_cache+cacheHalf, cacheHalf); _cacheSize = cacheHalf + size; _cachePos += cacheHalf; } } bool CachedFileChunk::read(void *buffer, uint32 size) { int theSize; int position; int blockSize; int cacheEnd; int bufferPos; // printf(" read chunk: size=%d cachePos=%d cacheSize=%d _offset=%d _curPos=%d\n", size, _cachePos, _cacheSize, _offset, _curPos); theSize = size; bufferPos = 0; while (theSize) { position = _offset + _curPos; blockSize = theSize; cacheEnd = _cachePos + _cacheSize; if (blockSize > cacheEnd-position) { blockSize = cacheEnd - position; //copy the rest of the cache into buffer memcpy((char*)buffer+bufferPos, _cache + (position-_cachePos), blockSize); //read new data into cache cache _data->seek(position+blockSize); _cacheSize = _data->read(_cache, _cacheMax); _cachePos = cacheEnd; } else { memcpy((char*)buffer+bufferPos, _cache + (position-_cachePos), blockSize); } theSize -= blockSize; bufferPos+= blockSize; _curPos +=blockSize; } return true; } int8 CachedFileChunk::getChar() { return (int8)getByte(); } byte CachedFileChunk::getByte() { byte b; read(&b,1); return b; } int16 CachedFileChunk::getShort() { return (int16)getWord(); } uint16 CachedFileChunk::getWord() { uint16 i; read(&i,2); return READ_LE_UINT16(&i); } uint32 CachedFileChunk::getDword() { uint32 i; read(&i,4); return READ_LE_UINT32(&i); } void CachedFileChunk::reinit(uint32 offset) { _offset = 0; _data->seek(0); _type = _data->readUint32BE(); _size = _data->readUint32BE(); _curPos = 0; _cachePos = 0; _cacheSize = _data->read(_cache, _cacheMax); } smush_player.h ----------------------------------------------------------------- The change is only the static _update needed static bool _updateNeeded; smush_player.cpp ----------------------------------------------------------------- bool SmushPlayer::_updateNeeded = false; void SmushPlayer::timerCallback(void *refCon) { if (!_updateNeeded) { ((SmushPlayer *)refCon)->parseNextFrame(); } } void SmushPlayer::play(const char *filename, int32 offset, int32 startFrame) { uint32 diff_time, start_time; // Verify the specified file exists ScummFile f; _vm->openFile(f, filename); if (!f.isOpen()) { warning("SmushPlayer::play() File not found %s", filename); return; } f.close(); tryOggFile(filename); _updateNeeded = false; // Hide mouse bool oldMouseState = _vm->_system->showMouse(false); // Load the video setupAnim(filename); init(); if (offset) { _base->seek(offset - 8, FileChunk::seek_start); _frame = startFrame; _middleAudio = true; } //primary warmup of the smush file parseNextFrame(); for (;;) { _vm->parseEvents(); _vm->processKbd(true); if (_updateNeeded) { _vm->_system->updateScreen(); _updateNeeded = false; //debugC(DEBUG_SMUSH, "Smush stats: BackendUpdateScreen( %03d )", end_time - start_time); } start_time = _vm->_system->getMillis(); _base->fillCache(); diff_time = _vm->_system->getMillis() - start_time; if (diff_time < 5) { _vm->_system->delayMillis(10-diff_time); } if (_vm->_smushVideoShouldFinish || _vm->_quit || _vm->_saveLoadFlag) break; }; release(); // Reset mouse state _vm->_system->showMouse(oldMouseState); } Also, the FileChunk class is replaced by CachedFileChunk in the: setupAnim and seekSan methods of the SmushPlayer.