STDMETHODIMP CStreamSwitcherAllocator::GetBuffer( IMediaSample** ppBuffer, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags) { HRESULT hr = VFW_E_NOT_COMMITTED; if (!m_bCommitted) { return hr; } /* TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %x\n"), this); m_pPin->m_evBlock.Wait(); TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %x\n"), this); */ if (m_fMediaTypeChanged) { if (!m_pPin || !m_pPin->m_pFilter) { return hr; } CStreamSwitcherOutputPin* pOut = (static_cast<CStreamSwitcherFilter*>(m_pPin->m_pFilter))->GetOutputPin(); if (!pOut || !pOut->CurrentAllocator()) { return hr; } ALLOCATOR_PROPERTIES Properties, Actual; if (FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) { return hr; } if (FAILED(GetProperties(&Properties))) { return hr; } if (!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer) { Properties.cbBuffer = Actual.cbBuffer; if (FAILED(Decommit())) { return hr; } if (FAILED(SetProperties(&Properties, &Actual))) { return hr; } if (FAILED(Commit())) { return hr; } ASSERT(Actual.cbBuffer >= Properties.cbBuffer); if (Actual.cbBuffer < Properties.cbBuffer) { return hr; } } } hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags); if (m_fMediaTypeChanged && SUCCEEDED(hr)) { (*ppBuffer)->SetMediaType(&m_mt); m_fMediaTypeChanged = false; } return hr; }
STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { if(!IsConnected()) return S_OK; CAutoLock cAutoLock(&m_csReceive); CStreamSwitcherFilter* pSSF = (CStreamSwitcherFilter*)m_pFilter; CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); if(!pOut || !pOut->IsConnected()) return VFW_E_NOT_CONNECTED; return pSSF->DeliverNewSegment(tStart, tStop, dRate); }
STDMETHODIMP CStreamSwitcherInputPin::EndFlush() { CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csState); HRESULT hr; CStreamSwitcherFilter* pSSF = (CStreamSwitcherFilter*)m_pFilter; CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); if(!IsConnected() || !pOut || !pOut->IsConnected()) return VFW_E_NOT_CONNECTED; if(FAILED(hr = __super::EndFlush())) return hr; return IsActive() ? pSSF->DeliverEndFlush() : Block(true), S_OK; }
STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { SetThreadName((DWORD)-1, "CStreamSwitcherInputPin"); if(!IsConnected()) return S_OK; CAutoLock cAutoLock(&m_csReceive); CStreamSwitcherFilter* pSSF = static_cast<CStreamSwitcherFilter*>(m_pFilter); CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); if(!pOut || !pOut->IsConnected()) return VFW_E_NOT_CONNECTED; return pSSF->DeliverNewSegment(tStart, tStop, dRate); }
STDMETHODIMP CStreamSwitcherInputPin::BeginFlush() { CAutoLock cAutoLock(&(static_cast<CStreamSwitcherFilter*>(m_pFilter))->m_csState); HRESULT hr; CStreamSwitcherFilter* pSSF = static_cast<CStreamSwitcherFilter*>(m_pFilter); CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); if(!IsConnected() || !pOut || !pOut->IsConnected()) return VFW_E_NOT_CONNECTED; if(FAILED(hr = __super::BeginFlush())) return hr; return IsActive() ? pSSF->DeliverBeginFlush() : Block(false), S_OK; }
STDMETHODIMP CStreamSwitcherInputPin::EndOfStream() { CAutoLock cAutoLock(&m_csReceive); CStreamSwitcherFilter* pSSF = static_cast<CStreamSwitcherFilter*>(m_pFilter); CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); if (!IsConnected() || !pOut || !pOut->IsConnected()) { return VFW_E_NOT_CONNECTED; } if (m_hNotifyEvent) { SetEvent(m_hNotifyEvent), m_hNotifyEvent = nullptr; return S_OK; } return IsActive() ? pSSF->DeliverEndOfStream() : S_OK; }
HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt) { HRESULT hr = S_OK; CStreamSwitcherOutputPin* pOut = (static_cast<CStreamSwitcherFilter*>(m_pFilter))->GetOutputPin(); if (pOut && pOut->IsConnected()) { if (CComPtr<IPinConnection> pPC = pOut->CurrentPinConnection()) { hr = pPC->DynamicQueryAccept(pmt); if (hr == S_OK) { return S_OK; } } hr = pOut->GetConnected()->QueryAccept(pmt); } return hr; }
STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample) { AM_MEDIA_TYPE* pmt = nullptr; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { const CMediaType mt(*pmt); DeleteMediaType(pmt), pmt = nullptr; SetMediaType(&mt); } // DAMN!!!!!! this doesn't work if the stream we are blocking // shares the same thread with another stream, mpeg splitters // are usually like that. Our nicely built up multithreaded // strategy is useless because of this, ARRRRRRGHHHHHH. #ifdef BLOCKSTREAM if (m_fCanBlock) { m_evBlock.Wait(); } #endif if (!IsActive()) { #ifdef BLOCKSTREAM if (m_fCanBlock) { return S_FALSE; } #endif TRACE(_T("&^$#@ : a stupid fix for this stupid problem\n")); //Sleep(32); return E_FAIL; // a stupid fix for this stupid problem } CAutoLock cAutoLock(&m_csReceive); CStreamSwitcherOutputPin* pOut = (static_cast<CStreamSwitcherFilter*>(m_pFilter))->GetOutputPin(); ASSERT(pOut->GetConnected()); HRESULT hr = __super::Receive(pSample); if (S_OK != hr) { return hr; } if (m_SampleProps.dwStreamId != AM_STREAM_MEDIA) { return pOut->Deliver(pSample); } // ALLOCATOR_PROPERTIES props, actual; hr = m_pAllocator->GetProperties(&props); hr = pOut->CurrentAllocator()->GetProperties(&actual); REFERENCE_TIME rtStart = 0, rtStop = 0; if (S_OK == pSample->GetTime(&rtStart, &rtStop)) { // } long cbBuffer = pSample->GetActualDataLength(); CMediaType mtOut = m_mt; mtOut = (static_cast<CStreamSwitcherFilter*>(m_pFilter))->CreateNewOutputMediaType(mtOut, cbBuffer); bool fTypeChanged = false; if (mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer) { fTypeChanged = true; m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/; /* if (CComQIPtr<IPinConnection> pPC = pOut->CurrentPinConnection()) { HANDLE hEOS = CreateEvent(nullptr, FALSE, FALSE, nullptr); hr = pPC->NotifyEndOfStream(hEOS); hr = pOut->DeliverEndOfStream(); WaitForSingleObject(hEOS, 3000); CloseHandle(hEOS); hr = pOut->DeliverBeginFlush(); hr = pOut->DeliverEndFlush(); } */ if (props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio) { props.cBuffers = 8; } props.cbBuffer = cbBuffer; if (actual.cbAlign != props.cbAlign || actual.cbPrefix != props.cbPrefix || actual.cBuffers < props.cBuffers || actual.cbBuffer < props.cbBuffer) { hr = pOut->DeliverBeginFlush(); hr = pOut->DeliverEndFlush(); hr = pOut->CurrentAllocator()->Decommit(); hr = pOut->CurrentAllocator()->SetProperties(&props, &actual); hr = pOut->CurrentAllocator()->Commit(); } } CComPtr<IMediaSample> pOutSample; if (FAILED(InitializeOutputSample(pSample, &pOutSample))) { return E_FAIL; } pmt = nullptr; if (SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt) { const CMediaType mt(*pmt); DeleteMediaType(pmt), pmt = nullptr; // TODO ASSERT(0); } if (fTypeChanged) { pOut->SetMediaType(&mtOut); (static_cast<CStreamSwitcherFilter*>(m_pFilter))->OnNewOutputMediaType(m_mt, mtOut); pOutSample->SetMediaType(&mtOut); } // Transform hr = (static_cast<CStreamSwitcherFilter*>(m_pFilter))->Transform(pSample, pOutSample); // if (S_OK == hr) { hr = pOut->Deliver(pOutSample); m_bSampleSkipped = FALSE; /* if (FAILED(hr)) { ASSERT(0); } */ } else if (S_FALSE == hr) { hr = S_OK; pOutSample = nullptr; m_bSampleSkipped = TRUE; if (!m_bQualityChanged) { m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0); m_bQualityChanged = TRUE; } } return hr; }
HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample) { if (!pInSample || !ppOutSample) { return E_POINTER; } CStreamSwitcherOutputPin* pOut = (static_cast<CStreamSwitcherFilter*>(m_pFilter))->GetOutputPin(); ASSERT(pOut->GetConnected()); CComPtr<IMediaSample> pOutSample; DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { dwFlags |= AM_GBF_NOTASYNCPOINT; } HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample , m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID ? &m_SampleProps.tStart : nullptr , m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID ? &m_SampleProps.tStop : nullptr , dwFlags); if (FAILED(hr)) { return hr; } if (!pOutSample) { return E_FAIL; } if (CComQIPtr<IMediaSample2> pOutSample2 = pOutSample) { AM_SAMPLE2_PROPERTIES OutProps; EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags; OutProps.dwSampleFlags = (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); OutProps.tStart = m_SampleProps.tStart; OutProps.tStop = m_SampleProps.tStop; OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); hr = pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { m_bSampleSkipped = FALSE; } } else { if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) { pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop); } if (m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { pOutSample->SetSyncPoint(TRUE); } if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { pOutSample->SetDiscontinuity(TRUE); m_bSampleSkipped = FALSE; } LONGLONG MediaStart, MediaEnd; if (pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR) { pOutSample->SetMediaTime(&MediaStart, &MediaEnd); } } *ppOutSample = pOutSample.Detach(); return S_OK; }