00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #include <assert.h>
00027 #include "dvdnav_internal.h"
00028 #include "dvdnav.h"
00029 #include "compat.h"
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) {
00042 vobu_admap_t *admap = NULL;
00043
00044 #ifdef LOG_DEBUG
00045 fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block);
00046 #endif
00047 *vobu = -1;
00048
00049
00050
00051 switch(domain) {
00052 case FP_DOMAIN:
00053 case VMGM_DOMAIN:
00054 admap = this->vm->vmgi->menu_vobu_admap;
00055 break;
00056 case VTSM_DOMAIN:
00057 admap = this->vm->vtsi->menu_vobu_admap;
00058 break;
00059 case VTS_DOMAIN:
00060 admap = this->vm->vtsi->vts_vobu_admap;
00061 break;
00062 default:
00063 fprintf(MSG_OUT, "libdvdnav: Error: Unknown domain for seeking.\n");
00064 }
00065 if(admap) {
00066 uint32_t address = 0;
00067 uint32_t vobu_start, next_vobu, first_address, last_address;
00068 int32_t found = 0;
00069
00070
00071 vobu_start = SRI_END_OF_CELL;
00072
00073 if (admap->last_byte > 20 &&
00074 admap->vobu_start_sectors[20] >= seekto_block)
00075 {
00076 while((!found) && ((address<<2) < admap->last_byte)) {
00077 next_vobu = admap->vobu_start_sectors[address];
00078
00079 if (next_vobu == seekto_block) {
00080 vobu_start = next_vobu;
00081 found = 1;
00082 } else if (vobu_start < seekto_block && next_vobu > seekto_block) {
00083 found = 1;
00084 } else {
00085 vobu_start = next_vobu;
00086 }
00087 address++;
00088 }
00089 }
00090 else {
00091 found = 0;
00092 first_address = 0;
00093 last_address = admap->last_byte >> 2;
00094 while (first_address <= last_address)
00095 {
00096 address = (first_address + last_address) / 2;
00097 next_vobu = admap->vobu_start_sectors[address];
00098 vobu_start = next_vobu;
00099 if (seekto_block > next_vobu)
00100 first_address = address + 1;
00101 else if (seekto_block < next_vobu)
00102 last_address = address - 1;
00103 else {
00104 break;
00105 }
00106 }
00107 found = 1;
00108 if (next_vobu > seekto_block)
00109 vobu_start = admap->vobu_start_sectors[last_address - 1];
00110 }
00111 if(found) {
00112 *vobu = vobu_start;
00113 return DVDNAV_STATUS_OK;
00114 } else {
00115 fprintf(MSG_OUT, "libdvdnav: Could not locate block\n");
00116 return DVDNAV_STATUS_ERR;
00117 }
00118 }
00119 fprintf(MSG_OUT, "libdvdnav: admap not located\n");
00120 return DVDNAV_STATUS_ERR;
00121 }
00122
00123 dvdnav_status_t dvdnav_time_search(dvdnav_t *this,
00124 uint64_t time, uint search_to_nearest_cell) {
00125
00126 uint64_t target = time;
00127 uint64_t length = 0;
00128 uint64_t cell_length = 0;
00129 uint64_t prev_length = 0;
00130 uint32_t first_cell_nr, last_cell_nr, cell_nr;
00131 int32_t found;
00132 uint64_t offset = 0;
00133 float diff2 = 1.0;
00134
00135 cell_playback_t *cell;
00136 dvd_state_t *state;
00137 dvdnav_status_t result;
00138
00139 if(this->position_current.still != 0) {
00140 printerr("Cannot seek in a still frame.");
00141 return DVDNAV_STATUS_ERR;
00142 }
00143
00144 pthread_mutex_lock(&this->vm_lock);
00145 state = &(this->vm->state);
00146 if(!state->pgc) {
00147 printerr("No current PGC.");
00148 pthread_mutex_unlock(&this->vm_lock);
00149 return DVDNAV_STATUS_ERR;
00150 }
00151
00152
00153 if (this->pgc_based) {
00154 first_cell_nr = 1;
00155 last_cell_nr = state->pgc->nr_of_cells;
00156 } else {
00157
00158 first_cell_nr = state->pgc->program_map[state->pgN-1];
00159
00160 if(state->pgN < state->pgc->nr_of_programs)
00161 last_cell_nr = state->pgc->program_map[state->pgN] - 1;
00162 else
00163 last_cell_nr = state->pgc->nr_of_cells;
00164 }
00165
00166 found = 0;
00167 for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) {
00168 cell = &(state->pgc->cell_playback[cell_nr-1]);
00169 cell_length = dvdnav_convert_time(&cell->playback_time);
00170 length += cell_length;
00171 if (target <= length) {
00172 offset = (cell->last_sector - cell->first_sector);
00173 diff2 = ((double)target - (double)prev_length) / (double)cell_length;
00174 offset = (diff2 * offset);
00175 target = cell->first_sector;
00176 if (!search_to_nearest_cell)
00177 target += offset;
00178 found = 1;
00179 break;
00180 }
00181 prev_length = length;
00182 }
00183
00184
00185 if(found) {
00186 int32_t vobu;
00187 #ifdef LOG_DEBUG
00188 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n",
00189 cell_nr, first_cell_nr, last_cell_nr);
00190 #endif
00191 if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) {
00192 int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector;
00193
00194 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {
00195 #ifdef LOG_DEBUG
00196 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" ,
00197 state->cellN, state->blockN, target, vobu, start);
00198 #endif
00199 this->vm->hop_channel += HOP_SEEK;
00200 pthread_mutex_unlock(&this->vm_lock);
00201 return DVDNAV_STATUS_OK;
00202 }
00203 }
00204 }
00205
00206 fprintf(MSG_OUT, "libdvdnav: Error when seeking\n");
00207 printerr("Error when seeking.");
00208 pthread_mutex_unlock(&this->vm_lock);
00209 return DVDNAV_STATUS_ERR;
00210 }
00211
00212 dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
00213 uint64_t offset, int32_t origin) {
00214 uint32_t target = 0;
00215 uint32_t length = 0;
00216 uint32_t first_cell_nr, last_cell_nr, cell_nr;
00217 int32_t found;
00218 cell_playback_t *cell;
00219 dvd_state_t *state;
00220 dvdnav_status_t result;
00221
00222 if(this->position_current.still != 0) {
00223 printerr("Cannot seek in a still frame.");
00224 return DVDNAV_STATUS_ERR;
00225 }
00226
00227 result = dvdnav_get_position(this, &target, &length);
00228 if(!result) {
00229 return DVDNAV_STATUS_ERR;
00230 }
00231
00232 pthread_mutex_lock(&this->vm_lock);
00233 state = &(this->vm->state);
00234 if(!state->pgc) {
00235 printerr("No current PGC.");
00236 pthread_mutex_unlock(&this->vm_lock);
00237 return DVDNAV_STATUS_ERR;
00238 }
00239 #ifdef LOG_DEBUG
00240 fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length);
00241 fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);
00242 #endif
00243
00244 switch(origin) {
00245 case SEEK_SET:
00246 if(offset > length) {
00247 printerr("Request to seek behind end.");
00248 pthread_mutex_unlock(&this->vm_lock);
00249 return DVDNAV_STATUS_ERR;
00250 }
00251 target = offset;
00252 break;
00253 case SEEK_CUR:
00254 if(target + offset > length) {
00255 printerr("Request to seek behind end.");
00256 pthread_mutex_unlock(&this->vm_lock);
00257 return DVDNAV_STATUS_ERR;
00258 }
00259 target += offset;
00260 break;
00261 case SEEK_END:
00262 if(offset > length) {
00263 printerr("Request to seek before start.");
00264 pthread_mutex_unlock(&this->vm_lock);
00265 return DVDNAV_STATUS_ERR;
00266 }
00267 target = length - offset;
00268 break;
00269 default:
00270
00271 printerr("Illegal seek mode.");
00272 pthread_mutex_unlock(&this->vm_lock);
00273 return DVDNAV_STATUS_ERR;
00274 }
00275
00276 if (this->pgc_based) {
00277 first_cell_nr = 1;
00278 last_cell_nr = state->pgc->nr_of_cells;
00279 } else {
00280
00281 first_cell_nr = state->pgc->program_map[state->pgN-1];
00282
00283 if(state->pgN < state->pgc->nr_of_programs)
00284 last_cell_nr = state->pgc->program_map[state->pgN] - 1;
00285 else
00286 last_cell_nr = state->pgc->nr_of_cells;
00287 }
00288
00289 found = 0;
00290 for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) {
00291 cell = &(state->pgc->cell_playback[cell_nr-1]);
00292 length += cell->last_sector - cell->first_sector + 1;
00293 if (target >= length) {
00294 target -= length;
00295 } else {
00296
00297 target += cell->first_sector;
00298 found = 1;
00299 break;
00300 }
00301 }
00302
00303 if(found) {
00304 int32_t vobu;
00305 #ifdef LOG_DEBUG
00306 fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n",
00307 cell_nr, first_cell_nr, last_cell_nr);
00308 #endif
00309 if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) {
00310 int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector;
00311
00312 if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {
00313 #ifdef LOG_DEBUG
00314 fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" ,
00315 state->cellN, state->blockN, target, vobu, start);
00316 #endif
00317 this->vm->hop_channel += HOP_SEEK;
00318 pthread_mutex_unlock(&this->vm_lock);
00319 return DVDNAV_STATUS_OK;
00320 }
00321 }
00322 }
00323
00324 fprintf(MSG_OUT, "libdvdnav: Error when seeking\n");
00325 fprintf(MSG_OUT, "libdvdnav: FIXME: Implement seeking to location %u\n", target);
00326 printerr("Error when seeking.");
00327 pthread_mutex_unlock(&this->vm_lock);
00328 return DVDNAV_STATUS_ERR;
00329 }
00330
00331 dvdnav_status_t dvdnav_part_search(dvdnav_t *this, int32_t part) {
00332 int32_t title, old_part;
00333
00334 if (dvdnav_current_title_info(this, &title, &old_part) == DVDNAV_STATUS_OK)
00335 return dvdnav_part_play(this, title, part);
00336 return DVDNAV_STATUS_ERR;
00337 }
00338
00339 dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *this) {
00340
00341 if(!this) {
00342 printerr("Passed a NULL pointer.");
00343 return DVDNAV_STATUS_ERR;
00344 }
00345
00346 pthread_mutex_lock(&this->vm_lock);
00347 if(!this->vm->state.pgc) {
00348 printerr("No current PGC.");
00349 pthread_mutex_unlock(&this->vm_lock);
00350 return DVDNAV_STATUS_ERR;
00351 }
00352
00353 #ifdef LOG_DEBUG
00354 fprintf(MSG_OUT, "libdvdnav: previous chapter\n");
00355 #endif
00356 if (!vm_jump_prev_pg(this->vm)) {
00357 fprintf(MSG_OUT, "libdvdnav: previous chapter failed.\n");
00358 printerr("Skip to previous chapter failed.");
00359 pthread_mutex_unlock(&this->vm_lock);
00360 return DVDNAV_STATUS_ERR;
00361 }
00362 this->position_current.still = 0;
00363 this->vm->hop_channel++;
00364 #ifdef LOG_DEBUG
00365 fprintf(MSG_OUT, "libdvdnav: previous chapter done\n");
00366 #endif
00367 pthread_mutex_unlock(&this->vm_lock);
00368
00369 return DVDNAV_STATUS_OK;
00370 }
00371
00372 dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *this) {
00373
00374 if(!this) {
00375 printerr("Passed a NULL pointer.");
00376 return DVDNAV_STATUS_ERR;
00377 }
00378
00379 pthread_mutex_lock(&this->vm_lock);
00380 if(!this->vm->state.pgc) {
00381 printerr("No current PGC.");
00382 pthread_mutex_unlock(&this->vm_lock);
00383 return DVDNAV_STATUS_ERR;
00384 }
00385
00386 #ifdef LOG_DEBUG
00387 fprintf(MSG_OUT, "libdvdnav: top chapter\n");
00388 #endif
00389 if (!vm_jump_top_pg(this->vm)) {
00390 fprintf(MSG_OUT, "libdvdnav: top chapter failed.\n");
00391 printerr("Skip to top chapter failed.");
00392 pthread_mutex_unlock(&this->vm_lock);
00393 return DVDNAV_STATUS_ERR;
00394 }
00395 this->position_current.still = 0;
00396 this->vm->hop_channel++;
00397 #ifdef LOG_DEBUG
00398 fprintf(MSG_OUT, "libdvdnav: top chapter done\n");
00399 #endif
00400 pthread_mutex_unlock(&this->vm_lock);
00401
00402 return DVDNAV_STATUS_OK;
00403 }
00404
00405 dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) {
00406 vm_t *try_vm;
00407
00408 if(!this) {
00409 printerr("Passed a NULL pointer.");
00410 return DVDNAV_STATUS_ERR;
00411 }
00412
00413 pthread_mutex_lock(&this->vm_lock);
00414 if(!this->vm->state.pgc) {
00415 printerr("No current PGC.");
00416 pthread_mutex_unlock(&this->vm_lock);
00417 return DVDNAV_STATUS_ERR;
00418 }
00419
00420 #ifdef LOG_DEBUG
00421 fprintf(MSG_OUT, "libdvdnav: next chapter\n");
00422 #endif
00423
00424 try_vm = vm_new_copy(this->vm);
00425 if (!vm_jump_next_pg(try_vm) || try_vm->stopped) {
00426 vm_free_copy(try_vm);
00427
00428 try_vm = vm_new_copy(this->vm);
00429 vm_get_next_cell(try_vm);
00430 if (try_vm->stopped) {
00431 vm_free_copy(try_vm);
00432 fprintf(MSG_OUT, "libdvdnav: next chapter failed.\n");
00433 printerr("Skip to next chapter failed.");
00434 pthread_mutex_unlock(&this->vm_lock);
00435 return DVDNAV_STATUS_ERR;
00436 }
00437 }
00438
00439 vm_merge(this->vm, try_vm);
00440 vm_free_copy(try_vm);
00441 this->position_current.still = 0;
00442 this->vm->hop_channel++;
00443 #ifdef LOG_DEBUG
00444 fprintf(MSG_OUT, "libdvdnav: next chapter done\n");
00445 #endif
00446 pthread_mutex_unlock(&this->vm_lock);
00447
00448 return DVDNAV_STATUS_OK;
00449 }
00450
00451 dvdnav_status_t dvdnav_menu_supported(dvdnav_t *this, DVDMenuID_t menu)
00452 {
00453 vm_t *try_vm;
00454
00455 if (!this) {
00456 printerr("Passed a NULL pointer.");
00457 return DVDNAV_STATUS_ERR;
00458 }
00459
00460 pthread_mutex_lock(&this->vm_lock);
00461 if(!this->vm->state.pgc) {
00462 printerr("No current PGC");
00463 pthread_mutex_unlock(&this->vm_lock);
00464 return DVDNAV_STATUS_ERR;
00465 }
00466
00467
00468 try_vm = vm_new_copy(this->vm);
00469 if ((menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) {
00470
00471 if (vm_jump_resume(try_vm) && !try_vm->stopped) {
00472 vm_free_copy(try_vm);
00473 pthread_mutex_unlock(&this->vm_lock);
00474 return DVDNAV_STATUS_OK;
00475 }
00476 }
00477
00478 if (menu == DVD_MENU_Escape) menu = DVD_MENU_Root;
00479
00480 if (vm_jump_menu(try_vm, menu) && !try_vm->stopped) {
00481 vm_free_copy(try_vm);
00482 pthread_mutex_unlock(&this->vm_lock);
00483 return DVDNAV_STATUS_OK;
00484 }
00485
00486 vm_free_copy(try_vm);
00487 printerr("No such menu or menu not reachable.");
00488 pthread_mutex_unlock(&this->vm_lock);
00489 return DVDNAV_STATUS_ERR;
00490 }
00491
00492 dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMenuID_t menu) {
00493 vm_t *try_vm;
00494
00495 if(!this) {
00496 printerr("Passed a NULL pointer.");
00497 return DVDNAV_STATUS_ERR;
00498 }
00499
00500 pthread_mutex_lock(&this->vm_lock);
00501 if(!this->vm->state.pgc) {
00502 printerr("No current PGC.");
00503 pthread_mutex_unlock(&this->vm_lock);
00504 return DVDNAV_STATUS_ERR;
00505 }
00506
00507
00508 try_vm = vm_new_copy(this->vm);
00509 if ( (menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) {
00510
00511 if (vm_jump_resume(try_vm) && !try_vm->stopped) {
00512
00513 vm_merge(this->vm, try_vm);
00514 vm_free_copy(try_vm);
00515 this->position_current.still = 0;
00516 this->vm->hop_channel++;
00517 pthread_mutex_unlock(&this->vm_lock);
00518 return DVDNAV_STATUS_OK;
00519 }
00520 }
00521 if (menu == DVD_MENU_Escape) menu = DVD_MENU_Root;
00522
00523 if (vm_jump_menu(try_vm, menu) && !try_vm->stopped) {
00524
00525 vm_merge(this->vm, try_vm);
00526 vm_free_copy(try_vm);
00527 this->position_current.still = 0;
00528 this->vm->hop_channel++;
00529 pthread_mutex_unlock(&this->vm_lock);
00530 return DVDNAV_STATUS_OK;
00531 } else {
00532 vm_free_copy(try_vm);
00533 printerr("No such menu or menu not reachable.");
00534 pthread_mutex_unlock(&this->vm_lock);
00535 return DVDNAV_STATUS_ERR;
00536 }
00537 }
00538
00539 dvdnav_status_t dvdnav_get_position(dvdnav_t *this, uint32_t *pos,
00540 uint32_t *len) {
00541 uint32_t cur_sector;
00542 int32_t cell_nr, first_cell_nr, last_cell_nr;
00543 cell_playback_t *cell;
00544 dvd_state_t *state;
00545
00546 if(!this || !pos || !len) {
00547 printerr("Passed a NULL pointer.");
00548 return DVDNAV_STATUS_ERR;
00549 }
00550 if(!this->started) {
00551 printerr("Virtual DVD machine not started.");
00552 return DVDNAV_STATUS_ERR;
00553 }
00554
00555 pthread_mutex_lock(&this->vm_lock);
00556 state = &(this->vm->state);
00557 if(!state->pgc || this->vm->stopped) {
00558 printerr("No current PGC.");
00559 pthread_mutex_unlock(&this->vm_lock);
00560 return DVDNAV_STATUS_ERR;
00561 }
00562 if (this->position_current.hop_channel != this->vm->hop_channel ||
00563 this->position_current.domain != state->domain ||
00564 this->position_current.vts != state->vtsN ||
00565 this->position_current.cell_restart != state->cell_restart) {
00566 printerr("New position not yet determined.");
00567 pthread_mutex_unlock(&this->vm_lock);
00568 return DVDNAV_STATUS_ERR;
00569 }
00570
00571
00572 cur_sector = this->vobu.vobu_start + this->vobu.blockN;
00573
00574 if (this->pgc_based) {
00575 first_cell_nr = 1;
00576 last_cell_nr = state->pgc->nr_of_cells;
00577 } else {
00578
00579 first_cell_nr = state->pgc->program_map[state->pgN-1];
00580
00581 if(state->pgN < state->pgc->nr_of_programs)
00582 last_cell_nr = state->pgc->program_map[state->pgN] - 1;
00583 else
00584 last_cell_nr = state->pgc->nr_of_cells;
00585 }
00586
00587 *pos = -1;
00588 *len = 0;
00589 for (cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr++) {
00590 cell = &(state->pgc->cell_playback[cell_nr-1]);
00591 if (cell_nr == state->cellN) {
00592
00593
00594 *pos = *len + cur_sector - cell->first_sector;
00595 }
00596 *len += cell->last_sector - cell->first_sector + 1;
00597 }
00598
00599 assert((signed)*pos != -1);
00600
00601 pthread_mutex_unlock(&this->vm_lock);
00602
00603 return DVDNAV_STATUS_OK;
00604 }
00605
00606 dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *this,
00607 uint32_t *pos,
00608 uint32_t *len) {
00609 uint32_t cur_sector;
00610 uint32_t first_cell_nr;
00611 uint32_t last_cell_nr;
00612 cell_playback_t *first_cell;
00613 cell_playback_t *last_cell;
00614 dvd_state_t *state;
00615
00616 if(!this || !pos || !len) {
00617 printerr("Passed a NULL pointer.");
00618 return DVDNAV_STATUS_ERR;
00619 }
00620
00621 state = &(this->vm->state);
00622 if(!state->pgc) {
00623 printerr("No current PGC.");
00624 return DVDNAV_STATUS_ERR;
00625 }
00626
00627
00628 cur_sector = this->vobu.vobu_start + this->vobu.blockN;
00629
00630
00631 first_cell_nr = state->pgc->program_map[0];
00632 first_cell = &(state->pgc->cell_playback[first_cell_nr-1]);
00633 last_cell_nr = state->pgc->nr_of_cells;
00634 last_cell = &(state->pgc->cell_playback[last_cell_nr-1]);
00635
00636 *pos = cur_sector - first_cell->first_sector;
00637 *len = last_cell->last_sector - first_cell->first_sector;
00638
00639 return DVDNAV_STATUS_OK;
00640 }
00641
00651 dvdnav_status_t dvdnav_time_search_within_cell(dvdnav_t *this,
00652 int relative_time)
00653 {
00654 if(!this) {
00655 printerr("Passed a NULL pointer.");
00656 return DVDNAV_STATUS_ERR;
00657 }
00658
00659 uint32_t cur_vobu, new_vobu = 0, start, offset;
00660 uint32_t first_cell_nr, last_cell_nr, cell_nr;
00661 cell_playback_t *cell;
00662 int i, length, scan_admap;
00663
00664 dsi_t * dsi;
00665 dvd_state_t *state;
00666 int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11,
00667 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
00668 pthread_mutex_lock(&this->vm_lock);
00669 length = relative_time;
00670 state = &(this->vm->state);
00671 cell_nr = state->cellN -1;
00672 cell = &(state->pgc->cell_playback[cell_nr]);
00673 cur_vobu = this->vobu.vobu_start;
00674 scan_admap = 0;
00675
00676 if (this->pgc_based) {
00677 first_cell_nr = 0;
00678 last_cell_nr = state->pgc->nr_of_cells - 1;
00679 } else {
00680 pthread_mutex_unlock(&this->vm_lock);
00681 printerr("dvdnav_time_search_within_cell: works only if pgc_based is enabled");
00682 return DVDNAV_STATUS_ERR;
00683 }
00684
00685 if (length != 0)
00686 {
00687 dsi = dvdnav_get_current_nav_dsi(this);
00688 if (length > 0) {
00689 for (i = 0; i < 19; i++) {
00690 if (stime[i]/2.0 <= length/2.0) {
00691 offset = dsi->vobu_sri.fwda[i];
00692 if (offset >> 31) {
00693 new_vobu = cur_vobu + (offset & 0xffff);
00694 } else {
00695 if (cell_nr == last_cell_nr) {
00696 offset = state->pgc->cell_playback[last_cell_nr].last_sector;
00697 scan_admap = 1;
00698 } else {
00699 cell_nr++;
00700 new_vobu = state->pgc->cell_playback[cell_nr].first_sector;
00701 }
00702 }
00703 break;
00704 }
00705 }
00706 } else {
00707 for (i = 0; i < 19; i++) {
00708 if (stime[18 - i]/2.0 >= abs(length)/2.0)
00709 {
00710 offset = dsi->vobu_sri.bwda[i];
00711 if (offset >> 31) {
00712 new_vobu = cur_vobu - (offset & 0xffff);
00713 } else {
00714 if (cell_nr != first_cell_nr) {
00715 cell_nr--;
00716 offset = state->pgc->cell_playback[cell_nr].last_sector;
00717 scan_admap = 1;
00718 }
00719 }
00720 break;
00721 }
00722 }
00723 }
00724 }
00725
00726 if (scan_admap)
00727 {
00728 if (dvdnav_scan_admap(this, state->domain, offset, &new_vobu) == DVDNAV_STATUS_ERR)
00729 {
00730 pthread_mutex_unlock(&this->vm_lock);
00731 return DVDNAV_STATUS_ERR;
00732 }
00733 }
00734 start = state->pgc->cell_playback[cell_nr].first_sector;
00735 if (vm_jump_cell_block(this->vm, cell_nr+1, new_vobu - start)) {
00736 this->vm->hop_channel += HOP_SEEK;
00737 }
00738 pthread_mutex_unlock(&this->vm_lock);
00739 return DVDNAV_STATUS_OK;
00740 }
00741