Mercurial > libdvdnav.hg
comparison searching.c @ 417:af0b6a8bf7e9 src
Always attempt to move forward on a seek
From John Stebbins original post (with pathc, Thanks!):
libdvdnav has a problem in that it is difficult to gracefully recover
from a read error and continue on to subsequent blocks on the disc. An
application would like to seek forward past the current block after
getting a read error in order to attempt to get past the bad block(s).
But dvdnav_sector_search() does not guarantee that a requested forward
seek will actually move the current position forward. It truncates down
to the nearest VOBU which will almost always cause a forward seek
request by a single block (or a small number of blocks) to move the
current position backward. This behaviour puts the application into a
loop of: read failure, attempted forward seek (which results in backward
seek), read failure ...
author | erik |
---|---|
date | Fri, 07 Oct 2011 17:06:24 +0000 |
parents | ec2408d48b85 |
children | 4219a513c804 |
comparison
equal
deleted
inserted
replaced
416:4e34a2fce645 | 417:af0b6a8bf7e9 |
---|---|
45 | 45 |
46 /* Scan the ADMAP for a particular block number. */ | 46 /* Scan the ADMAP for a particular block number. */ |
47 /* Return placed in vobu. */ | 47 /* Return placed in vobu. */ |
48 /* Returns error status */ | 48 /* Returns error status */ |
49 /* FIXME: Maybe need to handle seeking outside current cell. */ | 49 /* FIXME: Maybe need to handle seeking outside current cell. */ |
50 static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) { | 50 static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, int next, uint32_t *vobu) { |
51 vobu_admap_t *admap = NULL; | 51 vobu_admap_t *admap = NULL; |
52 | 52 |
53 #ifdef LOG_DEBUG | 53 #ifdef LOG_DEBUG |
54 fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block); | 54 fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block); |
55 #endif | 55 #endif |
87 if(vobu_start <= seekto_block && next_vobu > seekto_block) | 87 if(vobu_start <= seekto_block && next_vobu > seekto_block) |
88 break; | 88 break; |
89 vobu_start = next_vobu; | 89 vobu_start = next_vobu; |
90 address++; | 90 address++; |
91 } | 91 } |
92 *vobu = vobu_start; | 92 *vobu = next ? next_vobu : vobu_start; |
93 return DVDNAV_STATUS_OK; | 93 return DVDNAV_STATUS_OK; |
94 } | 94 } |
95 fprintf(MSG_OUT, "libdvdnav: admap not located\n"); | 95 fprintf(MSG_OUT, "libdvdnav: admap not located\n"); |
96 return DVDNAV_STATUS_ERR; | 96 return DVDNAV_STATUS_ERR; |
97 } | 97 } |
158 uint32_t vobu; | 158 uint32_t vobu; |
159 #ifdef LOG_DEBUG | 159 #ifdef LOG_DEBUG |
160 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", | 160 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", |
161 cell_nr, first_cell_nr, last_cell_nr); | 161 cell_nr, first_cell_nr, last_cell_nr); |
162 #endif | 162 #endif |
163 if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { | 163 if (dvdnav_scan_admap(this, state->domain, target, 0, &vobu) == DVDNAV_STATUS_OK) { |
164 uint32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; | 164 uint32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; |
165 | 165 |
166 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { | 166 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { |
167 #ifdef LOG_DEBUG | 167 #ifdef LOG_DEBUG |
168 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , | 168 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , |
182 } | 182 } |
183 | 183 |
184 dvdnav_status_t dvdnav_sector_search(dvdnav_t *this, | 184 dvdnav_status_t dvdnav_sector_search(dvdnav_t *this, |
185 uint64_t offset, int32_t origin) { | 185 uint64_t offset, int32_t origin) { |
186 uint32_t target = 0; | 186 uint32_t target = 0; |
187 uint32_t current_pos; | |
188 uint32_t cur_sector; | |
189 uint32_t cur_cell_nr; | |
187 uint32_t length = 0; | 190 uint32_t length = 0; |
188 uint32_t first_cell_nr, last_cell_nr, cell_nr; | 191 uint32_t first_cell_nr, last_cell_nr, cell_nr; |
189 int32_t found; | 192 int32_t found; |
193 int forward = 0; | |
190 cell_playback_t *cell; | 194 cell_playback_t *cell; |
191 dvd_state_t *state; | 195 dvd_state_t *state; |
192 dvdnav_status_t result; | 196 dvdnav_status_t result; |
193 | 197 |
194 if(this->position_current.still != 0) { | 198 if(this->position_current.still != 0) { |
210 } | 214 } |
211 #ifdef LOG_DEBUG | 215 #ifdef LOG_DEBUG |
212 fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length); | 216 fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length); |
213 fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN); | 217 fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN); |
214 #endif | 218 #endif |
219 | |
220 current_pos = target; | |
221 cur_sector = this->vobu.vobu_start + this->vobu.blockN; | |
222 cur_cell_nr = state->cellN; | |
215 | 223 |
216 switch(origin) { | 224 switch(origin) { |
217 case SEEK_SET: | 225 case SEEK_SET: |
218 if(offset >= length) { | 226 if(offset >= length) { |
219 printerr("Request to seek behind end."); | 227 printerr("Request to seek behind end."); |
242 /* Error occured */ | 250 /* Error occured */ |
243 printerr("Illegal seek mode."); | 251 printerr("Illegal seek mode."); |
244 pthread_mutex_unlock(&this->vm_lock); | 252 pthread_mutex_unlock(&this->vm_lock); |
245 return DVDNAV_STATUS_ERR; | 253 return DVDNAV_STATUS_ERR; |
246 } | 254 } |
255 forward = target > current_pos; | |
247 | 256 |
248 this->cur_cell_time = 0; | 257 this->cur_cell_time = 0; |
249 if (this->pgc_based) { | 258 if (this->pgc_based) { |
250 first_cell_nr = 1; | 259 first_cell_nr = 1; |
251 last_cell_nr = state->pgc->nr_of_cells; | 260 last_cell_nr = state->pgc->nr_of_cells; |
268 if (target >= length) { | 277 if (target >= length) { |
269 target -= length; | 278 target -= length; |
270 } else { | 279 } else { |
271 /* convert the target sector from Cell-relative to absolute physical sector */ | 280 /* convert the target sector from Cell-relative to absolute physical sector */ |
272 target += cell->first_sector; | 281 target += cell->first_sector; |
282 if (forward && (cell_nr == cur_cell_nr)) { | |
283 uint32_t vobu; | |
284 /* if we are seeking forward from the current position, make sure | |
285 * we move to a new position that is after our current position. | |
286 * simply truncating to the vobu will go backwards */ | |
287 if (dvdnav_scan_admap(this, state->domain, target, 0, &vobu) != DVDNAV_STATUS_OK) | |
288 break; | |
289 if (vobu <= cur_sector) { | |
290 if (dvdnav_scan_admap(this, state->domain, target, 1, &vobu) != DVDNAV_STATUS_OK) | |
291 break; | |
292 if (vobu > cell->last_sector) { | |
293 if (cell_nr == last_cell_nr) | |
294 break; | |
295 cell_nr++; | |
296 cell = &(state->pgc->cell_playback[cell_nr-1]); | |
297 target = cell->first_sector; | |
298 } else { | |
299 target = vobu; | |
300 } | |
301 } | |
302 } | |
273 found = 1; | 303 found = 1; |
274 break; | 304 break; |
275 } | 305 } |
276 } | 306 } |
277 | 307 |
279 uint32_t vobu; | 309 uint32_t vobu; |
280 #ifdef LOG_DEBUG | 310 #ifdef LOG_DEBUG |
281 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", | 311 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", |
282 cell_nr, first_cell_nr, last_cell_nr); | 312 cell_nr, first_cell_nr, last_cell_nr); |
283 #endif | 313 #endif |
284 if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { | 314 if (dvdnav_scan_admap(this, state->domain, target, 0, &vobu) == DVDNAV_STATUS_OK) { |
285 int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; | 315 int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; |
286 | 316 |
287 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { | 317 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) { |
288 #ifdef LOG_DEBUG | 318 #ifdef LOG_DEBUG |
289 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , | 319 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , |