// Handle an event from the capture engine. 
// NOTE: This method is called from the application's UI thread. 
HRESULT CaptureManager::OnCaptureEvent(WPARAM wParam, LPARAM lParam)
{
    GUID guidType;
    HRESULT hrStatus;

    IMFMediaEvent *pEvent = reinterpret_cast<IMFMediaEvent*>(wParam);

    HRESULT hr = pEvent->GetStatus(&hrStatus);
    if (FAILED(hr))
    {
        hrStatus = hr;
    }

    hr = pEvent->GetExtendedType(&guidType);
    if (SUCCEEDED(hr))
    {

#ifdef _DEBUG
        LPOLESTR str;
        if (SUCCEEDED(StringFromCLSID(guidType, &str)))
        {
            DBGMSG((L"MF_CAPTURE_ENGINE_EVENT: %s (hr = 0x%X)\n", str, hrStatus));
            CoTaskMemFree(str);
        }
#endif

        if (guidType == MF_CAPTURE_ENGINE_INITIALIZED)
        {
            OnCaptureEngineInitialized(hrStatus);
            SetErrorID(hrStatus, IDS_ERR_INITIALIZE);
        }
        else if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STARTED)
        {
            OnPreviewStarted(hrStatus);
            SetErrorID(hrStatus, IDS_ERR_PREVIEW);
        }
        else if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED)
        {
            OnPreviewStopped(hrStatus);
            SetErrorID(hrStatus, IDS_ERR_PREVIEW);
        }
        else if (guidType == MF_CAPTURE_ENGINE_RECORD_STARTED)
        {
            OnRecordStarted(hrStatus);
            SetErrorID(hrStatus, IDS_ERR_RECORD);
        }
        else if (guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED)
        {
            OnRecordStopped(hrStatus);
            SetErrorID(hrStatus, IDS_ERR_RECORD);
        }
        else if (guidType == MF_CAPTURE_ENGINE_PHOTO_TAKEN)
        {
            m_bPhotoPending = false;
            SetErrorID(hrStatus, IDS_ERR_PHOTO);
        }
        else if (guidType == MF_CAPTURE_ENGINE_ERROR)
        {
            DestroyCaptureEngine();
            SetErrorID(hrStatus, IDS_ERR_CAPTURE);
        }
        else if (FAILED(hrStatus))
        {
            SetErrorID(hrStatus, IDS_ERR_CAPTURE);
        }
    }

    pEvent->Release();
    SetEvent(m_hEvent);
    return hrStatus;
}
// Process any pending output from the decoder (until all output is
// processed).
//
// Thread context: decoder thread
bool DecoderMF::DoProcessOutput()
{
	bool						ret = false;
	HRESULT						hr;
	MFT_OUTPUT_DATA_BUFFER		mftDataBuffer;
	DWORD						mftStatus;
	bool						moreOutput;

	if (m_outputSample == NULL)
	{
		if (! CreateOutputSample())
			return false;
	}

	do
	{
		// Since we could be looping inside this method for a while,
		// if a whole stack of frames arrive at once, we want to exit
		// if the thread has been asked to die. So check on each
		// iteration of the loop.
		if (! m_decoderThreadRunning)
			return true;

		moreOutput = false;

		mftDataBuffer.dwStreamID = 0;
		mftDataBuffer.pSample = m_outputSample;
		mftDataBuffer.dwStatus = 0;
		mftDataBuffer.pEvents = NULL;
		mftStatus = 0;

		// Looks like we have to reset the sample before use:
		IMFMediaBuffer* mediaBuffer;
		hr = m_outputSample->GetBufferByIndex(0, &mediaBuffer);
		if (FAILED(hr))
			goto bail;

		hr = mediaBuffer->SetCurrentLength(0);
		if (FAILED(hr))
			goto bail;

		mediaBuffer->Release();

		hr = m_h264Decoder->ProcessOutput(0, 1, &mftDataBuffer, &mftStatus);

		// Check return code
		if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
			break;
		EnterCriticalSection(&m_criticalSection);
		if (hr == MF_E_TRANSFORM_STREAM_CHANGE || !m_previewConfigured)
		{
			// If the output format has changed, we need to handle
			// the stream change. This will happen after the first
			// few packets have been delivered.
			moreOutput = HandleStreamChange();
			LeaveCriticalSection(&m_criticalSection);
			if (!moreOutput)
				goto bail;
			continue;
		}
		LeaveCriticalSection(&m_criticalSection);
		if (FAILED(hr))
			goto bail;

		if (mftDataBuffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE)
			moreOutput = true;

		// Process each event:
		if (mftDataBuffer.pEvents != NULL)
		{
			DWORD numElements;
			hr = mftDataBuffer.pEvents->GetElementCount(&numElements);
			if (SUCCEEDED(hr))
			{
				for (DWORD i = 0; i < numElements; i++)
				{
					IUnknown* iunk = NULL;

					hr = mftDataBuffer.pEvents->GetElement(i, &iunk);
					if (SUCCEEDED(hr))
					{
						IMFMediaEvent* mediaEvent = NULL;
						hr = iunk->QueryInterface(IID_IMFMediaEvent, (void**)&mediaEvent);

						if (SUCCEEDED(hr))
						{
							OutputDebugString(_T("FIXME: process event!\n"));

							mediaEvent->Release();
						}

						iunk->Release();
					}
				}
			}

			mftDataBuffer.pEvents = NULL;
		}

		// Process sample:
		if (mftDataBuffer.pSample != NULL)
		{
			IMFMediaBuffer* mediaBuffer;
			hr = mftDataBuffer.pSample->GetBufferByIndex(0, &mediaBuffer);
			if (FAILED(hr))
				goto bail;

			EnterCriticalSection(&m_criticalSection);

				if (m_previewWindow != NULL && m_previewConfigured)
					m_previewWindow->DrawFrame(mediaBuffer);

			LeaveCriticalSection(&m_criticalSection);

			mediaBuffer->Release();
		}
	} while(moreOutput);

	ret = true;

bail:
	if (ret == false)
		OutputDebugString(_T("ERROR: failed to process output...\n"));

	return ret;
}
/** Asyncronous callback */
HRESULT FImfVideoPlayer::Invoke( IMFAsyncResult* AsyncResult )
{
	IMFMediaEvent* Event = NULL;
	HRESULT HResult = MediaSession->EndGetEvent( AsyncResult, &Event );

	if( FAILED( HResult ) )
	{
		Event->Release( );
		return S_OK;
	}

	MediaEventType EventType = MEUnknown;
	HResult = Event->GetType( &EventType );
	//Moving lower because it is referenced below to GetStatus if there was a problem: Event->Release( );

	if( FAILED( HResult ) )
	{
		Event->Release( );
		return S_OK;
	}

	/* Closed */
	if( EventType == MESessionClosed )
	{
		MovieIsFinished.Set( 1 );
		CloseIsPosted.Set( 1 );
	}
	else
	{
		HResult = MediaSession->BeginGetEvent( this, NULL );
		if( FAILED( HResult ) )
		{
			Event->Release( );
			return S_OK;
		}

		if( MovieIsRunning( ) )
		{
			/* End of clip */
			if( EventType == MEEndOfPresentation )
			{
				if( Looping )
					StartPlayback( );
				else
					MovieIsFinished.Set( 1 );
			}

			/* Unknown error, dont continue */
			else if( EventType == MEError )
			{
				HRESULT HReturnCode = S_OK;
				Event->GetStatus( &HReturnCode );

				/* Log error HResult */
				UE_LOG( LogImfVideoPlayer, Log, TEXT( "ImfVideoPlayer error recieved: %i" ), HReturnCode );

				MovieIsFinished.Set( 1 );
				CloseIsPosted.Set( 1 );
			}
		}

		/* DEBUG: Displays all event ID's in log */
		//UE_LOG( LogImfVideoPlayer, Log, TEXT( "ImfVideoPlayer event id: %i" ), EventType );
	}
	
	Event->Release( );

	return S_OK;
}