mfxStatus QSV_Encoder_Internal::Drain()
{
	mfxStatus sts = MFX_ERR_NONE;

	//
	// Drain the buffered encoded frames
	//
	while (MFX_ERR_NONE <= sts) 
	{
		int nTaskIdx = GetFreeTaskIndex(m_pTaskPool, m_nTaskPool);
		if (MFX_ERR_NOT_FOUND == nTaskIdx) 
		{
			// No more free tasks, need to sync
			sts = m_session.SyncOperation(m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
			MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

			m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
			m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
		}
		else 
		{
			for (;;) 
			{
				// Encode a frame asychronously (returns immediately)
				sts = m_pmfxENC->EncodeFrameAsync(NULL, NULL, &m_pTaskPool[nTaskIdx].mfxBS, &m_pTaskPool[nTaskIdx].syncp);

				if (MFX_ERR_NONE < sts && !m_pTaskPool[nTaskIdx].syncp) 
				{   // Repeat the call if warning and no output
					if (MFX_WRN_DEVICE_BUSY == sts)
						MSDK_SLEEP(1);  // Wait if device is busy, then repeat the same call
				}
				else if (MFX_ERR_NONE < sts && m_pTaskPool[nTaskIdx].syncp) 
				{
					sts = MFX_ERR_NONE;     // Ignore warnings if output is available
					break;
				}
				else
					break;
			}
		}
	}

	// MFX_ERR_MORE_DATA indicates that there are no more buffered frames, exit in case of other errors
	MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

	//
	// Sync all remaining tasks in task pool
	//
	while (m_pTaskPool[m_nFirstSyncTask].syncp) 
	{
		sts = m_session.SyncOperation(m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

		m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
		m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
	}

	return sts;
}
mfxStatus IntelDecoder::FlushDecoderAndRender()
{
	mfxStatus sts = MFX_ERR_NONE;
	mfxGetTime(&tStart);

	//
	// Stage 2: Retrieve the buffered decoded frames
	//
	while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts) {
		if (MFX_WRN_DEVICE_BUSY == sts)
			MSDK_SLEEP(1);  // Wait if device is busy, then repeat the same call to DecodeFrameAsync

		nIndex = GetFreeSurfaceIndex(pmfxSurfaces, numSurfaces);        // Find free frame surface
		MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC);

		// Decode a frame asychronously (returns immediately)
		sts = mfxDEC->DecodeFrameAsync(NULL, pmfxSurfaces[nIndex], &pmfxOutSurface, &syncp);

		// Ignore warnings if output is available,
		// if no output and no action required just repeat the DecodeFrameAsync call
		if (MFX_ERR_NONE < sts && syncp)
			sts = MFX_ERR_NONE;

		if (MFX_ERR_NONE == sts)
			sts = pSession->SyncOperation(syncp, 60000);      // Synchronize. Waits until decoded frame is ready

		if (MFX_ERR_NONE == sts) {
			++nFrame;
			if (impl_type == MFX_IMPL_SOFTWARE)
			{
				outMan.Render(pmfxOutSurface);
			}
			else
			{
				// Surface locking required when read/write D3D surfaces
				sts = pMfxAllocator->Lock(pMfxAllocator->pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));
				MSDK_BREAK_ON_ERROR(sts);

				outMan.Render(pmfxOutSurface);

				sts = pMfxAllocator->Unlock(pMfxAllocator->pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));
			}
			
			

			printf("Frame number: %d\r", nFrame);
			fflush(stdout);
		}
	}

	// MFX_ERR_MORE_DATA indicates that all buffers has been fetched, exit in case of other errors
	MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

	mfxGetTime(&tEnd);
	elapsed += TimeDiffMsec(tEnd, tStart) / 1000;
	double fps = ((double)nFrame / elapsed);
	printf("\nExecution time: %3.2f s (%3.2f fps)\n", elapsed, fps);
	return sts;
}
mfxStatus IntelDecoder::RunDecodeAndRender()
{
	mfxStatus sts = MFX_ERR_NONE;

	// ===============================================================
	// Start decoding the frames from the stream
	//
	
	mfxGetTime(&tStart);
	pmfxOutSurface = NULL;
	pmfxOutSurface_sw = NULL;
	nIndex = 0;
	nIndex2 = 0;
	nFrame = 0;

	//
	// Stage 1: Main decoding loop
	//
	while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts) {
		if (MFX_WRN_DEVICE_BUSY == sts)
			MSDK_SLEEP(1);  // Wait if device is busy, then repeat the same call to DecodeFrameAsync

		if (MFX_ERR_MORE_DATA == sts) {
			sts = ReadBitStreamData(&mfxBS, fSource);       // Read more data into input bit stream
			MSDK_BREAK_ON_ERROR(sts);
		}

		if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) {
			nIndex = GetFreeSurfaceIndex(pmfxSurfaces, numSurfaces);        // Find free frame surface
			MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC);
		}
		// Decode a frame asychronously (returns immediately)
		//  - If input bitstream contains multiple frames DecodeFrameAsync will start decoding multiple frames, and remove them from bitstream
		sts = mfxDEC->DecodeFrameAsync(&mfxBS, pmfxSurfaces[nIndex], &pmfxOutSurface, &syncp);

		// Ignore warnings if output is available,
		// if no output and no action required just repeat the DecodeFrameAsync call
		if (MFX_ERR_NONE < sts && syncp)
			sts = MFX_ERR_NONE;

		if (MFX_ERR_NONE == sts)
			sts = pSession->SyncOperation(syncp, 60000);      // Synchronize. Wait until decoded frame is ready

		if (MFX_ERR_NONE == sts) {
			++nFrame;

			if (impl_type == MFX_IMPL_SOFTWARE)
			{
				outMan.Render(pmfxOutSurface);
			}
			else
			{
				 // Surface locking required when read/write video surfaces
				sts = pMfxAllocator->Lock(pMfxAllocator->pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));
				MSDK_BREAK_ON_ERROR(sts);

				outMan.Render(pmfxOutSurface);

				sts = pMfxAllocator->Unlock(pMfxAllocator->pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));
				MSDK_BREAK_ON_ERROR(sts);
			}
			
			printf("Frame number: %d\r", nFrame);
			fflush(stdout);
		}
	}

	// MFX_ERR_MORE_DATA means that file has ended, need to go to buffering loop, exit in case of other errors
	MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

	mfxGetTime(&tEnd);
	elapsed = TimeDiffMsec(tEnd, tStart) / 1000;
	double fps = ((double)nFrame / elapsed);
	printf("\nExecution time: %3.2f s (%3.2f fps)\n", elapsed, fps);

	return sts;
}
mfxStatus QSV_Encoder_Internal::Encode(uint64_t ts, uint8_t *pDataY, uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV, mfxBitstream **pBS)
{
	mfxStatus sts = MFX_ERR_NONE;
	*pBS = NULL;
	int nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);    // Find free input frame surface
	int nTaskIdx = GetFreeTaskIndex(m_pTaskPool, m_nTaskPool);

	if (MFX_ERR_NOT_FOUND == nTaskIdx || MFX_ERR_NOT_FOUND == nSurfIdx)
	{
		// No more free tasks or surfaces, need to sync
		sts = m_session.SyncOperation(m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

		mfxU8 *pTemp = m_outBitstream.Data;
		memcpy(&m_outBitstream, &m_pTaskPool[m_nFirstSyncTask].mfxBS, sizeof(mfxBitstream));

		m_pTaskPool[m_nFirstSyncTask].mfxBS.Data = pTemp;
		m_pTaskPool[m_nFirstSyncTask].mfxBS.DataLength = 0;
		m_pTaskPool[m_nFirstSyncTask].mfxBS.DataOffset = 0;
		m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
		m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
		*pBS = &m_outBitstream;
		if (nTaskIdx == MFX_ERR_NOT_FOUND)
			nTaskIdx = GetFreeTaskIndex(m_pTaskPool, m_nTaskPool);
		if (nSurfIdx == MFX_ERR_NOT_FOUND)
			nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);
	}
	
	mfxFrameSurface1 *pSurface = m_pmfxSurfaces[nSurfIdx];
	sts = m_mfxAllocator.Lock(m_mfxAllocator.pthis, pSurface->Data.MemId, &(pSurface->Data));
	sts = LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV);
	pSurface->Data.TimeStamp = ts;
	sts = m_mfxAllocator.Unlock(m_mfxAllocator.pthis, pSurface->Data.MemId, &(pSurface->Data));
	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

	for (;;) 
	{
		// Encode a frame asychronously (returns immediately)
		sts = m_pmfxENC->EncodeFrameAsync(NULL, pSurface, &m_pTaskPool[nTaskIdx].mfxBS, &m_pTaskPool[nTaskIdx].syncp);

		if (MFX_ERR_NONE < sts && !m_pTaskPool[nTaskIdx].syncp)
		{
			// Repeat the call if warning and no output
			if (MFX_WRN_DEVICE_BUSY == sts)
				MSDK_SLEEP(1);  // Wait if device is busy, then repeat the same call
		}
		else if (MFX_ERR_NONE < sts && m_pTaskPool[nTaskIdx].syncp)
		{
			sts = MFX_ERR_NONE;     // Ignore warnings if output is available
			break;
		}
		else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
			// Allocate more bitstream buffer memory here if needed...
			break;
		}
		else
			break;
	}

	return sts;
}