//********************************************************* // Determines the total duration of the file (or timeshifting files) // // void CTsDuration::UpdateDuration(bool logging) { if (!m_pFileReadBuffer) { m_startPcr.Reset(); m_endPcr.Reset(); LogDebug("CTsDuration::UpdateDuration() - ERROR no buffer !!"); return; } int Loop=5 ; int searchLoopCnt; do { m_bSearchStart=true; m_bSearchEnd=false; m_startPcr.Reset(); m_endPcr.Reset(); m_maxPcr.Reset(); searchLoopCnt = 2; __int64 offset=0; Reset() ; // Reset internal "PacketSync" buffer if (logging) { LogDebug("UpdateDuration - find pcr"); } //find the first pcr in the file while (!m_startPcr.IsValid) { if (m_bStopping) { m_startPcr.Reset(); m_endPcr.Reset(); return; } DWORD dwBytesRead = 0; m_reader->SetFilePointer(offset,FILE_BEGIN); if (!SUCCEEDED(m_reader->Read(m_pFileReadBuffer,DUR_READ_SIZE,&dwBytesRead))) { return; } if (dwBytesRead<=0) { return; } OnRawData2(m_pFileReadBuffer,dwBytesRead); offset += (DUR_READ_SIZE*(searchLoopCnt/2)); //Move file pointer if (searchLoopCnt<65) { searchLoopCnt++; } else if (m_videoPid<0) { //failed to find a first PCR return; } else { //Search for any PCR from the beginning again m_videoPid = -1; searchLoopCnt = 2; offset = 0; Reset() ; // Reset internal "PacketSync" buffer } Sleep(1) ; } if (logging) { LogDebug("UpdateDuration - found startPcr, iterations:%d offset:%d", searchLoopCnt-2, offset); } //find the last pcr in the file m_bSearchEnd=true; m_bSearchStart=false; searchLoopCnt = 2; offset=DUR_READ_SIZE; while (!m_endPcr.IsValid) { if (m_bStopping) { m_startPcr.Reset(); m_endPcr.Reset(); return; } DWORD dwBytesRead = 0; m_reader->SetFilePointer(-offset,FILE_END); if (!SUCCEEDED(m_reader->Read(m_pFileReadBuffer,DUR_READ_SIZE,&dwBytesRead))) { m_startPcr.Reset(); m_endPcr.Reset(); return; } if (dwBytesRead<=0) { m_startPcr.Reset(); m_endPcr.Reset(); return; } Reset() ; // Reset internal "PacketSync" buffer OnRawData2(m_pFileReadBuffer,dwBytesRead); if (searchLoopCnt<65) { searchLoopCnt++; } else { //failed to find an end PCR m_startPcr.Reset(); m_endPcr.Reset(); return; } offset += ( (DUR_READ_SIZE*(searchLoopCnt/2)) - (188*16)); //step back a few packets less than a buffer so that buffers overlap Sleep(1) ; } if (logging) { LogDebug("UpdateDuration - found endPcr, iterations:%d offset:%d", searchLoopCnt-2, offset); } Loop-- ; if(m_endPcr.PcrReferenceBase < m_startPcr.PcrReferenceBase) { if (Loop < 4) // Show log on 2nd wrong detection. LogDebug("Abnormal start PCR, endPcr %I64d, startPcr %I64d",m_endPcr.PcrReferenceBase, m_startPcr.PcrReferenceBase); Sleep(20) ; } } while ((m_endPcr.PcrReferenceBase < m_startPcr.PcrReferenceBase) && Loop) ; // When startPcr > endPcr, it could be a result of wrong file used to find "startPcr". // If this file is just reused by TsWriter, and list buffer not updated yet, the search will operate // in the latest ts packets received causing the start higher the end ( readed in the previous buffer ) // The only thing to do to discriminate an error and a real rollover is to re-search startPcr. // Entering the following code with erroneous startPcr > endPcr makes an endless loop !! // The startPcr read can also failed when it occurs between deleting and reusing the ts buffer. // This abort the method. Duration will be updated on next call. if (Loop==0) LogDebug("PCR rollover normally found ! endPcr %I64d, startPcr %I64d",m_endPcr.PcrReferenceBase, m_startPcr.PcrReferenceBase); else { if(Loop<3) // 1 failed + 1 succeded is quasi-normal, more is a bit suspicious ( disk drive too slow or problem ? ) LogDebug("Recovered wrong start PCR, seek to 'begin' on reused file ! ( Retried %d times )",4-Loop) ; } //When the last pcr < first pcr then a pcr roll over occured //find where in the file this rollover happened //and fill maxPcr if (m_endPcr.PcrReferenceBase < m_startPcr.PcrReferenceBase) { m_maxPcr.PcrReferenceBase = 0x1ffffffffULL; m_maxPcr.PcrReferenceExtension = 0x1ffULL; m_maxPcr.IsValid = true; } }
//********************************************************* // 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; }