环境: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来定位的。以上理解有不对不处或需要补充的,请留言。