Ticket #2808: time_based_seeking.4.diff

File time_based_seeking.4.diff, 8.5 KB (added by skamithi, 17 years ago)

hopefully this should work well now. figured out a way using the DSI information efficient precise dvd seeking . in dvd nav changed the vobu search through the admap to use binary search algorithm. even at 2x on a dvd drive can now get smooth dvd seeking.

  • libs/libmythtv/DVDRingBuffer.cpp

     
    4545      seekpos(0), seekwhence(0),
    4646      dvdname(NULL), serialnumber(NULL),
    4747      seeking(false), seekTime(0),
     48      currentTime(0),
    4849      parent(0)
    4950{
    5051    memset(&dvdMenuButton, 0, sizeof(AVSubtitle));
     
    8182long long DVDRingBufferPriv::Seek(long long time)
    8283{
    8384    seekTime = (uint64_t)time;
    84     uint offset_divider = 1;
     85    uint searchToCellStart = 1;
    8586    int ffrewSkip = 1;
    8687    if (parent)
    8788        ffrewSkip = parent->GetFFRewSkip();
    88     dvdnav_status_t dvdRet = dvdnav_time_search(this->dvdnav, seekTime, offset_divider);
     89    if (ffrewSkip != 1)
     90        searchToCellStart = 0;
     91    dvdnav_status_t dvdRet =
     92        dvdnav_time_search(this->dvdnav, seekTime, searchToCellStart);
    8993    if (dvdRet == DVDNAV_STATUS_ERR)
    9094    {
    9195        VERBOSE(VB_PLAYBACK, LOC_ERR +
     
    9599    {
    96100        gotStop = false;
    97101        // TODO: precise seeking too inefficient
    98         //if (time > 0 && ffrewSkip == 1)
    99         //    seeking = true;
     102        if (time > 0 && ffrewSkip == 1)
     103            seeking = true;
    100104    }
    101105   
    102106    return currentpos;
     
    212216        return -1;
    213217    }
    214218
     219    QMutexLocker lock(&seekLock);
    215220    while (needed)
    216221    {
    217222        blockBuf = dvdBlockWriteBuf;
     
    391396                    }
    392397                }
    393398
     399                dvd_time_t timeFromCellStart = dsi->dsi_gi.c_eltm;
     400                currentTime = cellStart +
     401                    (uint)(dvdnav_convert_time(&timeFromCellStart));
    394402                currentpos = GetReadPosition();
    395403               
    396404                if (seeking)
    397405                {
    398                     dvd_time_t timeFromCellStart = dsi->dsi_gi.c_eltm;
    399                     uint64_t currentpts = cellStart +
    400                         (uint)dvdnav_convert_time(&timeFromCellStart);
    401                     if (currentpts >= seekTime)
     406                    uint relativeTime = (uint)((seekTime - currentTime)/ 90000);
     407                    if (relativeTime == 0)
    402408                    {
    403409                        seeking = false;
    404410                        seekTime = 0;
    405411                    }
     412                    else
     413                        dvdnav_time_search_within_cell(dvdnav, relativeTime);
    406414                }
    407415               
    408416                if (blockBuf != dvdBlockWriteBuf)
     
    990998uint DVDRingBufferPriv::GetCurrentTime(void)
    991999{
    9921000    QMutexLocker lock(&seekLock);
    993     dsi_t *dvdnavDsi = dvdnav_get_current_nav_dsi(dvdnav);
    994     dvd_time_t timeFromCellStart = dvdnavDsi->dsi_gi.c_eltm;
    995     uint currentTime = GetCellStart() +
    996         (uint)(dvdnav_convert_time(&timeFromCellStart) / 90000);
    997     return currentTime;
     1001    return (currentTime / 90000);
    9981002}
    9991003
    10001004uint DVDRingBufferPriv::GetAudioLanguage(int id)
  • libs/libmythtv/DVDRingBuffer.h

     
    160160    QString        serialnumber;
    161161    bool           seeking;
    162162    uint64_t       seekTime;
     163    uint           currentTime;
    163164
    164165    NuppelVideoPlayer *parent;
    165166
  • libs/libmythdvdnav/searching.c

     
    6363  }
    6464  if(admap) {
    6565    uint32_t address = 0;
    66     uint32_t vobu_start, next_vobu;
     66    uint32_t vobu_start, next_vobu, first_address, last_address;
    6767    int32_t found = 0;
    6868
    6969    /* Search through ADMAP for best sector */
    7070    vobu_start = SRI_END_OF_CELL;
    71     /* FIXME: Implement a faster search algorithm */
    72     while((!found) && ((address<<2) < admap->last_byte)) {
    73       next_vobu = admap->vobu_start_sectors[address];
     71    /* use binary search algorithm to improve efficiency */
     72    if (admap->last_byte > 20 &&
     73        admap->vobu_start_sectors[20] >= seekto_block)
     74    {
     75      while((!found) && ((address<<2) < admap->last_byte)) {
     76        next_vobu = admap->vobu_start_sectors[address];
    7477
    75       /* fprintf(MSG_OUT, "libdvdnav: Found block %u\n", next_vobu); */
    76 
    77       if (next_vobu == seekto_block) {
    78                 vobu_start = next_vobu;
    79         found = 1;
    80       } else if (vobu_start < seekto_block && next_vobu > seekto_block) {
    81         found = 1;
    82       } else {
    83         vobu_start = next_vobu;
     78        if (next_vobu == seekto_block) {
     79                  vobu_start = next_vobu;
     80          found = 1;
     81        } else if (vobu_start < seekto_block && next_vobu > seekto_block) {
     82          found = 1;
     83        } else {
     84          vobu_start = next_vobu;
     85        }
     86        address ++;
    8487      }
    85       address ++;
    8688    }
     89    else {
     90      found = 0;
     91      first_address = 0;
     92      last_address  = admap->last_byte >> 2;
     93      while ((!found) && first_address <= last_address)
     94      {
     95        address = (first_address + last_address) / 2;
     96        next_vobu = admap->vobu_start_sectors[address];
     97        if (seekto_block > next_vobu)
     98          first_address = address + 1;
     99        else if (seekto_block < next_vobu)
     100          last_address = address - 1;
     101        else {
     102          vobu_start = next_vobu;
     103          found = 1;
     104          break;
     105        }
     106      }
     107    }
    87108    if(found) {
    88109      *vobu = vobu_start;
    89110      return DVDNAV_STATUS_OK;
     
    97118}
    98119
    99120dvdnav_status_t dvdnav_time_search(dvdnav_t *this,
    100                                    uint64_t time, uint offset_divider) {
     121                                   uint64_t time, uint search_to_nearest_cell) {
    101122 
    102123  uint64_t target = time;
    103124  uint64_t length = 0;
     
    110131 
    111132  cell_playback_t *cell;
    112133  dvd_state_t *state;
    113   dsi_t *dsi;
    114134  dvdnav_status_t result;
    115135
    116136  if(this->position_current.still != 0) {
     
    146166    cell_length = dvdnav_convert_time(&cell->playback_time);
    147167    length += cell_length;
    148168    if (target <= length) {
    149       offset = (cell->last_sector - cell->first_sector) / offset_divider;
     169      offset = (cell->last_sector - cell->first_sector);
    150170      diff2  = ((double)target - (double)prev_length) / (double)cell_length;
    151171      offset = (diff2 * offset);
    152172      target = cell->first_sector;
    153       target += offset;
    154      
     173      if (!search_to_nearest_cell)
     174        target += offset;
    155175      found = 1;
    156176      break;
    157177    }
     
    619639 
    620640  return DVDNAV_STATUS_OK;
    621641}
     642
     643dvdnav_status_t dvdnav_time_search_within_cell(dvdnav_t *this,
     644                    uint relative_time)
     645{
     646  if(!this) {
     647    printerr("Passed a NULL pointer.");
     648    return DVDNAV_STATUS_ERR;
     649  }
     650
     651  uint32_t cur_vobu, new_vobu, start;
     652  int current_cell, i;
     653 
     654  dsi_t * dsi;
     655  dvd_state_t *state;
     656  int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11,
     657                    10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
     658  pthread_mutex_lock(&this->vm_lock);
     659  cur_vobu = this->vobu.vobu_start;
     660  for (i = 0; i <= 19; i++) {
     661    if (stime[i]/2.0 <= relative_time) {
     662      dsi = dvdnav_get_current_nav_dsi(this);
     663      new_vobu = cur_vobu + (dsi->vobu_sri.fwda[i] & 0xfffff);
     664      break;
     665    }
     666  }
     667 
     668  state = &(this->vm->state);
     669  current_cell = state->cellN;
     670  start =  state->pgc->cell_playback[current_cell-1].first_sector;
     671  if (vm_jump_cell_block(this->vm, state->cellN, new_vobu - start)) {
     672    this->vm->hop_channel += HOP_SEEK;
     673  }
     674  pthread_mutex_unlock(&this->vm_lock);
     675  return DVDNAV_STATUS_OK;
     676}
  • libs/libmythdvdnav/dvdnav.h

     
    362362 * Stop playing the current position and start playback of the title
    363363 * from the specified timecode.
    364364 *
    365  * Currently unimplemented!
     365 * if search_to_nearest_cell is set then search to the nearest Cell.
     366 * and then use dvdnav_time_search_within_cell for further seeking
     367 * Otherwise tries to guess the nearest VOBU by calculating an offset.
    366368 */
    367369dvdnav_status_t dvdnav_time_search(dvdnav_t *self,
    368                                    uint64_t time, uint offset_divider);
     370                                   uint64_t time, uint search_to_nearest_cell);
    369371
     372/* Seeks the nearest VOBU to the relative_time within the cell
     373 * relative_time is in seconds
     374 */
     375dvdnav_status_t dvdnav_time_search_within_cell(dvdnav_t *self,
     376                   uint relative_time);
    370377/*
    371378 * Stop playing current position and play the "GoUp"-program chain.
    372379 * (which generally leads to the title menu or a higer-level menu).