Ticket #8396: smush-speed.txt

File smush-speed.txt, 7.7 KB (added by SF/ole00, 18 years ago)

smush/chunk performance update source code

Line 
1Hello,
2
3I have an update for the scumm smush_player and chunk class.
4The old smush player was fairly excelent on fast computers
5wheere seek / and transfer times are very short. On the other hand
6if smush player was not fed properly right from the start (mostly
7happens on platforms where there is no read-ahead file caching, and on
8platforms where data transfer rate is slow - flash disks etc.) then
9the playback performace suffer. Another glitch concerned the
10time-compression on the start of the movie (first 2 or 3 seconds
11of the movie were missing - or played back at once with stacked voice
12streams) is also solved.
13
14This fix/update adds read-ahead caching to the chunk class
15(I have created CachedFileChunk from the FileChunk) and slightly
16modifies the smush_player.
17
18I'm sorry that the source is attached here, but I have no other
19easier way how to contribute.
20
21Hope it will be usefull.
22
23Ole
24
25
26
27chunk.h
28-----------------------------------------------------------
29class CachedFileChunk : public BaseChunk {
30private:
31 ScummFile *_data;
32 uint32 _offset;
33
34 unsigned char* _cache; //read ahead cache
35 uint32 _cachePos; //position at the start of the cache
36 uint32 _cacheSize;//current size of the cache
37 uint32 _cacheMax; //maximum size of the cache bugger
38 int8 _cacheOwner; //set to 1 if the chunk is cache owner
39 CachedFileChunk* _parent;
40protected:
41 CachedFileChunk(CachedFileChunk *);
42
43public:
44 CachedFileChunk(const char *fname);
45 virtual ~CachedFileChunk();
46 Chunk *subBlock();
47 bool read(void *buffer, uint32 size);
48 int8 getChar();
49 byte getByte();
50 short getShort();
51 uint16 getWord();
52 uint32 getDword();
53 void reinit(uint32 offset);
54 void setCache(unsigned char* cache, int32 cachePos, int32 cacheSize, int32 cacheMax);
55 void fillCache();
56};
57
58
59chunk.cpp
60----------------------------------------------------------
61#define DW_LE_BE(x) (((x)&0xFF)<<24) + (((x)&0xFF00) <<8) + (((x)&0xFF0000) >> 8) +(((x)&0xFF000000)>>24)
62
63CachedFileChunk::CachedFileChunk(CachedFileChunk * parent) {
64 _data = NULL;
65 _cacheOwner = 0;
66 _parent = parent;
67}
68
69CachedFileChunk::CachedFileChunk(const char *fname) {
70 _data = new ScummFile();
71 if (!g_scumm->openFile(*_data, fname))
72 error("FileChunk: Unable to open file %s", fname);
73
74 _type = _data->readUint32BE();
75 _size = _data->readUint32BE();
76 _offset = sizeof(Chunk::type) + sizeof(uint32);
77 _curPos = 0;
78
79 _cacheOwner = 1;
80 _cachePos = 0;
81 _cacheMax = 64 * 1024;
82 _cache = (unsigned char*) malloc(_cacheMax);
83
84 if (_cache == NULL) {
85 error("cache malloc failed! ");
86 }
87 memset(_cache, 0, _cacheMax);
88
89 _data->seek(0);
90 _cacheSize = _data->read(_cache, _cacheMax);
91 _parent = NULL;
92}
93
94CachedFileChunk::~CachedFileChunk() {
95 if (_data)
96 _data->decRef();
97
98 if (_parent != NULL) {
99 _parent->setCache(_cache, _cachePos, _cacheSize, _cacheMax);
100 }
101 if (_cacheOwner && _cache) {
102 free(_cache);
103 }
104}
105
106void CachedFileChunk::setCache(unsigned char* cache, int32 cachePos, int32 cacheSize, int32 cacheMax) {
107 _cache = cache;
108 _cachePos = cachePos;
109 _cacheSize = cacheSize;
110 _cacheMax = cacheMax;
111}
112
113
114Chunk *CachedFileChunk::subBlock() {
115 int dword;
116 CachedFileChunk *ptr = new CachedFileChunk(this);
117 ptr->setCache(_cache, _cachePos, _cacheSize, _cacheMax);
118
119 ptr->_data = _data;
120 _data->incRef();
121
122
123 dword = getDword();
124 ptr->_type = DW_LE_BE(dword);
125 dword = getDword();
126 ptr->_size = DW_LE_BE(dword);
127 _curPos -= 8;
128
129 ptr->_offset = _offset + _curPos + sizeof(Chunk::type) + sizeof(uint32) ;
130 ptr->_curPos = 0;
131
132 //seek behind the sub block
133 seek(sizeof(Chunk::type) + sizeof(uint32) + ptr->getSize());
134 return ptr;
135}
136void CachedFileChunk::fillCache() {
137 int position;
138 int cachePoint;
139 int cacheHalf;
140 int size;
141
142 //cache reached end of file
143 if (_cacheSize < _cacheMax) {
144 return;
145 }
146
147 cacheHalf = _cacheMax / 2;
148 position = _offset + _curPos;
149 cachePoint = _cachePos + cacheHalf;
150
151 //current position is beyond the half of the cache
152 //i.e. cache holds a lot of old data
153 if (position > cachePoint) {
154 //copy 2nd half of the cache to 1st half of the cache
155 memcpy(_cache, _cache + cacheHalf, cacheHalf);
156 //read the rest of the cache
157 size = _data->read(_cache+cacheHalf, cacheHalf);
158 _cacheSize = cacheHalf + size;
159 _cachePos += cacheHalf;
160 }
161}
162
163bool CachedFileChunk::read(void *buffer, uint32 size) {
164 int theSize;
165 int position;
166 int blockSize;
167 int cacheEnd;
168 int bufferPos;
169
170// printf(" read chunk: size=%d cachePos=%d cacheSize=%d _offset=%d _curPos=%d\n", size, _cachePos, _cacheSize, _offset, _curPos);
171 theSize = size;
172 bufferPos = 0;
173 while (theSize) {
174 position = _offset + _curPos;
175 blockSize = theSize;
176 cacheEnd = _cachePos + _cacheSize;
177 if (blockSize > cacheEnd-position) {
178 blockSize = cacheEnd - position;
179 //copy the rest of the cache into buffer
180 memcpy((char*)buffer+bufferPos, _cache + (position-_cachePos), blockSize);
181 //read new data into cache cache
182 _data->seek(position+blockSize);
183 _cacheSize = _data->read(_cache, _cacheMax);
184 _cachePos = cacheEnd;
185 } else {
186 memcpy((char*)buffer+bufferPos, _cache + (position-_cachePos), blockSize);
187 }
188 theSize -= blockSize;
189 bufferPos+= blockSize;
190 _curPos +=blockSize;
191 }
192 return true;
193}
194
195int8 CachedFileChunk::getChar() {
196 return (int8)getByte();
197}
198
199byte CachedFileChunk::getByte() {
200 byte b;
201 read(&b,1);
202 return b;
203}
204
205int16 CachedFileChunk::getShort() {
206 return (int16)getWord();
207}
208
209uint16 CachedFileChunk::getWord() {
210 uint16 i;
211 read(&i,2);
212 return READ_LE_UINT16(&i);
213}
214
215uint32 CachedFileChunk::getDword() {
216 uint32 i;
217 read(&i,4);
218 return READ_LE_UINT32(&i);
219}
220
221void CachedFileChunk::reinit(uint32 offset) {
222 _offset = 0;
223 _data->seek(0);
224 _type = _data->readUint32BE();
225 _size = _data->readUint32BE();
226 _curPos = 0;
227
228 _cachePos = 0;
229 _cacheSize = _data->read(_cache, _cacheMax);
230}
231
232smush_player.h
233-----------------------------------------------------------------
234
235The change is only the static _update needed
236static bool _updateNeeded;
237
238
239smush_player.cpp
240-----------------------------------------------------------------
241bool SmushPlayer::_updateNeeded = false;
242
243void SmushPlayer::timerCallback(void *refCon) {
244 if (!_updateNeeded) {
245 ((SmushPlayer *)refCon)->parseNextFrame();
246 }
247}
248
249
250
251void SmushPlayer::play(const char *filename, int32 offset, int32 startFrame) {
252 uint32 diff_time, start_time;
253
254 // Verify the specified file exists
255 ScummFile f;
256 _vm->openFile(f, filename);
257 if (!f.isOpen()) {
258 warning("SmushPlayer::play() File not found %s", filename);
259 return;
260 }
261 f.close();
262
263 tryOggFile(filename);
264
265 _updateNeeded = false;
266
267 // Hide mouse
268 bool oldMouseState = _vm->_system->showMouse(false);
269
270 // Load the video
271 setupAnim(filename);
272 init();
273
274 if (offset) {
275 _base->seek(offset - 8, FileChunk::seek_start);
276 _frame = startFrame;
277 _middleAudio = true;
278 }
279
280 //primary warmup of the smush file
281 parseNextFrame();
282
283 for (;;) {
284 _vm->parseEvents();
285 _vm->processKbd(true);
286
287
288 if (_updateNeeded) {
289 _vm->_system->updateScreen();
290 _updateNeeded = false;
291
292 //debugC(DEBUG_SMUSH, "Smush stats: BackendUpdateScreen( %03d )", end_time - start_time);
293
294 }
295 start_time = _vm->_system->getMillis();
296 _base->fillCache();
297 diff_time = _vm->_system->getMillis() - start_time;
298 if (diff_time < 5) {
299 _vm->_system->delayMillis(10-diff_time);
300 }
301
302 if (_vm->_smushVideoShouldFinish || _vm->_quit || _vm->_saveLoadFlag)
303 break;
304 };
305
306 release();
307
308 // Reset mouse state
309 _vm->_system->showMouse(oldMouseState);
310}
311
312Also, the FileChunk class is replaced by CachedFileChunk in the:
313setupAnim and seekSan methods of the SmushPlayer.
314
315