⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm.c

📁 基于linux的DVD播放器程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    //assert(state.rsm_pgcN == state.TT_PGCN_REG); // for VTS_DOMAIN    for(i = 0; i < 5; i++) {    state.rsm_regs[i] = state.registers.SPRM[4 + i];  }}/* Figure out the correct pgN from the cell and update state. */ static int update_PGN(void) {  int new_pgN = 0;    while(new_pgN < state.pgc->nr_of_programs 	&& state.cellN >= state.pgc->program_map[new_pgN])    new_pgN++;    if(new_pgN == state.pgc->nr_of_programs) /* We are at the last program */    if(state.cellN > state.pgc->nr_of_cells)      return 1; /* We are past the last cell */    state.pgN = new_pgN;    if(state.domain == VTS_DOMAIN) {    playback_type_t *pb_ty;    if(state.TTN_REG > vmgi->tt_srpt->nr_of_srpts)      return 0; // ??    pb_ty = &vmgi->tt_srpt->title[state.TTN_REG - 1].pb_ty;    if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) {#if 0 /* TTN_REG can't be trusted to have a correct value here... */      vts_ptt_srpt_t *ptt_srpt = vtsi->vts_ptt_srpt;      assert(state.VTS_TTN_REG <= ptt_srpt->nr_of_srpts);      assert(get_PGCN() == ptt_srpt->title[state.VTS_TTN_REG - 1].ptt[0].pgcn);      assert(1 == ptt_srpt->title[state.VTS_TTN_REG - 1].ptt[0].pgn);#endif      state.PTTN_REG = state.pgN;    }  }    return 0;}static int next_PG(link_t *link_values){    // TODO this is how Sequential PGCs work  //      we have to add Random/shuffle behaviour  // Does pgN always contain the current value?  if(state.pgN == state.pgc->nr_of_programs) {    if(get_PGC(state.pgc->next_pgc_nr)) { /* This should be conditional on beeing a user command!! */      /* This is what a compliant player should, do it seems. */      //return -1; // there is no next PG      /* We think that the following makes more sense though. */      *link_values = play_PGC_post();    } else {      *link_values = play_PGC();    }  } else {    state.pgN += 1;    *link_values = play_PG();  }  return 0; // ok}static int prev_PG(link_t *link_values){    // TODO this is how Sequential PGCs work  //      we have to add Random/shuffle behaviour  // Does pgN always contain the current value?    if(state.pgN == 1) {    if(get_PGC(state.pgc->prev_pgc_nr))      return -1; // error / unable to..    *link_values = play_PGC();  } else {    state.pgN -= 1;    *link_values = play_PG();  }  return 0; // ok}static link_t play_PGC(void) {      link_t link_values;    if(state.domain != FP_DOMAIN)    DNOTE("play_PGC: state.pgcN (%i)\n", get_PGCN());  else    DNOTE("%s", "play_PGC: first_play_pgc\n");  // These should have been set before play_PGC is called.  // They won't be set automaticaly and the when the pre-commands are  // executed they might be used (for instance in a CallSS that will   // save resume state)  // state.pgN, state.cellN  state.cellN = 0; // FIXME set cellN everytime pgN is set! ?!  /* eval -> updates the state and returns either      - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)     - just play video i.e first PG       (This is what happens if you fall of the end of the pre_cmds)     - or a error (are there more cases?) */  if(state.pgc->command_tbl && state.pgc->command_tbl->nr_of_pre) {    if(vmEval_CMD(state.pgc->command_tbl->pre_cmds, 		  state.pgc->command_tbl->nr_of_pre, 		  &state.registers, &link_values)) {      // link_values contains the 'jump' return value      return link_values;    } else {      DNOTE("%s", "PGC pre commands didn't do a Jump, Link or Call\n");    }  }  return play_PG();}  static link_t play_PG(void){  DNOTE("play_PG: state.pgN (%i)\n", state.pgN);    assert(state.pgN > 0);  if(state.pgN > state.pgc->nr_of_programs) {    DNOTE("state.pgN (%i) == pgc->nr_of_programs + 1 (%i)\n", 	  state.pgN, state.pgc->nr_of_programs + 1);    assert(state.pgN == state.pgc->nr_of_programs + 1);    return play_PGC_post();  }    state.cellN = state.pgc->program_map[state.pgN - 1];    return play_Cell();}static link_t play_Cell(void){  cell_playback_t *const cell_pb = state.pgc->cell_playback;    DNOTE("play_Cell: state.cellN (%i)\n", state.cellN);    assert(state.cellN > 0);  if(state.cellN > state.pgc->nr_of_cells) {    DNOTE("state.cellN (%i) == pgc->nr_of_cells + 1 (%i)\n", 	  state.cellN, state.pgc->nr_of_cells + 1);    assert(state.cellN == state.pgc->nr_of_cells + 1);     return play_PGC_post();  }    /* Multi angle/Interleaved */  switch(cell_pb[state.cellN - 1].block_mode) {  case BLOCK_MODE_NOT_IN_BLOCK:    assert(cell_pb[state.cellN - 1].block_type == BLOCK_TYPE_NONE);    break;  case BLOCK_MODE_FIRST_CELL:    switch(cell_pb[state.cellN - 1].block_type) {    case BLOCK_TYPE_NONE:      assert(0);    case BLOCK_TYPE_ANGLE_BLOCK:      /* Loop and check each cell instead? So we don't get outsid the block. */      state.cellN += state.AGL_REG - 1;      assert(state.cellN <= state.pgc->nr_of_cells);      assert(cell_pb[state.cellN - 1].block_mode != BLOCK_MODE_NOT_IN_BLOCK);      assert(cell_pb[state.cellN - 1].block_type == BLOCK_TYPE_ANGLE_BLOCK);      break;    case 2: // ??    case 3: // ??    default:      WARNING("Invalid? Cell block_mode (%d), block_type (%d)\n",	      cell_pb[state.cellN - 1].block_mode,	      cell_pb[state.cellN - 1].block_type);    }    break;  case BLOCK_MODE_IN_BLOCK:  case BLOCK_MODE_LAST_CELL:  // These might perhaps happen for RSM or LinkC commands?  default:    WARNING("%s", "Cell is in block but did not enter at first cell!\n");  }    /* Updates state.pgN and PTTN_REG */  if(update_PGN()) {    /* Should not happen */    link_t tmp = {LinkTailPGC, /* No Button */ 0, 0, 0};    assert(0);    return tmp;  }    {    link_t tmp = {PlayThis, /* Block in Cell */ 0, 0, 0};    return tmp;  }}static link_t play_Cell_post(void){  cell_playback_t *const cell_pb = state.pgc->cell_playback;  int cell_cmd_nr;    DNOTE("play_Cell_post: state.cellN (%i)\n", state.cellN);    cell_cmd_nr = cell_pb[state.cellN - 1].cell_cmd_nr;    /* Still time is already taken care of before we get called. */      if(cell_cmd_nr != 0      && (state.pgc->command_tbl == NULL	 || state.pgc->command_tbl->nr_of_cell < cell_cmd_nr)) {    WARNING("Invalid Cell command vtsn=%d dom=%d pgc=%d\n",	    state.vtsN, state.domain, get_PGCN());    cell_cmd_nr = 0;  }         /* Deal with a Cell command, if any */  if(cell_cmd_nr != 0) {    link_t link_values;        DNOTE("%s", "Cell command pressent, executing\n");    if(vmEval_CMD(&state.pgc->command_tbl->cell_cmds[cell_cmd_nr - 1], 1,		  &state.registers, &link_values)) {      return link_values;    } else {       DNOTE("%s", "Cell command didn't do a Jump, Link or Call\n");      // Error ?? goto tail? goto next PG? or what? just continue?    }  }      /* Where to continue after playing the cell... */  /* Multi angle/Interleaved */  switch(cell_pb[state.cellN - 1].block_mode) {  case BLOCK_MODE_NOT_IN_BLOCK:    assert(cell_pb[state.cellN - 1].block_type == 	   BLOCK_TYPE_NONE);    state.cellN++;    break;  case BLOCK_MODE_FIRST_CELL:  case BLOCK_MODE_IN_BLOCK:  case BLOCK_MODE_LAST_CELL:  default:    switch(cell_pb[state.cellN - 1].block_type) {    case BLOCK_TYPE_NONE:      assert(0);    case BLOCK_TYPE_ANGLE_BLOCK:      /* Skip the 'other' angles */      state.cellN++;      while(state.cellN <= state.pgc->nr_of_cells &&	    cell_pb[state.cellN - 1].block_mode >=	    BLOCK_MODE_IN_BLOCK) {	state.cellN++;      }      break;    case 2: // ??    case 3: // ??    default:      WARNING("Invalid? Cell block_mode (%d), block_type (%d)\n",	      cell_pb[state.cellN - 1].block_mode,	      cell_pb[state.cellN - 1].block_type);    }    break;  }      /* Figure out the correct pgN for the new cell */   if(update_PGN()) {    DNOTE("%s", "last cell in this PGC\n");    return play_PGC_post();  }  return play_Cell();}static link_t play_PGC_post(void){  link_t link_values;  DNOTE("%s", "play_PGC_post:\n");    assert(state.pgc->still_time == 0); // FIXME $$$  /* eval -> updates the state and returns either      - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)     - or a error (are there more cases?)     - if you got to the end of the post_cmds, then what ?? */  if(state.pgc->command_tbl &&     vmEval_CMD(state.pgc->command_tbl->post_cmds,		state.pgc->command_tbl->nr_of_post, 		&state.registers, &link_values)) {    return link_values;  }    // Or perhaps handle it here?  {    link_t link_next_pgc = {LinkNextPGC, 0, 0, 0};    DNOTE("%s", "** Fell of the end of the pgc, continuing in NextPGC\n");    if(state.domain == FP_DOMAIN) {      /* User should select a title them self, i.e. we should probably go 	 to the STOP_DOMAIN.  Untill we have that implemented start playing	 title track 1 instead since we're sure that that isn't optional. */      if(get_TT(1) == -1)	assert(0);      /* This won't create an infinite loop becase we can't ever get to the	 FP_DOMAIN again without executing a command. */      return play_PGC();    }    assert(state.pgc->next_pgc_nr != 0);    /* Should end up in the STOP_DOMAIN if next_pgc i 0. */    return link_next_pgc;  }}/* Should only be called in the VTS Domain and only for  * One_Sequential_PGC_Title PGCs.  * returns 0 if it fails.                                */int vm_time_play(dvd_time_t *time, unsigned int offset){  playback_type_t *pb_ty;  int pgcN;  int seconds;    if(state.domain != VTS_DOMAIN) {    /* No time seek possible */    return 0;  }  // Should we also check the state.pgc->pg_playback_mode, or instead?  // Is the TTN_REG up to date?   pb_ty = &vmgi->tt_srpt->title[state.TTN_REG - 1].pb_ty;  if(pb_ty->multi_or_random_pgc_title != /* One_Sequential_PGC_Title */ 0) {    /* No time seek possible */    return 0;  }    // Do we have a Time Map table?  if(!vtsi->vts_tmapt) {    return 0;  }    seconds = time2sec(time) + offset;  if(seconds < 0)    seconds = 0;    fprintf(stderr, "Time Play/Skipp to offset %dseconds\n", seconds);    pgcN = get_PGCN();  // Is there an entry for this pgc?  assert(pgcN != -1);    if(pgcN <= vtsi->vts_tmapt->nr_of_tmaps) {      vts_tmap_t *tmap = &vtsi->vts_tmapt->tmap[pgcN - 1];      int index;      map_ent_t entry;      int32_t vobu_addr;            /*       * Restructure this as a loop over all the entries, keeping       * count of the 'flags' so we know the cell number?       * Is that even guaranteed to be correct?       */            if(tmap->tmu == 0) // Valid time unit (resolution)	return 0; // No seek      index = seconds / tmap->tmu;       if(tmap->nr_of_entries < index) // Enough entries?	return 0; // No seek            entry = tmap->map_ent[index];      vobu_addr = entry & 0x7fffffff; // High bit is discontinuty flag            /* Should we instead do a linear scan of the table and count       * the 'flag's to that way get the right cell?       * Can one have time seek for multiangle pgc's?       */      { 	cell_playback_t *cells = state.pgc->cell_playback;	state.cellN = get_cellN_for_vobu(vobu_addr); //scan the cell table?	assert(vobu_addr >= cells[state.cellN - 1].first_sector);	assert(vobu_addr <= cells[state.cellN - 1].last_vobu_start_sector);	state.blockN = vobu_addr - cells[state.cellN - 1].first_sector;	update_PGN();      }      return 1;  }    return 0;}static link_t process_command(link_t link_values){  link_t do_nothing = { PlayThis, 0, 0, 0};  do_nothing.data1 = state.blockN;  /* FIXME $$$ Move this to a separate function? */  while(link_values.command != PlayThis) {    #ifdef TRACE    vmPrint_LINK(link_values);#endif        switch(link_values.command) {    case LinkNoLink:      return do_nothing;          case LinkTopC:      link_values = play_Cell();      break;    case LinkNextC:      // What if cellN becomes > nr_of_cells?      if(state.cellN == state.pgc->nr_of_cells)	return do_nothing; // it should do nothing      state.cellN += 1;      link_values = play_Cell();      break;    case LinkPrevC:      // What if cellN becomes < 1?      if(state.cellN == 0)	return do_nothing; // it should do nothing      state.cellN -= 1;      link_values = play_Cell();      break;          case LinkTopPG:      // Does pgN always contain the current value?      link_values = play_PG();      break;    case LinkNextPG:      if(next_PG(&link_values) == -1)	return do_nothing; // it must do nothing, do not exit...      break;    case LinkPrevPG:      if(prev_PG(&link_values) == -1)	return do_nothing; // it must do nothing, do not exit...      break;          case LinkTopPGC:      link_values = play_PGC();      break;    case LinkNextPGC:      assert(state.pgc->next_pgc_nr != 0);      if(get_PGC(state.pgc->next_pgc_nr))	return do_nothing; // do nothing, do not exit... assert(0);      link_values = play_PGC();      break;    case LinkPrevPGC:      assert(state.pgc->prev_pgc_nr != 0);      if(get_PGC(state.pgc->prev_pgc_nr))	return do_nothing; // do nothing, do not exit... assert(0);      link_values = play_PGC();      break;    case LinkGoUpPGC:      assert(state.pgc->goup_pgc_nr != 0);      if(get_PGC(state.pgc->goup_pgc_nr))	return do_nothing; // do nothing, do not exit... assert(0);      link_values = play_PGC();      break;    case LinkTailPGC:      link_values = play_PGC_post();      break;          case LinkRSM:      /* Updates link_values if successful */      if(!vm_resume_int(&link_values)) {	/* Nothing / Faild.  What should we do? Do we need closer interaction	 * with the command evaluatore to be able to turn this in to a NOP? */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -