HRESULT CTimeStretchFilter::CheckSample(IMediaSample* pSample) { if (!pSample) return S_OK; AM_MEDIA_TYPE *pmt = NULL; bool bFormatChanged = false; HRESULT hr = S_OK; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) bFormatChanged = !FormatsEqual((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, m_pInputFormat); if (bFormatChanged) { uint unprocessedSamplesBefore = numUnprocessedSamples(); uint zeros = flushEx(); uint unprocessedSamplesAfter = numUnprocessedSamples(); UINT32 outFramesAfter = numSamples(); UINT32 totalSamples = zeros + unprocessedSamplesBefore; UINT32 totalProcessedSamples = totalSamples - unprocessedSamplesAfter; //double bias = (double)totalProcessedSamples / (double)outFramesAfter; REFERENCE_TIME estimatedSampleDuration = totalProcessedSamples * UNITS / m_pOutputFormat->Format.nSamplesPerSec; double bias = m_pClock->GetBias(); double adjustment = m_pClock->Adjustment(); double AVMult = m_pClock->SuggestedAudioMultiplier(estimatedSampleDuration, bias, adjustment); setTempoInternal(AVMult, 1.0); CreateOutput(totalProcessedSamples, outFramesAfter, bias, adjustment, AVMult, true); // Empty SoundTouch's buffers clear(); // Apply format change ChannelOrder chOrder; hr = NegotiateFormat((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, 1, &chOrder); pSample->SetDiscontinuity(false); if (FAILED(hr)) { DeleteMediaType(pmt); Log("CTimeStretchFilter::CheckFormat failed to change format: 0x%08x", hr); return hr; } else { m_chOrder = chOrder; return S_FALSE; // format changed } } return S_OK; }
HRESULT CTimeStretchFilter::CheckSample(IMediaSample* pSample, REFERENCE_TIME* rtDrained) { if (!pSample) return S_OK; AM_MEDIA_TYPE *pmt = NULL; bool bFormatChanged = false; HRESULT hr = S_OK; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) bFormatChanged = !FormatsEqual((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, m_pInputFormat); if (bFormatChanged) { REFERENCE_TIME rtStart = 0; REFERENCE_TIME rtStop = 0; HRESULT hr = pSample->GetTime(&rtStart, &rtStop); if (SUCCEEDED(hr)) { Log("CTimeStretchFilter - CheckSample - resyncing in middle of stream on format change - rtStart: %6.3f m_rtInSampleTime: %6.3f", rtStart / 10000000.0, m_rtInSampleTime / 10000000.0); *rtDrained = DrainBuffers(pSample, rtStart); } else Log("CTimeStretchFilter::CheckFormat failed to get timestamps from sample: 0x%08x", hr); // Apply format change ChannelOrder chOrder; hr = NegotiateFormat((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, 1, &chOrder); pSample->SetDiscontinuity(false); if (FAILED(hr)) { DeleteMediaType(pmt); Log("CTimeStretchFilter::CheckFormat failed to change format: 0x%08x", hr); return hr; } else { m_chOrder = chOrder; return S_FALSE; // format changed } } return S_OK; }
HRESULT CWASAPIRenderFilter::CheckSample(IMediaSample* pSample, UINT32 framesToFlush) { if (!pSample) return S_OK; AM_MEDIA_TYPE *pmt = NULL; bool bFormatChanged = false; HRESULT hr = S_OK; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) bFormatChanged = !FormatsEqual((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, m_pInputFormat); if (bFormatChanged) { // Release outstanding buffer hr = m_pRenderClient->ReleaseBuffer(framesToFlush, 0); if (FAILED(hr)) Log("CWASAPIRenderFilter::CheckFormat - ReleaseBuffer: 0x%08x", hr); // Apply format change ChannelOrder chOrder; hr = NegotiateFormat((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, 1, &chOrder); pSample->SetDiscontinuity(false); if (FAILED(hr)) { DeleteMediaType(pmt); Log("CWASAPIRenderFilter::CheckFormat failed to change format: 0x%08x", hr); return hr; } else { m_chOrder = chOrder; return S_FALSE; } } else if (pSample->IsDiscontinuity() == S_OK) { hr = m_pRenderClient->ReleaseBuffer(framesToFlush, 0); if (FAILED(hr)) Log("CWASAPIRenderFilter::CheckFormat - discontinuity - ReleaseBuffer: 0x%08x", hr); pSample->SetDiscontinuity(false); m_nSampleNum = 0; return S_FALSE; } return S_OK; }
// Processing HRESULT CChannelMixer::PutSample(IMediaSample *pSample) { if (!pSample) return S_OK; AM_MEDIA_TYPE *pmt = NULL; bool bFormatChanged = false; HRESULT hr = S_OK; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) bFormatChanged = !FormatsEqual((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, m_pInputFormat); if (pSample->IsDiscontinuity() == S_OK) m_bDiscontinuity = true; CAutoLock lock (&m_csOutputSample); if (m_bFlushing) return S_OK; if (bFormatChanged) { // Process any remaining input if (!m_bPassThrough) hr = ProcessData(NULL, 0, NULL); // Apply format change locally, // next filter will evaluate the format change when it receives the sample Log("CChannelMixer::PutSample: Processing format change"); ChannelOrder chOrder; hr = NegotiateFormat((WAVEFORMATEXTENSIBLE*)pmt->pbFormat, 1, &chOrder); if (FAILED(hr)) { DeleteMediaType(pmt); Log("CChannelMixer: PutSample failed to change format: 0x%08x", hr); return hr; } m_chOrder = chOrder; } if (pmt) DeleteMediaType(pmt); if (m_bPassThrough) { if (m_pNextSink) return m_pNextSink->PutSample(pSample); return S_OK; // perhaps we should return S_FALSE to indicate sample was dropped } long nOffset = 0; long cbSampleData = pSample->GetActualDataLength(); BYTE *pData = NULL; REFERENCE_TIME rtStop = 0; REFERENCE_TIME rtStart = 0; pSample->GetTime(&rtStart, &rtStop); // Detect discontinuity in stream timeline if ((abs(m_rtNextIncomingSampleTime - rtStart) > MAX_SAMPLE_TIME_ERROR) && m_nSampleNum != 0) { Log("CChannelMixer - stream discontinuity: %6.3f", (rtStart - m_rtNextIncomingSampleTime) / 10000000.0); m_rtInSampleTime = rtStart; if (m_nSampleNum > 0) { Log("CChannelMixer - using buffered sample data"); FlushStream(); } else Log("CChannelMixer - discarding buffered sample data"); } if (m_nSampleNum == 0) m_rtInSampleTime = rtStart; UINT nFrames = cbSampleData / m_pInputFormat->Format.nBlockAlign; REFERENCE_TIME duration = nFrames * UNITS / m_pInputFormat->Format.nSamplesPerSec; m_rtNextIncomingSampleTime = rtStart + duration; m_nSampleNum++; hr = pSample->GetPointer(&pData); ASSERT(pData); if (FAILED(hr)) { Log("CChannelMixer::PutSample - failed to get sample's data pointer: 0x%08x", hr); return hr; } while (nOffset < cbSampleData && SUCCEEDED(hr)) { long cbProcessed = 0; hr = ProcessData(pData + nOffset, cbSampleData - nOffset, &cbProcessed); nOffset += cbProcessed; } return hr; }