環境:mplayer,及它下面的stream
說明:1。本文只是閱讀它的代碼,沒有進行調試跟蹤,可能有出入不對的地方.
2。希望讀者對dvd的邏輯結構有些瞭解,如vts, pgc, chapter, cell它們的關係.
dvd如何通過時間來定位的,可通過dvd_seek_to_time來分析,看看它是如何通過時間來定位的。也就是把時間轉換成sector, DVDReadBlocks中的參數offset Block
它的定位就有點象物理學中的千分尺(遊標卡尺),先通過時間查到所屬dvd的cell,再在cell中找到時間偏移量,這時才確定dvd_read_sector所需要的cur_pack. <<DVDReadBlocks(d->title, d->cur_pack, 1, data)>>
static int dvd_seek_to_time(stream_t *stream, ifo_handle_t *vts_file, double sec)
{
unsigned int i, j, k, timeunit, ac_time, tmap_sector=0, cell_sector=0, vobu_sector=0;
int t=0;
double tm, duration;
off_t pos = -1;
dvd_priv_t *d = stream->priv;
vts_tmapt_t *vts_tmapt = vts_file->vts_tmapt;
if(!vts_file->vts_tmapt || sec < 0)
return 0;
//pgc時間長度。(從opes_s源代碼來看,mplay是以pgc爲單元來處理播放的)
duration = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title-1) / 1000.0f;
if(sec > duration)
return 0;
//在pgc中找到vobu的sector,用於找到所屬的cell
i=d->cur_pgc_idx;
timeunit = vts_tmapt->tmap[i].tmu;
for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) {
ac_time = timeunit * (j + 1);
if(ac_time >= sec)
break;
tmap_sector = vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff;
}
//search enclosing cell
//定位cell,當前tmap_sector所屬的dvd cell
for(i=0; i<d->cur_pgc->nr_of_cells; i++) {
if(tmap_sector >= d->cur_pgc->cell_playback[i].first_sector &&
tmap_sector <= d->cur_pgc->cell_playback[i].last_sector) {
cell_sector = d->cur_pgc->cell_playback[i].first_sector;
break;
}
}
// 讓查詢指針指向cell的起始位置
pos = ((off_t)cell_sector)<<11;
stream_seek(stream, pos);
do {
stream_skip(stream, 2048);
t = mp_dvdtimetomsec(&d->dsi_pack.dsi_gi.c_eltm);
} while(!t);
tm = dvd_get_current_time(stream, 0);
// 讓查詢指針指向cell的偏移位置(tmap_sector與cell_sector在同一時刻是不同的值)
pos = ((off_t)tmap_sector)<<11;
stream_seek(stream, pos);
//now get current time in terms of the cell+cell time offset
memset(&d->dsi_pack.dsi_gi.c_eltm, 0, sizeof(dvd_time_t));
//找到sec在cell中對應的位置stream->pos.
while(tm <= sec) {
if(!stream_skip(stream, 2048))
break;
tm = dvd_get_current_time(stream, 0);
};
//後面這段個人還不太理解它的作用,下面猜測可能:
1。與關鍵幀相關以確定畫面是在一個關鍵位置上
2。tmap_sector與cell_sector對應關係的轉換
3. 有關文檔參考:http://www.mpucoder.com/DVD/ifo.html#vam
tmap_sector = stream->pos >> 11;
//search closest VOBU sector
k=(vts_file->vts_vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE)/4; //entries in the vobu admap
for(i=1; i<k; i++) {
if(vts_file->vts_vobu_admap->vobu_start_sectors[i] > tmap_sector)
break;
}
vobu_sector = vts_file->vts_vobu_admap->vobu_start_sectors[i-1];
pos = ((off_t)vobu_sector) << 11;
stream_seek(stream, pos);
return 1;
}
這個函數多次調用stream_seek,stream_skip,從它們源代碼來看,最終會調用fill_buffer->dvd_read_sector->DVDReadBlocks來定位的。
以上理解有不對不處或需要補充的,請留言。