00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "config.h"
00028
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include <inttypes.h>
00034 #include <assert.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <fcntl.h>
00038
00039 #include "ifo_types.h"
00040 #include "ifo_read.h"
00041
00042 #include "dvdnav_internal.h"
00043
00044 #ifdef _MSC_VER
00045 #include <io.h>
00046 #endif
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 static link_t play_PGC(vm_t *vm);
00061 static link_t play_PGC_PG(vm_t *vm, int pgN);
00062 static link_t play_PGC_post(vm_t *vm);
00063 static link_t play_PG(vm_t *vm);
00064 static link_t play_Cell(vm_t *vm);
00065 static link_t play_Cell_post(vm_t *vm);
00066
00067
00068 static int process_command(vm_t *vm,link_t link_values);
00069
00070
00071 static int set_TT(vm_t *vm, int tt);
00072 static int set_PTT(vm_t *vm, int tt, int ptt);
00073 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn);
00074 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part);
00075 static int set_FP_PGC(vm_t *vm);
00076 static int set_MENU(vm_t *vm, int menu);
00077 static int set_PGCN(vm_t *vm, int pgcN);
00078 static int set_PGN(vm_t *vm);
00079 static void set_RSMinfo(vm_t *vm, int cellN, int blockN);
00080
00081
00082 static int get_TT(vm_t *vm, int vtsN, int vts_ttn);
00083 static int get_ID(vm_t *vm, int id);
00084 static int get_PGCN(vm_t *vm);
00085
00086 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
00087 static pgcit_t* get_PGCIT(vm_t *vm);
00088
00089
00090
00091
00092 #ifdef TRACE
00093 static void vm_print_current_domain_state(vm_t *vm) {
00094 switch((vm->state).domain) {
00095 case VTS_DOMAIN:
00096 fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n");
00097 break;
00098
00099 case VTSM_DOMAIN:
00100 fprintf(MSG_OUT, "libdvdnav: Video Title Menu Domain: -\n");
00101 break;
00102
00103 case VMGM_DOMAIN:
00104 fprintf(MSG_OUT, "libdvdnav: Video Manager Menu Domain: -\n");
00105 break;
00106
00107 case FP_DOMAIN:
00108 fprintf(MSG_OUT, "libdvdnav: First Play Domain: -\n");
00109 break;
00110
00111 default:
00112 fprintf(MSG_OUT, "libdvdnav: Unknown Domain: -\n");
00113 break;
00114 }
00115 fprintf(MSG_OUT, "libdvdnav: VTS:%d PGC:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n",
00116 (vm->state).vtsN,
00117 get_PGCN(vm),
00118 (vm->state).pgN,
00119 (vm->state).cellN,
00120 (vm->state).blockN,
00121 (vm->state).VTS_TTN_REG,
00122 (vm->state).TTN_REG,
00123 (vm->state).TT_PGCN_REG);
00124 }
00125 #endif
00126
00127 static void dvd_read_name(char *name, char *serial, const char *device) {
00128
00129
00130
00131 off_t off;
00132 int fd, i;
00133 char *pos;
00134 uint8_t data[DVD_VIDEO_LB_LEN];
00135
00136 *name = 0;
00137
00138 fd = open(device, O_RDONLY);
00139 if (fd > 0) {
00140 off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET );
00141 if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) {
00142 off = read( fd, data, DVD_VIDEO_LB_LEN );
00143 if (off == ( (off_t) DVD_VIDEO_LB_LEN )) {
00144 fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
00145 if (data[24] == 8) {
00146
00147 for(i = 25; i < 73; i++) {
00148 if((data[i] == 0)) break;
00149 if((data[i] > 32) && (data[i] < 127)) {
00150 fprintf(MSG_OUT, "%c", data[i]);
00151 } else {
00152 fprintf(MSG_OUT, " ");
00153 }
00154 }
00155
00156 strncpy(name, &data[25], 48);
00157 name[48] = 0;
00158 pos = name + strlen(name);
00159 while (pos >= name && *--pos == ' ');
00160 *++pos = '\0';
00161 }
00162 fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
00163 for(i=73; i < 89; i++ ) {
00164 if((data[i] == 0)) break;
00165 if((data[i] > 32) && (data[i] < 127)) {
00166 fprintf(MSG_OUT, "%c", data[i]);
00167 } else {
00168 fprintf(MSG_OUT, " ");
00169 }
00170 }
00171 strncpy(serial, &data[73], 16);
00172 fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
00173 for(i=89; i < 128; i++ ) {
00174 if((data[i] == 0)) break;
00175 if((data[i] > 32) && (data[i] < 127)) {
00176 fprintf(MSG_OUT, "%c", data[i]);
00177 } else {
00178 fprintf(MSG_OUT, " ");
00179 }
00180 }
00181 fprintf(MSG_OUT, "\n");
00182 } else {
00183 fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n");
00184 }
00185 } else {
00186 fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
00187 }
00188 if (strlen(name) == 0) {
00189
00190
00191 off = lseek( fd, 16 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET );
00192 if( off == ( 16 * (off_t) DVD_VIDEO_LB_LEN ) ) {
00193 off = read( fd, data, DVD_VIDEO_LB_LEN );
00194 if (off == ( (off_t) DVD_VIDEO_LB_LEN )) {
00195
00196 name[49] = 0;
00197 strncpy(name, data + 39, 49);
00198 pos = name + strlen(name);
00199 while (pos >= name && *--pos == ' ');
00200 *++pos = '\0';
00201 }
00202 }
00203 }
00204
00205 if (strlen(name)) {
00206 for (pos = name; pos < strlen(name) + name; pos++) {
00207 if (*pos == '_') *pos = ' ';
00208 }
00209 }
00210 close(fd);
00211 } else {
00212 fprintf(MSG_OUT, "NAME OPEN FAILED\n");
00213 }
00214 }
00215
00216 static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) {
00217 if((vm->state).vtsN == vtsN) {
00218 return 1;
00219 }
00220
00221 if(vm->vtsi != NULL)
00222 ifoClose(vm->vtsi);
00223
00224 vm->vtsi = ifoOpenVTSI(dvd, vtsN);
00225 if(vm->vtsi == NULL) {
00226 fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed\n");
00227 return 0;
00228 }
00229 if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) {
00230 fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed\n");
00231 return 0;
00232 }
00233 if(!ifoRead_PGCIT(vm->vtsi)) {
00234 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed\n");
00235 return 0;
00236 }
00237 if(!ifoRead_PGCI_UT(vm->vtsi)) {
00238 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed\n");
00239 return 0;
00240 }
00241 if(!ifoRead_VOBU_ADMAP(vm->vtsi)) {
00242 fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed\n");
00243 return 0;
00244 }
00245 if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) {
00246 fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n");
00247 return 0;
00248 }
00249 (vm->state).vtsN = vtsN;
00250
00251 return 1;
00252 }
00253
00254
00255
00256
00257 vm_t* vm_new_vm() {
00258 return (vm_t*)calloc(sizeof(vm_t), sizeof(char));
00259 }
00260
00261 void vm_free_vm(vm_t *vm) {
00262 vm_stop(vm);
00263 free(vm);
00264 }
00265
00266
00267
00268
00269 ifo_handle_t *vm_get_vmgi(vm_t *vm) {
00270 return vm->vmgi;
00271 }
00272
00273 ifo_handle_t *vm_get_vtsi(vm_t *vm) {
00274 return vm->vtsi;
00275 }
00276
00277
00278
00279
00280 dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
00281 return vm->dvd;
00282 }
00283
00284
00285
00286
00287 int vm_start(vm_t *vm) {
00288
00289 set_FP_PGC(vm);
00290 process_command(vm, play_PGC(vm));
00291 return !vm->stopped;
00292 }
00293
00294 void vm_stop(vm_t *vm) {
00295 if(vm->vmgi) {
00296 ifoClose(vm->vmgi);
00297 vm->vmgi=NULL;
00298 }
00299 if(vm->vtsi) {
00300 ifoClose(vm->vtsi);
00301 vm->vtsi=NULL;
00302 }
00303 if(vm->dvd) {
00304 DVDClose(vm->dvd);
00305 vm->dvd=NULL;
00306 }
00307 vm->stopped = 1;
00308 }
00309
00310 int vm_reset(vm_t *vm, const char *dvdroot) {
00311
00312 memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM));
00313 memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM));
00314 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
00315 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
00316 memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time));
00317 (vm->state).registers.SPRM[0] = ('e'<<8)|'n';
00318 (vm->state).AST_REG = 15;
00319 (vm->state).SPST_REG = 62;
00320 (vm->state).AGL_REG = 1;
00321 (vm->state).TTN_REG = 1;
00322 (vm->state).VTS_TTN_REG = 1;
00323
00324 (vm->state).PTTN_REG = 1;
00325 (vm->state).HL_BTNN_REG = 1 << 10;
00326 (vm->state).PTL_REG = 15;
00327 (vm->state).registers.SPRM[12] = ('U'<<8)|'S';
00328 (vm->state).registers.SPRM[16] = ('e'<<8)|'n';
00329 (vm->state).registers.SPRM[18] = ('e'<<8)|'n';
00330 (vm->state).registers.SPRM[20] = 0x1;
00331 (vm->state).registers.SPRM[14] = 0x100;
00332
00333 (vm->state).pgN = 0;
00334 (vm->state).cellN = 0;
00335 (vm->state).cell_restart = 0;
00336
00337 (vm->state).domain = FP_DOMAIN;
00338 (vm->state).rsm_vtsN = 0;
00339 (vm->state).rsm_cellN = 0;
00340 (vm->state).rsm_blockN = 0;
00341
00342 (vm->state).vtsN = -1;
00343
00344 if (vm->dvd && dvdroot) {
00345
00346 vm_stop(vm);
00347 }
00348 if (!vm->dvd) {
00349 vm->dvd = DVDOpen(dvdroot);
00350 if(!vm->dvd) {
00351 fprintf(MSG_OUT, "libdvdnav: vm: faild to open/read the DVD\n");
00352 return 0;
00353 }
00354 dvd_read_name(vm->dvd_name, vm->serial_number, dvdroot);
00355 vm->map = remap_loadmap(vm->dvd_name);
00356 vm->vmgi = ifoOpenVMGI(vm->dvd);
00357 if(!vm->vmgi) {
00358 fprintf(MSG_OUT, "libdvdnav: vm: faild to read VIDEO_TS.IFO\n");
00359 return 0;
00360 }
00361 if(!ifoRead_FP_PGC(vm->vmgi)) {
00362 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n");
00363 return 0;
00364 }
00365 if(!ifoRead_TT_SRPT(vm->vmgi)) {
00366 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n");
00367 return 0;
00368 }
00369 if(!ifoRead_PGCI_UT(vm->vmgi)) {
00370 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n");
00371 return 0;
00372 }
00373 if(!ifoRead_PTL_MAIT(vm->vmgi)) {
00374 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n");
00375
00376 }
00377 if(!ifoRead_VTS_ATRT(vm->vmgi)) {
00378 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n");
00379
00380 }
00381 if(!ifoRead_VOBU_ADMAP(vm->vmgi)) {
00382 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n");
00383
00384 }
00385
00386 }
00387 if (vm->vmgi) {
00388 int i, mask;
00389 fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:",
00390 vm->vmgi->vmgi_mat->vmg_category);
00391 for (i = 1, mask = 1; i <= 8; i++, mask <<= 1)
00392 if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0)
00393 fprintf(MSG_OUT, " %d", i);
00394 fprintf(MSG_OUT, "\n");
00395 }
00396 return 1;
00397 }
00398
00399
00400
00401
00402 vm_t *vm_new_copy(vm_t *source) {
00403 vm_t *target = vm_new_vm();
00404 int vtsN;
00405 int pgcN = get_PGCN(source);
00406 int pgN = (source->state).pgN;
00407
00408 assert(pgcN);
00409
00410 memcpy(target, source, sizeof(vm_t));
00411
00412
00413 target->vtsi = NULL;
00414 vtsN = (target->state).vtsN;
00415 if (vtsN > 0) {
00416 (target->state).vtsN = 0;
00417 if (!ifoOpenNewVTSI(target, target->dvd, vtsN))
00418 assert(0);
00419
00420
00421 if (!set_PGCN(target, pgcN))
00422 assert(0);
00423 (target->state).pgN = pgN;
00424 }
00425
00426 return target;
00427 }
00428
00429 void vm_merge(vm_t *target, vm_t *source) {
00430 if(target->vtsi)
00431 ifoClose(target->vtsi);
00432 memcpy(target, source, sizeof(vm_t));
00433 memset(source, 0, sizeof(vm_t));
00434 }
00435
00436 void vm_free_copy(vm_t *vm) {
00437 if(vm->vtsi)
00438 ifoClose(vm->vtsi);
00439 free(vm);
00440 }
00441
00442
00443
00444
00445 void vm_position_get(vm_t *vm, vm_position_t *position) {
00446 position->button = (vm->state).HL_BTNN_REG >> 10;
00447 position->vts = (vm->state).vtsN;
00448 position->domain = (vm->state).domain;
00449 position->spu_channel = (vm->state).SPST_REG;
00450 position->audio_channel = (vm->state).AST_REG;
00451 position->angle_channel = (vm->state).AGL_REG;
00452 position->hop_channel = vm->hop_channel;
00453 position->cell = (vm->state).cellN;
00454 position->cell_restart = (vm->state).cell_restart;
00455 position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
00456 position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time;
00457 position->block = (vm->state).blockN;
00458
00459
00460 if ((vm->state).cellN == (vm->state).pgc->nr_of_cells)
00461 position->still += (vm->state).pgc->still_time;
00462
00463 if (position->still)
00464 return;
00465
00466
00467
00468
00469
00470
00471
00472
00473 if (((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector ==
00474 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_vobu_start_sector) &&
00475 ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
00476 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector < 1024)) {
00477 int time;
00478 int size = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
00479 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
00480 time = ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour >> 4 ) * 36000;
00481 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour & 0x0f) * 3600;
00482 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute >> 4 ) * 600;
00483 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute & 0x0f) * 60;
00484 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second >> 4 ) * 10;
00485 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1;
00486 if (!time || size / time > 30)
00487
00488 return;
00489 if (time > 0xff) time = 0xff;
00490 position->still = time;
00491 }
00492 }
00493
00494 void vm_get_next_cell(vm_t *vm) {
00495 process_command(vm, play_Cell_post(vm));
00496 }
00497
00498
00499
00500
00501 int vm_jump_pg(vm_t *vm, int pg) {
00502 (vm->state).pgN = pg;
00503 process_command(vm, play_PG(vm));
00504 return 1;
00505 }
00506
00507 int vm_jump_cell_block(vm_t *vm, int cell, int block) {
00508 (vm->state).cellN = cell;
00509 process_command(vm, play_Cell(vm));
00510
00511 if ((vm->state).cellN == cell)
00512 (vm->state).blockN = block;
00513 return 1;
00514 }
00515
00516 int vm_jump_title_part(vm_t *vm, int title, int part) {
00517 link_t link;
00518
00519 if(!set_PTT(vm, title, part))
00520 return 0;
00521
00522
00523
00524
00525 link = play_PGC_PG(vm, (vm->state).pgN);
00526 if (link.command != PlayThis)
00527
00528 process_command(vm, play_PG(vm));
00529 else
00530 process_command(vm, link);
00531 return 1;
00532 }
00533
00534 int vm_jump_top_pg(vm_t *vm) {
00535 process_command(vm, play_PG(vm));
00536 return 1;
00537 }
00538
00539 int vm_jump_next_pg(vm_t *vm) {
00540 if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) {
00541
00542 process_command(vm, play_PGC_post(vm));
00543 return 1;
00544 } else {
00545 vm_jump_pg(vm, (vm->state).pgN + 1);
00546 return 1;
00547 }
00548 }
00549
00550 int vm_jump_prev_pg(vm_t *vm) {
00551 if ((vm->state).pgN <= 1) {
00552
00553 if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) {
00554 process_command(vm, play_PGC(vm));
00555 vm_jump_pg(vm, (vm->state).pgc->nr_of_programs);
00556 return 1;
00557 }
00558 return 0;
00559 } else {
00560 vm_jump_pg(vm, (vm->state).pgN - 1);
00561 return 1;
00562 }
00563 }
00564
00565 int vm_jump_up(vm_t *vm) {
00566 if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) {
00567 process_command(vm, play_PGC(vm));
00568 return 1;
00569 }
00570 return 0;
00571 }
00572
00573 int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) {
00574 domain_t old_domain = (vm->state).domain;
00575
00576 switch ((vm->state).domain) {
00577 case VTS_DOMAIN:
00578 set_RSMinfo(vm, 0, (vm->state).blockN);
00579
00580 case VTSM_DOMAIN:
00581 case VMGM_DOMAIN:
00582 switch(menuid) {
00583 case DVD_MENU_Title:
00584 case DVD_MENU_Escape:
00585 (vm->state).domain = VMGM_DOMAIN;
00586 break;
00587 case DVD_MENU_Root:
00588 case DVD_MENU_Subpicture:
00589 case DVD_MENU_Audio:
00590 case DVD_MENU_Angle:
00591 case DVD_MENU_Part:
00592 (vm->state).domain = VTSM_DOMAIN;
00593 break;
00594 }
00595 if(get_PGCIT(vm) && set_MENU(vm, menuid)) {
00596 process_command(vm, play_PGC(vm));
00597 return 1;
00598 } else {
00599 (vm->state).domain = old_domain;
00600 }
00601 break;
00602 case FP_DOMAIN:
00603 break;
00604 }
00605
00606 return 0;
00607 }
00608
00609 int vm_jump_resume(vm_t *vm) {
00610 link_t link_values = { LinkRSM, 0, 0, 0 };
00611
00612 if (!(vm->state).rsm_vtsN)
00613 return 0;
00614 if (!process_command(vm, link_values))
00615 return 0;
00616 return 1;
00617 }
00618
00619 int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) {
00620 link_t link_values;
00621
00622 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values))
00623 return process_command(vm, link_values);
00624 else
00625 return 0;
00626 }
00627
00628
00629
00630
00631 int vm_get_current_menu(vm_t *vm, int *menuid) {
00632 pgcit_t* pgcit;
00633 int pgcn;
00634 pgcn = (vm->state).pgcN;
00635 pgcit = get_PGCIT(vm);
00636 *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ;
00637 return 1;
00638 }
00639
00640 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
00641 vts_ptt_srpt_t *vts_ptt_srpt;
00642 int title, part = 0, vts_ttn;
00643 int found;
00644 int16_t pgcN, pgN;
00645
00646 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt;
00647 pgcN = get_PGCN(vm);
00648 pgN = vm->state.pgN;
00649
00650 found = 0;
00651 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) {
00652 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) {
00653 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) {
00654 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) {
00655 found = 1;
00656 break;
00657 }
00658 if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN &&
00659 vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) {
00660 part--;
00661 found = 1;
00662 break;
00663 }
00664 }
00665 }
00666 if (found) break;
00667 }
00668 vts_ttn++;
00669 part++;
00670
00671 if (!found) {
00672 fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n");
00673 return 0;
00674 }
00675
00676 title = get_TT(vm, vm->state.vtsN, vts_ttn);
00677
00678 #ifdef TRACE
00679 if (title) {
00680 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n");
00681 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
00682 title, part,
00683 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn ,
00684 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn );
00685 }
00686 #endif
00687 *title_result = title;
00688 *part_result = part;
00689 return 1;
00690 }
00691
00692
00693
00694
00695 int vm_get_audio_stream(vm_t *vm, int audioN) {
00696 int streamN = -1;
00697
00698 if((vm->state).domain != VTS_DOMAIN)
00699 audioN = 0;
00700
00701 if(audioN < 8) {
00702
00703 if ((vm->state).pgc->audio_control[audioN].present)
00704 streamN = (vm->state).pgc->audio_control[audioN].s_audio;
00705 }
00706
00707 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
00708 streamN = 0;
00709
00710
00711
00712 return streamN;
00713 }
00714
00715
00716
00717
00718
00719
00720
00721 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) {
00722 int streamN = -1;
00723 int source_aspect = vm_get_video_aspect(vm);
00724
00725 if((vm->state).domain != VTS_DOMAIN)
00726 subpN = 0;
00727
00728 if(subpN < 32) {
00729
00730 if((vm->state).pgc->subp_control[subpN].present) {
00731 if(source_aspect == 0)
00732 streamN = (vm->state).pgc->subp_control[subpN].s_4p3;
00733 if(source_aspect == 3) {
00734 switch (mode) {
00735 case 0:
00736 streamN = (vm->state).pgc->subp_control[subpN].s_wide;
00737 break;
00738 case 1:
00739 streamN = (vm->state).pgc->subp_control[subpN].s_lbox;
00740 break;
00741 case 2:
00742 streamN = (vm->state).pgc->subp_control[subpN].s_panscan;
00743 break;
00744 }
00745 }
00746 }
00747 }
00748 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
00749 streamN = 0;
00750
00751
00752 return streamN;
00753 }
00754
00755 int vm_get_audio_active_stream(vm_t *vm) {
00756 int audioN;
00757 int streamN;
00758 audioN = (vm->state).AST_REG ;
00759 streamN = vm_get_audio_stream(vm, audioN);
00760
00761
00762 if(streamN == -1) {
00763 for(audioN = 0; audioN < 8; audioN++) {
00764 if((vm->state).pgc->audio_control[audioN].present) {
00765 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0)
00766 break;
00767 }
00768 }
00769 }
00770
00771 return streamN;
00772 }
00773
00774 int vm_get_subp_active_stream(vm_t *vm, int mode) {
00775 int subpN;
00776 int streamN;
00777 subpN = (vm->state).SPST_REG & ~0x40;
00778 streamN = vm_get_subp_stream(vm, subpN, mode);
00779
00780
00781 if(streamN == -1) {
00782 for(subpN = 0; subpN < 32; subpN++) {
00783 if((vm->state).pgc->subp_control[subpN].present) {
00784 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0)
00785 break;
00786 }
00787 }
00788 }
00789
00790 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40))
00791
00792 return -1;
00793 else
00794 return (streamN & 0x1F);
00795 }
00796
00797 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) {
00798 *num_avail = 1;
00799 *current = 1;
00800
00801 if((vm->state).domain == VTS_DOMAIN) {
00802 title_info_t *title;
00803
00804 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
00805 return;
00806 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1];
00807 if(title->title_set_nr != (vm->state).vtsN ||
00808 title->vts_ttn != (vm->state).VTS_TTN_REG)
00809 return;
00810 *num_avail = title->nr_of_angles;
00811 *current = (vm->state).AGL_REG;
00812 }
00813 }
00814
00815 int vm_get_audio_stream_count(vm_t *vm) {
00816 int count = 0;
00817 switch ((vm->state).domain) {
00818 case VTS_DOMAIN:
00819 count = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
00820 break;
00821 case VTSM_DOMAIN:
00822 count = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams;
00823 break;
00824 case VMGM_DOMAIN:
00825 case FP_DOMAIN:
00826 count = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams;
00827 break;
00828 }
00829 return count;
00830 }
00831
00832 int vm_get_subp_stream_count(vm_t *vm) {
00833 int count = 0;
00834 switch ((vm->state).domain) {
00835 case VTS_DOMAIN:
00836 count = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
00837 break;
00838 case VTSM_DOMAIN:
00839 count = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams;
00840 break;
00841 case VMGM_DOMAIN:
00842 case FP_DOMAIN:
00843 count = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams;
00844 break;
00845 }
00846 return count;
00847 }
00848
00849
00850 void vm_get_video_res(vm_t *vm, int *width, int *height) {
00851 video_attr_t attr = vm_get_video_attr(vm);
00852
00853 if(attr.video_format != 0)
00854 *height = 576;
00855 else
00856 *height = 480;
00857 switch(attr.picture_size) {
00858 case 0:
00859 *width = 720;
00860 break;
00861 case 1:
00862 *width = 704;
00863 break;
00864 case 2:
00865 *width = 352;
00866 break;
00867 case 3:
00868 *width = 352;
00869 *height /= 2;
00870 break;
00871 }
00872 }
00873
00874 int vm_get_video_aspect(vm_t *vm) {
00875 int aspect = vm_get_video_attr(vm).display_aspect_ratio;
00876
00877 assert(aspect == 0 || aspect == 3);
00878 (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
00879 (vm->state).registers.SPRM[14] |= aspect << 10;
00880
00881 return aspect;
00882 }
00883
00884 int vm_get_video_scale_permission(vm_t *vm) {
00885 return vm_get_video_attr(vm).permitted_df;
00886 }
00887
00888 int vm_get_video_format(vm_t *vm) {
00889 return vm_get_video_attr(vm).video_format;
00890 }
00891
00892 video_attr_t vm_get_video_attr(vm_t *vm) {
00893 switch ((vm->state).domain) {
00894 case VTS_DOMAIN:
00895 return vm->vtsi->vtsi_mat->vts_video_attr;
00896 case VTSM_DOMAIN:
00897 return vm->vtsi->vtsi_mat->vtsm_video_attr;
00898 case VMGM_DOMAIN:
00899 case FP_DOMAIN:
00900 return vm->vmgi->vmgi_mat->vmgm_video_attr;
00901 default:
00902 abort();
00903 }
00904 }
00905
00906 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) {
00907 switch ((vm->state).domain) {
00908 case VTS_DOMAIN:
00909 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
00910 case VTSM_DOMAIN:
00911 return vm->vtsi->vtsi_mat->vtsm_audio_attr;
00912 case VMGM_DOMAIN:
00913 case FP_DOMAIN:
00914 return vm->vmgi->vmgi_mat->vmgm_audio_attr;
00915 default:
00916 abort();
00917 }
00918 }
00919
00920 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) {
00921 switch ((vm->state).domain) {
00922 case VTS_DOMAIN:
00923 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
00924 case VTSM_DOMAIN:
00925 return vm->vtsi->vtsi_mat->vtsm_subp_attr;
00926 case VMGM_DOMAIN:
00927 case FP_DOMAIN:
00928 return vm->vmgi->vmgi_mat->vmgm_subp_attr;
00929 default:
00930 abort();
00931 }
00932 }
00933
00934
00935
00936
00937 static link_t play_PGC(vm_t *vm) {
00938 link_t link_values;
00939
00940 #ifdef TRACE
00941 fprintf(MSG_OUT, "libdvdnav: play_PGC:");
00942 if((vm->state).domain != FP_DOMAIN) {
00943 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
00944 } else {
00945 fprintf(MSG_OUT, " first_play_pgc\n");
00946 }
00947 #endif
00948
00949
00950
00951
00952
00953 (vm->state).pgN = 1;
00954 (vm->state).cellN = 0;
00955 (vm->state).blockN = 0;
00956
00957
00958
00959
00960
00961
00962 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
00963 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
00964 (vm->state).pgc->command_tbl->nr_of_pre,
00965 &(vm->state).registers, &link_values)) {
00966
00967 return link_values;
00968 } else {
00969 #ifdef TRACE
00970 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
00971 #endif
00972 }
00973 }
00974 return play_PG(vm);
00975 }
00976
00977 static link_t play_PGC_PG(vm_t *vm, int pgN) {
00978 link_t link_values;
00979
00980 #ifdef TRACE
00981 fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:");
00982 if((vm->state).domain != FP_DOMAIN) {
00983 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
00984 } else {
00985 fprintf(MSG_OUT, " first_play_pgc\n");
00986 }
00987 #endif
00988
00989
00990
00991
00992
00993 (vm->state).pgN = pgN;
00994 (vm->state).cellN = 0;
00995 (vm->state).blockN = 0;
00996
00997
00998
00999
01000
01001
01002 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
01003 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
01004 (vm->state).pgc->command_tbl->nr_of_pre,
01005 &(vm->state).registers, &link_values)) {
01006
01007 return link_values;
01008 } else {
01009 #ifdef TRACE
01010 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
01011 #endif
01012 }
01013 }
01014 return play_PG(vm);
01015 }
01016
01017 static link_t play_PGC_post(vm_t *vm) {
01018 link_t link_values;
01019
01020 #ifdef TRACE
01021 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
01022 #endif
01023
01024
01025
01026
01027
01028
01029 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post &&
01030 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds,
01031 (vm->state).pgc->command_tbl->nr_of_post,
01032 &(vm->state).registers, &link_values)) {
01033 return link_values;
01034 }
01035
01036 #ifdef TRACE
01037 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n");
01038 #endif
01039
01040 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) {
01041 link_values.command = Exit;
01042 return link_values;
01043 }
01044 return play_PGC(vm);
01045 }
01046
01047 static link_t play_PG(vm_t *vm) {
01048 #ifdef TRACE
01049 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN);
01050 #endif
01051
01052 assert((vm->state).pgN > 0);
01053 if((vm->state).pgN > (vm->state).pgc->nr_of_programs) {
01054 #ifdef TRACE
01055 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n",
01056 (vm->state).pgN, (vm->state).pgc->nr_of_programs );
01057 #endif
01058 assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1);
01059 return play_PGC_post(vm);
01060 }
01061
01062 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1];
01063
01064 return play_Cell(vm);
01065 }
01066
01067 static link_t play_Cell(vm_t *vm) {
01068 static const link_t play_this = {PlayThis, 0, 0, 0};
01069
01070 #ifdef TRACE
01071 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN);
01072 #endif
01073
01074 assert((vm->state).cellN > 0);
01075 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) {
01076 #ifdef TRACE
01077 fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n",
01078 (vm->state).cellN, (vm->state).pgc->nr_of_cells );
01079 #endif
01080 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1);
01081 return play_PGC_post(vm);
01082 }
01083
01084
01085 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
01086 case 0:
01087 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
01088 break;
01089 case 1:
01090 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
01091 case 0:
01092 assert(0);
01093 break;
01094 case 1:
01095
01096 (vm->state).cellN += (vm->state).AGL_REG - 1;
01097 #ifdef STRICT
01098 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells);
01099 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0);
01100 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1);
01101 #else
01102 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) ||
01103 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) ||
01104 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) {
01105 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n");
01106 (vm->state).cellN -= (vm->state).AGL_REG - 1;
01107 }
01108 #endif
01109 break;
01110 case 2:
01111 case 3:
01112 default:
01113 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
01114 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
01115 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
01116 assert(0);
01117 }
01118 break;
01119 case 2:
01120 case 3:
01121
01122 default:
01123 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n");
01124 }
01125
01126
01127 if(!set_PGN(vm)) {
01128
01129 assert(0);
01130 return play_PGC_post(vm);
01131 }
01132 (vm->state).cell_restart++;
01133 (vm->state).blockN = 0;
01134 #ifdef TRACE
01135 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n");
01136 #endif
01137 return play_this;
01138 }
01139
01140 static link_t play_Cell_post(vm_t *vm) {
01141 cell_playback_t *cell;
01142
01143 #ifdef TRACE
01144 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN);
01145 #endif
01146
01147 cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1];
01148
01149
01150
01151
01152 if(cell->cell_cmd_nr != 0) {
01153 link_t link_values;
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164 if ((vm->state).pgc->command_tbl != NULL &&
01165 (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) {
01166 #ifdef TRACE
01167 fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n");
01168 #endif
01169 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1,
01170 &(vm->state).registers, &link_values)) {
01171 return link_values;
01172 } else {
01173 #ifdef TRACE
01174 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n");
01175 #endif
01176 }
01177 } else {
01178 #ifdef TRACE
01179 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n");
01180 #endif
01181 }
01182 }
01183
01184
01185
01186 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
01187 case 0:
01188 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
01189 (vm->state).cellN++;
01190 break;
01191 case 1:
01192 case 2:
01193 case 3:
01194 default:
01195 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
01196 case 0:
01197 assert(0);
01198 break;
01199 case 1:
01200
01201 (vm->state).cellN++;
01202 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells &&
01203 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) {
01204 (vm->state).cellN++;
01205 }
01206 break;
01207 case 2:
01208 case 3:
01209 default:
01210 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
01211 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
01212 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
01213 assert(0);
01214 }
01215 break;
01216 }
01217
01218
01219 if(!set_PGN(vm)) {
01220 #ifdef TRACE
01221 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n");
01222 #endif
01223 return play_PGC_post(vm);
01224 }
01225 return play_Cell(vm);
01226 }
01227
01228
01229
01230
01231 static int process_command(vm_t *vm, link_t link_values) {
01232
01233 while(link_values.command != PlayThis) {
01234
01235 #ifdef TRACE
01236 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n");
01237 vm_print_link(link_values);
01238 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command,
01239 link_values.data1, link_values.data2, link_values.data3);
01240 vm_print_current_domain_state(vm);
01241 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n");
01242 #endif
01243
01244 switch(link_values.command) {
01245 case LinkNoLink:
01246
01247 if(link_values.data1 != 0)
01248 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01249 return 0;
01250
01251 case LinkTopC:
01252
01253
01254 if(link_values.data1 != 0)
01255 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01256 link_values = play_Cell(vm);
01257 break;
01258 case LinkNextC:
01259
01260
01261 if(link_values.data1 != 0)
01262 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01263 (vm->state).cellN += 1;
01264 link_values = play_Cell(vm);
01265 break;
01266 case LinkPrevC:
01267
01268
01269 if(link_values.data1 != 0)
01270 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01271 assert((vm->state).cellN > 1);
01272 (vm->state).cellN -= 1;
01273 link_values = play_Cell(vm);
01274 break;
01275
01276 case LinkTopPG:
01277
01278
01279 if(link_values.data1 != 0)
01280 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01281 link_values = play_PG(vm);
01282 break;
01283 case LinkNextPG:
01284
01285
01286 if(link_values.data1 != 0)
01287 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01288 (vm->state).pgN += 1;
01289 link_values = play_PG(vm);
01290 break;
01291 case LinkPrevPG:
01292
01293
01294 if(link_values.data1 != 0)
01295 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01296 assert((vm->state).pgN > 1);
01297 (vm->state).pgN -= 1;
01298 link_values = play_PG(vm);
01299 break;
01300
01301 case LinkTopPGC:
01302
01303
01304 if(link_values.data1 != 0)
01305 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01306 link_values = play_PGC(vm);
01307 break;
01308 case LinkNextPGC:
01309
01310
01311 if(link_values.data1 != 0)
01312 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01313 assert((vm->state).pgc->next_pgc_nr != 0);
01314 if(set_PGCN(vm, (vm->state).pgc->next_pgc_nr))
01315 link_values = play_PGC(vm);
01316 else
01317 link_values.command = Exit;
01318 break;
01319 case LinkPrevPGC:
01320
01321
01322 if(link_values.data1 != 0)
01323 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01324 assert((vm->state).pgc->prev_pgc_nr != 0);
01325 if(set_PGCN(vm, (vm->state).pgc->prev_pgc_nr))
01326 link_values = play_PGC(vm);
01327 else
01328 link_values.command = Exit;
01329 break;
01330 case LinkGoUpPGC:
01331
01332
01333 if(link_values.data1 != 0)
01334 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01335 assert((vm->state).pgc->goup_pgc_nr != 0);
01336 if(set_PGCN(vm, (vm->state).pgc->goup_pgc_nr))
01337 link_values = play_PGC(vm);
01338 else
01339 link_values.command = Exit;
01340 break;
01341 case LinkTailPGC:
01342
01343
01344 if(link_values.data1 != 0)
01345 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01346 link_values = play_PGC_post(vm);
01347 break;
01348
01349 case LinkRSM:
01350 {
01351
01352 int i;
01353
01354
01355 if (!(vm->state).rsm_vtsN) {
01356 fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n");
01357 link_values.command = Exit;
01358 break;
01359 }
01360
01361 (vm->state).domain = VTS_DOMAIN;
01362 if (!ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN))
01363 assert(0);
01364 set_PGCN(vm, (vm->state).rsm_pgcN);
01365
01366
01367
01368
01369 for(i = 0; i < 5; i++) {
01370 (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i];
01371 }
01372
01373 if(link_values.data1 != 0)
01374 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01375
01376 if((vm->state).rsm_cellN == 0) {
01377 assert((vm->state).cellN);
01378 (vm->state).pgN = 1;
01379 link_values = play_PG(vm);
01380 } else {
01381
01382 (vm->state).cellN = (vm->state).rsm_cellN;
01383 link_values.command = PlayThis;
01384 link_values.data1 = (vm->state).rsm_blockN & 0xffff;
01385 link_values.data2 = (vm->state).rsm_blockN >> 16;
01386 if(!set_PGN(vm)) {
01387
01388 assert(0);
01389 link_values.command = LinkTailPGC;
01390 link_values.data1 = 0;
01391 }
01392 }
01393 }
01394 break;
01395 case LinkPGCN:
01396
01397 if(!set_PGCN(vm, link_values.data1))
01398 assert(0);
01399 link_values = play_PGC(vm);
01400 break;
01401 case LinkPTTN:
01402
01403
01404
01405 assert((vm->state).domain == VTS_DOMAIN);
01406 if(link_values.data2 != 0)
01407 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01408 if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1))
01409 assert(0);
01410 link_values = play_PG(vm);
01411 break;
01412 case LinkPGN:
01413
01414
01415 if(link_values.data2 != 0)
01416 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01417
01418 (vm->state).pgN = link_values.data1;
01419 link_values = play_PG(vm);
01420 break;
01421 case LinkCN:
01422
01423
01424 if(link_values.data2 != 0)
01425 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01426
01427 (vm->state).cellN = link_values.data1;
01428 link_values = play_Cell(vm);
01429 break;
01430
01431 case Exit:
01432 vm->stopped = 1;
01433 return 0;
01434
01435 case JumpTT:
01436
01437
01438
01439
01440
01441 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01442 if(set_TT(vm, link_values.data1))
01443 link_values = play_PGC(vm);
01444 else
01445 link_values.command = Exit;
01446 break;
01447 case JumpVTS_TT:
01448
01449
01450
01451
01452
01453 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN);
01454 if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1))
01455 assert(0);
01456 link_values = play_PGC(vm);
01457 break;
01458 case JumpVTS_PTT:
01459
01460
01461
01462
01463
01464 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN);
01465 if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2))
01466 assert(0);
01467 link_values = play_PGC_PG(vm, (vm->state).pgN);
01468 break;
01469
01470 case JumpSS_FP:
01471
01472
01473
01474
01475 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
01476 if (!set_FP_PGC(vm))
01477 assert(0);
01478 link_values = play_PGC(vm);
01479 break;
01480 case JumpSS_VMGM_MENU:
01481
01482
01483
01484 assert((vm->state).domain != VTS_DOMAIN);
01485 (vm->state).domain = VMGM_DOMAIN;
01486 if(!set_MENU(vm, link_values.data1))
01487 assert(0);
01488 link_values = play_PGC(vm);
01489 break;
01490 case JumpSS_VTSM:
01491
01492
01493
01494
01495
01496
01497 if(link_values.data1 != 0) {
01498 if (link_values.data1 != (vm->state).vtsN) {
01499
01500 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01501 (vm->state).domain = VTSM_DOMAIN;
01502 if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1))
01503 assert(0);
01504 } else {
01505
01506
01507 assert((vm->state).domain == VTSM_DOMAIN ||
01508 (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01509 (vm->state).domain = VTSM_DOMAIN;
01510 }
01511 } else {
01512
01513 assert((vm->state).domain == VTSM_DOMAIN);
01514 }
01515
01516
01517
01518 (vm->state).VTS_TTN_REG = link_values.data2;
01519
01520
01521 (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG);
01522 if(!set_MENU(vm, link_values.data3))
01523 assert(0);
01524 link_values = play_PGC(vm);
01525 break;
01526 case JumpSS_VMGM_PGC:
01527
01528
01529 assert((vm->state).domain != VTS_DOMAIN);
01530 (vm->state).domain = VMGM_DOMAIN;
01531 if(!set_PGCN(vm, link_values.data1))
01532 assert(0);
01533 link_values = play_PGC(vm);
01534 break;
01535
01536 case CallSS_FP:
01537
01538 assert((vm->state).domain == VTS_DOMAIN);
01539
01540 set_RSMinfo(vm, link_values.data1, 0);
01541 set_FP_PGC(vm);
01542 link_values = play_PGC(vm);
01543 break;
01544 case CallSS_VMGM_MENU:
01545
01546
01547 assert((vm->state).domain == VTS_DOMAIN);
01548
01549 set_RSMinfo(vm, link_values.data2, 0);
01550 (vm->state).domain = VMGM_DOMAIN;
01551 if(!set_MENU(vm, link_values.data1))
01552 assert(0);
01553 link_values = play_PGC(vm);
01554 break;
01555 case CallSS_VTSM:
01556
01557
01558 assert((vm->state).domain == VTS_DOMAIN);
01559
01560 set_RSMinfo(vm, link_values.data2, 0);
01561 (vm->state).domain = VTSM_DOMAIN;
01562 if(!set_MENU(vm, link_values.data1))
01563 assert(0);
01564 link_values = play_PGC(vm);
01565 break;
01566 case CallSS_VMGM_PGC:
01567
01568
01569 assert((vm->state).domain == VTS_DOMAIN);
01570
01571 set_RSMinfo(vm, link_values.data2, 0);
01572 (vm->state).domain = VMGM_DOMAIN;
01573 if(!set_PGCN(vm, link_values.data1))
01574 assert(0);
01575 link_values = play_PGC(vm);
01576 break;
01577 case PlayThis:
01578
01579 assert(0);
01580 break;
01581 }
01582
01583 #ifdef TRACE
01584 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n");
01585 vm_print_current_domain_state(vm);
01586 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n");
01587 #endif
01588
01589 }
01590 (vm->state).blockN = link_values.data1 | (link_values.data2 << 16);
01591 return 1;
01592 }
01593
01594
01595
01596
01597 static int set_TT(vm_t *vm, int tt) {
01598 return set_PTT(vm, tt, 1);
01599 }
01600
01601 static int set_PTT(vm_t *vm, int tt, int ptt) {
01602 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
01603 return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
01604 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt);
01605 }
01606
01607 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) {
01608 return set_VTS_PTT(vm, vtsN, vts_ttn, 1);
01609 }
01610
01611 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) {
01612 int pgcN, pgN, res;
01613
01614 (vm->state).domain = VTS_DOMAIN;
01615
01616 if (vtsN != (vm->state).vtsN)
01617 if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN))
01618 return 0;
01619
01620 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
01621 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) {
01622 return 0;
01623 }
01624
01625 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn;
01626 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn;
01627
01628 (vm->state).TT_PGCN_REG = pgcN;
01629 (vm->state).PTTN_REG = part;
01630 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
01631 assert( (vm->state.TTN_REG) != 0 );
01632 (vm->state).VTS_TTN_REG = vts_ttn;
01633 (vm->state).vtsN = vtsN;
01634
01635
01636 res = set_PGCN(vm, pgcN);
01637 (vm->state).pgN = pgN;
01638 return res;
01639 }
01640
01641 static int set_FP_PGC(vm_t *vm) {
01642 (vm->state).domain = FP_DOMAIN;
01643 if (!vm->vmgi->first_play_pgc) {
01644 return set_PGCN(vm, 1);
01645 }
01646 (vm->state).pgc = vm->vmgi->first_play_pgc;
01647 (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc;
01648 return 1;
01649 }
01650
01651
01652 static int set_MENU(vm_t *vm, int menu) {
01653 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
01654 return set_PGCN(vm, get_ID(vm, menu));
01655 }
01656
01657 static int set_PGCN(vm_t *vm, int pgcN) {
01658 pgcit_t *pgcit;
01659
01660 pgcit = get_PGCIT(vm);
01661 assert(pgcit != NULL);
01662
01663 vm->pgcN_invalid = 0;
01664
01665 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
01666 #ifdef TRACE
01667 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);
01668 #endif
01669 vm->pgcN_invalid = 1;
01670 return 0;
01671 }
01672
01673 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc;
01674 (vm->state).pgcN = pgcN;
01675 (vm->state).pgN = 1;
01676
01677 if((vm->state).domain == VTS_DOMAIN)
01678 (vm->state).TT_PGCN_REG = pgcN;
01679
01680 return 1;
01681 }
01682
01683
01684 static int set_PGN(vm_t *vm) {
01685 int new_pgN = 0;
01686
01687 while(new_pgN < (vm->state).pgc->nr_of_programs
01688 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN])
01689 new_pgN++;
01690
01691 if(new_pgN == (vm->state).pgc->nr_of_programs)
01692 if((vm->state).cellN > (vm->state).pgc->nr_of_cells)
01693 return 0;
01694
01695 (vm->state).pgN = new_pgN;
01696
01697 if((vm->state).domain == VTS_DOMAIN) {
01698 playback_type_t *pb_ty;
01699 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
01700 return 0;
01701 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
01702 if(pb_ty->multi_or_random_pgc_title == 0) {
01703 int dummy, part;
01704 vm_get_current_title_part(vm, &dummy, &part);
01705 (vm->state).PTTN_REG = part;
01706 } else {
01707
01708 fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n");
01709 }
01710 }
01711 return 1;
01712 }
01713
01714
01715 static void set_RSMinfo(vm_t *vm, int cellN, int blockN) {
01716 int i;
01717
01718 if(cellN) {
01719 (vm->state).rsm_cellN = cellN;
01720 (vm->state).rsm_blockN = blockN;
01721 } else {
01722 (vm->state).rsm_cellN = (vm->state).cellN;
01723 (vm->state).rsm_blockN = blockN;
01724 }
01725 (vm->state).rsm_vtsN = (vm->state).vtsN;
01726 (vm->state).rsm_pgcN = get_PGCN(vm);
01727
01728
01729
01730 for(i = 0; i < 5; i++) {
01731 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i];
01732 }
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) {
01743 int i;
01744 int tt=0;
01745
01746 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) {
01747 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN &&
01748 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) {
01749 tt=i;
01750 break;
01751 }
01752 }
01753 return tt;
01754 }
01755
01756
01757
01758
01759 static int get_ID(vm_t *vm, int id) {
01760 int pgcN, i;
01761 pgcit_t *pgcit;
01762
01763
01764 pgcit = get_PGCIT(vm);
01765 assert(pgcit != NULL);
01766 #ifdef TRACE
01767 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id);
01768 #endif
01769
01770
01771 id |=0x80;
01772
01773
01774 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01775 if( (pgcit->pgci_srp[i].entry_id) == id) {
01776 pgcN = i + 1;
01777 #ifdef TRACE
01778 fprintf(MSG_OUT, "libdvdnav: Found menu.\n");
01779 #endif
01780 return pgcN;
01781 }
01782 }
01783 #ifdef TRACE
01784 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f);
01785 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01786 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) {
01787 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n",
01788 pgcit->pgci_srp[i].entry_id & 0x7f);
01789 }
01790 }
01791 #endif
01792 return 0;
01793 }
01794
01795
01796 static int get_PGCN(vm_t *vm) {
01797 pgcit_t *pgcit;
01798 int pgcN = 1;
01799
01800 pgcit = get_PGCIT(vm);
01801
01802 if (pgcit) {
01803 while(pgcN <= pgcit->nr_of_pgci_srp) {
01804 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) {
01805 assert((vm->state).pgcN == pgcN);
01806 return pgcN;
01807 }
01808 pgcN++;
01809 }
01810 }
01811 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n",
01812 (vm->state).domain);
01813 return 0;
01814 }
01815
01816 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) {
01817 int i;
01818
01819 if(h == NULL || h->pgci_ut == NULL) {
01820 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n");
01821 return NULL;
01822 }
01823
01824 i = 0;
01825 while(i < h->pgci_ut->nr_of_lus
01826 && h->pgci_ut->lu[i].lang_code != lang)
01827 i++;
01828 if(i == h->pgci_ut->nr_of_lus) {
01829 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n",
01830 (char)(lang >> 8), (char)(lang & 0xff),
01831 (char)(h->pgci_ut->lu[0].lang_code >> 8),
01832 (char)(h->pgci_ut->lu[0].lang_code & 0xff));
01833 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: ");
01834 for(i = 0; i < h->pgci_ut->nr_of_lus; i++) {
01835 fprintf(MSG_OUT, "%c%c ",
01836 (char)(h->pgci_ut->lu[i].lang_code >> 8),
01837 (char)(h->pgci_ut->lu[i].lang_code & 0xff));
01838 }
01839 fprintf(MSG_OUT, "\n");
01840 i = 0;
01841 }
01842
01843 return h->pgci_ut->lu[i].pgcit;
01844 }
01845
01846
01847 static pgcit_t* get_PGCIT(vm_t *vm) {
01848 pgcit_t *pgcit;
01849
01850 switch ((vm->state).domain) {
01851 case VTS_DOMAIN:
01852 pgcit = vm->vtsi->vts_pgcit;
01853 break;
01854 case VTSM_DOMAIN:
01855 pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]);
01856 break;
01857 case VMGM_DOMAIN:
01858 case FP_DOMAIN:
01859 pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]);
01860 break;
01861 default:
01862 abort();
01863 }
01864
01865 return pgcit;
01866 }
01867
01868
01869
01870
01871 #ifdef TRACE
01872 void vm_position_print(vm_t *vm, vm_position_t *position) {
01873 fprintf(MSG_OUT, "libdvdnav: But=%x Spu=%x Aud=%x Ang=%x Hop=%x vts=%x dom=%x cell=%x cell_restart=%x cell_start=%x still=%x block=%x\n",
01874 position->button,
01875 position->spu_channel,
01876 position->audio_channel,
01877 position->angle_channel,
01878 position->hop_channel,
01879 position->vts,
01880 position->domain,
01881 position->cell,
01882 position->cell_restart,
01883 position->cell_start,
01884 position->still,
01885 position->block);
01886 }
01887 #endif
01888