📄 vm.c
字号:
do_nothing.data1 = state.blockN; link_values = do_nothing; } } *link_return = link_values; return 1; // Success}int vm_resume(void){ link_t link_values; if(!vm_resume_int(&link_values)) return 0; link_values = process_command(link_values); assert(link_values.command == PlayThis); state.blockN = link_values.data1; return 1; // Jump}/** * Return the substream id for 'logical' audio stream audioN. * 0 <= audioN < 8 */int vm_get_audio_stream(int audioN){ int streamN = -1; if(state.domain == VTSM_DOMAIN || state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { audioN = 0; } if(audioN < 8) { /* Is there any contol info for this logical stream */ if(state.pgc->audio_control[audioN] & (1<<15)) { streamN = (state.pgc->audio_control[audioN] >> 8) & 0x07; } } if(state.domain == VTSM_DOMAIN || state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { if(streamN == -1) streamN = 0; } return streamN;}/** * Return the substream id for 'logical' subpicture stream subpN. * 0 <= subpN < 32 */int vm_get_subp_stream(int subpN){ int streamN = -1; int source_aspect = get_video_aspect(); if(state.domain == VTSM_DOMAIN || state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { subpN = 0; } if(subpN < 32) { /* a valid logical stream */ /* Is this logical stream present */ if(state.pgc->subp_control[subpN] >> 31) { if(source_aspect == 0) /* 4:3 */ streamN = (state.pgc->subp_control[subpN] >> 24) & 0x1f; if(source_aspect == 3) /* 16:9 */ streamN = (state.pgc->subp_control[subpN] >> 16) & 0x1f; } } /* Paranoia.. if no stream select 0 anyway */ if(state.domain == VTSM_DOMAIN || state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { if(streamN == -1) streamN = 0; } return streamN;}int vm_get_subp_active_stream(void){ int subpN = state.SPST_REG & ~0x40; int streamN = vm_get_subp_stream(subpN); /* If no such stream, then select the first one that exists. */ if(streamN == -1) for(subpN = 0; subpN < 32; subpN++) if(state.pgc->subp_control[subpN] >> 31) { streamN = vm_get_subp_stream(subpN); break; } /* We should instead send the on/off status to the spudecoder / mixer */ /* If we are in the title domain see if the spu mixing is on */ if(state.domain == VTS_DOMAIN && !(state.SPST_REG & 0x40)) { return -1; } else { return streamN; }}void vm_get_angle_info(int *num_avail, int *current){ *num_avail = 1; *current = 1; if(state.domain == VTS_DOMAIN) { // TTN_REG does not allways point to the correct title.. title_info_t *title; if(state.TTN_REG > vmgi->tt_srpt->nr_of_srpts) return; title = &vmgi->tt_srpt->title[state.TTN_REG - 1]; if(title->title_set_nr != state.vtsN || title->vts_ttn != state.VTS_TTN_REG) return; *num_avail = title->nr_of_angles; *current = state.AGL_REG; if(*current > *num_avail) // Is this really a good idee? *current = *num_avail; }}void vm_get_audio_info(int *num_avail, int *current){ if(state.domain == VTS_DOMAIN) { *num_avail = vtsi->vtsi_mat->nr_of_vts_audio_streams; *current = state.AST_REG; } else if(state.domain == VTSM_DOMAIN) { *num_avail = vtsi->vtsi_mat->nr_of_vtsm_audio_streams; // 1 *current = 1; } else if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { *num_avail = vmgi->vmgi_mat->nr_of_vmgm_audio_streams; // 1 *current = 1; }}void vm_get_subp_info(int *num_avail, int *current){ if(state.domain == VTS_DOMAIN) { *num_avail = vtsi->vtsi_mat->nr_of_vts_subp_streams; *current = state.SPST_REG; } else if(state.domain == VTSM_DOMAIN) { *num_avail = vtsi->vtsi_mat->nr_of_vtsm_subp_streams; // 1 *current = 0x41; } else if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { *num_avail = vmgi->vmgi_mat->nr_of_vmgm_subp_streams; // 1 *current = 0x41; }}int vm_get_domain(void){ /* The enum for this domain the one in the dvdcontrol interface * (ogle/dvd.h) are in sync, so no coversion is necessary. */ return state.domain;}void vm_get_volume_info(int *nrofvolumes,int *volume,int *side,int *nroftitles){ *nrofvolumes = vmgi->vmgi_mat->vmg_nr_of_volumes; *volume = vmgi->vmgi_mat->vmg_this_volume_nr; *side = vmgi->vmgi_mat->disc_side; *nroftitles = vmgi->vmgi_mat->vmg_nr_of_title_sets;}int vm_get_titles(void){ int titles = 0; titles = vmgi->tt_srpt->nr_of_srpts; return titles;}int vm_get_ptts_for_title(int titleN){ int ptts = 0; if(titleN <= vmgi->tt_srpt->nr_of_srpts) { ptts = vmgi->tt_srpt->title[titleN - 1].nr_of_ptts; } return ptts;}subp_attr_t vm_get_subp_attr(int streamN){ subp_attr_t attr; if(state.domain == VTS_DOMAIN) { attr = vtsi->vtsi_mat->vts_subp_attr[streamN]; } else if(state.domain == VTSM_DOMAIN) { attr = vtsi->vtsi_mat->vtsm_subp_attr; } else if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { attr = vmgi->vmgi_mat->vmgm_subp_attr; } return attr;}user_ops_t vm_get_uops(void){ return state.pgc->prohibited_ops;}audio_attr_t vm_get_audio_attr(int streamN){ audio_attr_t attr; if(state.domain == VTS_DOMAIN) { attr = vtsi->vtsi_mat->vts_audio_attr[streamN]; } else if(state.domain == VTSM_DOMAIN) { attr = vtsi->vtsi_mat->vtsm_audio_attr; } else if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { attr = vmgi->vmgi_mat->vmgm_audio_attr; } return attr;}video_attr_t vm_get_video_attr(void){ video_attr_t attr; if(state.domain == VTS_DOMAIN) { attr = vtsi->vtsi_mat->vts_video_attr; } else if(state.domain == VTSM_DOMAIN) { attr = vtsi->vtsi_mat->vtsm_video_attr; } else if(state.domain == VMGM_DOMAIN || state.domain == FP_DOMAIN) { attr = vmgi->vmgi_mat->vmgm_video_attr; } return attr;}void vm_get_video_res(int *width, int *height){ video_attr_t attr; attr = vm_get_video_attr(); if(attr.video_format != 0) *height = 576; else *height = 480; switch(attr.picture_size) { case 0: *width = 720; break; case 1: *width = 704; break; case 2: *width = 352; break; case 3: *width = 352; *height /= 2; break; }}unsigned int bcd2int(unsigned int bcd){ unsigned int pot = 1; unsigned int res = 0; while(bcd != 0) { res += (bcd & 0x0f) * pot; bcd >>= 4; pot *= 10; } return res;}unsigned int int2bcd(unsigned int number){ unsigned int pot = 1; unsigned int res = 0; while(number != 0) { res += (number % 10) * pot; number /= 10; pot <<= 4; } return res;}static unsigned int time2sec(dvd_time_t *time){ unsigned int acc_s; // convert from bcd to seconds acc_s = bcd2int(time->hour) * 60 * 60; acc_s += bcd2int(time->minute) * 60; acc_s += bcd2int(time->second); /* frames = bcd2int(time->frame_u & 0x3f); switch(acc->frame_u >> 6) { case 1: frame_rate = 25; break; case 3: frame_rate = 30; // 29.97 break; default: frame_rate = 30; // ?? break; } // normalize time, should we round to nearest? (+ frame_rate/2) acc_s += frames / frame_rate; */ return acc_s;}static void time_add(dvd_time_t *acc, const dvd_time_t *diff){ unsigned int acc_s, diff_s; int frame_rate, frames; if((acc->frame_u & 0xc0) != (diff->frame_u & 0xc0)) { // argh.. frame rates differ.. what?!? // at most it will cause 5/25 fault for each addition DNOTE("frame rates differ in time_add %i %i\n", acc->frame_u>>6, diff->frame_u>>6); } // convert from bcd to seconds acc_s = bcd2int(acc->hour) * 60 * 60; acc_s += bcd2int(acc->minute) * 60; acc_s += bcd2int(acc->second); diff_s = bcd2int(diff->hour) * 60 * 60; diff_s += bcd2int(diff->minute) * 60; diff_s += bcd2int(diff->second); // add time acc_s += diff_s; frames = bcd2int(acc->frame_u & 0x3f) + bcd2int(diff->frame_u & 0x3f); switch(acc->frame_u >> 6) { case 1: frame_rate = 25; break; case 3: frame_rate = 30; // 29.97 break; default: frame_rate = 30; // ?? break; } // normalize time acc_s += frames / frame_rate; // convert back to bcd acc->frame_u = int2bcd(frames % frame_rate) | (acc->frame_u & 0xc0); acc->second = int2bcd(acc_s % 60); acc->minute = int2bcd((acc_s / 60) % 60); acc->hour = int2bcd(acc_s / (60 * 60));}void vm_get_total_time(dvd_time_t *current_time){ *current_time = state.pgc->playback_time; /* This should give the same time as well.... */ //vm_get_cell_start_time(current_time, state.pgc->nr_of_cells);}void vm_get_current_time(dvd_time_t *current_time, dvd_time_t *cell_elapsed){ vm_get_cell_start_time(current_time, state.cellN); /* Add the time within the cell. */ time_add(current_time, cell_elapsed);}/* Should return status info or something... */void vm_get_cell_start_time(dvd_time_t *current_time, int cellN){ dvd_time_t angle_time; playback_type_t *pb_ty; cell_playback_t *const cell_pb = state.pgc->cell_playback; int i; current_time->hour = 0; current_time->minute = 0; current_time->second = 0; /* Frame code */ current_time->frame_u = state.pgc->playback_time.frame_u & 0xc0; /* Should only be called for One_Sequential_PGC_Title PGCs. */ if(state.domain != VTS_DOMAIN) { /* No time info */ return; } 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 info */ return; } assert(cellN <= state.pgc->nr_of_cells); for(i = 1; i < cellN; i++) { /* Multi angle/Interleaved */ switch(cell_pb[i - 1].block_mode) { case BLOCK_MODE_NOT_IN_BLOCK: assert(cell_pb[i - 1].block_type == BLOCK_TYPE_NONE); time_add(current_time, &cell_pb[i - 1].playback_time); break; case BLOCK_MODE_FIRST_CELL: switch(cell_pb[i - 1].block_type) { case BLOCK_TYPE_NONE: assert(0); case BLOCK_TYPE_ANGLE_BLOCK: time_add(current_time, &cell_pb[i - 1].playback_time); angle_time = cell_pb[i - 1].playback_time; break; case 2: // ?? case 3: // ?? default: WARNING("Invalid? Cell block_mode (%d), block_type (%d)\n", cell_pb[i - 1].block_mode, cell_pb[i - 1].block_type); } break; case BLOCK_MODE_IN_BLOCK: case BLOCK_MODE_LAST_CELL: /* Check that the cells for each angle have equal duration. */ /* THEY WON'T !! */ assert(!memcmp(&angle_time, &cell_pb[i - 1].playback_time, sizeof(dvd_time_t))); break; default: WARNING("%s", "Cell is in block but did not enter at first cell!\n"); } }}// Must be called before domain is changed (get_PGCN())static void saveRSMinfo(int cellN, int blockN){ int i; if(cellN != 0) { state.rsm_cellN = cellN; state.rsm_blockN = 0; } else { state.rsm_cellN = state.cellN; state.rsm_blockN = blockN; } state.rsm_vtsN = state.vtsN; state.rsm_pgcN = get_PGCN();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -