void TsStreamFileSource::seekToTimeAbsolute(CRefTime& seekTime, CTsDuration& duration) { FileReader* reader = (FileReader*)fFid; double startTime = seekTime.Millisecs(); startTime /= 1000.0f; LogDebug("StreamingServer:: Seek-> %f/%f", startTime, duration.Duration().Millisecs()/1000.0f); CTsFileSeek seek(duration); seek.SetFileReader(reader); for(int i(0) ; i < 4 ; i++) { bool eof = seek.Seek(seekTime); if (eof) { REFERENCE_TIME rollBackTime = reader->GetTimeshift() ? 5000000 : 30000000; // 0.5s/3s //reached end-of-file, try to seek to an earlier position if ((seekTime.m_time - rollBackTime) > 0) { seekTime.m_time -= rollBackTime; } else { break; //very short file.... } } else { break; //we've succeeded } } m_buffer.Clear(); }
// // Run // // Overriden to open the dump file // STDMETHODIMP EMReadFrameFilter::Run(REFERENCE_TIME tStart) { IReferenceClock *pClock = m_pClock; CAutoLock cObjectLock(m_pLock); CRefTime agnusStreamTimeObject; StreamTime(agnusStreamTimeObject); long millisekunder = agnusStreamTimeObject.Millisecs(); return CBaseFilter::Run(tStart); }
// // SeekDone // STDMETHODIMP CDVBSub::SeekDone( CRefTime& rtSeek ) { // Notify reset observer (clears all cached subtitles on client side) if( m_pResetObserver ) { (*m_pResetObserver)(); } // milliseconds to PCR (90Khz) m_CurrentSeekPosition = rtSeek.Millisecs() * 90; LogDebugPTS( "SeekDone", m_CurrentSeekPosition ); return S_OK; }
void CTsReaderFilter::SeekPreStart(CRefTime& rtAbsSeek) { bool doSeek = true; CTsDuration tsduration=GetDuration(); SetMediaPosition(rtAbsSeek.m_time) ; //Note that the seek timestamp (m_rtStart) is done in the range //from earliest - latest from GetAvailable() //We however would like the seek timestamp to be in the range 0-fileduration CRefTime rtSeek = rtAbsSeek; float seekTime = (float)rtSeek.Millisecs(); seekTime /= 1000.0f; //get the earliest timestamp available in the file float earliesTimeStamp = 0; earliesTimeStamp = tsduration.StartPcr().ToClock() - tsduration.FirstStartPcr().ToClock(); if (earliesTimeStamp < 0) earliesTimeStamp = 0; //correct the seek time seekTime -= earliesTimeStamp; if (seekTime < 0) seekTime = 0; seekTime *= 1000.0f; rtSeek = CRefTime((LONG)seekTime); // Now rtSeek contains the "relative" position from "0 to buffer/file duration" // Should we really seek ? // Because all skips generated after "Stop()" cause a lot of problem // This remove all these stupid skips. if(m_State == State_Stopped) { if ((m_bStoppedForUnexpectedSeek || (m_absSeekTime==rtAbsSeek)) && !m_bForceSeekOnStop && !m_bForceSeekAfterRateChange) { // LogDebug("CTsReaderFilter::--SeekStart() Stopped state -- No new seek %f", // (float)rtSeek.Millisecs()/1000.0f); m_bStoppedForUnexpectedSeek=false ; m_seekTime = rtSeek ; m_absSeekTime = rtAbsSeek ; return ; } } if (((m_absSeekTime==rtAbsSeek) && !m_bStreamCompensated && !m_bForceSeekAfterRateChange) || (m_demultiplexer.IsMediaChanging() && !m_bOnZap && !m_bForceSeekOnStop && !m_bForceSeekAfterRateChange)) { doSeek = false; LogDebug("CTsReaderFilter::--SeekStart()-- No new seek %f ( Abs %f / %f ) - Stream compensated: %d, OnZap: %d, Force %d, Media changing: %d", (float)rtSeek.Millisecs()/1000.0f, (float)rtAbsSeek.Millisecs()/1000.0f, (float)m_duration.EndPcr().ToClock(),m_bStreamCompensated,m_bOnZap,m_bForceSeekOnStop, m_demultiplexer.IsMediaChanging()); // m_bStreamCompensated=false ; m_bForceSeekOnStop = false ; } else { LogDebug("CTsReaderFilter::--SeekStart()-- LiveTv : %d, TimeShifting: %d %3.3f ( Abs %f / %f ), OnZap: %d, Force %d, ForceRC %d, Media changing %d", m_bLiveTv,m_bTimeShifting,(float)rtSeek.Millisecs()/1000.0,(float)rtAbsSeek.Millisecs()/1000.0f, (float)m_duration.EndPcr().ToClock(),m_bOnZap,m_bForceSeekOnStop,m_bForceSeekAfterRateChange,m_demultiplexer.IsMediaChanging()); m_bForceSeekOnStop = false ; if (m_bForceSeekAfterRateChange) { m_bSeekAfterRcDone = true; m_bForceSeekAfterRateChange = false ; } if (m_bTimeShifting) { LONG duration = m_duration.Duration().Millisecs() ; LONG seekTime = rtSeek.Millisecs() ; if (seekTime + 200 > duration) // End of timeshift buffer requested. { if (m_bLiveTv && !m_bAnalog && (m_fileDuration != NULL)) doSeek=false ; // Live & not analog & not RTSP do not seek m_bLiveTv=true ; } else m_bLiveTv=false ; LogDebug("Zap to File Seek : %d mS ( %f / %f ) LiveTv : %d, Seek : %d",GetTickCount()-m_lastPause, (float)seekTime/1000.0f, (float)duration/1000.0f, m_bLiveTv, doSeek); } m_seekTime=rtSeek ; m_absSeekTime = rtAbsSeek ; if (!doSeek && !m_bOnZap) return ; // m_demultiplexer.SetHoldAudio(true) ; // m_demultiplexer.SetHoldVideo(true) ; m_WaitForSeekToEof=1 ; // m_demultiplexer.CallTeletextEventCallback(TELETEXT_EVENT_SEEK_START,TELETEXT_EVENTVALUE_NONE); // Stop threads //// if (GetAudioPin()->IsConnected()) { //deliver a begin-flush to the codec filter so it stops asking for data GetAudioPin()->DeliverBeginFlush(); //stop the thread GetAudioPin()->Stop(); } if (GetVideoPin()->IsConnected()) { //deliver a begin-flush to the codec filter so it stops asking for data GetVideoPin()->DeliverBeginFlush(); //stop the thread GetVideoPin()->Stop(); } m_bStreamCompensated=false ; m_demultiplexer.m_bAudioVideoReady=false ; if (!m_bOnZap || !m_demultiplexer.IsNewPatReady() || m_bAnalog) // On zapping, new PAT has occured, we should not flush to avoid loosing data. { // new PAT has not occured, we should flush to avoid restart with old data. m_demultiplexer.FlushAudio() ; m_demultiplexer.FlushVideo() ; } m_bOnZap=false ; // m_demultiplexer.SetHoldAudio(false) ; // m_demultiplexer.SetHoldVideo(false) ; //do the seek... if (doSeek && !m_demultiplexer.IsMediaChanging()&& !m_demultiplexer.IsAudioChanging()) Seek(rtSeek, true); //tell filter we're done with seeking // m_pTsReaderFilter->SeekDone(rtSeek); m_WaitForSeekToEof=0 ; // if (m_fileDuration != NULL) { if (rtSeek >= m_duration.Duration()) { rtSeek=m_duration.Duration(); } } if (GetAudioPin()->IsConnected()) { // deliver a end-flush to the codec filter so it will start asking for data again GetAudioPin()->DeliverEndFlush(); // Update m_rtStart in case of has not seeked yet GetAudioPin()->SetStart(rtAbsSeek) ; // and restart the thread GetAudioPin()->Run(); } if (GetVideoPin()->IsConnected()) { //deliver a end-flush to the codec filter so it will start asking for data again GetVideoPin()->DeliverEndFlush(); // Update m_rtStart in case of has not seeked yet GetVideoPin()->SetStart(rtAbsSeek) ; // and restart the thread GetVideoPin()->Run(); } m_demultiplexer.CallTeletextEventCallback(TELETEXT_EVENT_SEEK_END,TELETEXT_EVENTVALUE_NONE); if (m_pDVBSubtitle) { m_pDVBSubtitle->SetFirstPcr(m_duration.FirstStartPcr().PcrReferenceBase); m_pDVBSubtitle->SeekDone(rtSeek); } } return ; }
//********************************************************* // Seeks in the file to the specific timestamp // refTime : timestamp. Should be 0 < timestamp < duration // // The method will make a guess where the timestamp is located in the file // and do a PCR seek from there until it finds the correct timestamp // bool CTsFileSeek::Seek(CRefTime refTime) { double fileDuration=(double)m_duration.Duration().Millisecs(); double seekTimeStamp=(double)refTime.Millisecs(); //sanity checks... if (seekTimeStamp < 0) seekTimeStamp=0; //if (seekTimeStamp > fileDuration) seekTimeStamp=fileDuration; //make a guess where should start looking in the file double percent=seekTimeStamp/fileDuration; __int64 filePos=(__int64)(m_reader->GetFileSize()*percent); filePos/=188; filePos*=188; seekTimeStamp /= 1000.0f; // convert to seconds. m_seekPid=m_duration.GetPid(); LogDebug("FileSeek: seek to %f filepos:%x pid:%x", seekTimeStamp,(DWORD)filePos, m_seekPid); byte buffer[188*10]; __int64 binaryMax=m_reader->GetFileSize(); __int64 binaryMin=0; __int64 lastFilePos=0; int seekingIteration=0; __int64 firstFilePos=filePos; int noPCRIteration=0; bool noPCRloop = false; Reset() ; // Reset "PacketSync" while (true) { //sanity checks if (filePos<=0) { //no need to seek for timestamp 0, //simply set the pointer at the beginning of the file m_reader->SetFilePointer(0,FILE_BEGIN); return false; } if (filePos+sizeof(buffer) > m_reader->GetFileSize()) { //no need to seek when we want to seek to end of file //simply set the pointer at the end of the file m_reader->SetFilePointer(0,FILE_END); return false; } //set filepointer to filePos m_reader->SetFilePointer(filePos,FILE_BEGIN); //read buffer from file at position filePos DWORD dwBytesRead; if (!SUCCEEDED(m_reader->Read(buffer, sizeof(buffer),&dwBytesRead))) { LogDebug("FileSeek: read failed at filePos: %x - target time: %f, iterations: %d", (DWORD)filePos, seekTimeStamp, seekingIteration); return true; } if (dwBytesRead <= 0) //end-of-file { LogDebug("FileSeek: end-of-file at filePos: %x - target time: %f, iterations: %d", (DWORD)filePos, seekTimeStamp, seekingIteration); return true; } //process data m_pcrFound.Reset(); OnRawData2(buffer,dwBytesRead); //did we find a pcr? if (m_pcrFound.IsValid) { //yes. pcr found double clockFound=m_pcrFound.ToClock(); double diff = clockFound - seekTimeStamp; //LogDebug(" got %f at filepos %x diff %f ( %I64x, %I64x )", clockFound, (DWORD)filePos, diff, binaryMin, binaryMax); // Make sure that seeking position is at least the target one if (0 <= diff && diff <= SEEKING_ACCURACY) { LogDebug("FileSeek: stop seek: %f at %x - target: %f, diff: %f, iterations: %d", clockFound, (DWORD)filePos, seekTimeStamp, diff, seekingIteration); m_reader->SetFilePointer(filePos,FILE_BEGIN); return false; } noPCRIteration = 0; seekingIteration++; if( seekingIteration > MAX_SEEKING_ITERATIONS ) { LogDebug("FileSeek: stop seek max iterations reached (%d): %f at %x - target: %f, diff: %f", MAX_SEEKING_ITERATIONS, clockFound, (DWORD)filePos, seekTimeStamp, diff); if (fabs(diff) < 2.0) { m_reader->SetFilePointer(filePos,FILE_BEGIN); } else { //Set the file pointer to the initial estimate - the best we can do... m_reader->SetFilePointer(firstFilePos,FILE_BEGIN); } return false; } // lower bound becomes valid if( clockFound > seekTimeStamp ) { if (filePos < binaryMax) binaryMax = filePos-1; } else { if (filePos > binaryMin) binaryMin = filePos+1; } lastFilePos=filePos; filePos = binaryMin + ( binaryMax - binaryMin ) / 2; filePos/=188; filePos*=188; if (lastFilePos==filePos) { LogDebug("FileSeek: stop seek closer target found : %f at %x - target: %f, diff: %f", clockFound, (DWORD)filePos, seekTimeStamp, diff); m_reader->SetFilePointer(filePos,FILE_BEGIN); return false; } Reset() ; // Random jump, Reset "PacketSync" } else // no first PCR { //move filepointer forward and continue searching for a PCR filePos += sizeof(buffer); noPCRIteration++; if (noPCRIteration > MAX_BUFFER_ITERATIONS) { if (noPCRloop) //second time this has happened { LogDebug("FileSeek: stop seek, no PCR found, max iterations reached (%d)", MAX_BUFFER_ITERATIONS); //Set the file pointer to the initial estimate - the best we can do... m_reader->SetFilePointer(firstFilePos,FILE_BEGIN); return false; } //Let's try looking for any PCR pid //starting again from the initial position LogDebug("FileSeek: No PCR found (pid = %d), trying for any PCR pid", m_seekPid); m_seekPid = -1; filePos = firstFilePos; noPCRIteration = 0; noPCRloop = true; } } } return false; }