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; }
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; }
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; }