Beispiel #1
0
bool CDVDInputStreamNavigator::SeekChapter(int iChapter)
{
  bool enabled = IsSubtitleStreamEnabled();
  int audio    = GetActiveAudioStream();
  int subtitle = GetActiveSubtitleStream();

  if (iChapter == (m_iPart + 1))
  {
    if (m_dll.dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR)
    {
      CLog::Log(LOGERROR, "dvdnav: dvdnav_next_pg_search( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
      return false;
    }
  }
  else
  if (iChapter == (m_iPart - 1))
  {
    if (m_dll.dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR)
    {
      CLog::Log(LOGERROR, "dvdnav: dvdnav_prev_pg_search( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
      return false;
    }
  }
  else  
  if (m_dll.dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR)
  {
    CLog::Log(LOGERROR, "dvdnav: dvdnav_part_play failed( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
    return false;
  }

  SetActiveSubtitleStream(subtitle);
  SetActiveAudioStream(audio);
  EnableSubtitleStream(enabled);
  return true;
}
Beispiel #2
0
bool CDVDInputStreamNavigator::SeekChapter(int iChapter)
{
  if (!m_dvdnav)
    return false;

  // cannot allow to return true in case of buttons (overlays) because otherwise back in DVDPlayer FlushBuffers will remove menu overlays
  // therefore we just skip the request in case there are buttons and return false
  if (IsInMenu() && GetTotalButtons() > 0)
  {
    CLog::Log(LOGDEBUG, "%s - Seeking chapter is not allowed in menu set with buttons", __FUNCTION__);
    return false;
  }

  bool enabled = IsSubtitleStreamEnabled();
  int audio    = GetActiveAudioStream();
  int subtitle = GetActiveSubtitleStream();

  if (iChapter == (m_iPart + 1))
  {
    if (m_dll.dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR)
    {
      CLog::Log(LOGERROR, "dvdnav: dvdnav_next_pg_search( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
      return false;
    }
  }
  else
  if (iChapter == (m_iPart - 1))
  {
    if (m_dll.dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR)
    {
      CLog::Log(LOGERROR, "dvdnav: dvdnav_prev_pg_search( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
      return false;
    }
  }
  else  
  if (m_dll.dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR)
  {
    CLog::Log(LOGERROR, "dvdnav: dvdnav_part_play failed( %s )", m_dll.dvdnav_err_to_string(m_dvdnav));
    return false;
  }

  SetActiveSubtitleStream(subtitle);
  SetActiveAudioStream(audio);
  EnableSubtitleStream(enabled);
  return true;
}
Beispiel #3
0
int CDVDInputStreamNavigator::ProcessBlock(BYTE* dest_buffer, int* read)
{
  if (!m_dvdnav) return -1;

  int result;
  int len;
  int iNavresult = NAVRESULT_NOP;

  // m_tempbuffer will be used for anything that isn't a normal data block
  uint8_t* buf = m_lastblock;
  iNavresult = -1;

  if(m_holdmode == HOLDMODE_HELD)
    return NAVRESULT_HOLD;

  try
  {
    // the main reading function
    if(m_holdmode == HOLDMODE_SKIP)
    { /* we where holding data, return the data held */
      m_holdmode = HOLDMODE_DATA;
      result = DVDNAV_STATUS_OK;
    }
    else
      result = m_dll.dvdnav_get_next_cache_block(m_dvdnav, &buf, &m_lastevent, &len);

  }
  catch (...)
  {
    CLog::Log(LOGERROR, "CDVDInputStreamNavigator::ProcessBlock - exception thrown in dvdnav_get_next_cache_block.");

    // okey, we are probably holding a vm_lock here so leave it.. this could potentialy cause problems if we aren't holding it
    // but it's more likely that we do
    LeaveCriticalSection((LPCRITICAL_SECTION)&(m_dvdnav->vm_lock));
    m_bEOF = true;
    return NAVRESULT_ERROR;
  }

  if (result == DVDNAV_STATUS_ERR)
  {
    CLog::Log(LOGERROR,"Error getting next block: %s\n", m_dll.dvdnav_err_to_string(m_dvdnav));
    m_bEOF = true;
    return NAVRESULT_ERROR;
  }

    switch (m_lastevent)
    {
    case DVDNAV_BLOCK_OK:
      {
        // We have received a regular block of the currently playing MPEG stream.
        // buf contains the data and len its length (obviously!) (which is always 2048 bytes btw)
        m_holdmode = HOLDMODE_NONE;
        memcpy(dest_buffer, buf, len);
        *read = len;
        iNavresult = NAVRESULT_DATA;
      }
      break;

    case DVDNAV_NOP:
      // Nothing to do here.
      break;

    case DVDNAV_STILL_FRAME:
      {
        // We have reached a still frame. A real player application would wait
        // the amount of time specified by the still's length while still handling
        // user input to make menus and other interactive stills work.
        // A length of 0xff means an indefinite still which has to be skipped
        // indirectly by some user interaction.
        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_STILL_FRAME);

        /* if user didn't care for action, just skip it */
        if(iNavresult == NAVRESULT_NOP)
          SkipStill();
      }
      break;

    case DVDNAV_WAIT:
      {
        // We have reached a point in DVD playback, where timing is critical.
        // Player application with internal fifos can introduce state
        // inconsistencies, because libdvdnav is always the fifo's length
        // ahead in the stream compared to what the application sees.
        // Such applications should wait until their fifos are empty
        // when they receive this type of event.
        if(m_holdmode == HOLDMODE_NONE)
        {
          CLog::Log(LOGDEBUG, " - DVDNAV_WAIT (HOLDING)");
          m_holdmode = HOLDMODE_HELD;
          iNavresult = NAVRESULT_HOLD;
        }
        else
          iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_WAIT);

        /* if user didn't care for action, just skip it */
        if(iNavresult == NAVRESULT_NOP)
          SkipWait();
      }
      break;

    case DVDNAV_SPU_CLUT_CHANGE:
      // Player applications should pass the new colour lookup table to their
      // SPU decoder. The CLUT is given as 16 uint32_t's in the buffer.
      {
        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_SPU_CLUT_CHANGE);
      }
      break;

    case DVDNAV_SPU_STREAM_CHANGE:
      // Player applications should inform their SPU decoder to switch channels
      {
        dvdnav_spu_stream_change_event_t* event = (dvdnav_spu_stream_change_event_t*)buf;

        //libdvdnav never sets logical, why.. don't know..
        event->logical = GetActiveSubtitleStream();

        if(event->logical<0 && GetSubTitleStreamCount()>0)
        {
          /* this will not take effect in this event */
          CLog::Log(LOGINFO, "%s - none or invalid subtitle stream selected, defaulting to first", __FUNCTION__);
          SetActiveSubtitleStream(0);
        }
        m_bCheckButtons = true;
        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_SPU_STREAM_CHANGE);
      }
      break;

    case DVDNAV_AUDIO_STREAM_CHANGE:
      // Player applications should inform their audio decoder to switch channels
      {

        //dvdnav_get_audio_logical_stream actually does the oposite to the docs..
        //taking a audiostream as given on dvd, it gives the physical stream that
        //refers to in the mpeg file

        dvdnav_audio_stream_change_event_t* event = (dvdnav_audio_stream_change_event_t*)buf;

        //wroong... stupid docs..
        //event->logical = dvdnav_get_audio_logical_stream(m_dvdnav, event->physical);
        //logical should actually be set to the (vm->state).AST_REG

        event->logical = GetActiveAudioStream();
        if(event->logical<0)
        {
          /* this will not take effect in this event */
          CLog::Log(LOGINFO, "%s - none or invalid audio stream selected, defaulting to first", __FUNCTION__);
          SetActiveAudioStream(0);
        }

        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_AUDIO_STREAM_CHANGE);
      }

      break;

    case DVDNAV_HIGHLIGHT:
      {
        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_HIGHLIGHT);
      }
      break;

    case DVDNAV_VTS_CHANGE:
      // Some status information like video aspect and video scale permissions do
      // not change inside a VTS. Therefore this event can be used to query such
      // information only when necessary and update the decoding/displaying
      // accordingly.
      {
        if(m_holdmode == HOLDMODE_NONE)
        {
          CLog::Log(LOGDEBUG, " - DVDNAV_VTS_CHANGE (HOLDING)");
          m_holdmode = HOLDMODE_HELD;
          iNavresult = NAVRESULT_HOLD;
        }
        else
          iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_VTS_CHANGE);

        m_bInMenu = (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav));
      }
      break;

    case DVDNAV_CELL_CHANGE:
      {
        // Some status information like the current Title and Part numbers do not
        // change inside a cell. Therefore this event can be used to query such
        // information only when necessary and update the decoding/displaying
        // accordingly.

        // this may lead to a discontinuity, but it's also the end of the
        // vobunit, so make sure everything in demuxer is output
        if(m_holdmode == HOLDMODE_NONE)
        {
          CLog::Log(LOGDEBUG, "DVDNAV_CELL_CHANGE (HOLDING)");
          m_holdmode = HOLDMODE_HELD;
          iNavresult = NAVRESULT_HOLD;
          break;
        }

        uint32_t pos, len;

        m_dll.dvdnav_current_title_info(m_dvdnav, &m_iTitle, &m_iPart);
        m_dll.dvdnav_get_number_of_titles(m_dvdnav, &m_iTitleCount);
        if(m_iTitle > 0)
          m_dll.dvdnav_get_number_of_parts(m_dvdnav, m_iTitle, &m_iPartCount);
        else
          m_iPartCount = 0;
        m_dll.dvdnav_get_position(m_dvdnav, &pos, &len);

        CLog::Log(LOGDEBUG, "%s - Cell change: Title %d, Chapter %d\n", __FUNCTION__, m_iTitle, m_iPart);
        CLog::Log(LOGDEBUG, "%s - At position %.0f%% inside the feature\n", __FUNCTION__, 100 * (double)pos / (double)len);
        //Get total segment time

        dvdnav_cell_change_event_t* cell_change_event = (dvdnav_cell_change_event_t*)buf;
        m_iCellStart = cell_change_event->cell_start; // store cell time as we need that for time later
        m_iTotalTime = (int) (cell_change_event->pgc_length / 90);
        m_icurrentGroupId = cell_change_event->pgN * 1000 + cell_change_event->cellN;

        iNavresult = m_pDVDPlayer->OnDVDNavResult(buf, DVDNAV_CELL_CHANGE);
      }
      break;

    case DVDNAV_NAV_PACKET:
      {
        // A NAV packet provides PTS discontinuity information, angle linking information and
        // button definitions for DVD menus. Angles are handled completely inside libdvdnav.
        // For the menus to work, the NAV packet information has to be passed to the overlay
        // engine of the player so that it knows the dimensions of the button areas.

        // Applications with fifos should not use these functions to retrieve NAV packets,
        // they should implement their own NAV handling, because the packet you get from these
        // functions will already be ahead in the stream which can cause state inconsistencies.
        // Applications with fifos should therefore pass the NAV packet through the fifo
        // and decoding pipeline just like any other data.

        // Calculate current time
        //unsigned int pos, len;
        //m_dll.dvdnav_get_position(m_dvdnav, &pos, &len);
        //m_iTime = (int)(((__int64)m_iTotalTime * pos) / len);

        pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav);
        m_dll.dvdnav_get_current_nav_dsi(m_dvdnav);

        if(!pci)
        {
          iNavresult = NAVRESULT_NOP;
          break;
        }

        /* if we have any buttons or are not in vts domain we assume we are in meny */
        m_bInMenu = pci->hli.hl_gi.hli_ss || (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav));

        /* check for any gap in the stream, this is likely a discontinuity */
        __int64 gap = (__int64)pci->pci_gi.vobu_s_ptm - m_iVobUnitStop;
        if(gap)
        {
          /* make sure demuxer is flushed before we change any correction */
          if(m_holdmode == HOLDMODE_NONE)
          {
            CLog::Log(LOGDEBUG, "DVDNAV_NAV_PACKET (HOLDING)");
            m_holdmode = HOLDMODE_HELD;
            iNavresult = NAVRESULT_HOLD;
            break;
          }
          m_iVobUnitCorrection += gap;

          CLog::Log(LOGDEBUG, "DVDNAV_NAV_PACKET - DISCONTINUITY FROM:%"PRId64" TO:%"PRId64" DIFF:%"PRId64, (m_iVobUnitStop * 1000)/90, ((__int64)pci->pci_gi.vobu_s_ptm*1000)/90, (gap*1000)/90);
        }

        m_iVobUnitStart = pci->pci_gi.vobu_s_ptm;
        m_iVobUnitStop = pci->pci_gi.vobu_e_ptm;

        m_iTime = (int) ( m_dll.dvdnav_convert_time( &(pci->pci_gi.e_eltm) ) + m_iCellStart ) / 90;

        if (m_bCheckButtons)
        {
          CheckButtons();
          m_bCheckButtons = false;
        }

        iNavresult = m_pDVDPlayer->OnDVDNavResult((void*)pci, DVDNAV_NAV_PACKET);
      }
      break;

    case DVDNAV_HOP_CHANNEL:
      // This event is issued whenever a non-seamless operation has been executed.
      // Applications with fifos should drop the fifos content to speed up responsiveness.
      {
        iNavresult = m_pDVDPlayer->OnDVDNavResult(NULL, DVDNAV_HOP_CHANNEL);
      }
      break;

    case DVDNAV_STOP:
      {
        // Playback should end here.

        // don't read any further, it could be libdvdnav had some problems reading
        // the disc. reading further results in a crash
        m_bEOF = true;

        m_pDVDPlayer->OnDVDNavResult(NULL, DVDNAV_STOP);
        iNavresult = NAVRESULT_ERROR;
      }
      break;

    default:
      {
        CLog::Log(LOGDEBUG,"CDVDInputStreamNavigator: Unknown event (%i)\n", m_lastevent);
      }
      break;

    }

    // check if libdvdnav gave us some other buffer to work with
    // probably not needed since function will check if buf
    // is part of the internal cache, but do it for good measure
    if( buf != m_lastblock )
      m_dll.dvdnav_free_cache_block(m_dvdnav, buf);

  return iNavresult;
}