📄 hxflsrc.cpp
字号:
STDMETHODIMP HXFileSource::PacketReady(HX_RESULT status, IHXPacket* pPacket){ HX_RESULT theErr = HXR_OK; // We should have been initialized by now HX_ASSERT(m_bInitialized); if (!m_bInitialized) { return HXR_NOT_INITIALIZED; } // Report a non-HXR_OK error code only if no packet. If a packet // accompanies the error code we assume end of stream and handle // later on (see below). if (!pPacket) { if (HXR_OK != status) { mLastError = status; ReportError(mLastError); return HXR_OK; } else { // HXR_OK with a NULL packet makes no sense return HXR_INVALID_PARAMETER; } } IHXBuffer* pBuffer = 0; UINT32 ulPacketTime = 0; // packet time encoded UINT32 ulPacketFilledDuration = 0; // packets' time have been filled UINT32 ulEventBeginTime = 0; // start pos of the packet(event) INT64 llActualPacketTime = 0; // packet time with timestamp rollover INT64 llActualEventBeginTime = 0; // start pos of the packet(event) with timestamp rollover ULONG32 ulFlags = 0; UINT16 uStreamNumber = 0; UINT8 unASMFlags = 0; UINT16 unASMRuleNumber = 0; UINT32 streamPreRoll = 0; UINT32 ulMinimumTotalPreroll = 0; if (HXR_OK != pPacket->Get(pBuffer, ulPacketTime, uStreamNumber, unASMFlags, unASMRuleNumber)) { theErr = HXR_FAILED; return theErr; }#if defined(_DEBUG) && defined(DEBUG_LOG_INFO) HXStaticStatLog::StatPrintf("Packet: StreamNumber: %u TimeStamp: %lu\n", uStreamNumber, ulPacketTime);#endif HX_RELEASE(pBuffer); CHXEvent* theEvent = NULL; STREAM_INFO* lpStreamInfo = NULL; CHXEventList* lEventList = NULL; if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo)) { return HXR_INVALID_PARAMETER; } if (status != HXR_OK) { if (!lpStreamInfo->m_bSrcStreamDone) { // if the status is not OK, it is probably the end of the stream.. // we should mark this stream as DONE... lpStreamInfo->m_bPacketRequested = FALSE; lpStreamInfo->m_bSrcStreamFillingDone = TRUE; lpStreamInfo->m_bSrcStreamDone = TRUE; if (m_uNumStreamsToBeFilled > 0) { m_uNumStreamsToBeFilled--; } if (m_uActiveStreams > 0) { m_uActiveStreams--; } if (m_uActiveStreams == 0) { SetEndOfClip(); } } return HXR_OK; } lpStreamInfo->m_ulReceived++; if (!theErr) { // reset lpStreamInfo->m_bPacketRequested = FALSE; lEventList = &lpStreamInfo->m_EventList; } /* * Save off the initial timestamp for live streams so we can buffer * relative to the first timstamp */ if (m_bInitialPacket) { m_bInitialPacket = FALSE; m_ulFirstPacketTime = ulPacketTime; } // This is the time according to the stream... llActualPacketTime = lpStreamInfo->BufferingState().CreateINT64Timestamp(ulPacketTime); llActualEventBeginTime = llActualPacketTime + m_ulDelay; /* subtract start time from player time */ if (m_ulStartTime > 0) { if (m_ulStartTime < llActualPacketTime) { llActualPacketTime -= m_ulStartTime; } else { llActualPacketTime = 0; } if (m_ulStartTime < llActualEventBeginTime) { llActualEventBeginTime -= m_ulStartTime; } else { llActualEventBeginTime = 0; } } HX_ASSERT(llActualEventBeginTime < MAX_UINT32); HX_ASSERT(llActualPacketTime < MAX_UINT32); ulEventBeginTime = INT64_TO_UINT32(llActualEventBeginTime); ulPacketFilledDuration = INT64_TO_UINT32(llActualPacketTime);#if defined(HELIX_FEATURE_RECORDCONTROL) if (m_pRecordControl) { m_pRecordControl->OnPacket(pPacket, m_ulStartTime - m_ulDelay); }#endif /* HELIX_FEATURE_RECORDCONTROL */ if (!m_bPlayFromRecordControl) { /* * force a minimum preroll of 1 second to ensure that we deliver * packet in time to the renderers. e.g. with delayed RealText * with a preroll of 0 and delay of 10 seconds, it is * possible to send packets at time 0 AFTER 10 seconds if we * do not ensure this minimum preroll * helps in fixing random "realtext not displaying" bug */#ifdef HELIX_FEATURE_MIN_PREROLL streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),150);#else //HELIX_FEATURE_MIN_PREROLL streamPreRoll = max(lpStreamInfo->BufferingState().GetMinPrerollInMs(),1000);#endif //HELIX_FEATURE_MIN_PREROLL ulEventBeginTime = (ulEventBeginTime > streamPreRoll) ? (ulEventBeginTime - streamPreRoll) : 0; theEvent = new CHXEvent(pPacket, ulEventBeginTime); if(!theEvent) { theErr = HXR_OUTOFMEMORY; } // enqueue the event into event queue if(!theErr) { /* offset used by Player::ProcessCurrentEvents to send to renderer::OnPacket */ theEvent->SetTimeOffset(m_ulStartTime - m_ulDelay); theErr = lEventList->InsertEvent(theEvent); } if (!theErr) { m_pBufferManager->UpdateCounters(pPacket); } } m_llLastFillEndTime = llActualPacketTime; if (m_bInFillMode) { UINT32 ulDuration = 0; UINT32 ulRemainToBufferInMs = 0; UINT32 ulRemainToBuffer = 0; m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs, ulRemainToBuffer); /* Logic: In FillBuffers(), we ask for a packet for a particular stream. If the fileformat does not return the packet immediately (i.e. we go again to ask for the packet from the same stream but find out that we had already asked for it earlier and have not yet received it, the streamFilling is marked as done for that fillbuffer() iteration. In the meantime, we keep on asking for the packets from other streams In meanwhile, if the fileformat returns a packet for the stream marked as done earlier, we re-activate that stream if the time of the packet is less than the time we fill all streams up to. */ if (lpStreamInfo->m_bSrcStreamFillingDone && (ulRemainToBufferInMs > 0 || ulRemainToBuffer > 0) && ulPacketFilledDuration <= lpStreamInfo->m_ulDuration && !lpStreamInfo->m_bSrcStreamDone) { lpStreamInfo->m_bSrcStreamFillingDone = FALSE; m_uNumStreamsToBeFilled++; } if (!lpStreamInfo->m_bSrcStreamDone && !lpStreamInfo->m_bSrcStreamFillingDone && m_uNumStreamsToBeFilled > 0) { /* When playing from Record Control buffering can happen after seek to a cached position. In this case we dont need to accelerate packet retriaval and can stop filling the stream. */ if (ulPacketFilledDuration > lpStreamInfo->m_ulDuration || (ulRemainToBufferInMs == 0 && ulRemainToBuffer == 0) || (m_bPlayFromRecordControl && ulPacketFilledDuration >= m_pPlayer->GetInternalCurrentPlayTime() + ulRemainToBufferInMs)) { // this value also updated in PacketReady() lpStreamInfo->m_bSrcStreamFillingDone = TRUE; if (m_uNumStreamsToBeFilled > 0) { m_uNumStreamsToBeFilled--; } } } } if (!theErr) { m_bReceivedData = TRUE; } else if (theEvent) { HX_DELETE(theEvent); } return theErr;}STDMETHODIMP HXFileSource::StreamDone(UINT16 uStreamNumber){ STREAM_INFO *lpStreamInfo = NULL; if (!mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void *&) lpStreamInfo)) { return HXR_INVALID_PARAMETER; } if (!lpStreamInfo->m_bSrcStreamDone) { lpStreamInfo->m_bSrcStreamDone = TRUE; lpStreamInfo->m_bSrcStreamFillingDone = TRUE; lpStreamInfo->m_bPacketRequested = FALSE; if (m_uNumStreamsToBeFilled > 0) { m_uNumStreamsToBeFilled--; } if (m_uActiveStreams > 0) { m_uActiveStreams--; } if (m_uActiveStreams == 0) { SetEndOfClip(); } } return HXR_OK;}STDMETHODIMP HXFileSource::SeekDone(HX_RESULT status){ HX_RESULT lResult = HXR_OK; if (m_nSeeking > 0) { m_nSeeking--; } _ProcessIdle(FALSE); return lResult;}STDMETHODIMP HXFileSource::RedirectDone(IHXBuffer* pURL){ HX_RESULT hr = HXR_NOTIMPL; // handle redirect to diff. protocol from HTTP file system if (m_pszURL && pURL) { if (strncasecmp(m_pszURL, "http://", 7) == 0 && strncasecmp((const char*)pURL->GetBuffer(), "http://", 7) != 0) { if (m_bPartOfNextGroup) { m_bRedirectPending = TRUE; HX_DELETE(m_pRedirectURL); m_pRedirectURL = new CHXURL((const char*)pURL->GetBuffer()); } else { hr = m_pSourceInfo->HandleRedirectRequest((char*)pURL->GetBuffer()); } } } return hr;}// routine to read from the file to keep all streams filled to their preroll valueHX_RESULT HXFileSource::FillBuffers(void){ /* * Do not call GetPacket if we have not yet received SeekDone from * the file format plugin. * || * We are in a paused state and no rebuffering and no fast start * is required. * || * We are in force end mode such as seeking to the end of the source duration */ if (m_nSeeking > 0 || (m_bPaused && !m_bFastStartInProgress && !m_bRebufferingRequired && !m_pRecordControl) || m_bForcedSourceEnd) { return HXR_OK; } HX_RESULT theErr = HXR_OK; UINT32 ulRemainToBufferInMs = 0; UINT32 ulRemainToBuffer = 0; UINT32 lPlayPos = m_pPlayer->GetInternalCurrentPlayTime(); UINT32 ulCurrentTime = HX_GET_TICKCOUNT(); m_uNumStreamsToBeFilled = 0; m_ulMaxPreRoll = 0; CHXMapLongToObj::Iterator ndxStream = mStreamInfoTable->Begin(); STREAM_INFO* lpStreamInfo = NULL; m_pBufferManager->GetMaximumPreroll(m_ulMaxPreRoll); m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs, ulRemainToBuffer); for(; ndxStream != mStreamInfoTable->End(); ++ndxStream) { lpStreamInfo = (STREAM_INFO*) (*ndxStream); if(!lpStreamInfo->m_bSrcStreamDone) { m_uNumStreamsToBeFilled++; lpStreamInfo->m_bSrcStreamFillingDone = FALSE; } } /* * The fill end time must be offset by the intial timestamp if this * is a live stream which is saved in the initial PacketReady */ // we will always attempt to have m_MaxPreRoll time of data in the audio and video event queues m_llFillEndTime = CAST_TO_INT64 (lPlayPos + m_ulMaxPreRoll + m_pPlayer->m_ulMinimumAudioPreroll + m_pPlayer->GetGranularity()); if (!m_pRecordControl && !m_bRebufferingRequired && ulRemainToBufferInMs == 0 && ulRemainToBuffer == 0 && m_llFillEndTime <= m_llLastFillEndTime) { return HXR_OK; }#if defined(HELIX_FEATURE_RECORDCONTROL) if (m_pRecordControl && !m_pRecordControl->CanAcceptPackets()) { return HXR_OK; }#endif /* HELIX_FEATURE_RECORDCONTROL */ m_bInFillMode = TRUE; while(!theErr && m_uNumStreamsToBeFilled > 0) { ndxStream = mStreamInfoTable->Begin(); for (; !theErr && ndxStream != mStreamInfoTable->End(); ++ndxStream) { lpStreamInfo = (STREAM_INFO*) (*ndxStream); if (!lpStreamInfo->m_bSrcStreamDone && !lpStreamInfo->m_bSrcStreamFillingDone && !lpStreamInfo->m_bPacketRequested) { // this will be reset in PacketReady() lpStreamInfo->m_bPacketRequested = TRUE; HX_RESULT retVal = m_pFFObject->GetPacket((UINT16) lpStreamInfo->m_uStreamNumber); if (HXR_OK != retVal ) { StreamDone(lpStreamInfo->m_uStreamNumber); // Don't lose OOM errors. if( retVal == HXR_OUTOFMEMORY ) { theErr = retVal; }#ifdef HELIX_FEATURE_STOP_STREAM_BY_TEMP_FILE_ERROR if( retVal == HXR_TEMP_FILE ) { theErr = retVal; m_pBufferManager->Stop(); SetEndOfClip(); mLastError = retVal; ReportError(mLastError); }#endif //HELIX_FEATURE_STOP_STREAM_BY_TEMP_FILE_ERROR } } else if (lpStreamInfo->m_bPacketRequested) { /* This logic applies to only single threaded application * where if we request a packet, we are either gonna get it * immediately or not get it at all till a later time-- * GetPacket() to ff->read to fs->readdone to ff-> * packetready to fileresponse(this) * In this case, m_uNumStreamsToBeFilled * will be adjusted in packetready depending on timestamp of stream * and where we wanna fill that stream upto * If packet requested is TRUE, it means fileformat did not response * immediately and thus one less stream is to be filled. * This however may not work in multi-threaded case where * fileplugin can send a response at any time. */ if (!lpStreamInfo->m_bSrcStreamFillingDone) { lpStreamInfo->m_bSrcStreamFillingDone = TRUE; if (m_uNumStreamsToBeFilled > 0) { m_uNumStreamsToBeFilled--; } } } } } m_bInFillMode = FALSE; return theErr;}void HXFileSource::SetEndOfClip(BOOL bForcedEndofClip) { m_bForcedSourceEnd = bForcedEndofClip; if (!m_bSourceEnd) { m_bSourceEnd = TRUE; m_pBufferManager->Stop(); m_pPlayer->EndOfSource(this);#if defined(HELIX_FEATURE_RECORDCONTROL) if (m_pRecordControl) { m_pRecordControl->OnEndOfPackets(); }#endif /* HELIX_FEATURE_RECORDCONTROL*/ }}// IUnknown methods/////////////////////////////////////////////////////////////////////////// Method:// IUnknown::QueryInterface// Purpose:// Implement this to export the interfaces supported by your // object.//STDMETHODIMP HXFileSource::CMimeFinderFileResponse::QueryInterface(REFIID riid, void** ppvObj){ QInterfaceList qiList[] = { { GET_IIDHANDLE(IID_IHXFileMimeMapperResponse), (IHXFileMimeMapperResponse*)this }, { GET_IIDHANDLE(IID_IHXFileRecognizerResponse), (IHXFileRecognizerResponse*)this }, { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXFileMimeMapperResponse*)this }, }; return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);}/////////////////////////////////////////////////////////////////////////// Method:// IUnknown::AddRef// Purpose:// Everyone usually implements this the same... feel free to use// this implementation.//STDMETHODIMP_(ULONG32) HXFileSource::CMimeFinderFileResponse::AddRef(){ return Inte
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -