關於mplayer dvd seek定位函數dvd_seek_to_time

環境: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來定位的。
以上理解有不對不處或需要補充的,請留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章