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" ,