HRESULT CAudioPin::CompleteConnect(IPin *pReceivePin) { m_bInFillBuffer = false; m_bPinNoAddPMT = false; m_bAddPMT = true; m_bDisableSlowPlayDiscontinuity=false; //LogDebug("audPin:CompleteConnect()"); HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); if (!SUCCEEDED(hr)) return E_FAIL; PIN_INFO pinInfo; FILTER_INFO filterInfo; hr=pReceivePin->QueryPinInfo(&pinInfo); if (!SUCCEEDED(hr)) return E_FAIL; else if (pinInfo.pFilter==NULL) return E_FAIL; else pinInfo.pFilter->Release(); // we dont need the filter just the info hr=pinInfo.pFilter->QueryFilterInfo(&filterInfo); filterInfo.pGraph->Release(); if (SUCCEEDED(hr)) { char szName[MAX_FILTER_NAME]; int cch = WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, MAX_FILTER_NAME, szName, MAX_FILTER_NAME, 0, 0); LogDebug("audPin:CompleteConnect() ok, filter: %s, iPosition: %d", szName, m_iPosition); m_bConnected=true; CLSID &ref=m_pTsReaderFilter->GetCLSIDFromPin(pReceivePin); m_pTsReaderFilter->m_audioDecoderCLSID = ref; if (m_pTsReaderFilter->m_audioDecoderCLSID == CLSID_LAVAUDIO) { m_bDisableSlowPlayDiscontinuity = (m_pTsReaderFilter->m_regLAV_AutoAVSync > 0); LogDebug("audPin:CompleteConnect() DisableSlowPlayDiscontinuity = %d", m_bDisableSlowPlayDiscontinuity); } } else { LogDebug("audPin:CompleteConnect() failed:%x, iPosition: %d", hr, m_iPosition); return E_FAIL; } if (m_pTsReaderFilter->IsTimeShifting()) { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } else { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } //LogDebug("audPin:CompleteConnect() end"); return hr; }
HRESULT CSubtitlePin::CompleteConnect(IPin *pReceivePin) { m_bInFillBuffer=false; //LogDebug("subPin:CompleteConnect()"); HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); if (!SUCCEEDED(hr)) return E_FAIL; PIN_INFO pinInfo; FILTER_INFO filterInfo; hr=pReceivePin->QueryPinInfo(&pinInfo); if (!SUCCEEDED(hr)) return E_FAIL; else if (pinInfo.pFilter==NULL) return E_FAIL; else pinInfo.pFilter->Release(); // we dont need the filter just the info hr=pinInfo.pFilter->QueryFilterInfo(&filterInfo); filterInfo.pGraph->Release(); if (SUCCEEDED(hr)) { char szName[MAX_FILTER_NAME]; int cch = WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, MAX_FILTER_NAME, szName, MAX_FILTER_NAME, 0, 0); LogDebug("subPin:CompleteConnect() ok, filter: %s", szName); m_bConnected=true; } else { LogDebug("subPin:CompleteConnect() failed:%x",hr); return E_FAIL; } if (m_pTsReaderFilter->IsTimeShifting()) { //m_rtDuration=CRefTime(MAX_TIME); REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } else { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } //LogDebug("subPin:CompleteConnect() end"); return hr; }
void TsMPEG2TransportFileServerMediaSubsession::seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes) { if (m_pDuration==NULL) { LogDebug("TsMp2TFSMediaSubsession::seekStreamSource - error, m_pDuration is NULL"); return; } TsMPEG2TransportStreamFramer* framer=(TsMPEG2TransportStreamFramer*)inputSource; TsStreamFileSource* source=(TsStreamFileSource*)framer->inputSource(); if (seekNPT==0.0) { source->seekToByteAbsolute(0LL); return; } double fileDuration=duration(); if (seekNPT>(fileDuration-0.1)) seekNPT=(fileDuration-0.1); if (seekNPT <0) seekNPT=0; double pos=seekNPT / fileDuration; __int64 fileSize=source->fileSize(); pos*=fileSize; pos/=188; pos*=188; source->seekToTimeAbsolute(CRefTime((LONG)(seekNPT*1000.0)), *m_pDuration) ; m_iDurationCount = 0; //LogDebug("TsMp2TFSMediaSubsession::seekStreamSource %f / %f", seekNPT, fileDuration); }
STDMETHODIMP CVideoPin::GetDuration(LONGLONG *pDuration) { REFERENCE_TIME refTime; m_pFilter->GetDuration(&refTime); m_rtDuration = CRefTime(refTime); return CSourceSeeking::GetDuration(pDuration); }
//****************************************************** /// Returns the file duration in REFERENCE_TIME /// For nomal .ts files it returns the current pcr - first pcr in the file /// for timeshifting files it returns the current pcr - the first pcr ever read /// So the duration keeps growing, even if timeshifting files are wrapped and being resued! // STDMETHODIMP CSubtitlePin::GetDuration(LONGLONG *pDuration) { if (m_pTsReaderFilter->IsTimeShifting()) { CRefTime totalDuration = m_pTsReaderFilter->m_duration.TotalDuration(); m_rtDuration = totalDuration; } else { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } return CSourceSeeking::GetDuration(pDuration); }
//****************************************************** /// Returns the file duration in REFERENCE_TIME /// For nomal .ts files it returns the current pcr - first pcr in the file /// for timeshifting files it returns the current pcr - the first pcr ever read /// So the duration keeps growing, even if timeshifting files are wrapped and being resued! // STDMETHODIMP CAudioPin::GetDuration(LONGLONG *pDuration) { //LogDebug("audPin:GetDuration"); if (m_pTsReaderFilter->IsTimeShifting()) { CRefTime totalDuration=m_pTsReaderFilter->m_duration.TotalDuration(); m_rtDuration=totalDuration; } else { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } if (pDuration!=NULL) { return CSourceSeeking::GetDuration(pDuration); } //LogDebug("audPin:GetDuration duration = %.3f ms, TotDuration = %.3f ms", (float)m_pTsReaderFilter->m_duration.Duration().Millisecs(), (float)m_pTsReaderFilter->m_duration.TotalDuration().Millisecs()); return S_OK; }
HRESULT CAudioPin::CompleteConnect(IPin *pReceivePin) { HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); if (SUCCEEDED(hr)) { LogDebug("aud:CompleteConnect() done"); m_bConnected = true; } else { LogDebug("aud:CompleteConnect() failed:%x", hr); return hr; } REFERENCE_TIME refTime; m_pFilter->GetDuration(&refTime); m_rtDuration = CRefTime(refTime); pReceivePin->QueryInterface(IID_IPinConnection, (void**)&m_pPinConnection); m_pReceiver = pReceivePin; return hr; }
HRESULT CVideoPin::CompleteConnect(IPin* pReceivePin) { HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); if (SUCCEEDED(hr)) { LogDebug("vid:CompleteConnect() done"); m_bConnected = true; m_currentDecoder = GetDecoderCLSID(pReceivePin); } else { LogDebug("vid:CompleteConnect() failed:%x", hr); m_currentDecoder = GUID_NULL; return hr; } REFERENCE_TIME refTime; m_pFilter->GetDuration(&refTime); m_rtDuration = CRefTime(refTime); m_pReceiver = pReceivePin; return hr; }
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 ; }
STDMETHODIMP CTsReaderFilter::Load(LPCOLESTR pszFileName,const AM_MEDIA_TYPE *pmt) { LogDebug("CTsReaderFilter::Load()"); //clean up any old file readers if (m_fileReader != NULL) delete m_fileReader; if (m_fileDuration != NULL) delete m_fileDuration; m_fileReader = NULL; m_fileDuration = NULL; m_seekTime = CRefTime(0L); m_absSeekTime = CRefTime(0L); m_WaitForSeekToEof=0; m_bRecording=false ; wcscpy(m_fileName, pszFileName); char url[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0 ,m_fileName, -1, url, MAX_PATH, 0, 0); //check file type int length=strlen(url); if ((length > 5) && (_strcmpi(&url[length-4], ".tsp") == 0)) { // .tsp file m_bTimeShifting = true; m_bLiveTv = true; FILE* fd = fopen(url, "rb"); if (fd == NULL) return E_FAIL; fread(url, 1, 100, fd); int bytesRead = fread(url, 1, sizeof(url), fd); if (bytesRead >= 0) url[bytesRead] = 0; fclose(fd); LogDebug("open %s", url); if ( !m_rtspClient.OpenStream(url)) return E_FAIL; m_buffer.Clear(); m_buffer.Run(true); m_rtspClient.Play(0.0,0.0); m_tickCount = GetTickCount(); m_fileReader = new CMemoryReader(m_buffer); m_demultiplexer.SetFileReader(m_fileReader); m_demultiplexer.Start(); m_buffer.Run(false); LogDebug("close rtsp:%s", url); m_rtspClient.Stop(); m_tickCount = GetTickCount()-m_rtspClient.Duration(); // Will be ready to update "virtual end Pcr" on recording in progress. double duration = m_rtspClient.Duration() / 1000.0f; CPcr pcrstart, pcrEnd, pcrMax; pcrstart = m_duration.StartPcr(); duration += pcrstart.ToClock(); pcrEnd.FromClock(duration); pcrstart.IsValid=true ; m_duration.Set(pcrstart, pcrEnd, pcrMax); //Load() } else if ((length > 7) && (strnicmp(url, "rtsp://",7) == 0)) { //rtsp:// stream //open stream LogDebug("open rtsp:%s", url); if ( !m_rtspClient.OpenStream(url)) return E_FAIL; m_bTimeShifting = true; m_bLiveTv = true; //are we playing a recording via RTSP if (strstr(url, "/stream") == NULL) { //yes, then we're not timeshifting m_bTimeShifting = false; m_bLiveTv = false; } //play m_buffer.Clear(); m_buffer.Run(true); m_rtspClient.Play(0.0,0.0); m_fileReader = new CMemoryReader(m_buffer); //get audio /video pids m_demultiplexer.SetFileReader(m_fileReader); m_demultiplexer.Start(); m_buffer.Run(false); // stop streaming LogDebug("close rtsp:%s", url); m_rtspClient.Stop(); m_tickCount = GetTickCount()-m_rtspClient.Duration(); //get the duration of the stream double duration = m_rtspClient.Duration() / 1000.0f; CPcr pcrstart, pcrEnd, pcrMax; pcrstart = m_duration.StartPcr(); duration += pcrstart.ToClock(); pcrEnd.FromClock(duration); pcrstart.IsValid=true ; m_duration.Set(pcrstart, pcrEnd, pcrMax); //Load() } else { if ((length < 9) || (_strcmpi(&url[length-9], ".tsbuffer") != 0)) { //local .ts file m_bTimeShifting = false; m_bLiveTv = false ; m_fileReader = new FileReader(); m_fileDuration = new FileReader(); } else { //local timeshift buffer file file m_bTimeShifting = true; m_bLiveTv = true; m_fileReader = new MultiFileReader(); m_fileDuration = new MultiFileReader(); } //open file m_fileReader->SetFileName(m_fileName); m_fileReader->OpenFile(); m_fileDuration->SetFileName(m_fileName); m_fileDuration->OpenFile(); //detect audio/video pids m_demultiplexer.SetFileReader(m_fileReader); m_demultiplexer.Start(); //get file duration m_duration.SetFileReader(m_fileDuration); m_duration.UpdateDuration(); float milli = m_duration.Duration().Millisecs(); milli /= 1000.0; LogDebug("start:%x end:%x %f", (DWORD)m_duration.StartPcr().PcrReferenceBase, (DWORD) m_duration.EndPcr().PcrReferenceBase, milli); m_fileReader->SetFilePointer(0LL, FILE_BEGIN); } //AddGraphToRot(GetFilterGraph()); SetDuration(); return S_OK; }
// Constructor CTsReaderFilter::CTsReaderFilter(IUnknown *pUnk, HRESULT *phr): CSource(NAME("CTsReaderFilter"), pUnk, CLSID_TSReader), m_pAudioPin(NULL), m_demultiplexer( m_duration, *this), m_rtspClient(m_buffer), m_pDVBSubtitle(NULL), m_pCallback(NULL), m_pRequestAudioCallback(NULL) { // use the following line if you are having trouble setting breakpoints // #pragma comment( lib, "strmbasd" ) TCHAR filename[1024]; GetLogFile(filename); ::DeleteFile(filename); LogDebug("---------- v0.4.12 -------------------"); m_fileReader=NULL; m_fileDuration=NULL; Compensation=CRefTime(0L); LogDebug("CTsReaderFilter::ctor"); m_pAudioPin = new CAudioPin(GetOwner(), this, phr,&m_section); m_pVideoPin = new CVideoPin(GetOwner(), this, phr,&m_section); m_pSubtitlePin = new CSubtitlePin(GetOwner(), this, phr,&m_section); if (m_pAudioPin == NULL) { *phr = E_OUTOFMEMORY; return; } wcscpy(m_fileName,L""); m_dwGraphRegister = 0; m_rtspClient.Initialize(); HKEY key; if (ERROR_SUCCESS==RegCreateKey(HKEY_CURRENT_USER, "Software\\MediaPortal\\TsReader",&key)) { RegCloseKey(key); } // Set default filtering mode (normal), if not overriden externaly (see ITSReader::SetRelaxedMode) m_demultiplexer.m_DisableDiscontinuitiesFiltering = false; if(!DoNotAllowSlowMotionDuringZapping()) { LogDebug("Slow motion video allowed during zapping"); m_pAudioPin->m_EnableSlowMotionOnZapping = true; } else { LogDebug("No slow motion video allowed during zapping"); m_pAudioPin->m_EnableSlowMotionOnZapping = false; } LogDebug("Wait for seeking to eof - false - constructor"); m_WaitForSeekToEof=0; m_bLiveTv = false; m_RandomCompensation = 0; m_bAnalog = false; m_bStopping = false; m_bOnZap = false; m_bPauseOnClockTooFast = false; SetMediaPosition(0) ; m_bStoppedForUnexpectedSeek=false ; m_bForceSeekOnStop=false ; m_bForceSeekAfterRateChange=false ; m_bSeekAfterRcDone=false ; m_videoDecoderCLSID=GUID_NULL; m_bFastSyncFFDShow=false; m_ShowBufferAudio = INIT_SHOWBUFFERAUDIO; m_ShowBufferVideo = INIT_SHOWBUFFERVIDEO; m_MPmainThreadID = GetCurrentThreadId() ; }
HRESULT CVideoPin::CompleteConnect(IPin *pReceivePin) { m_bInFillBuffer = false; m_bPinNoNewSegFlush = false; m_bPinNoAddPMT = false; m_bAddPMT = true; if (m_pTsReaderFilter->m_bForceFFDShowSyncFix) { m_pTsReaderFilter->m_bFastSyncFFDShow = true; } else { m_pTsReaderFilter->m_bFastSyncFFDShow = false; } HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); if (!SUCCEEDED(hr)) return E_FAIL; PIN_INFO pinInfo; FILTER_INFO filterInfo; hr=pReceivePin->QueryPinInfo(&pinInfo); if (!SUCCEEDED(hr)) return E_FAIL; else if (pinInfo.pFilter==NULL) return E_FAIL; else pinInfo.pFilter->Release(); // we dont need the filter just the info hr=pinInfo.pFilter->QueryFilterInfo(&filterInfo); filterInfo.pGraph->Release(); if (SUCCEEDED(hr)) { char szName[MAX_FILTER_NAME]; int cch = WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, MAX_FILTER_NAME, szName, MAX_FILTER_NAME, 0, 0); LogDebug("vidPin:CompleteConnect() ok, filter: %s", szName); m_bConnected=true; CLSID &ref=m_pTsReaderFilter->GetCLSIDFromPin(pReceivePin); m_pTsReaderFilter->m_videoDecoderCLSID = ref; if (m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_FFDSHOWVIDEO) { m_pTsReaderFilter->m_bFastSyncFFDShow=true; //LogDebug("vidPin:CompleteConnect() FFDShow Video Decoder connected"); } else if (m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_FFDSHOWDXVA) { m_bPinNoAddPMT = true; //LogDebug("vidPin:CompleteConnect() FFDShow DXVA Video Decoder connected, disable AddPMT"); } else if (m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_MSDTVDVDVIDEO) { m_bPinNoNewSegFlush = true; //LogDebug("vidPin:CompleteConnect() MS DTV-DVD Video Decoder connected, disable NewSegFlush"); } } else { LogDebug("vidPin:CompleteConnect() failed:%x",hr); return E_FAIL; } if (m_pTsReaderFilter->IsTimeShifting()) { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } else { REFERENCE_TIME refTime; m_pTsReaderFilter->GetDuration(&refTime); m_rtDuration=CRefTime(refTime); } //LogDebug("vidPin:CompleteConnect() end"); return hr; }