Пример #1
0
// Format negotiation
HRESULT CTimeStretchFilter::NegotiateFormat(const WAVEFORMATEXTENSIBLE* pwfx, int nApplyChangesDepth, ChannelOrder* pChOrder)
{
  if (!pwfx)
    return VFW_E_TYPE_NOT_ACCEPTED;

#ifdef INTEGER_SAMPLES
  // only accept 16bit int
  if (pwfx->Format.wBitsPerSample != 16 || pwfx->SubFormat != KSDATAFORMAT_SUBTYPE_PCM)
    return VFW_E_TYPE_NOT_ACCEPTED;
#else 
  // only accept 32bit float
  if (pwfx->Format.wBitsPerSample != 32 || pwfx->SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
    return VFW_E_TYPE_NOT_ACCEPTED;
#endif

  if (FormatsEqual(pwfx, m_pInputFormat))
  {
    *pChOrder = m_chOrder;
    return S_OK;
  }

  bool bApplyChanges = (nApplyChangesDepth != 0);
  if (nApplyChangesDepth != INFINITE && nApplyChangesDepth > 0)
    nApplyChangesDepth--;

  HRESULT hr = m_pNextSink->NegotiateFormat(pwfx, nApplyChangesDepth, pChOrder);
  if (FAILED(hr))
    return hr;

  hr = VFW_E_CANNOT_CONNECT;
  
  if (!pwfx)
    return SetFormat(NULL);

  if (bApplyChanges)
  {
    LogWaveFormat(pwfx, "TS   - applying ");

    AM_MEDIA_TYPE tmp;
    HRESULT result = CreateAudioMediaType((WAVEFORMATEX*)pwfx, &tmp, true);
    if (SUCCEEDED(result))
    {
      if (m_pMediaType)
        DeleteMediaType(m_pMediaType);
      m_pMediaType = CreateMediaType(&tmp);
    }

    SetInputFormat(pwfx);
    SetOutputFormat(pwfx);
    SetFormat(pwfx);
  }
  else
    LogWaveFormat(pwfx, "TS   -          ");

  m_chOrder = *pChOrder;

  return S_OK;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #5
0
HRESULT CChannelMixer::NegotiateFormat(const WAVEFORMATEXTENSIBLE* pwfx, int nApplyChangesDepth, ChannelOrder* pChOrder)
{
  if (!pwfx)
    return VFW_E_TYPE_NOT_ACCEPTED;

  if (FormatsEqual(pwfx, m_pInputFormat))
  {
    *pChOrder = m_chOrder;
    return S_OK;
  }

  if (!m_pNextSink)
    return VFW_E_TYPE_NOT_ACCEPTED;

  bool bApplyChanges = (nApplyChangesDepth != 0);
  if (nApplyChangesDepth != INFINITE && nApplyChangesDepth > 0)
    nApplyChangesDepth--;

  if (pwfx->SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
    return VFW_E_TYPE_NOT_ACCEPTED;

  HRESULT hr = S_OK;
  bool expandToStereo = pwfx->Format.nChannels == 1 && m_pSettings->m_bExpandMonoToStereo;

  if (!m_pSettings->m_bForceChannelMixing && !expandToStereo)
  {
    // try the format directly
    hr = m_pNextSink->NegotiateFormat(pwfx, nApplyChangesDepth, pChOrder);
    if (SUCCEEDED(hr))
    {
      if (bApplyChanges)
      {
        SetInputFormat(pwfx);
        SetOutputFormat(pwfx);
        m_bPassThrough = false;
        hr = SetupConversion(*pChOrder);
      }

      m_chOrder = *pChOrder;
      return hr;
    }
  }

  WAVEFORMATEXTENSIBLE* pOutWfx;
  CopyWaveFormatEx(&pOutWfx, pwfx);

  if (!expandToStereo || m_pSettings->m_bForceChannelMixing)
  {
    pOutWfx->dwChannelMask = m_pSettings->m_lSpeakerConfig;
    pOutWfx->Format.nChannels = m_pSettings->m_lSpeakerCount;
  }
  else // Expand mono to stereo
  {
    pOutWfx->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
    pOutWfx->Format.nChannels = 2;
  }

  pOutWfx->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;  
  pOutWfx->Format.nBlockAlign = pOutWfx->Format.wBitsPerSample / 8 * pOutWfx->Format.nChannels;
  pOutWfx->Format.nAvgBytesPerSec = pOutWfx->Format.nBlockAlign * pOutWfx->Format.nSamplesPerSec;
  
  hr = m_pNextSink->NegotiateFormat(pOutWfx, nApplyChangesDepth, pChOrder);
  m_chOrder = *pChOrder;


  if (FAILED(hr))
  {
    SAFE_DELETE_WAVEFORMATEX(pOutWfx);
    return hr;
  }

  if (bApplyChanges)
  {
    LogWaveFormat(pwfx, "MIX  - applying ");

    m_bPassThrough = false;
    SetInputFormat(pwfx);
    SetOutputFormat(pOutWfx, true);
    hr = SetupConversion(*pChOrder);
  }
  else
  {
    LogWaveFormat(pwfx, "MIX  -          ");
    SAFE_DELETE_WAVEFORMATEX(pOutWfx);
  }

  return hr;
}
Пример #6
0
// 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;
}
HRESULT CSampleRateConverter::NegotiateFormat(const WAVEFORMATEXTENSIBLE* pwfx, int nApplyChangesDepth, ChannelOrder* pChOrder)
{
  if (!pwfx)
    return VFW_E_TYPE_NOT_ACCEPTED;

  if (FormatsEqual(pwfx, m_pInputFormat))
  {
    *pChOrder = m_chOrder;
    return S_OK;
  }

  if (!m_pNextSink)
    return VFW_E_TYPE_NOT_ACCEPTED;

  bool bApplyChanges = (nApplyChangesDepth != 0);
  if (nApplyChangesDepth != INFINITE && nApplyChangesDepth > 0)
    nApplyChangesDepth--;

  // Try passthrough
  HRESULT hr = m_pNextSink->NegotiateFormat(pwfx, nApplyChangesDepth, pChOrder);
  if (SUCCEEDED(hr))
  {
    if (bApplyChanges)
    {
      m_bPassThrough = true;
      SetInputFormat(pwfx);
      SetOutputFormat(pwfx);
    }

    m_chOrder = *pChOrder;
    return hr;
  }

  if (pwfx->SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
    return VFW_E_TYPE_NOT_ACCEPTED;

  WAVEFORMATEXTENSIBLE* pOutWfx;
  CopyWaveFormatEx(&pOutWfx, pwfx);
  pOutWfx->Format.nSamplesPerSec = 0;

  hr = VFW_E_TYPE_NOT_ACCEPTED;

  const unsigned int sampleRateCount = sizeof(gAllowedSampleRates) / sizeof(int);
  unsigned int startPoint = 0;

  // TODO test duplicate sample rates first

  // Search for the input sample rate in sample rate array
  bool foundSampleRate = false;
  for (unsigned int i = 0; i < sampleRateCount && !foundSampleRate; i++)
  {
    if (gAllowedSampleRates[i] == pwfx->Format.nSamplesPerSec)
    {
      startPoint = ++i; // select closest sample rate in ascending order 
      foundSampleRate = true;
    }
  }

  if (!foundSampleRate)
    Log("CSampleRateConverter::NegotiateFormat - sample rate (%d) not found in the source array", pwfx->Format.nSamplesPerSec);
  
  unsigned int sampleRatesTested = 0;
  for (int i = startPoint; FAILED(hr) && pOutWfx->Format.nSamplesPerSec == 0 && sampleRatesTested < sampleRateCount; i++)
  {
    if (pOutWfx->Format.nSamplesPerSec == pwfx->Format.nSamplesPerSec)
    {
      sampleRatesTested++;
      continue; // skip if same as source
    }

    pOutWfx->Format.nSamplesPerSec = gAllowedSampleRates[i];
    pOutWfx->Format.nAvgBytesPerSec = gAllowedSampleRates[i] * pOutWfx->Format.nBlockAlign;

    hr = m_pNextSink->NegotiateFormat(pOutWfx, nApplyChangesDepth, pChOrder);
    sampleRatesTested++;

    if (FAILED(hr))
      pOutWfx->Format.nSamplesPerSec = 0;

    // Search from the lower end
    if (i == sampleRateCount - 1)
      i = 0;
  }

  if (FAILED(hr))
  {
    SAFE_DELETE_WAVEFORMATEX(pOutWfx);
    return hr;
  }
  if (bApplyChanges)
  {
    LogWaveFormat(pwfx, "SRC  - applying ");

    m_bPassThrough = false;
    SetInputFormat(pwfx);
    SetOutputFormat(pOutWfx, true);
    hr = SetupConversion();
    // TODO: do something meaningfull if SetupConversion fails
    //if (FAILED(hr))
  }
  else
  {
    LogWaveFormat(pwfx, "SRC  -          ");
    SAFE_DELETE_WAVEFORMATEX(pOutWfx);
  }

  m_chOrder = *pChOrder;

  return S_OK;
}
// Format negotiation
HRESULT CWASAPIRenderFilter::NegotiateFormat(const WAVEFORMATEXTENSIBLE* pwfx, int nApplyChangesDepth, ChannelOrder* pChOrder)
{
  if (!pwfx)
    return VFW_E_TYPE_NOT_ACCEPTED;

  if (FormatsEqual(pwfx, m_pInputFormat))
  {
    *pChOrder = m_chOrder;
    return S_OK;
  }

  bool bApplyChanges = nApplyChangesDepth != 0;

  bool bitDepthForced = (m_pSettings->m_nForceBitDepth != 0 && m_pSettings->m_nForceBitDepth != pwfx->Format.wBitsPerSample);
  bool sampleRateForced = (m_pSettings->m_nForceSamplingRate != 0 && m_pSettings->m_nForceSamplingRate != pwfx->Format.nSamplesPerSec);
  
  if ((bitDepthForced || sampleRateForced) &&
       pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL ||
       pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT && bitDepthForced)
    return VFW_E_TYPE_NOT_ACCEPTED;
  
  if (((bitDepthForced && m_pSettings->m_nForceBitDepth != pwfx->Format.wBitsPerSample) ||
       (sampleRateForced && m_pSettings->m_nForceSamplingRate != pwfx->Format.nSamplesPerSec)))
    return VFW_E_TYPE_NOT_ACCEPTED;

  CAutoLock lock(&m_csResources);

  HRESULT hr = CreateAudioClient();
  if (FAILED(hr))
  {
    Log("CWASAPIRenderFilter::NegotiateFormat Error, audio client not initialized: (0x%08x)", hr);
    return VFW_E_CANNOT_CONNECT;
  }

  WAVEFORMATEXTENSIBLE* pwfxAccepted = NULL;
  hr = IsFormatSupported(pwfx, &pwfxAccepted);
  if (FAILED(hr))
  {
    SAFE_DELETE_WAVEFORMATEX(pwfxAccepted);
    return hr;
  }

  if (bApplyChanges)
  {
    LogWaveFormat(pwfx, "REN - applying  ");

    // Stop and discard audio client
    StopAudioClient();
    SAFE_RELEASE(m_pRenderClient);
    SAFE_RELEASE(m_pAudioClock);
    SAFE_RELEASE(m_pAudioClient);

    // We must use incoming format so the WAVEFORMATEXTENSIBLE to WAVEFORMATEXT difference
    // that some audio drivers require is not causing an infonite loop of format changes
    SetInputFormat(pwfx);

    // Reinitialize audio client
    hr = CreateAudioClient(true);
  }
  else
    LogWaveFormat(pwfx, "Input format    ");

  m_chOrder = *pChOrder = DS_ORDER;
  SAFE_DELETE_WAVEFORMATEX(pwfxAccepted);

  return hr;
}