Ejemplo n.º 1
0
STDMETHODIMP_(DeviceStreamState) CCustomPin::SetState(
    _In_ DeviceStreamState State
)
{
    HRESULT hr = S_OK;

    DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Id:%d Transition into state: %d ", streamId(), State);

    DeviceStreamState oldState = setPreferredStreamState( State );

    if ( oldState != State )
    {
        ComPtr<IMFMediaType> preferredMediaType = nullptr;

        if (State == DeviceStreamState_Run)
        {
            GetMediaTypeAt(0, preferredMediaType.ReleaseAndGetAddressOf());
        }

        setPreferredMediaType(preferredMediaType.Get());
        setPreferredStreamState( State );

        {
            //
            // Notify the device transform manager that we have changed state
            //
            ComPtr<IMFMediaEvent> pEvent = nullptr;
            DMFTCHECKHR_GOTO( MFCreateMediaEvent(METransformInputStreamStateChanged, GUID_NULL, S_OK, NULL, pEvent.ReleaseAndGetAddressOf()), done );
            DMFTCHECKHR_GOTO( pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, streamId()), done );
            DMFTCHECKHR_GOTO( Parent()->QueueEvent(pEvent.Get()), done );
        }
        //
        // Wait to be notified back from the pipeline.
        //
        DMFTCHECKHR_GOTO( WaitForSetInputPinMediaChange(),done );
    }
done:
    DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
    return oldState;
}
Ejemplo n.º 2
0
HRESULT WavSource::Start(
    IMFPresentationDescriptor* pPresentationDescriptor,
    const GUID* pguidTimeFormat,
    const PROPVARIANT* pvarStartPosition
    )
{
    HRESULT hr = S_OK;
    LONGLONG llStartOffset = 0;
    BOOL bIsSeek = FALSE;    
    BOOL bIsRestartFromCurrentPosition = FALSE;     
    BOOL bQueuedStartEvent = FALSE;

    IMFMediaEvent *pEvent = NULL;

    PROPVARIANT var;
    PropVariantInit(&var);

    // Check parameters. 
    // Start position and presentation descriptor cannot be NULL.
    if (pvarStartPosition == NULL || pPresentationDescriptor == NULL)
    {
        return E_INVALIDARG;
    }

    // Check the time format. Must be "reference time" units.
    if ((pguidTimeFormat != NULL) && (*pguidTimeFormat != GUID_NULL))
    {
        // Unrecognized time format GUID.
        return MF_E_UNSUPPORTED_TIME_FORMAT;
    }

    EnterCriticalSection(&m_critSec);

    // Fail if the source is shut down.
    hr = CheckShutdown();

    if (FAILED(hr)) { goto done; }

    // Check the start position.
    if (pvarStartPosition->vt == VT_I8)
    {
        // Start position is given in pvarStartPosition in 100-ns units.
        llStartOffset = pvarStartPosition->hVal.QuadPart;

        if (m_state != STATE_STOPPED)
        {
            // Source is running or paused, so this is a seek.
            bIsSeek = TRUE;
        }
    }
    else if (pvarStartPosition->vt == VT_EMPTY)
    {
        // Start position is "current position". 
        // For stopped, that means 0. Otherwise, use the current position.
        if (m_state == STATE_STOPPED)
        {
            llStartOffset = 0;
        }
        else
        {
            llStartOffset = GetCurrentPosition();
            bIsRestartFromCurrentPosition = TRUE;
        }
    }
    else
    {
        // We don't support this time format.
        hr =  MF_E_UNSUPPORTED_TIME_FORMAT;
        goto done;
    }

    // Validate the caller's presentation descriptor.
    hr = ValidatePresentationDescriptor(pPresentationDescriptor);

    if (FAILED(hr)) { goto done; }

    // Sends the MENewStream or MEUpdatedStream event.
    hr = QueueNewStreamEvent(pPresentationDescriptor);

    if (FAILED(hr)) { goto done; }

    // Notify the stream of the new start time.
    hr = m_pStream->SetPosition(llStartOffset);

    if (FAILED(hr)) { goto done; }

    // Send Started or Seeked events. 

    var.vt = VT_I8;
    var.hVal.QuadPart = llStartOffset;

    // Send the source event.
    if (bIsSeek)
    {
        hr = QueueEvent(MESourceSeeked, GUID_NULL, hr, &var);

        if (FAILED(hr)) { goto done; }
    }
    else
    {
        // For starting, if we are RESTARTING from the current position and our 
        // previous state was running/paused, then we need to add the 
        // MF_EVENT_SOURCE_ACTUAL_START attribute to the event. This requires
        // creating the event object first.

        // Create the event.
        hr = MFCreateMediaEvent(MESourceStarted, GUID_NULL, hr, &var, &pEvent);

        if (FAILED(hr)) { goto done; }

        // For restarts, set the actual start time as an attribute.
        if (bIsRestartFromCurrentPosition)
        {
            hr = pEvent->SetUINT64(MF_EVENT_SOURCE_ACTUAL_START, llStartOffset);
            if (FAILED(hr)) { goto done; }
        }
        
        // Now  queue the event.
        hr = m_pEventQueue->QueueEvent(pEvent);

        if (FAILED(hr)) { goto done; }
    }

    bQueuedStartEvent = TRUE;

    // Send the stream event.
    if (m_pStream)
    {
        if (bIsSeek)
        {
            hr = m_pStream->QueueEvent(MEStreamSeeked, GUID_NULL, hr, &var);
        }
        else
        {
            hr = m_pStream->QueueEvent(MEStreamStarted, GUID_NULL, hr, &var);
        }
    
        if (FAILED(hr)) { goto done; }
    }

    if (bIsSeek)
    {
        // For seek requests, flush any queued samples.
        hr = m_pStream->Flush();
    }
    else
    {
        // Otherwise, deliver any queued samples.
        hr = m_pStream->DeliverQueuedSamples();
    }
    
    if (FAILED(hr)) { goto done; }

    m_state = STATE_STARTED;

done:

    // If a failure occurred and we have not sent the 
    // MESourceStarted/MESourceSeeked event yet, then it is 
    // OK just to return an error code from Start().

    // If a failure occurred and we have already sent the 
    // event (with a success code), then we need to raise an
    // MEError event.

    if (FAILED(hr) && bQueuedStartEvent)
    {
        hr = QueueEvent(MEError, GUID_NULL, hr, &var);
    }

    PropVariantClear(&var);
    SafeRelease(&pEvent);

    LeaveCriticalSection(&m_critSec);

    return hr;
}
HRESULT CHWMFT::ProcessOutput(
    DWORD                   dwFlags,
    DWORD                   dwOutputBufferCount,
    MFT_OUTPUT_DATA_BUFFER* pOutputSamples,
    DWORD*                  pdwStatus)
{
    /*****************************************
    ** See http://msdn.microsoft.com/en-us/library/ms704014(v=VS.85).aspx
    *****************************************/

    HRESULT     hr      = S_OK;
    IMFSample*  pSample = NULL;

    TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter",  __FUNCTION__);

    do
    {
        if(IsLocked() != FALSE)
        {
            hr = MF_E_TRANSFORM_ASYNC_LOCKED;
            break;
        }

        {
            CAutoLock lock(&m_csLock);

            TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): HaveOutputCount: %u",  __FUNCTION__, m_dwHaveOutputCount);

            if(m_dwHaveOutputCount == 0)
            {
                // This call does not correspond to a have output call

                hr = E_UNEXPECTED;
                break;
            }
            else
            {
                m_dwHaveOutputCount--;
            }
        }

        /*****************************************
        ** Todo: If your MFT supports more than one
        ** stream, make sure you modify
        ** MFT_MAX_STREAMS and adjust this function
        ** accordingly
        *****************************************/
        if(dwOutputBufferCount < MFT_MAX_STREAMS)
        {
            hr = E_INVALIDARG;
            break;
        }

        if(IsMFTReady() == FALSE)
        {
            hr = MF_E_TRANSFORM_TYPE_NOT_SET;
            break;
        }

        /***************************************
        ** Since this in an internal function
        ** we know m_pOutputSampleQueue can never be
        ** NULL due to InitializeTransform()
        ***************************************/
        hr = m_pOutputSampleQueue->GetNextSample(&pSample);
        if(FAILED(hr))
        {
            break;
        }

        if(pSample == NULL)
        {
            hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
            break;
        }

        /*******************************
        ** Todo: This MFT only has one
        ** input stream, so the output
        ** samples array and stream ID
        ** will only use the first
        ** member
        *******************************/
        pOutputSamples[0].dwStreamID    = 0;
        
        if((pOutputSamples[0].pSample) == NULL)
        {
            // The MFT is providing it's own samples
            (pOutputSamples[0].pSample)   = pSample;
            (pOutputSamples[0].pSample)->AddRef();
        }
        else
        {
            // The pipeline has allocated the samples
            IMFMediaBuffer* pBuffer = NULL;

            do
            {
                hr = pSample->ConvertToContiguousBuffer(&pBuffer);
                if(FAILED(hr))
                {
                    break;
                }

                hr = (pOutputSamples[0].pSample)->AddBuffer(pBuffer);
                if(FAILED(hr))
                {
                    break;
                }
            }while(false);

            SAFERELEASE(pBuffer);

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

        /***************************************
        ** Since this in an internal function
        ** we know m_pOutputSampleQueue can never be
        ** NULL due to InitializeTransform()
        ***************************************/
        if(m_pOutputSampleQueue->IsQueueEmpty() != FALSE)
        {
            // We're out of samples in the output queue
            CAutoLock lock(&m_csLock);

            if((m_dwStatus & MYMFT_STATUS_DRAINING) != 0)
            {
                // We're done draining, time to send the event
                IMFMediaEvent*  pDrainCompleteEvent  = NULL;

                do
                {
                    hr = MFCreateMediaEvent(METransformDrainComplete , GUID_NULL, S_OK, NULL, &pDrainCompleteEvent);
                    if(FAILED(hr))
                    {
                        break;
                    }

                    /*******************************
                    ** Todo: This MFT only has one
                    ** input stream, so the drain
                    ** is always on stream zero.
                    ** Update this is your MFT
                    ** has more than one stream
                    *******************************/
                    hr = pDrainCompleteEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, 0);
                    if(FAILED(hr))
                    {
                        break;
                    }

                    /***************************************
                    ** Since this in an internal function
                    ** we know m_pEventQueue can never be
                    ** NULL due to InitializeTransform()
                    ***************************************/
                    hr = m_pEventQueue->QueueEvent(pDrainCompleteEvent);
                    if(FAILED(hr))
                    {
                        break;
                    }
                }while(false);

                SAFERELEASE(pDrainCompleteEvent);

                if(FAILED(hr))
                {
                    break;
                }

                m_dwStatus &= (~MYMFT_STATUS_DRAINING);
            }
        }
    }while(false);

    SAFERELEASE(pSample);

    TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit (hr=0x%x)",  __FUNCTION__, hr);

    return hr;
}
Ejemplo n.º 4
0
HRESULT HDMediaSource::DoStart(SourceOperation* op)
{
	DbgLogPrintf(L"%s::DoStart...",L"HDMediaSource");

	if (op->GetOperation() != SourceOperation::OP_START)
		return E_UNEXPECTED;

	ComPtr<IMFPresentationDescriptor> ppd;
	auto start_op = static_cast<StartOperation*>(op);
	HRESULT hr = start_op->GetPresentationDescriptor(ppd.GetAddressOf());
	if (FAILED(hr))
		return hr;

	bool bSeek = false,bResume = false;
	bool forceSeek = false;
	AutoPropVar propvar(&op->GetData());
	if (propvar.GetType() == VT_I8)
	{
		if ((_state != STATE_STOPPED) && (propvar.GetInt64() != 0))
		{
			bSeek = true;
		}else if (propvar.GetInt64() <= 0)
		{
			if (_state == STATE_STARTED || _state == STATE_PAUSED)
				bSeek = forceSeek = true;
		}
	}else if (propvar.GetType() == VT_EMPTY)
	{
		if (_state == STATE_PAUSED)
			bResume = true;
	}

	if (bResume)
		DbgLogPrintf(L"%s::DoStart->Resume Play...",L"HDMediaSource");

	hr = SelectStreams(ppd.Get(),op->GetData(),bSeek,false);

	_seekAfterFlag = false; //指示Seek后的第一个Packet
	if ((SUCCEEDED(hr) && (propvar.GetInt64() != 0)) || forceSeek) {
		hr = SeekOpen(propvar.GetInt64()); //to Seek...
	}else{
		if (start_op->GetSeekToTime() != PACKET_NO_PTS)
			_pMediaParser->Seek(start_op->GetSeekToTime(), true, AVSeekDirection::SeekDirection_Auto);
	}

	if (SUCCEEDED(hr))
	{
		DbgLogPrintf(L"%s::DoStart->Event %s",L"HDMediaSource",
			bSeek ? L"MESourceSeeked":L"MESourceStarted");

		ComPtr<IMFMediaEvent> pNewEvent;
		hr = MFCreateMediaEvent(bSeek ? MESourceSeeked:MESourceStarted,GUID_NULL,S_OK,
			&op->GetData(),pNewEvent.GetAddressOf());

		if (SUCCEEDED(hr)) //[optional] MF_EVENT_SOURCE_ACTUAL_START...
			hr = _pEventQueue->QueueEvent(pNewEvent.Get());

		if (SUCCEEDED(hr) && !bResume)
		{
			_state = STATE_BUFFERING;
			if (_network_mode)
				SendNetworkStartBuffering();
			else
				PreloadStreamPacket(); //如果不是打开网络流,DoOpen就执行LoadSample队列

#ifdef _DEBUG
			double queueMaxTime = GetAllStreamMaxQueueTime();
			DbgLogPrintf(L"%s::DoStart->Queue Max Time %0.3f",L"HDMediaSource",(float)queueMaxTime);
#endif
		}

		if (SUCCEEDED(hr))
		{
			for (unsigned i = 0;i < _streamList.Count();i++)
			{
				ComPtr<HDMediaStream> pStream;
				_streamList.GetAt(i,pStream.GetAddressOf());

				if (pStream->IsActive()) {
					pStream->Start(op->GetData(),bSeek);
					pStream->SetOnceState();
				}
			}
		}
	}

	_state = STATE_STARTED;

	if (FAILED(hr))
		_pEventQueue->QueueEventParamVar(MESourceStarted,GUID_NULL,hr,nullptr);

	DbgLogPrintf(L"%s::DoStart Result:0x%08X",L"HDMediaSource",hr);
	return hr;
}