Beispiel #1
0
HRESULT
CPullPin::CollectAndDeliver(
    REFERENCE_TIME tStart,
    REFERENCE_TIME tStop)
{
    IMediaSample* pSample = NULL;   // better be sure pSample is set
    DWORD_PTR dwUnused;
    HRESULT hr = m_pReader->WaitForNext(
			INFINITE,
			&pSample,
			&dwUnused);
    if (FAILED(hr)) {
	if (pSample) {
	    pSample->Release();
	}
    } else {
	hr = DeliverSample(pSample, tStart, tStop);
    }
    if (FAILED(hr)) {
	CleanupCancelled();
	OnError(hr);
    }
    return hr;

}
// If the presenter is waiting to frame-step, this method starts the frame-step operation.
HRESULT EVRCustomPresenter::StartFrameStep()
{
  assert(m_RenderState == RENDER_STATE_STARTED);

  HRESULT hr = S_OK;
  IMFSample *pSample = NULL;

  if (m_FrameStep.state == FRAMESTEP_WAITING_START)
  {
    // We have a frame-step request, and are waiting for the clock to start.
    // Set the state to "pending," which means we are waiting for samples.
    m_FrameStep.state = FRAMESTEP_PENDING;

    // If the frame-step queue already has samples, process them now.
    // We break the loop when the frame-step queue is empty or the frame-step operation is complete
    while (!m_FrameStep.samples.IsEmpty() && (m_FrameStep.state == FRAMESTEP_PENDING))
    {
      hr = m_FrameStep.samples.RemoveFront(&pSample);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pSample)
        CHECK_HR(hr, "EVRCustomPresenter::StartFrameStep VideoSampleList::RemoveFront() failed");
      }

      hr = DeliverFrameStepSample(pSample);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pSample)
        CHECK_HR(hr, "EVRCustomPresenter::StartFrameStep EVRCustomPresenter::DeliverFrameStepSample() failed");
      }

      SAFE_RELEASE(pSample);
    }
  }
  else if (m_FrameStep.state == FRAMESTEP_NONE)
  {
    // We are not frame stepping. Therefore, if the frame-step queue has samples, we need to process them normally.
    while (!m_FrameStep.samples.IsEmpty())
    {
      hr = m_FrameStep.samples.RemoveFront(&pSample);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pSample)
          CHECK_HR(hr, "EVRCustomPresenter::StartFrameStep VideoSampleList::RemoveFront() failed");
      }

      hr = DeliverSample(pSample, FALSE);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pSample)
        CHECK_HR(hr, "EVRCustomPresenter::StartFrameStep EVRCustomPresenter::DeliverSample() failed");
      }

      SAFE_RELEASE(pSample);
    }
  }

  return hr;
}
HRESULT WavStream::DeliverQueuedSamples()
{
    HRESULT hr = S_OK;
    IMFSample *pSample = NULL;

    EnterCriticalSection(&m_critSec);

    // If we already reached the end of the stream, send the MEEndStream 
    // event again.
    if (m_EOS)
    {
        hr = QueueEvent(MEEndOfStream, GUID_NULL, S_OK, NULL);
    }

    if (SUCCEEDED(hr))
    {   
        // Deliver any queued samples. 
        while (!m_sampleQueue.IsEmpty())
        {
            hr = m_sampleQueue.Dequeue(&pSample);
            if (FAILED(hr))
            {
                break;
            }

            hr = DeliverSample(pSample);
            if (FAILED(hr))
            {
                break;
            }

            SafeRelease(&pSample);
        }
    }

    LeaveCriticalSection(&m_critSec);

    // If we reached the end of the stream, send the end-of-presentation event from
    // the media source.
    if (SUCCEEDED(hr))
    {   
        if (m_EOS)
        {
            hr = m_pSource->QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, NULL);
        }
    }

    SafeRelease(&pSample);
    return hr;
}
// Process a video sample for frame-stepping.
HRESULT EVRCustomPresenter::DeliverFrameStepSample(IMFSample *pSample)
{
  HRESULT hr = S_OK;
  IUnknown *pUnk = NULL;

  // For rate 0, discard any sample that ends earlier than the clock time.
  if (IsScrubbing() && m_pClock && IsSampleTimePassed(m_pClock, pSample))
  {
    // Discard this sample.
  }
  else if (m_FrameStep.state >= FRAMESTEP_SCHEDULED)
  {
    // A frame was already submitted. Put this sample on the frame-step queue, 
    // in case we are asked to step to the next frame. If frame-stepping is
    // cancelled, this sample will be processed normally.
    hr = m_FrameStep.samples.InsertBack(pSample);
    CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample VideoSampleList::InsertBack() failed");
  }
  else
  {
    // We're ready to frame-step.

    // Decrement the number of steps.
    if (m_FrameStep.steps > 0)
    {
      m_FrameStep.steps--;
    }

    if (m_FrameStep.steps > 0)
    {
      // This is not the last step. Discard this sample.
    }
    else if (m_FrameStep.state == FRAMESTEP_WAITING_START)
    {
      // This is the right frame, but the clock hasn't started yet. Put the
      // sample on the frame-step queue. When the clock starts, the sample
      // will be processed.
      hr = m_FrameStep.samples.InsertBack(pSample);
      CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample VideoSampleList::InsertBack() failed");
    }
    else
    {
      // This is the right frame *and* the clock has started. Deliver this sample.
      hr = DeliverSample(pSample, FALSE);
      CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStepSample EVRCustomPresenter::DeliverSample() failed");

      // QI for IUnknown so that we can identify the sample later.
      // (Per COM rules, an object alwayss return the same pointer when QI'ed for IUnknown.)
      hr = pSample->QueryInterface(__uuidof(IUnknown), (void**)&pUnk);
      if (FAILED(hr))
      {
        SAFE_RELEASE(pUnk);
        CHECK_HR(hr, "EVRCustomPresenter::DeliverFrameStempSample IMFSample::QueryInterface() failed");
      }
      // Save this value.
      m_FrameStep.pSampleNoRef = (DWORD_PTR)pUnk; // No add-ref. 

      // NOTE: We do not AddRef the IUnknown pointer, because that would prevent the 
      // sample from invoking the OnSampleFree callback after the sample is presented. 
      // We use this IUnknown pointer purely to identify the sample later; we never
      // attempt to dereference the pointer.

      // Update our state.
      m_FrameStep.state = FRAMESTEP_SCHEDULED;
    }
  }

  SAFE_RELEASE(pUnk);
  return hr;
}
HRESULT WavStream::RequestSample(IUnknown* pToken)
{
    if (m_pSource == NULL)
    {
        return E_UNEXPECTED;
    }

    HRESULT hr = S_OK;

    IMFMediaSource *pSource = NULL;
    IMFSample *pSample = NULL;  // Sample to deliver.

    EnterCriticalSection(&m_critSec);

    // Check if we are shut down.
    hr = CheckShutdown();

    // Check if we already reached the end of the stream.
    if (SUCCEEDED(hr))
    {   
        if (m_EOS)
        {
            hr = MF_E_END_OF_STREAM;
        }
    }

    // Check the source is stopped.
    // GetState does not hold the source's critical section. Safe to call.
    if (SUCCEEDED(hr))
    {   
        if (m_pSource->GetState() == WavSource::STATE_STOPPED)
        {
            hr = MF_E_INVALIDREQUEST;
        }
    }

    if (SUCCEEDED(hr))
    {   
        // Create a new audio sample.
        hr = CreateAudioSample(&pSample);
    }

    if (SUCCEEDED(hr))
    {   
        // If the caller provided a token, attach it to the sample as
        // an attribute. 

        // NOTE: If we processed sample requests asynchronously, we would
        // need to call AddRef on the token and put the token onto a FIFO
        // queue. See documenation for IMFMediaStream::RequestSample.
        if (pToken)
        {
            hr = pSample->SetUnknown(MFSampleExtension_Token, pToken);
        }
    }

    // If paused, queue the sample for later delivery. Otherwise, deliver the sample now.
    if (SUCCEEDED(hr))
    {   
        if (m_pSource->GetState() == WavSource::STATE_PAUSED)
        {
            hr = m_sampleQueue.Queue(pSample);
        }
        else
        {
            hr = DeliverSample(pSample);
        }
    }

    // Cache a pointer to the source, prior to leaving the critical section.
    if (SUCCEEDED(hr))
    {   
        pSource = m_pSource;
        pSource->AddRef();
    }

    LeaveCriticalSection(&m_critSec);


    // We only have one stream, so the end of the stream is also the end of the
    // presentation. Therefore, when we reach the end of the stream, we need to 
    // queue the end-of-presentation event from the source. Logically we would do 
    // this inside the CheckEndOfStream method. However, we cannot hold the
    // source's critical section while holding the stream's critical section, at
    // risk of deadlock. 

    if (SUCCEEDED(hr))
    {   
        if (m_EOS)
        {
            hr = pSource->QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, NULL);
        }
    }

    SafeRelease(&pSample);
    SafeRelease(&pSource);
    return hr;
}
Beispiel #6
0
void
CPullPin::Process(void)
{
    // is there anything to do?
    if (m_tStop <= m_tStart) {
	EndOfStream();
	return;
    }

    BOOL bDiscontinuity = TRUE;

    // if there is more than one sample at the allocator,
    // then try to queue 2 at once in order to overlap.
    // -- get buffer count and required alignment
    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr = m_pAlloc->GetProperties(&Actual);

    // align the start position downwards
    REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS;
    REFERENCE_TIME tCurrent = tStart;

    REFERENCE_TIME tStop = m_tStop;
    if (tStop > m_tDuration) {
	tStop = m_tDuration;
    }

    // align the stop position - may be past stop, but that
    // doesn't matter
    REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS;


    DWORD dwRequest;

    if (!m_bSync) {

	//  Break out of the loop either if we get to the end or we're asked
	//  to do something else
	while (tCurrent < tAlignStop) {

	    // Break out without calling EndOfStream if we're asked to
	    // do something different
	    if (CheckRequest(&dwRequest)) {
		return;
	    }

	    // queue a first sample
	    if (Actual.cBuffers > 1) {

		hr = QueueSample(tCurrent, tAlignStop, TRUE);
		bDiscontinuity = FALSE;

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



	    // loop queueing second and waiting for first..
	    while (tCurrent < tAlignStop) {

		hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity);
		bDiscontinuity = FALSE;

		if (FAILED(hr)) {
		    return;
		}

		hr = CollectAndDeliver(tStart, tStop);
		if (S_OK != hr) {

		    // stop if error, or if downstream filter said
		    // to stop.
		    return;
		}
	    }

	    if (Actual.cBuffers > 1) {
		hr = CollectAndDeliver(tStart, tStop);
		if (FAILED(hr)) {
		    return;
		}
	    }
	}
    } else {

	// sync version of above loop
	while (tCurrent < tAlignStop) {

	    // Break out without calling EndOfStream if we're asked to
	    // do something different
	    if (CheckRequest(&dwRequest)) {
		return;
	    }

	    IMediaSample* pSample;

	    hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0);
	    if (FAILED(hr)) {
		OnError(hr);
		return;
	    }

	    LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS);
	    if (tStopThis > tAlignStop) {
		tStopThis = tAlignStop;
	    }
	    pSample->SetTime(&tCurrent, &tStopThis);
	    tCurrent = tStopThis;

	    if (bDiscontinuity) {
		pSample->SetDiscontinuity(TRUE);
		bDiscontinuity = FALSE;
	    }

	    hr = m_pReader->SyncReadAligned(pSample);

	    if (FAILED(hr)) {
		pSample->Release();
		OnError(hr);
		return;
	    }

	    hr = DeliverSample(pSample, tStart, tStop);
	    if (hr != S_OK) {
		if (FAILED(hr)) {
		    OnError(hr);
		}
		return;
	    }
	}
    }

    EndOfStream();
}