📄 vm.c
字号:
/* BUTTON number:data2 */ if(link_values.data2 != 0) (vm->state).HL_BTNN_REG = link_values.data2 << 10; /* Update any other state, pgN, PTTN perhaps? */ (vm->state).cellN = link_values.data1; link_values = play_Cell(vm); break; case Exit: vm->stopped = 1; return 0; case JumpTT: /* Jump to VTS Title Domain */ /* Only allowed from the First Play domain(PGC) */ /* or the Video Manager domain (VMG) */ /* Stop SPRM9 Timer */ /* Set SPRM1 and SPRM2 */ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ if(set_TT(vm, link_values.data1)) link_values = play_PGC(vm); else link_values.command = Exit; break; case JumpVTS_TT: /* Jump to Title:data1 in same VTS Title Domain */ /* Only allowed from the VTS Menu Domain(VTSM) */ /* or the Video Title Set Domain(VTS) */ /* Stop SPRM9 Timer */ /* Set SPRM1 and SPRM2 */ assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case JumpVTS_PTT: /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ /* Only allowed from the VTS Menu Domain(VTSM) */ /* or the Video Title Set Domain(VTS) */ /* Stop SPRM9 Timer */ /* Set SPRM1 and SPRM2 */ assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2)) assert(0); link_values = play_PGC_PG(vm, (vm->state).pgN); break; case JumpSS_FP: /* Jump to First Play Domain */ /* Only allowed from the VTS Menu Domain(VTSM) */ /* or the Video Manager domain (VMG) */ /* Stop SPRM9 Timer and any GPRM counters */ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */ if (!set_FP_PGC(vm)) assert(0); link_values = play_PGC(vm); break; case JumpSS_VMGM_MENU: /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */ /* Allowed from anywhere except the VTS Title domain */ /* Stop SPRM9 Timer and any GPRM counters */ assert((vm->state).domain != VTS_DOMAIN); /* ?? */ (vm->state).domain = VMGM_DOMAIN; if(!set_MENU(vm, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case JumpSS_VTSM: /* Jump to a menu in Video Title domain, */ /* or to a Menu is the current VTS */ /* Stop SPRM9 Timer and any GPRM counters */ /* ifoOpenNewVTSI:data1 */ /* VTS_TTN_REG:data2 */ /* get_MENU:data3 */ if(link_values.data1 != 0) { if (link_values.data1 != (vm->state).vtsN) { /* the normal case */ assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ (vm->state).domain = VTSM_DOMAIN; if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1)) /* Also sets (vm->state).vtsN */ assert(0); } else { /* This happens on some discs like "Captain Scarlet & the Mysterons" or * the German RC2 of "Anatomie" in VTSM. */ assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ (vm->state).domain = VTSM_DOMAIN; } } else { /* This happens on 'The Fifth Element' region 2. */ assert((vm->state).domain == VTSM_DOMAIN); } /* I don't know what title is supposed to be used for. */ /* Alien or Aliens has this != 1, I think. */ /* assert(link_values.data2 == 1); */ (vm->state).VTS_TTN_REG = link_values.data2; /* TTN_REG (SPRM4), VTS_TTN_REG (SPRM5), TT_PGCN_REG (SPRM6) are linked, */ /* so if one changes, the others must change to match it. */ (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG); if(!set_MENU(vm, link_values.data3)) assert(0); link_values = play_PGC(vm); break; case JumpSS_VMGM_PGC: /* set_PGCN:data1 */ /* Stop SPRM9 Timer and any GPRM counters */ assert((vm->state).domain != VTS_DOMAIN); /* ?? */ (vm->state).domain = VMGM_DOMAIN; if(!set_PGCN(vm, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case CallSS_FP: /* set_RSMinfo:data1 */ assert((vm->state).domain == VTS_DOMAIN); /* ?? */ /* Must be called before domain is changed */ set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0); set_FP_PGC(vm); link_values = play_PGC(vm); break; case CallSS_VMGM_MENU: /* set_MENU:data1 */ /* set_RSMinfo:data2 */ assert((vm->state).domain == VTS_DOMAIN); /* ?? */ /* Must be called before domain is changed */ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); (vm->state).domain = VMGM_DOMAIN; if(!set_MENU(vm, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case CallSS_VTSM: /* set_MENU:data1 */ /* set_RSMinfo:data2 */ assert((vm->state).domain == VTS_DOMAIN); /* ?? */ /* Must be called before domain is changed */ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); (vm->state).domain = VTSM_DOMAIN; if(!set_MENU(vm, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case CallSS_VMGM_PGC: /* set_PGC:data1 */ /* set_RSMinfo:data2 */ assert((vm->state).domain == VTS_DOMAIN); /* ?? */ /* Must be called before domain is changed */ set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); (vm->state).domain = VMGM_DOMAIN; if(!set_PGCN(vm, link_values.data1)) assert(0); link_values = play_PGC(vm); break; case PlayThis: /* Should never happen. */ assert(0); break; }#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: After printout starts:\n"); vm_print_current_domain_state(vm); fprintf(MSG_OUT, "libdvdnav: After printout ends.\n");#endif } (vm->state).blockN = link_values.data1 | (link_values.data2 << 16); return 1;}/* Set functions */static int set_TT(vm_t *vm, int tt) { return set_PTT(vm, tt, 1);}static int set_PTT(vm_t *vm, int tt, int ptt) { assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts); return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr, vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt);}static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) { return set_VTS_PTT(vm, vtsN, vts_ttn, 1);}static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) { int pgcN, pgN, res; (vm->state).domain = VTS_DOMAIN; if (vtsN != (vm->state).vtsN) if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN)) /* Also sets (vm->state).vtsN */ return 0; if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) || (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) { return 0; } pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn; pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn; (vm->state).TT_PGCN_REG = pgcN; (vm->state).PTTN_REG = part; (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn); assert( (vm->state.TTN_REG) != 0 ); (vm->state).VTS_TTN_REG = vts_ttn; (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */ /* Any other registers? */ res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */ (vm->state).pgN = pgN; return res;}static int set_FP_PGC(vm_t *vm) { (vm->state).domain = FP_DOMAIN; if (!vm->vmgi->first_play_pgc) { return set_PGCN(vm, 1); } (vm->state).pgc = vm->vmgi->first_play_pgc; (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc; return 1;}static int set_MENU(vm_t *vm, int menu) { assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); return set_PGCN(vm, get_ID(vm, menu));}static int set_PGCN(vm_t *vm, int pgcN) { pgcit_t *pgcit; pgcit = get_PGCIT(vm); assert(pgcit != NULL); /* ?? Make this return -1 instead */ if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);#endif return 0; } (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc; (vm->state).pgcN = pgcN; (vm->state).pgN = 1; if((vm->state).domain == VTS_DOMAIN) (vm->state).TT_PGCN_REG = pgcN; return 1;}/* Figure out the correct pgN from the cell and update (vm->state). */ static int set_PGN(vm_t *vm) { int new_pgN = 0; while(new_pgN < (vm->state).pgc->nr_of_programs && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN]) new_pgN++; if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */ if((vm->state).cellN > (vm->state).pgc->nr_of_cells) return 0; /* We are past the last cell */ (vm->state).pgN = new_pgN; if((vm->state).domain == VTS_DOMAIN) { playback_type_t *pb_ty; if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) return 0; /* ?? */ pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty; if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) { int dummy, part; vm_get_current_title_part(vm, &dummy, &part); (vm->state).PTTN_REG = part; } else { /* FIXME: Handle RANDOM or SHUFFLE titles. */ fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n"); } } return 1;}/* Must be called before domain is changed (set_PGCN()) */static void set_RSMinfo(vm_t *vm, int cellN, int blockN) { int i; if(cellN) { (vm->state).rsm_cellN = cellN; (vm->state).rsm_blockN = blockN; } else { (vm->state).rsm_cellN = (vm->state).cellN; (vm->state).rsm_blockN = blockN; } (vm->state).rsm_vtsN = (vm->state).vtsN; (vm->state).rsm_pgcN = get_PGCN(vm); /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */ for(i = 0; i < 5; i++) { (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i]; }}/* Get functions *//* Searches the TT tables, to find the current TT. * returns the current TT. * returns 0 if not found. */static int get_TT(vm_t *vm, int vtsN, int vts_ttn) { int i; int tt=0; for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) { if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN && vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) { tt=i; break; } } return tt;}/* Search for entry_id match of the PGC Category in the current VTS PGCIT table. * Return pgcN based on entry_id match. */static int get_ID(vm_t *vm, int id) { int pgcN, i; pgcit_t *pgcit; /* Relies on state to get the correct pgcit. */ pgcit = get_PGCIT(vm); assert(pgcit != NULL);#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id);#endif /* Force high bit set. */ id |=0x80; /* Get menu/title */ for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { if( (pgcit->pgci_srp[i].entry_id) == id) { pgcN = i + 1;#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: Found menu.\n");#endif return pgcN; } }#ifdef TRACE fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f); for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) { fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n", pgcit->pgci_srp[i].entry_id & 0x7f); } }#endif return 0; /* error */}/* FIXME: we have a pgcN member in the vm's state now, so this should be obsolete */static int get_PGCN(vm_t *vm) { pgcit_t *pgcit; int pgcN = 1; pgcit = get_PGCIT(vm); if (pgcit) { while(pgcN <= pgcit->nr_of_pgci_srp) { if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) { assert((vm->state).pgcN == pgcN); return pgcN; } pgcN++; } } fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n", (vm->state).domain); return 0; /* error */}static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) { int i; if(h == NULL || h->pgci_ut == NULL) { fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n"); return NULL; /* error? */ } i = 0; while(i < h->pgci_ut->nr_of_lus && h->pgci_ut->lu[i].lang_code != lang) i++; if(i == h->pgci_ut->nr_of_lus) { fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n", (char)(lang >> 8), (char)(lang & 0xff), (char)(h->pgci_ut->lu[0].lang_code >> 8), (char)(h->pgci_ut->lu[0].lang_code & 0xff)); fprintf(MSG_OUT, "libdvdnav: Menu Languages available: "); for(i = 0; i < h->pgci_ut->nr_of_lus; i++) { fprintf(MSG_OUT, "%c%c ", (char)(h->pgci_ut->lu[i].lang_code >> 8), (char)(h->pgci_ut->lu[i].lang_code & 0xff)); } fprintf(MSG_OUT, "\n"); i = 0; /* error? */ } return h->pgci_ut->lu[i].pgcit;}/* Uses state to decide what to return */static pgcit_t* get_PGCIT(vm_t *vm) { pgcit_t *pgcit; switch ((vm->state).domain) { case VTS_DOMAIN: pgcit = vm->vtsi->vts_pgcit; break; case VTSM_DOMAIN: pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]); break; case VMGM_DOMAIN: case FP_DOMAIN: pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]); break; default: abort(); } return pgcit;}/* Debug functions */#ifdef TRACEvoid vm_position_print(vm_t *vm, vm_position_t *position) { 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", position->button, position->spu_channel, position->audio_channel, position->angle_channel, position->hop_channel, position->vts, position->domain, position->cell, position->cell_restart, position->cell_start, position->still, position->block);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -