📄 dvdread.c
字号:
ESNew( p_demux, 0xe0, 0 ); /* Video, FIXME ? */ p_sys->i_aspect = p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio;#define audio_control \ p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1] /* Audio ES, in the order they appear in the .ifo */ for( i = 1; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams; i++ ) { int i_position = 0; uint16_t i_id; //IfoPrintAudio( p_demux, i ); /* Audio channel is active if first byte is 0x80 */ if( audio_control & 0x8000 ) { i_position = ( audio_control & 0x7F00 ) >> 8; msg_Dbg( p_demux, "audio position %d", i_position ); switch( p_vts->vtsi_mat->vts_audio_attr[i - 1].audio_format ) { case 0x00: /* A52 */ i_id = (0x80 + i_position) | 0xbd00; break; case 0x02: case 0x03: /* MPEG audio */ i_id = 0xc000 + i_position; break; case 0x04: /* LPCM */ i_id = (0xa0 + i_position) | 0xbd00; break; case 0x06: /* DTS */ i_id = (0x88 + i_position) | 0xbd00; break; default: i_id = 0; msg_Err( p_demux, "unknown audio type %.2x", p_vts->vtsi_mat->vts_audio_attr[i - 1].audio_format ); } ESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat-> vts_audio_attr[i - 1].lang_code ); } }#undef audio_control#define spu_palette \ p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette memcpy( p_sys->clut, spu_palette, 16 * sizeof( uint32_t ) );#define spu_control \ p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1] /* Sub Picture ES */ for( i = 1; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ ) { int i_position = 0; uint16_t i_id; //IfoPrintSpu( p_sys, i ); msg_Dbg( p_demux, "spu %d 0x%02x", i, spu_control ); if( spu_control & 0x80000000 ) { /* there are several streams for one spu */ if( p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) { /* 16:9 */ switch( p_vts->vtsi_mat->vts_video_attr.permitted_df ) { case 1: /* letterbox */ i_position = spu_control & 0xff; break; case 2: /* pan&scan */ i_position = ( spu_control >> 8 ) & 0xff; break; default: /* widescreen */ i_position = ( spu_control >> 16 ) & 0xff; break; } } else { /* 4:3 */ i_position = ( spu_control >> 24 ) & 0x7F; } i_id = (0x20 + i_position) | 0xbd00; ESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat-> vts_subp_attr[i - 1].lang_code ); } }#undef spu_control } else if( i_title != -1 && i_title != p_sys->i_title ) { return VLC_EGENERIC; /* Couldn't set title */ } /* * Chapter selection */ if( i_chapter >= 0 && i_chapter < p_sys->i_chapters ) { pgc_id = p_vts->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[i_chapter].pgcn; pgn = p_vts->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[i_chapter].pgn; p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc; p_sys->i_cur_cell = p_pgc->program_map[pgn - 1] - 1; p_sys->i_chapter = i_chapter; DvdReadFindCell( p_demux ); p_sys->i_title_offset = 0; for( i = p_sys->i_title_start_cell; i < p_sys->i_cur_cell; i++ ) { p_sys->i_title_offset += p_pgc->cell_playback[i].last_sector - p_pgc->cell_playback[i].first_sector + 1; } p_sys->i_pack_len = 0; p_sys->i_next_vobu = p_sys->i_cur_block = p_pgc->cell_playback[p_sys->i_cur_cell].first_sector; if( p_demux->info.i_seekpoint != i_chapter ) { p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; p_demux->info.i_seekpoint = i_chapter; } } else if( i_chapter != -1 ) { return VLC_EGENERIC; /* Couldn't set chapter */ }#undef p_pgc#undef p_vts#undef p_vmg return VLC_SUCCESS;}/***************************************************************************** * DvdReadSeek : Goes to a given position on the stream. ***************************************************************************** * This one is used by the input and translate chronological position from * input to logical position on the device. *****************************************************************************/static void DvdReadSeek( demux_t *p_demux, int i_block_offset ){ demux_sys_t *p_sys = p_demux->p_sys; int i_chapter = 0; int i_cell = 0; int i_vobu = 0; int i_sub_cell = 0; int i_block;#define p_pgc p_sys->p_cur_pgc#define p_vts p_sys->p_vts_file /* Find cell */ i_block = i_block_offset; for( i_cell = p_sys->i_title_start_cell; i_cell <= p_sys->i_title_end_cell; i_cell++ ) { if( i_block < (int)p_pgc->cell_playback[i_cell].last_sector - (int)p_pgc->cell_playback[i_cell].first_sector + 1 ) break; i_block -= (p_pgc->cell_playback[i_cell].last_sector - p_pgc->cell_playback[i_cell].first_sector + 1); } if( i_cell > p_sys->i_title_end_cell ) { msg_Err( p_demux, "couldn't find cell for block %i", i_block_offset ); return; } i_block += p_pgc->cell_playback[i_cell].first_sector; p_sys->i_title_offset = i_block_offset; /* Find chapter */ for( i_chapter = 0; i_chapter < p_sys->i_chapters; i_chapter++ ) { int pgc_id, pgn, i_tmp; pgc_id = p_vts->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[i_chapter].pgcn; pgn = p_vts->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[i_chapter].pgn; i_tmp = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc->program_map[pgn-1]; if( i_tmp > i_cell ) break; } if( i_chapter < p_sys->i_chapters && p_demux->info.i_seekpoint != i_chapter ) { p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; p_demux->info.i_seekpoint = i_chapter; } /* Find vobu */ while( (int)p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu] <= i_block ) { i_vobu++; } /* Find sub_cell */ while( p_vts->vts_c_adt->cell_adr_table[i_sub_cell].start_sector < p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu-1] ) { i_sub_cell++; }#if 1 msg_Dbg( p_demux, "cell %d i_sub_cell %d chapter %d vobu %d " "cell_sector %d vobu_sector %d sub_cell_sector %d", i_cell, i_sub_cell, i_chapter, i_vobu, p_sys->p_cur_pgc->cell_playback[i_cell].first_sector, p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu], p_vts->vts_c_adt->cell_adr_table[i_sub_cell - 1].start_sector);#endif p_sys->i_cur_block = i_block; p_sys->i_next_vobu = p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu]; p_sys->i_pack_len = p_sys->i_next_vobu - i_block; p_sys->i_cur_cell = i_cell; p_sys->i_chapter = i_chapter; DvdReadFindCell( p_demux );#undef p_vts#undef p_pgc return;}/***************************************************************************** * DvdReadHandleDSI *****************************************************************************/static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ){ demux_sys_t *p_sys = p_demux->p_sys; navRead_DSI( &p_sys->dsi_pack, &p_data[DSI_START_BYTE] ); /* * Determine where we go next. These values are the ones we mostly * care about. */ p_sys->i_cur_block = p_sys->dsi_pack.dsi_gi.nv_pck_lbn; p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; /* * Store the timecodes so we can get the current time */ p_sys->i_title_cur_time = (mtime_t) (p_sys->dsi_pack.dsi_gi.nv_pck_scr / 90 * 1000); p_sys->i_cell_cur_time = (mtime_t) dvdtime_to_time( &p_sys->dsi_pack.dsi_gi.c_eltm, 0 ); /* * If we're not at the end of this cell, we can determine the next * VOBU to display using the VOBU_SRI information section of the * DSI. Using this value correctly follows the current angle, * avoiding the doubled scenes in The Matrix, and makes our life * really happy. */ p_sys->i_next_vobu = p_sys->i_cur_block + ( p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); if( p_sys->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL && p_sys->i_angle > 1 ) { switch( ( p_sys->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 ) { case 0x4: /* Interleaved unit with no angle */ if( p_sys->dsi_pack.sml_pbi.ilvu_sa != 0 ) { p_sys->i_next_vobu = p_sys->i_cur_block + p_sys->dsi_pack.sml_pbi.ilvu_sa; p_sys->i_pack_len = p_sys->dsi_pack.sml_pbi.ilvu_ea; } else { p_sys->i_next_vobu = p_sys->i_cur_block + p_sys->dsi_pack.dsi_gi.vobu_ea + 1; } break; case 0x5: /* vobu is end of ilvu */ if( p_sys->dsi_pack.sml_agli.data[p_sys->i_angle-1].address ) { p_sys->i_next_vobu = p_sys->i_cur_block + p_sys->dsi_pack.sml_agli.data[p_sys->i_angle-1].address; p_sys->i_pack_len = p_sys->dsi_pack.sml_pbi.ilvu_ea; break; } case 0x6: /* vobu is beginning of ilvu */ case 0x9: /* next scr is 0 */ case 0xa: /* entering interleaved section */ case 0x8: /* non interleaved cells in interleaved section */ default: p_sys->i_next_vobu = p_sys->i_cur_block + ( p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); break; } } else if( p_sys->dsi_pack.vobu_sri.next_vobu == SRI_END_OF_CELL ) { p_sys->i_cur_cell = p_sys->i_next_cell; /* End of title */ if( p_sys->i_cur_cell >= p_sys->p_cur_pgc->nr_of_cells ) return; DvdReadFindCell( p_demux ); p_sys->i_next_vobu = p_sys->p_cur_pgc->cell_playback[p_sys->i_cur_cell].first_sector; p_sys->i_cell_duration = (mtime_t)dvdtime_to_time( &p_sys->p_cur_pgc->cell_playback[p_sys->i_cur_cell].playback_time, 0 ); }#if 0 msg_Dbg( p_demux, "scr %d lbn 0x%02x vobu_ea %d vob_id %d c_id %d c_time %lld", p_sys->dsi_pack.dsi_gi.nv_pck_scr, p_sys->dsi_pack.dsi_gi.nv_pck_lbn, p_sys->dsi_pack.dsi_gi.vobu_ea, p_sys->dsi_pack.dsi_gi.vobu_vob_idn, p_sys->dsi_pack.dsi_gi.vobu_c_idn, dvdtime_to_time( &p_sys->dsi_pack.dsi_gi.c_eltm, 0 ) ); msg_Dbg( p_demux, "cell duration: %lld", (mtime_t)dvdtime_to_time( &p_sys->p_cur_pgc->cell_playback[p_sys->i_cur_cell].playback_time, 0 ) ); msg_Dbg( p_demux, "cat 0x%02x ilvu_ea %d ilvu_sa %d size %d", p_sys->dsi_pack.sml_pbi.category, p_sys->dsi_pack.sml_pbi.ilvu_ea, p_sys->dsi_pack.sml_pbi.ilvu_sa, p_sys->dsi_pack.sml_pbi.size ); msg_Dbg( p_demux, "next_vobu %d next_ilvu1 %d next_ilvu2 %d", p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff, p_sys->dsi_pack.sml_agli.data[ p_sys->i_angle - 1 ].address, p_sys->dsi_pack.sml_agli.data[ p_sys->i_angle ].address);#endif}/***************************************************************************** * DvdReadFindCell *****************************************************************************/static void DvdReadFindCell( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; pgc_t *p_pgc; int pgc_id, pgn; int i = 0;#define cell p_sys->p_cur_pgc->cell_playback if( cell[p_sys->i_cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { p_sys->i_cur_cell += p_sys->i_angle - 1; while( cell[p_sys->i_cur_cell+i].block_mode != BLOCK_MODE_LAST_CELL ) { i++; } p_sys->i_next_cell = p_sys->i_cur_cell + i + 1; } else { p_sys->i_next_cell = p_sys->i_cur_cell + 1; }#undef cell if( p_sys->i_chapter + 1 >= p_sys->i_chapters ) return; pgc_id = p_sys->p_vts_file->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[p_sys->i_chapter + 1].pgcn; pgn = p_sys->p_vts_file->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[p_sys->i_chapter + 1].pgn; p_pgc = p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc; if( p_sys->i_cur_cell >= p_pgc->program_map[pgn - 1] - 1 ) { p_sys->i_chapter++; if( p_sys->i_chapter < p_sys->i_chapters && p_demux->info.i_seekpoint != p_sys->i_chapter ) { p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; p_demux->info.i_seekpoint = p_sys->i_chapter; } }}/***************************************************************************** * DemuxTitles: get the titles/chapters structure *****************************************************************************/static void DemuxTitles( demux_t *p_demux, int *pi_angle ){ demux_sys_t *p_sys = p_demux->p_sys; input_title_t *t; seekpoint_t *s; int32_t i_titles; int i; /* Find out number of titles/chapters */#define tt_srpt p_sys->p_vmg_file->tt_srpt i_titles = tt_srpt->nr_of_srpts; msg_Dbg( p_demux, "number of titles: %d", i_titles ); for( i = 0; i < i_titles; i++ ) { int32_t i_chapters = 0; int j; i_chapters = tt_srpt->title[i].nr_of_ptts; msg_Dbg( p_demux, "title %d has %d chapters", i, i_chapters ); t = vlc_input_title_New(); for( j = 0; j < __MAX( i_chapters, 1 ); j++ ) { s = vlc_seekpoint_New(); TAB_APPEND( t->i_seekpoint, t->seekpoint, s ); } TAB_APPEND( p_sys->i_titles, p_sys->titles, t ); }#undef tt_srpt}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -