Mercurial > libdvdnav.hg
comparison read_cache.c @ 225:9b1b740e3fc9 src
big build system changes
* cleaned up all Makefiles and added a Makefile.common
* added relchk script
* moved libdvdread files to a dvdread subdir
* moved DVD VM to a vm subdir
* removed unused code in read_cache.c
author | mroi |
---|---|
date | Sun, 11 Jan 2004 21:43:13 +0000 |
parents | 7eda95524e83 |
children | 065a2835ba90 |
comparison
equal
deleted
inserted
replaced
224:f19fce15577b | 225:9b1b740e3fc9 |
---|---|
17 * along with this program; if not, write to the Free Software | 17 * along with this program; if not, write to the Free Software |
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
19 * | 19 * |
20 * $Id$ | 20 * $Id$ |
21 * | 21 * |
22 */ | |
23 /* | |
24 * There was a multithreaded read ahead cache in here for some time, but | |
25 * it had only been used for a short time. If you want to have a look at it, | |
26 * search the CVS attic. | |
22 */ | 27 */ |
23 | 28 |
24 #ifdef HAVE_CONFIG_H | 29 #ifdef HAVE_CONFIG_H |
25 #include "config.h" | 30 #include "config.h" |
26 #endif | 31 #endif |
28 #include "dvdnav.h" | 33 #include "dvdnav.h" |
29 #include "read_cache.h" | 34 #include "read_cache.h" |
30 #include <pthread.h> | 35 #include <pthread.h> |
31 #include <sys/time.h> | 36 #include <sys/time.h> |
32 #include <time.h> | 37 #include <time.h> |
33 | |
34 | |
35 #define DVDNAV_PROFILE | |
36 | |
37 | |
38 /* Read-ahead cache structure. */ | |
39 #if _MULTITHREAD_ | |
40 | |
41 /* For the multithreaded cache, the cache is a ring buffer + writing | |
42 * thread that continuously reads data into the buffer until it is | |
43 * full or the 'upper-bound' has been reached. | |
44 */ | |
45 | |
46 #define CACHE_BUFFER_SIZE 2048 /* Cache this number of blocks at a time */ | |
47 | |
48 struct read_cache_s { | |
49 pthread_mutex_t cache_lock; | |
50 pthread_t read_thread; | |
51 | |
52 /* Buffer */ | |
53 uint8_t *buffer; | |
54 | |
55 /* Size of buffer */ | |
56 int32_t size; | |
57 /* block offset from sector start of buffer 'head' */ | |
58 uint32_t pos; | |
59 /* block offset from sector start of read point */ | |
60 uint32_t read_point; | |
61 /* block offset from buffer start to ring-boundary */ | |
62 uint32_t start; | |
63 | |
64 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ | |
65 dvdnav_t *dvd_self; | |
66 }; | |
67 | |
68 #else | |
69 | 38 |
70 #define READ_CACHE_CHUNKS 10 | 39 #define READ_CACHE_CHUNKS 10 |
71 | 40 |
72 /* all cache chunks must be memory aligned to allow use of raw devices */ | 41 /* all cache chunks must be memory aligned to allow use of raw devices */ |
73 #define ALIGNMENT 2048 | 42 #define ALIGNMENT 2048 |
96 pthread_mutex_t lock; | 65 pthread_mutex_t lock; |
97 | 66 |
98 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ | 67 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ |
99 dvdnav_t *dvd_self; | 68 dvdnav_t *dvd_self; |
100 }; | 69 }; |
101 #endif | |
102 | 70 |
103 /* | 71 /* |
104 #define READ_CACHE_TRACE 0 | 72 #define READ_CACHE_TRACE 0 |
105 */ | 73 */ |
106 | 74 |
120 # define dprintf(fmt, ...) /* Nowt */ | 88 # define dprintf(fmt, ...) /* Nowt */ |
121 #endif /* _MSC_VER */ | 89 #endif /* _MSC_VER */ |
122 # endif | 90 # endif |
123 #endif | 91 #endif |
124 | 92 |
125 #if _MULTITHREAD_ | |
126 | |
127 void * read_cache_read_thread (void * this_gen) { | |
128 int cont = 1; | |
129 int32_t diff, start; | |
130 uint32_t pos, size, startp, endp; | |
131 uint32_t s,c; | |
132 uint8_t *at; | |
133 read_cache_t *self = (read_cache_t*)this_gen; | |
134 | |
135 while(cont) { | |
136 | |
137 pthread_mutex_lock(&self->cache_lock); | |
138 | |
139 if(self->size >= 0) { | |
140 diff = self->read_point - self->pos; | |
141 if(diff >= self->size/2) { | |
142 dprintf("(II) Read thread -- "); | |
143 | |
144 startp = (self->start) % CACHE_BUFFER_SIZE; | |
145 endp = abs((self->start + diff - 1) % CACHE_BUFFER_SIZE); | |
146 dprintf("startp = %i, endp = %i -- ",startp, endp); | |
147 | |
148 pos = self->pos + diff; | |
149 size = self->size - diff; | |
150 start = (self->start + diff) % CACHE_BUFFER_SIZE; | |
151 | |
152 /* Fill remainder of buffer */ | |
153 | |
154 if(startp > endp) { | |
155 s = pos + size; c = CACHE_BUFFER_SIZE - startp; | |
156 at = self->buffer + (startp * DVD_VIDEO_LB_LEN); | |
157 if(c > 0) { | |
158 dprintf("(1) Reading from %i to %i to %i ", s, s+c-1, startp); | |
159 pthread_mutex_unlock(&self->cache_lock); | |
160 DVDReadBlocks(self->dvd_self->file, s,c, at); | |
161 pthread_mutex_lock(&self->cache_lock); | |
162 } | |
163 | |
164 s = pos + size + c; c = CACHE_BUFFER_SIZE - size - c; | |
165 at = self->buffer; | |
166 if(c > 0) { | |
167 dprintf("(2) Reading from %i to %i to %i ", s, s+c-1, 0); | |
168 pthread_mutex_unlock(&self->cache_lock); | |
169 DVDReadBlocks(self->dvd_self->file, s,c, at); | |
170 pthread_mutex_lock(&self->cache_lock); | |
171 } | |
172 } else { | |
173 s = pos + size; c = CACHE_BUFFER_SIZE - size; | |
174 at = self->buffer + (startp * DVD_VIDEO_LB_LEN); | |
175 if(c > 0) { | |
176 dprintf("(3) Reading from %i to %i to %i ", s, s+c-1, startp); | |
177 pthread_mutex_unlock(&self->cache_lock); | |
178 DVDReadBlocks(self->dvd_self->file, s,c, at); | |
179 pthread_mutex_lock(&self->cache_lock); | |
180 } | |
181 } | |
182 | |
183 dprintf("\n"); | |
184 | |
185 self->pos = pos; | |
186 self->start = start; self->size = CACHE_BUFFER_SIZE; | |
187 } | |
188 } | |
189 | |
190 pthread_mutex_unlock(&self->cache_lock); | |
191 cont = (self->buffer != NULL); | |
192 usleep(100); | |
193 } | |
194 | |
195 return NULL; | |
196 } | |
197 | |
198 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { | |
199 read_cache_t *me; | |
200 | |
201 me = (read_cache_t*)malloc(sizeof(struct read_cache_s)); | |
202 | |
203 if(me) { | |
204 int err; | |
205 | |
206 me->dvd_self = dvd_self; | |
207 me->buffer = (uint8_t*)malloc(CACHE_BUFFER_SIZE * DVD_VIDEO_LB_LEN); | |
208 me->start = 0; | |
209 me->pos = 0; | |
210 me->read_point = 0; | |
211 me->size = -1; | |
212 | |
213 /* Initialise the mutex */ | |
214 pthread_mutex_init(&me->cache_lock, NULL); | |
215 | |
216 if ((err = pthread_create (&me->read_thread, | |
217 NULL, read_cache_read_thread, me)) != 0) { | |
218 dprintf("read_cache: can't create new thread (%s)\n",strerror(err)); | |
219 } | |
220 } | |
221 | |
222 return me; | |
223 } | |
224 | |
225 void dvdnav_read_cache_free(read_cache_t* self) { | |
226 dvdnav_t *tmp; | |
227 | |
228 pthread_mutex_lock(&self->cache_lock); | |
229 | |
230 if(self->buffer) { | |
231 free(self->buffer); | |
232 self->buffer = NULL; | |
233 self->size = -2; | |
234 } | |
235 | |
236 pthread_mutex_unlock(&self->cache_lock); | |
237 | |
238 pthread_join(self->read_thread, NULL); | |
239 | |
240 pthread_mutex_destroy(&self->cache_lock); | |
241 | |
242 tmp = self->dvd_self; | |
243 free(self); | |
244 | |
245 /* We free the main structure, too, because we have no buffers out there. */ | |
246 free(tmp); | |
247 } | |
248 | |
249 /* This function MUST be called whenever self->file changes. */ | |
250 void dvdnav_read_cache_clear(read_cache_t *self) { | |
251 if(!self) | |
252 return; | |
253 | |
254 pthread_mutex_lock(&self->cache_lock); | |
255 self->size = -1; | |
256 self->start = 0; | |
257 self->pos = 0; | |
258 self->read_point = 0; | |
259 pthread_mutex_unlock(&self->cache_lock); | |
260 } | |
261 | |
262 /* This function is called just after reading the NAV packet. */ | |
263 void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) { | |
264 if(!self) | |
265 return; | |
266 | |
267 if(!self->dvd_self->use_read_ahead) { | |
268 return; | |
269 } | |
270 | |
271 pthread_mutex_lock(&self->cache_lock); | |
272 dprintf("Requested pre-cache (%i -> +%i) : current state pos=%i, size=%i.\n", | |
273 sector, block_count, self->pos, self->size); | |
274 | |
275 /* Are the contents of the buffer in any way relevant? */ | |
276 if((self->size > 0) && (sector >= self->pos) && (sector <= self->pos+self->size)) { | |
277 dprintf("Contents relevant ... adjusting\n"); | |
278 self->read_point = sector; | |
279 } else { | |
280 /* Flush the cache as its not much use */ | |
281 dprintf("Contents irrelevent... flushing\n"); | |
282 self->size = 0; | |
283 self->start = 0; | |
284 self->pos = sector; | |
285 self->read_point = sector; | |
286 } | |
287 | |
288 pthread_mutex_unlock(&self->cache_lock); | |
289 } | |
290 | |
291 /* This function will do the cache read */ | |
292 int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t **buf) { | |
293 int result, diff; | |
294 | |
295 if(!self) | |
296 return 0; | |
297 | |
298 pthread_mutex_lock(&self->cache_lock); | |
299 dprintf("Read from %i -> +%i (buffer pos=%i, read_point=%i, size=%i)... ", sector, block_count, | |
300 self->pos, self->read_point, self->size); | |
301 if((self->size > 0) && (sector >= self->read_point) && | |
302 (sector + block_count <= self->pos + self->size)) { | |
303 /* Hit */ | |
304 | |
305 /* Drop any skipped blocks */ | |
306 diff = sector - self->read_point; | |
307 if(diff > 0) | |
308 self->read_point += diff; | |
309 | |
310 diff = self->read_point - self->pos; | |
311 | |
312 if(((self->start + diff) % CACHE_BUFFER_SIZE) + block_count <= CACHE_BUFFER_SIZE) { | |
313 dprintf("************** Single read\n"); | |
314 memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), | |
315 block_count * DVD_VIDEO_LB_LEN); | |
316 self->read_point += block_count; | |
317 pthread_mutex_unlock(&self->cache_lock); | |
318 | |
319 return (int)block_count; | |
320 } else { | |
321 int32_t boundary = CACHE_BUFFER_SIZE - self->start; | |
322 | |
323 dprintf("************** Multiple read\n"); | |
324 memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), | |
325 boundary * DVD_VIDEO_LB_LEN); | |
326 memcpy(*buf + (boundary * DVD_VIDEO_LB_LEN), self->buffer, | |
327 (block_count-boundary) * DVD_VIDEO_LB_LEN); | |
328 self->read_point += block_count; | |
329 pthread_mutex_unlock(&self->cache_lock); | |
330 | |
331 return (int)block_count; | |
332 } | |
333 } else { | |
334 /* Miss */ | |
335 | |
336 fprintf(MSG_OUT, "libdvdnav: DVD read cache miss! (not bad but a performance hit) sector=%d\n", sector); | |
337 result = DVDReadBlocks( self->dvd_self->file, sector, block_count, *buf); | |
338 self->read_point = sector+block_count; | |
339 if(self->read_point > self->pos + self->size) { | |
340 /* Flush the cache as its not much use */ | |
341 dprintf("Contents irrelevent... flushing\n"); | |
342 self->size = 0; | |
343 self->start = 0; | |
344 self->pos = sector+block_count; | |
345 } | |
346 pthread_mutex_unlock(&self->cache_lock); | |
347 usleep(300); | |
348 return result; | |
349 } | |
350 | |
351 /* Should never get here */ | |
352 return 0; | |
353 } | |
354 | |
355 dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) { | |
356 return DVDNAV_STATUS_OK; | |
357 } | |
358 | |
359 #else | |
360 | 93 |
361 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { | 94 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { |
362 read_cache_t *self; | 95 read_cache_t *self; |
363 int i; | 96 int i; |
364 | 97 |
518 if (use >= 0) { | 251 if (use >= 0) { |
519 read_cache_chunk_t *chunk; | 252 read_cache_chunk_t *chunk; |
520 | 253 |
521 /* Increment read-ahead size if sector follows the last sector */ | 254 /* Increment read-ahead size if sector follows the last sector */ |
522 if (sector == (self->last_sector + 1)) { | 255 if (sector == (self->last_sector + 1)) { |
523 self->read_ahead_incr++; | 256 if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX) |
257 self->read_ahead_incr++; | |
524 } else { | 258 } else { |
525 self->read_ahead_size = READ_AHEAD_SIZE_MIN; | 259 self->read_ahead_size = READ_AHEAD_SIZE_MIN; |
526 self->read_ahead_incr = 0; | 260 self->read_ahead_incr = 0; |
527 } | 261 } |
528 self->last_sector = sector; | 262 self->last_sector = sector; |
537 read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN; | 271 read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN; |
538 *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN; | 272 *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN; |
539 chunk->usage_count++; | 273 chunk->usage_count++; |
540 pthread_mutex_unlock(&self->lock); | 274 pthread_mutex_unlock(&self->lock); |
541 | 275 |
542 /* Read blocks if needed */ | 276 dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count); |
543 if (sector >= (chunk->cache_start_sector + chunk->cache_read_count)) { | 277 |
544 | 278 /* read_ahead_size */ |
545 dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count); | 279 incr = self->read_ahead_incr >> 1; |
546 | 280 if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) { |
547 /* read_ahead_size */ | 281 self->read_ahead_size = READ_AHEAD_SIZE_MAX; |
548 incr = self->read_ahead_incr >> 1; | 282 } else { |
549 if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) { | 283 self->read_ahead_size += incr; |
550 self->read_ahead_size = READ_AHEAD_SIZE_MAX; | 284 } |
551 } else { | 285 |
552 self->read_ahead_size = self->read_ahead_size + incr; | 286 /* real read size */ |
553 } | 287 start = chunk->cache_start_sector + chunk->cache_read_count; |
554 self->read_ahead_incr = 0; | 288 if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) { |
555 | 289 size = chunk->cache_block_count - chunk->cache_read_count; |
556 /* real read size */ | 290 } else { |
557 start = chunk->cache_start_sector + chunk->cache_read_count; | 291 size = self->read_ahead_size; |
558 if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) { | 292 /* ensure that the sector we want will be read */ |
559 size = chunk->cache_block_count - chunk->cache_read_count; | 293 if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size) |
560 } else { | 294 size = sector - chunk->cache_start_sector - chunk->cache_read_count; |
561 size = self->read_ahead_size; | 295 } |
562 } | 296 dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size); |
563 dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size); | 297 |
564 | 298 if (size) |
565 chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file, | 299 chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file, |
566 start, | 300 start, |
567 size, | 301 size, |
568 read_ahead_buf); | 302 read_ahead_buf); |
569 } | |
570 | 303 |
571 res = DVD_VIDEO_LB_LEN * block_count; | 304 res = DVD_VIDEO_LB_LEN * block_count; |
572 | 305 |
573 } else { | 306 } else { |
574 | 307 |
609 /* when we want to dispose the cache, try freeing it now */ | 342 /* when we want to dispose the cache, try freeing it now */ |
610 dvdnav_read_cache_free(cache); | 343 dvdnav_read_cache_free(cache); |
611 | 344 |
612 return DVDNAV_STATUS_OK; | 345 return DVDNAV_STATUS_OK; |
613 } | 346 } |
614 | |
615 #endif |