HRESULT CPushAudioPin::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); do { while (!CheckRequest(&com)) { HRESULT hr; CAutoLock lock(&m_cSharedState); if( WaitForSingleObject( this->buffLockEvent, 500 ) == WAIT_OBJECT_0 ){ if( this->buffData.size() != 0 ){ if( this->buffLockEvent != NULL ){ SetEvent(this->buffLockEvent); } IMediaSample *pSample; hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; } hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); if(hr != S_OK) { return S_OK; } } else if (hr == S_FALSE) { pSample->Release(); DeliverEndOfStream(); return S_OK; } else { pSample->Release(); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } }else{ if( this->buffLockEvent != NULL ){ SetEvent(this->buffLockEvent); } Sleep(10); } } } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); } } while (com != CMD_STOP); return S_FALSE; }
int CBaseSplitterOutputPin::ThreadProcDelivery(int cnt) { CAutoPtr<Packet> p; { CAutoLock cAutoLock(&m_queue); if((cnt = m_queue.GetCount()) > 0) p = m_queue.Remove(); } if(S_OK == m_hrDeliver && cnt > 0) { ASSERT(!m_fFlushing); m_fFlushed = false; // flushing can still start here, to release a blocked deliver call HRESULT hr = p ? DeliverPacket(p) : DeliverEndOfStream(); m_eEndFlush.Wait(); // .. so we have to wait until it is done if(hr != S_OK && !m_fFlushed) // and only report the error in m_hrDeliver if we didn't flush the stream { // CAutoLock cAutoLock(&m_csQueueLock); m_hrDeliver = hr; cnt = 0; } } return cnt; }
void CDynamicSourceStream::FatalError(HRESULT hr) { // Make sure the user is reporting a failure. ASSERT(FAILED(hr)); m_bRunTimeError = TRUE; DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); }
DWORD CBaseSplitterOutputPin::ThreadProc() { m_hrDeliver = S_OK; m_fFlushing = m_fFlushed = false; m_eEndFlush.Set(); while(1) { Sleep(1); DWORD cmd; if(CheckRequest(&cmd)) { m_hThread = NULL; cmd = GetRequest(); Reply(S_OK); ASSERT(cmd == CMD_EXIT); return 0; } int cnt = 0; do { CAutoPtr<Packet> p; { CAutoLock cAutoLock(&m_queue); if((cnt = m_queue.GetCount()) > 0) p = m_queue.Remove(); } if(S_OK == m_hrDeliver && cnt > 0) { ASSERT(!m_fFlushing); m_fFlushed = false; // flushing can still start here, to release a blocked deliver call HRESULT hr = p ? DeliverPacket(p) : DeliverEndOfStream(); m_eEndFlush.Wait(); // .. so we have to wait until it is done if(hr != S_OK && !m_fFlushed) // and only report the error in m_hrDeliver if we didn't flush the stream { // CAutoLock cAutoLock(&m_csQueueLock); m_hrDeliver = hr; break; } } } while(--cnt > 0); } }
STDMETHODIMP StreamOutputPin::EndOfStream(void) { CAutoLock cAutoLock(this->m_pLock); this->m_pFilter->m_encoder->Stop(TRUE); DeliverEndOfStream(); this->m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, NULL); return S_OK; }
//---------------------------------------------------------------------------- //! @brief サンプルをダウンストリームへ送り続ける処理 //! @return エラーコード //---------------------------------------------------------------------------- HRESULT CDemuxOutputPin::DoBufferProcessingLoop(void) { Command com; HRESULT hr; OnThreadStartPlay(); do { while( !CheckRequest(&com) ) { // Virtual function user will override. IMediaSample *pSample; hr = RetrieveBuffer(&pSample); if( hr == S_OK ) { hr = Deliver(pSample); pSample->Release(); if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data DeliverEndOfStream(); return S_OK; } else { // derived class encountered an error DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } } if( com == CMD_RUN || com == CMD_PAUSE ) { Reply(NOERROR); } else if( com != CMD_STOP ) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while( com != CMD_STOP ); return S_FALSE; }
// // DoBufferProcessingLoop // // Grabs a buffer and calls the users processing function. // Overridable, so that different delivery styles can be catered for. HRESULT CSourceStream::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); do { while (!CheckRequest(&com)) { IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } // Virtual function user will override. hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); return S_OK; } else { // derived class encountered an error pSample->Release(); DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while (com != CMD_STOP); return S_FALSE; }
HRESULT CAudioPin::DoBufferProcessingLoop(void) { if (!m_bConnected) { return S_OK; m_bThreadRunning = false; } Command com; OnThreadStartPlay(); m_bThreadRunning = true; SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); do { while (!CheckRequest(&com)) { IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { Sleep(1); continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } // Virtual function user will override. hr = FillBuffer(pSample); if (hr == S_OK) { // Some decoders seem to crash when we provide empty samples if ((pSample->GetActualDataLength() > 0) && !m_pTsReaderFilter->IsStopping() && m_bConnected) { hr = Deliver(pSample); m_sampleCount++ ; } else { m_bDiscontinuity = true; } pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); m_bThreadRunning = false; return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); m_bThreadRunning = false; return S_OK; } else { // derived class encountered an error pSample->Release(); DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); m_bThreadRunning = false; return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while (com != CMD_STOP); m_bThreadRunning = false; return S_FALSE; }
// vlakno na output DWORD CAMROutputPin::ThreadProc() { while (true) { DWORD cmd = GetRequest(); switch (cmd) { case CMD_EXIT: Reply(0); return 0; break; case CMD_STOP: { Reply(0); } break; case CMD_RUN: { Reply(0); if (!IsConnected()) { break; } // deliver packets DWORD cmd2; BOOL is_first = true; DataPacketAMR *packet; HRESULT hr; do { if (ev_abort.Check()) { break; } hr = NOERROR; HANDLE events[] = { ev_can_read, ev_abort}; DWORD ret = WaitForMultipleObjects(2, events, FALSE, 10); if (ret == WAIT_OBJECT_0) { // look for new packet in queue { CAutoLock lck(&lock_queue); packet = queue.RemoveHead(); if (queue.IsEmpty()) { ev_can_read.Reset(); } // allow buffering if (GetBufferTime_MS() < buffer_time_ms) { ev_can_write.Set(); } } // bud dorucime End Of Stream, alebo packet if (packet->type == DataPacketAMR::PACKET_TYPE_EOS) { DeliverEndOfStream(); } else if (packet->type == DataPacketAMR::PACKET_TYPE_NEW_SEGMENT) { hr = DeliverNewSegment(packet->rtStart, packet->rtStop, packet->rate); } else if (packet->type == DataPacketAMR::PACKET_TYPE_DATA) { hr = DeliverDataPacketAMR(*packet); } delete packet; if (FAILED(hr)) { break; } } } while (!CheckRequest(&cmd2)); } break; default: Reply(E_UNEXPECTED); break; } } return 0; }
HRESULT CAudioPin::FillBuffer(IMediaSample *pSample) { try { Packet* buffer = NULL; do { if (m_demux.m_bAudioWaitForSeek) { m_demux.m_bAudioWaitForSeek = false; m_bSeekDone = false; } if (!m_bSeekDone || m_pFilter->IsStopping() || m_bFlushing || m_demux.IsMediaChanging() || m_demux.m_bRebuildOngoing || m_demux.m_eAudioClipSeen->Check()) { Sleep(1); return ERROR_NO_DATA; } if (m_pCachedBuffer) { LogDebug("aud: cached fetch %6.3f clip: %d playlist: %d", m_pCachedBuffer->rtStart / 10000000.0, m_pCachedBuffer->nClipNumber, m_pCachedBuffer->nPlaylist); buffer = m_pCachedBuffer; m_pCachedBuffer = NULL; } else buffer = m_demux.GetAudio(); if (m_demux.EndOfFile()) { LogDebug("aud: set EOF"); m_demux.m_eAudioClipSeen->Set(); return S_FALSE; } if (!buffer) { if (m_bFirstSample) Sleep(10); else { if (!m_bClipEndingNotified) { // Deliver end of stream notification to allow audio renderer to stop buffering. // This should only happen when the stream enters into paused state //LogDebug("aud: FillBuffer - DeliverEndOfStream"); //DeliverEndOfStream(); m_bClipEndingNotified = true; } else Sleep(10); return ERROR_NO_DATA; } } else { bool checkPlaybackState = false; REFERENCE_TIME rtStart = m_rtStart; //JoinAudioBuffers(buffer, &demux); { CAutoLock lock(m_section); if (m_demux.m_bAudioResetStreamPosition) { m_demux.m_bAudioResetStreamPosition = false; m_bZeroTimeStream = true; } if ((buffer->nNewSegment & NS_NEW_CLIP) == NS_NEW_CLIP) { LogDebug("aud: Playlist changed to %d - nNewSegment: %d offset: %6.3f rtStart: %6.3f rtPlaylistTime: %6.3f", buffer->nPlaylist, buffer->nNewSegment, buffer->rtOffset / 10000000.0, buffer->rtStart / 10000000.0, buffer->rtPlaylistTime / 10000000.0); checkPlaybackState = true; m_bClipEndingNotified = false; m_demux.m_eAudioClipSeen->Set(); } // Do not convert LPCM to PCM if audio decoder supports LPCM (LAV audio decoder style) if (!m_bUsePCM && buffer->pmt && buffer->pmt->subtype == MEDIASUBTYPE_PCM) buffer->pmt->subtype = MEDIASUBTYPE_BD_LPCM_AUDIO; if (buffer->pmt && m_mt != *buffer->pmt && !((buffer->nNewSegment & NS_NEW_CLIP)==NS_NEW_CLIP)) { HRESULT hrAccept = S_FALSE; LogMediaType(buffer->pmt); if (m_pPinConnection && false) // TODO - DS audio renderer seems to be only one that supports this hrAccept = m_pPinConnection->DynamicQueryAccept(buffer->pmt); else if (m_pReceiver) { //LogDebug("aud: DynamicQueryAccept - not avail"); GUID guid = buffer->pmt->subtype; if (buffer->pmt->subtype == MEDIASUBTYPE_PCM) { buffer->pmt->subtype = MEDIASUBTYPE_BD_LPCM_AUDIO; hrAccept = m_pReceiver->QueryAccept(buffer->pmt); } if (hrAccept != S_OK) { buffer->pmt->subtype = guid; hrAccept = m_pReceiver->QueryAccept(buffer->pmt); m_bUsePCM = true; } else m_bUsePCM = false; } if (hrAccept != S_OK) { CMediaType mt(*buffer->pmt); SetMediaType(&mt); LogDebug("aud: graph rebuilding required"); m_demux.m_bAudioRequiresRebuild = true; checkPlaybackState = true; DeliverEndOfStream(); } else { LogDebug("aud: format change accepted"); CMediaType mt(*buffer->pmt); SetMediaType(&mt); pSample->SetMediaType(&mt); m_pCachedBuffer = buffer; return ERROR_NO_DATA; } } } // lock ends if (checkPlaybackState) { m_pCachedBuffer = buffer; LogDebug("aud: cached push %6.3f clip: %d playlist: %d", m_pCachedBuffer->rtStart / 10000000.0, m_pCachedBuffer->nClipNumber, m_pCachedBuffer->nPlaylist); if (checkPlaybackState) { if (buffer->pmt && m_mt != *buffer->pmt && !((buffer->nNewSegment & NS_NEW_CLIP)==NS_NEW_CLIP)) { CMediaType mt(*buffer->pmt); SetMediaType(&mt); } } m_pCachedBuffer->nNewSegment = 0; return ERROR_NO_DATA; } bool hasTimestamp = buffer->rtStart != Packet::INVALID_TIME; REFERENCE_TIME rtCorrectedStartTime = 0; REFERENCE_TIME rtCorrectedStopTime = 0; if (hasTimestamp && m_dRateSeeking == 1.0) { bool setPMT = false; if (m_bDiscontinuity || buffer->bDiscontinuity) { LogDebug("aud: set discontinuity"); pSample->SetDiscontinuity(true); setPMT = true; m_bDiscontinuity = false; } if (buffer->pmt || setPMT) { LogDebug("aud: set PMT"); pSample->SetMediaType(buffer->pmt); m_bDiscontinuity = false; } if (hasTimestamp) { if (m_bZeroTimeStream) { m_rtStreamTimeOffset = buffer->rtStart - buffer->rtClipStartTime; m_bZeroTimeStream=false; } // Now we have the final timestamp, set timestamp in sample //REFERENCE_TIME refTime=(REFERENCE_TIME)cRefTimeStart; //refTime /= m_dRateSeeking; //the if rate===1.0 makes this redundant pSample->SetSyncPoint(true); // allow all packets to be seeking targets rtCorrectedStartTime = buffer->rtStart - m_rtStreamTimeOffset;//- m_rtStart; rtCorrectedStopTime = buffer->rtStop - m_rtStreamTimeOffset;// - m_rtStart; pSample->SetTime(&rtCorrectedStartTime, &rtCorrectedStopTime); } else { // Buffer has no timestamp pSample->SetTime(NULL, NULL); pSample->SetSyncPoint(false); } { CAutoLock lock(&m_csDeliver); if (!m_bFlushing) { ProcessAudioSample(buffer, pSample); #ifdef LOG_AUDIO_PIN_SAMPLES LogDebug("aud: %6.3f corr %6.3f Playlist time %6.3f clip: %d playlist: %d", buffer->rtStart / 10000000.0, rtCorrectedStartTime / 10000000.0, buffer->rtPlaylistTime / 10000000.0, buffer->nClipNumber, buffer->nPlaylist); #endif } else { LogDebug("aud: dropped sample as flush is active!"); delete buffer; return ERROR_NO_DATA; } } m_bFirstSample = false; delete buffer; } else { // Buffer was not displayed because it was out of date, search for next. delete buffer; buffer = NULL; } } } while (!buffer); return NOERROR; } // Should we return something else than NOERROR when hitting an exception? catch (int e) { LogDebug("aud: FillBuffer exception %d", e); } catch (...) { LogDebug("aud: FillBuffer exception ..."); } return NOERROR; }
HRESULT CMPVlcSourceStream::DoBufferProcessingLoop(void) { Command com; HRESULT result = S_OK; BOOL bStop = false; OnThreadStartPlay(); LogInfo("Starting grabber thread"); if (m_exec) { LogInfo("Executing external command: %s %s", m_exec, m_exec_opt); ::ShellExecuteA(0, NULL, m_exec, m_exec_opt, NULL, SW_HIDE); Sleep(m_exec_wait); } //libvlc_vlm_seek_media(m_vlc, "vlc_ds_stream", 0); if (libvlc_vlm_play_media (m_vlc, "vlc_ds_stream") != 0) { LogError("libvlc_vlm_play_media failed"); return S_FALSE; } OVERLAPPED o; o.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); o.Internal = o.InternalHigh = o.Offset = o.OffsetHigh = 0; ConnectNamedPipe(m_hPipe, &o); WaitForSingleObject(o.hEvent, 20000); BOOL fConnected = HasOverlappedIoCompleted(&o); SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); if (!fConnected) { LogError("ConnectNamedPipe failed"); CancelIo(m_hPipe); CloseHandle(o.hEvent); return S_FALSE; } else do { BOOL requestAvail = FALSE; while ((requestAvail = CheckRequest(&com)) == FALSE) { //LogDebug ("Command: %d", com); IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) continue; // fill buffer // ------------------------------------------------------------------------------------ hr = S_OK; BYTE *pData; DWORD cbData; CheckPointer(pSample, E_POINTER); // Access the sample's data buffer pSample->GetPointer((BYTE **)&pData); cbData = pSample->GetSize(); DWORD startRecvTime = GetTickCount(); m_buffsize = 0; do { DWORD cbBytesRead = 0; ResetEvent(o.hEvent); o.Internal = o.InternalHigh = o.Offset = o.OffsetHigh = 0; BOOL fSuccess = ReadFile( m_hPipe, pData + m_buffsize, cbData - m_buffsize, &cbBytesRead, &o); if (GetLastError() == ERROR_IO_PENDING) { for (int n=0; n < 20; n++) { if ((requestAvail = CheckRequest(&com)) == TRUE) break; if (WaitForSingleObject(o.hEvent, 1000) == WAIT_OBJECT_0) break; } fSuccess = GetOverlappedResult(m_hPipe, &o, &cbBytesRead, false); } if (!fSuccess || cbBytesRead == 0) { CancelIo(m_hPipe); break; } m_buffsize += cbBytesRead; } while ( !requestAvail && m_buffsize < (cbData * 3 / 4) && abs((signed long)(GetTickCount() - startRecvTime)) < 100); // ------------------------------------------------------------------------------------ if (m_buffsize != 0 && !(requestAvail && com == CMD_STOP)) { LogDebug("Posting %d / %d bytes", m_buffsize, pSample->GetSize()); REFERENCE_TIME rtStart = startRecvTime; REFERENCE_TIME rtStop = GetTickCount(); pSample->SetTime(&rtStart, &rtStop); pSample->SetActualDataLength(m_buffsize); pSample->SetSyncPoint(TRUE); hr = Deliver(pSample); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { LogInfo("Deliver() returned %08x; stopping", hr); bStop = true; } } else { // FillBuffer returned false bStop = true; DeliverEndOfStream(); } pSample->Release(); if (bStop) break; } if (requestAvail) { LogInfo("Received command: %d", com); if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); LogDebug("Unexpected command %d!!!", com); } } } while (com != CMD_STOP && bStop == false); //DeliverEndOfStream(); LogDebug("end loop"); HANDLE hSDThread = CreateThread(NULL, 0, &VlcStreamDiscardThread, LPVOID(m_hPipe), 0, 0); libvlc_vlm_stop_media(m_vlc, "vlc_ds_stream"); LogDebug("libvlc_vlm_stop_media"); if (WaitForSingleObject(hSDThread, 30000) == WAIT_TIMEOUT) { DWORD ec; LogError("Terminating StreamDiscardThread!"); GetExitCodeThread(hSDThread, &ec); TerminateThread(hSDThread, ec); } DisconnectNamedPipe(m_hPipe); LogDebug("DoBufferProcessingLoop end"); CloseHandle(o.hEvent); return result; }
// // DoBufferProcessingLoop // // Grabs a buffer and calls the users processing function. // Overridable, so that different delivery styles can be catered for. HRESULT CDynamicSourceStream::DoBufferProcessingLoop(void) { Command com; bool fOutputFormatChanged = false; OnThreadStartPlay(); do { while(!CheckRequest(&com)) { // CAutoUsingOutputPin::CAutoUsingOutputPin() only changes the value of hr // if an error occurs. HRESULT hr = S_OK; CAutoUsingOutputPin auopUsingOutputPin(this, &hr); if(FAILED(hr)) { FatalError(hr); return hr; } if(m_fReconnectOutputPin) { hr = DynamicReconnect(NULL); m_fReconnectOutputPin = false; if(FAILED(hr)) { FatalError(hr); return hr; } fOutputFormatChanged = true; } IMediaSample *pSample; hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if(FAILED(hr)) { Sleep(1); continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } if(fOutputFormatChanged) { pSample->SetDiscontinuity(TRUE); fOutputFormatChanged = false; } // Virtual function user will override. hr = FillBuffer(pSample); if(hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); return S_OK; } } else if(hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); return S_OK; } else { // derived class encountered an error pSample->Release(); DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); FatalError(hr); return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if(com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if(com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); } } while(com != CMD_STOP); return S_FALSE; }
DWORD CLAVOutputPin::ThreadProc() { std::string name = "CLAVOutputPin " + std::string(CBaseDemuxer::CStreamList::ToString(m_pinType)); SetThreadName(-1, name.c_str()); m_hrDeliver = S_OK; m_fFlushing = m_fFlushed = false; m_eEndFlush.Set(); bool bFailFlush = false; while(1) { Sleep(1); DWORD cmd; if(CheckRequest(&cmd)) { cmd = GetRequest(); Reply(S_OK); ASSERT(cmd == CMD_EXIT); return 0; } size_t cnt = 0; do { Packet *pPacket = NULL; // Get a packet from the queue (scoped for lock) { CAutoLock cAutoLock(&m_queue); if((cnt = m_queue.Size()) > 0) { pPacket = m_queue.Get(); } } // We need to check cnt instead of pPacket, since it can be NULL for EndOfStream if(m_hrDeliver == S_OK && cnt > 0) { ASSERT(!m_fFlushing); m_fFlushed = false; // flushing can still start here, to release a blocked deliver call HRESULT hr = pPacket ? DeliverPacket(pPacket) : DeliverEndOfStream(); // .. so, wait until flush finished m_eEndFlush.Wait(); if(hr != S_OK && !m_fFlushed) { DbgLog((LOG_TRACE, 10, L"OutputPin::ThreadProc(): Delivery failed on %s pin, hr: %0#.8x", CBaseDemuxer::CStreamList::ToStringW(GetPinType()), hr)); if (!bFailFlush && hr == S_FALSE) { DbgLog((LOG_TRACE, 10, L"OutputPin::ThreadProc(): Trying to revive it by flushing...")); GetConnected()->BeginFlush(); GetConnected()->EndFlush(); bFailFlush = true; } else { m_hrDeliver = hr; } break; } } else if (pPacket) { // in case of stream switches or other events, we may end up here SAFE_DELETE(pPacket); } } while(cnt > 1 && m_hrDeliver == S_OK); } return 0; }
DWORD CBaseSplitterOutputPin::ThreadProc() { SetThreadName(DWORD(-1), "CBaseSplitterOutputPin"); m_hrDeliver = S_OK; m_fFlushing = m_fFlushed = false; m_eEndFlush.Set(); // fix for Microsoft DTV-DVD Video Decoder - video freeze after STOP/PLAY bool iHaaliRenderConnect = false; CComPtr<IPin> pPinTo = this, pTmp; while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { pTmp = nullptr; CComPtr<IBaseFilter> pBF = GetFilterFromPin(pPinTo); if (GetCLSID(pBF) == CLSID_DXR) { // Haali Renderer iHaaliRenderConnect = true; break; } pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); } if (IsConnected() && !iHaaliRenderConnect) { GetConnected()->BeginFlush(); GetConnected()->EndFlush(); } for (;;) { Sleep(1); DWORD cmd; if (CheckRequest(&cmd)) { m_hThread = nullptr; cmd = GetRequest(); Reply(S_OK); ASSERT(cmd == CMD_EXIT); return 0; } int cnt = 0; do { CAutoPtr<Packet> p; { CAutoLock cAutoLock(&m_queue); if ((cnt = m_queue.GetCount()) > 0) { p = m_queue.Remove(); } } if (S_OK == m_hrDeliver && cnt > 0) { ASSERT(!m_fFlushing); m_fFlushed = false; // flushing can still start here, to release a blocked deliver call HRESULT hr = p ? DeliverPacket(p) : DeliverEndOfStream(); m_eEndFlush.Wait(); // .. so we have to wait until it is done if (hr != S_OK && !m_fFlushed) { // and only report the error in m_hrDeliver if we didn't flush the stream // CAutoLock cAutoLock(&m_csQueueLock); m_hrDeliver = hr; break; } } } while (--cnt > 0); } }
HRESULT CVideoPin::FillBuffer(IMediaSample* pSample) { try { Packet* buffer = NULL; do { if (m_pFilter->IsStopping() || m_demux.IsMediaChanging() || m_bFlushing || !m_bSeekDone || m_demux.m_bRebuildOngoing) { Sleep(1); return ERROR_NO_DATA; } if (m_demux.EndOfFile()) { LogDebug("vid: set EOF"); return S_FALSE; } if (m_demux.m_bVideoClipSeen || m_demux.m_bAudioRequiresRebuild && !m_demux.m_bVideoClipSeen && !m_demux.m_eAudioClipSeen->Check()) { CheckPlaybackState(); return ERROR_NO_DATA; } if (m_pCachedBuffer) { LogDebug("vid: cached fetch %6.3f clip: %d playlist: %d", m_pCachedBuffer->rtStart / 10000000.0, m_pCachedBuffer->nClipNumber, m_pCachedBuffer->nPlaylist); buffer = m_pCachedBuffer; m_pCachedBuffer = NULL; buffer->bDiscontinuity = true; if (m_bProvidePMT) { CMediaType mt(*buffer->pmt); SetMediaType(&mt); pSample->SetMediaType(&mt); m_bProvidePMT = false; } } else buffer = m_demux.GetVideo(); if (!buffer) { if (m_bFirstSample) Sleep(10); else { if (!m_bClipEndingNotified) { // Deliver end of stream notification to flush the video decoder. // This should only happen when the stream enters into paused state LogDebug("vid: FillBuffer - DeliverEndOfStream"); DeliverEndOfStream(); m_bClipEndingNotified = true; } else Sleep(10); return ERROR_NO_DATA; } } else { bool checkPlaybackState = false; { CAutoLock lock(m_section); if (buffer->nNewSegment > 0) { if ((buffer->nNewSegment & NS_NEW_CLIP) == NS_NEW_CLIP) { LogDebug("vid: Playlist changed to %d - nNewSegment: %d offset: %6.3f rtStart: %6.3f rtPlaylistTime: %6.3f", buffer->nPlaylist, buffer->nNewSegment, buffer->rtOffset / 10000000.0, buffer->rtStart / 10000000.0, buffer->rtPlaylistTime / 10000000.0); m_demux.m_bVideoClipSeen = true; m_bInitDuration = true; checkPlaybackState = true; m_bClipEndingNotified = false; if (buffer->bResuming || buffer->nNewSegment & NS_INTERRUPTED) { m_bDoFakeSeek = true; m_rtStreamOffset = buffer->rtPlaylistTime; m_bZeroTimeStream = true; m_demux.m_bAudioResetStreamPosition = true; } else m_rtStreamOffset = 0; // LAV video decoder requires an end of stream notification to be able to provide complete video frames // to downstream filters in a case where we are waiting for the audio pin to see the clip boundary as // we cannot provide yet the next clip's PMT downstream since audio stream could require a rebuild if (m_currentDecoder == CLSID_LAVVideo && (buffer->nNewSegment & NS_NEW_PLAYLIST)) { LogDebug("DeliverEndOFStream LAV Only for audio pin wait (%d,%d)", buffer->nPlaylist, buffer->nClipNumber); DeliverEndOfStream(); } } if ((buffer->nNewSegment & NS_STREAM_RESET) == NS_STREAM_RESET) m_bInitDuration = true; } if (buffer->pmt) { GUID subtype = subtype = buffer->pmt->subtype; if (buffer->pmt->subtype == FOURCCMap('1CVW') && m_VC1Override != GUID_NULL) { buffer->pmt->subtype = m_VC1Override; LogDebug("vid: FillBuffer - force VC-1 GUID"); } if (!CompareMediaTypes(buffer->pmt, &m_mt)) { LogMediaType(buffer->pmt); HRESULT hrAccept = S_FALSE; m_bProvidePMT = true; if (m_pReceiver && CheckVideoFormat(&buffer->pmt->subtype, &m_currentDecoder)) { // Currently no other video decoders than LAV seems to be compatible with // the dynamic format changes if (m_currentDecoder == CLSID_LAVVideo) hrAccept = m_pReceiver->QueryAccept(buffer->pmt); } if (hrAccept != S_OK) { CMediaType mt(*buffer->pmt); SetMediaType(&mt); LogDebug("vid: graph rebuilding required"); m_demux.m_bVideoRequiresRebuild = true; m_bZeroTimeStream = true; checkPlaybackState = true; //LogDebug("DeliverEndOFStream for rebuild (%d,%d)", buffer->nPlaylist, buffer->nClipNumber); //DeliverEndOfStream(); } else { LogDebug("vid: format change accepted"); CMediaType mt(*buffer->pmt); SetMediaType(&mt); pSample->SetMediaType(&mt); buffer->nNewSegment = 0; m_pCachedBuffer = buffer; //if (m_currentDecoder == CLSID_LAVVideo) //{ // LogDebug("DeliverEndOFStream LAV Only (%d,%d)", buffer->nPlaylist, buffer->nClipNumber); // DeliverEndOfStream(); //} return ERROR_NO_DATA; } } // comparemediatypes } } // lock ends m_rtTitleDuration = buffer->rtTitleDuration; if (checkPlaybackState) { buffer->nNewSegment = 0; m_pCachedBuffer = buffer; CheckPlaybackState(); LogDebug("vid: cached push %6.3f clip: %d playlist: %d", m_pCachedBuffer->rtStart / 10000000.0, m_pCachedBuffer->nClipNumber, m_pCachedBuffer->nPlaylist); return ERROR_NO_DATA; } bool hasTimestamp = buffer->rtStart != Packet::INVALID_TIME; REFERENCE_TIME rtCorrectedStartTime = 0; REFERENCE_TIME rtCorrectedStopTime = 0; if (hasTimestamp) { if (m_bZeroTimeStream) { m_rtStreamTimeOffset = buffer->rtStart - buffer->rtClipStartTime; m_bZeroTimeStream = false; } if (m_bDiscontinuity || buffer->bDiscontinuity) { LogDebug("vid: set discontinuity"); pSample->SetDiscontinuity(true); pSample->SetMediaType(buffer->pmt); m_bDiscontinuity = false; } rtCorrectedStartTime = buffer->rtStart - m_rtStreamTimeOffset; rtCorrectedStopTime = buffer->rtStop - m_rtStreamTimeOffset; pSample->SetTime(&rtCorrectedStartTime, &rtCorrectedStopTime); if (m_bInitDuration) { m_pFilter->SetTitleDuration(m_rtTitleDuration); m_pFilter->ResetPlaybackOffset(buffer->rtPlaylistTime - rtCorrectedStartTime); m_bInitDuration = false; } m_pFilter->OnPlaybackPositionChange(); } else // Buffer has no timestamp pSample->SetTime(NULL, NULL); pSample->SetSyncPoint(buffer->bSyncPoint); { CAutoLock lock(&m_csDeliver); if (!m_bFlushing) { BYTE* pSampleBuffer; pSample->SetActualDataLength(buffer->GetDataSize()); pSample->GetPointer(&pSampleBuffer); memcpy(pSampleBuffer, buffer->GetData(), buffer->GetDataSize()); m_bFirstSample = false; #ifdef LOG_VIDEO_PIN_SAMPLES LogDebug("vid: %6.3f corr %6.3f playlist time %6.3f clip: %d playlist: %d size: %d", buffer->rtStart / 10000000.0, rtCorrectedStartTime / 10000000.0, buffer->rtPlaylistTime / 10000000.0, buffer->nClipNumber, buffer->nPlaylist, buffer->GetCount()); #endif } else { LogDebug("vid: dropped sample as flush is active!"); return ERROR_NO_DATA; } } //static int iFrameNumber = 0; //LogMediaSample(pSample, iFrameNumber++); delete buffer; } } while (!buffer); return NOERROR; } catch(...) { LogDebug("vid: FillBuffer exception"); } return S_OK; }
HRESULT CMPIptvSourceStream::DoBufferProcessingLoop(void) { Command com; OnThreadStartPlay(); WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #ifdef logging LogDebug("Starting grabber thread"); #endif sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (localip) { addr.sin_addr.s_addr = inet_addr(localip); } else { addr.sin_addr.s_addr = htonl(INADDR_ANY); } addr.sin_port = htons((u_short)port); ip_mreq imr; imr.imr_multiaddr.s_addr = inet_addr(ip); if (localip) { imr.imr_interface.s_addr = inet_addr(localip); } else { imr.imr_interface.s_addr = INADDR_ANY; } unsigned long nonblocking = 1; if((m_socket = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { /* u_long argp = 1; ioctlsocket(m_socket, FIONBIO, &argp); */ DWORD dw = TRUE; int dwLen = sizeof(dw); if(setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } if(setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&dw, &dwLen); #ifdef logging LogDebug("Socket receive buffer is: %d (%d)", dw, dwLen); LogDebug("Trying to set receive buffer to %d", IPTV_SOCKET_BUFFER_SIZE); #endif dw = IPTV_SOCKET_BUFFER_SIZE; if(setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (const char*)&dw, sizeof(dw)) < 0) { closesocket(m_socket); m_socket = -1; } dwLen = sizeof(dw); getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&dw, &dwLen); #ifdef logging LogDebug("New socket receive buffer is: %d (%d)", dw, dwLen); #endif if (ioctlsocket(m_socket, FIONBIO, &nonblocking) != 0) { closesocket(m_socket); m_socket = -1; } if(bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { closesocket(m_socket); m_socket = -1; } if(IN_MULTICAST(htonl(imr.imr_multiaddr.s_addr))) { int ret = setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&imr, sizeof(imr)); if(ret < 0) ret = ::WSAGetLastError(); ret = ret; } } SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); int fromlen = sizeof(addr); m_buffsize = 0; timeval tv; //Will be used for select() below tv.tv_sec = 0; tv.tv_usec = 100000; //100 msec do { BOOL requestAvail; while ((requestAvail = CheckRequest(&com)) == FALSE) { DWORD startRecvTime; startRecvTime = GetTickCount(); #ifdef FILL_DIRECTLY_INTO_BUFFER IMediaSample *pSample; char *pData; long cbData; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) continue; CheckPointer(pSample, E_POINTER); // Access the sample's data buffer pSample->GetPointer((BYTE **)&pData); cbData = pSample->GetSize(); #endif do { //Try to read the complete remaining buffer size //But stop reading after 100ms have passed (slow streams like internet radio) #ifdef FILL_DIRECTLY_INTO_BUFFER int len = recvfrom(m_socket, &pData[m_buffsize], cbData - m_buffsize, 0, (SOCKADDR*)&addr, &fromlen); #else int len = recvfrom(m_socket, &m_buffer[m_buffsize], IPTV_BUFFER_SIZE - m_buffsize, 0, (SOCKADDR*)&addr, &fromlen); #endif if(len <= 0) { //Wait until there's something in the receive buffer fd_set myFDsocket; myFDsocket.fd_count = 1; myFDsocket.fd_array[0] = m_socket; int selectRet = select(0, &myFDsocket, NULL, NULL, &tv); #ifdef logging LogDebug("select return code: %d", selectRet); #endif continue; //On error or nothing read just repeat the loop } #ifdef logging LogDebug("Read %d bytes at pos %d of %d", len, m_buffsize, IPTV_BUFFER_SIZE); #endif m_buffsize += len; #ifdef FILL_DIRECTLY_INTO_BUFFER } while ((requestAvail = CheckRequest(&com)) == FALSE && m_buffsize < (cbData * 3 / 4) && abs((signed long)(GetTickCount() - startRecvTime)) < 100); #else } while ((requestAvail = CheckRequest(&com)) == FALSE && m_buffsize < (IPTV_BUFFER_SIZE * 3 / 4) && abs((signed long)(GetTickCount() - startRecvTime)) < 100); #endif if (requestAvail) break; #ifndef FILL_DIRECTLY_INTO_BUFFER if (m_buffsize == 0) continue; //100ms passed but no buffer received IMediaSample *pSample; HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); if (FAILED(hr)) { continue; // go round again. Perhaps the error will go away // or the allocator is decommited & we will be asked to // exit soon. } #endif // fill buffer hr = FillBuffer(pSample); if (hr == S_OK) { hr = Deliver(pSample); pSample->Release(); // downstream filter returns S_FALSE if it wants us to // stop or an error if it's reporting an error. if(hr != S_OK) { #ifdef logging LogDebug("Deliver() returned %08x; stopping", hr); #endif if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return S_OK; } } else if (hr == S_FALSE) { // derived class wants us to stop pushing data pSample->Release(); DeliverEndOfStream(); if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return S_OK; } else { // derived class encountered an error pSample->Release(); #ifdef logging LogDebug("Error %08lX from FillBuffer!!!", hr); #endif DeliverEndOfStream(); m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); if(m_socket >= 0) {closesocket(m_socket); m_socket = -1;} WSACleanup(); return hr; } // all paths release the sample } // For all commands sent to us there must be a Reply call! if (com == CMD_RUN || com == CMD_PAUSE) { Reply(NOERROR); } else if (com != CMD_STOP) { Reply((DWORD) E_UNEXPECTED); #ifdef logging LogDebug("Unexpected command %d!!!", com); #endif } } while (com != CMD_STOP);
DWORD CAVIOutputPin::ThreadProc() { CAVIScanner* scanner = m_pSplitter->GetAVIScanner(); bool bFirst = true; REFERENCE_TIME tStart = 0; REFERENCE_TIME tStop = 0; REFERENCE_TIME duration = 0; bool bDeliverEOS = true; DWORD req = 0; HRESULT hr = S_OK; REFERENCE_TIME tSeekStart = 0; REFERENCE_TIME tSeekStop = 0; double dRate; m_pSplitter->GetSeekingParams(&tSeekStart, &tSeekStop, &dRate); DeliverNewSegment(tSeekStart, tSeekStop, dRate); int startPos = GetIndexStartPosEntry(tSeekStart); for (int i = startPos; i < m_pIndex->size(); i++) { const INDEXENTRY& entry = (*m_pIndex)[i]; if (!entry.dwChunkLength) continue; CComPtr<IMediaSample> pSample; hr = GetNewSample(&pSample, entry.dwChunkLength); // Break out without calling EndOfStream if we're asked to // do something different if (CheckRequest(&req)) { bDeliverEOS = false; break; } if (bFirst) { bFirst = false; pSample->SetDiscontinuity(TRUE); } if (entry.dwFlags & AVIIF_INDEX) pSample->SetSyncPoint(TRUE); tStart = GetCurTime(i) - tSeekStart; tStop = GetCurTime(i+1)- tSeekStart; pSample->SetTime(&tStart,&tStop); if (tStart < 0 && tStop <= 0) pSample->SetPreroll(TRUE); BYTE* pbData = 0; pSample->GetPointer(&pbData); scanner->ReadData(entry.chunkOffset, entry.dwChunkLength, pbData); hr = Deliver(pSample); if (FAILED(hr) || hr == S_FALSE) { while(true) { if (CheckRequest(&req)) { bDeliverEOS = false; break; } Sleep(100); } } } if (bDeliverEOS) DeliverEndOfStream(); req =GetRequest(); Reply(S_OK); return 0; }