2025-11-28 00:35:46 +09:00

1087 lines
29 KiB
C++

#include "CHWMFT.h"
#include "CHWMFT_DecodeTask.h"
#include "CAutoLock.h"
#include <mfapi.h>
#include <mferror.h>
#include "CHWMFT_DebugLogger.h"
#include <initguid.h>
// {1F620607-A7FF-4B94-82F4-993F2E17B497}
DEFINE_GUID(MYMFT_MFSampleExtension_Marker,
0x1f620607, 0xa7ff, 0x4b94, 0x82, 0xf4, 0x99, 0x3f, 0x2e, 0x17, 0xb4, 0x97);
// Helper Macros
#define SAFERELEASE(x) \
if((x) != NULL) \
{ \
(x)->Release(); \
(x) = NULL; \
} \
#define MFT_NUM_DEFAULT_ATTRIBUTES 4
#define MFT_HW_URL L"MSFT Win8 SDK HW MFT Sample"
// Global Variables
const GUID* g_ppguidInputTypes[] =
{
&MFVideoFormat_H264,
&MFVideoFormat_MPEG2,
&MFVideoFormat_WVC1,
&MFVideoFormat_MP4V,
};
const DWORD g_dwNumInputTypes = sizeof(g_ppguidInputTypes) / sizeof(g_ppguidInputTypes[0]);
const GUID* g_ppguidOutputTypes[] =
{
&MFVideoFormat_RGB32,
&MFVideoFormat_NV12,
};
const DWORD g_dwNumOutputTypes = sizeof(g_ppguidOutputTypes) / sizeof(g_ppguidOutputTypes[0]);
// Initializer
HRESULT CHWMFT::CreateInstance(IMFTransform** ppHWMFT)
{
HRESULT hr = S_OK;
CHWMFT* pMyHWMFT = NULL;
do
{
if(ppHWMFT == NULL)
{
hr = E_POINTER;
break;
}
pMyHWMFT = new CHWMFT();
if(FAILED(hr))
{
break;
}
hr = pMyHWMFT->InitializeTransform();
if(FAILED(hr))
{
break;
}
hr = pMyHWMFT->QueryInterface(IID_IMFTransform, (void**)ppHWMFT);
if(FAILED(hr))
{
break;
}
}while(false);
SAFERELEASE(pMyHWMFT);
return hr;
}
/****************************
********** ***********
****************************/
CHWMFT::CHWMFT(void)
{
/****************************************************
** Todo: Initialize All Member variables used by your
** MFT
****************************************************/
// Do no insert anything before this call, this is the DLLs object count
InterlockedIncrement(&m_ulNumObjects);
if(InterlockedCompareExchange(&m_ulNumObjects, 1, 1) == 1)
{
// we're the first object, turn on tracing
TraceInitialize();
}
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
m_ulRef = 1;
m_ulSampleCounter = 0;
m_pInputMT = NULL;
m_pOutputMT = NULL;
m_pAttributes = NULL;
m_pEventQueue = NULL;
m_dwStatus = 0;
m_dwNeedInputCount = 0;
m_dwHaveOutputCount = 0;
m_dwDecodeWorkQueueID = 0;
m_llCurrentSampleTime = 0;
m_bShutdown = FALSE;
m_bFirstSample = TRUE;
m_bDXVA = FALSE;
m_pInputSampleQueue = NULL;
m_pOutputSampleQueue = NULL;
InitializeCriticalSection(&m_csLock);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit", __FUNCTION__);
}
CHWMFT::~CHWMFT(void)
{
/****************************************************
** Todo: Release All Member variables used by your
** MFT
****************************************************/
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
SAFERELEASE(m_pInputMT);
SAFERELEASE(m_pOutputMT);
SAFERELEASE(m_pAttributes);
if(m_pEventQueue != NULL)
{
m_pEventQueue->Shutdown();
SAFERELEASE(m_pEventQueue);
}
SAFERELEASE(m_pInputSampleQueue);
SAFERELEASE(m_pOutputSampleQueue);
DeleteCriticalSection(&m_csLock);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit", __FUNCTION__);
if(InterlockedCompareExchange(&m_ulNumObjects, 1, 1) == 1)
{
// We're the last instance, turn off tracing
TraceUninitialize();
}
InterlockedDecrement(&m_ulNumObjects);
// Do no insert anything after this call, this is the DLLs object count
}
HRESULT CHWMFT::InitializeTransform(void)
{
/*************************************
** Todo: Use this function to setup
** anything that can't be setup in
** the constructor
*************************************/
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
hr = MFCreateAttributes(&m_pAttributes, MFT_NUM_DEFAULT_ATTRIBUTES);
if(FAILED(hr))
{
break;
}
/*********************************
** Certain Attributes are required
** for HW MFTs
** See http://msdn.microsoft.com/en-us/library/dd940330(VS.85).aspx#attributes
*********************************/
hr = m_pAttributes->SetUINT32(MF_TRANSFORM_ASYNC, TRUE);
if(FAILED(hr))
{
break;
}
/****************************************
** !!MSFT_TODO: Report as HW MFT
****************************************
hr = m_pAttributes->SetString(MFT_ENUM_HARDWARE_URL_Attribute, MFT_HW_URL);
if(FAILED(hr))
{
break;
}
hr = m_pAttributes->SetString(MFT_ENUM_HARDWARE_VENDOR_ID_Attribut, MFT_HW_VENDOR_ID);
if(FAILED(hr))
{
break;
}
*/
hr = m_pAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE);
if(FAILED(hr))
{
break;
}
/**********************************
** Since this is an Async MFT, an
** event queue is required
** MF Provides a standard implementation
**********************************/
hr = MFCreateEventQueue(&m_pEventQueue);
if(FAILED(hr))
{
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to create MF Event Queue (hr=0x%x)", __FUNCTION__, hr);
break;
}
hr = CSampleQueue::Create(&m_pInputSampleQueue);
if(FAILED(hr))
{
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to create Input Sample Queue (hr=0x%x)", __FUNCTION__, hr);
break;
}
hr = CSampleQueue::Create(&m_pOutputSampleQueue);
if(FAILED(hr))
{
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to create Output Sample Queue (hr=0x%x)", __FUNCTION__, hr);
break;
}
/**********************************
** Since this is an Async MFT, all
** work will be done using standard
** MF Work Queues
**********************************/
hr = MFAllocateWorkQueueEx(MF_STANDARD_WORKQUEUE, &m_dwDecodeWorkQueueID);
if(FAILED(hr))
{
break;
}
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit (hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::CheckInputType(
IMFMediaType* pMT)
{
/*************************************
** Todo: Your MFT should verify the
** Input media type is acceptable
** Modify this function as necessary
*************************************/
HRESULT hr = S_OK;
GUID guid = GUID_NULL;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
/******************************
** No need to verify pMT != NULL
** as this is a private function
******************************/
hr = pMT->GetGUID(MF_MT_MAJOR_TYPE, &guid);
if(FAILED(hr))
{
break;
}
if(guid != MFMediaType_Video)
{
hr = MF_E_INVALIDMEDIATYPE;
break;
}
hr = pMT->GetGUID(MF_MT_SUBTYPE, &guid);
if(FAILED(hr))
{
break;
}
hr = MF_E_INVALIDMEDIATYPE; // Gets set to S_OK if MT is acceptable
for(DWORD i = 0; i < g_dwNumInputTypes; i++)
{
if(guid == *(g_ppguidInputTypes[i]))
{
hr = S_OK;
break;
}
}
if(FAILED(hr))
{
break;
}
// The Mediatype is acceptable
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::CheckOutputType(
IMFMediaType* pMT)
{
/*************************************
** Todo: Your MFT should verify the
** Output media type is acceptable
** Modify this function as necessary
*************************************/
HRESULT hr = S_OK;
GUID guid = GUID_NULL;
UINT32 un32HighWord = 0;
UINT32 un32LowWord = 0;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
/******************************
** No need to verify pMT != NULL
** as this is a private function
******************************/
hr = pMT->GetGUID(MF_MT_MAJOR_TYPE, &guid);
if(FAILED(hr))
{
break;
}
if(guid != MFMediaType_Video)
{
hr = MF_E_INVALIDMEDIATYPE;
break;
}
hr = pMT->GetGUID(MF_MT_SUBTYPE, &guid);
if(FAILED(hr))
{
break;
}
hr = MF_E_INVALIDMEDIATYPE; // Gets set to S_OK if MT is acceptable
for(DWORD i = 0; i < g_dwNumOutputTypes; i++)
{
if(guid == *(g_ppguidOutputTypes[i]))
{
hr = S_OK;
break;
}
}
if(FAILED(hr))
{
break;
}
hr = MFGetAttributeSize(pMT, MF_MT_FRAME_SIZE, &un32HighWord, &un32LowWord);
if(FAILED(hr))
{
break;
}
if((un32HighWord != MFT_OUTPUT_WIDTH) || (un32LowWord != MFT_OUTPUT_HEIGHT))
{
hr = MF_E_INVALIDMEDIATYPE;
break;
}
hr = MFGetAttributeRatio(pMT, MF_MT_FRAME_RATE, &un32HighWord, &un32LowWord);
if(FAILED(hr))
{
break;
}
if((un32HighWord != MFT_FRAMERATE_NUMERATOR) || (un32LowWord != MFT_FRAMERATE_DENOMINATOR))
{
hr = MF_E_INVALIDMEDIATYPE;
break;
}
// The Mediatype is acceptable
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::ShutdownEventQueue(void)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
/***************************************
** Since this in an internal function
** we know m_pEventQueue can never be
** NULL due to InitializeTransform()
***************************************/
hr = m_pEventQueue->Shutdown();
if(FAILED(hr))
{
break;
}
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::OnStartOfStream(void)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
{
CAutoLock lock(&m_csLock);
m_dwStatus |= MYMFT_STATUS_STREAM_STARTED;
}
/*******************************
** Todo: This MFT only has one
** input stream, so RequestSample
** is always called with '0'. If
** your MFT has more than one
** input stream, you will
** have to change this logic
*******************************/
hr = RequestSample(0);
if(FAILED(hr))
{
break;
}
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::OnEndOfStream(void)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
CAutoLock lock(&m_csLock);
m_dwStatus &= (~MYMFT_STATUS_STREAM_STARTED);
/*****************************************
** See http://msdn.microsoft.com/en-us/library/dd317909(VS.85).aspx#processinput
** Upon receiving EOS, the outstanding process
** input request should be reset to 0
*****************************************/
m_dwNeedInputCount = 0;
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::OnDrain(
const UINT32 un32StreamID)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
CAutoLock lock(&m_csLock);
m_dwStatus |= (MYMFT_STATUS_DRAINING);
/*******************************
** Todo: This MFT only has one
** input stream, so it does not
** track the stream being drained.
** If your MFT has more than one
** input stream, you will
** have to change this logic
*******************************/
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::OnFlush(void)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
CAutoLock lock(&m_csLock);
m_dwStatus &= (~MYMFT_STATUS_STREAM_STARTED);
hr = FlushSamples();
if(FAILED(hr))
{
break;
}
m_llCurrentSampleTime = 0; // Reset our sample time to 0 on a flush
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::OnMarker(
const ULONG_PTR pulID)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
// No need to lock, our sample queue is thread safe
/***************************************
** Since this in an internal function
** we know m_pInputSampleQueue can never be
** NULL due to InitializeTransform()
***************************************/
hr = m_pInputSampleQueue->MarkerNextSample(pulID);
if(FAILED(hr))
{
break;
}
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::RequestSample(
const UINT32 un32StreamID)
{
HRESULT hr = S_OK;
IMFMediaEvent* pEvent = NULL;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
{
CAutoLock lock(&m_csLock);
if((m_dwStatus & MYMFT_STATUS_STREAM_STARTED) == 0)
{
// Stream hasn't started
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Stream Hasn't Started", __FUNCTION__);
hr = MF_E_NOTACCEPTING;
break;
}
}
hr = MFCreateMediaEvent(METransformNeedInput, GUID_NULL, S_OK, NULL, &pEvent);
if(FAILED(hr))
{
break;
}
hr = pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, un32StreamID);
if(FAILED(hr))
{
break;
}
/***************************************
** Since this in an internal function
** we know m_pEventQueue can never be
** NULL due to InitializeTransform()
***************************************/
{
CAutoLock lock(&m_csLock);
hr = m_pEventQueue->QueueEvent(pEvent);
if(FAILED(hr))
{
break;
}
m_dwNeedInputCount++;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): NeedInputCount: %u", __FUNCTION__, m_dwNeedInputCount);
}
}while(false);
SAFERELEASE(pEvent);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::FlushSamples(void)
{
HRESULT hr = S_OK;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
CAutoLock lock(&m_csLock);
hr = OnEndOfStream(); // Treat this like an end of stream, don't accept new samples until
if(FAILED(hr)) // a new stream is started
{
break;
}
m_dwHaveOutputCount = 0; // Don't Output samples until new input samples are given
hr = m_pInputSampleQueue->RemoveAllSamples();
if(FAILED(hr))
{
break;
}
hr = m_pOutputSampleQueue->RemoveAllSamples();
if(FAILED(hr))
{
break;
}
m_bFirstSample = TRUE; // Be sure to reset our first sample so we know to set discontinuity
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::ScheduleFrameDecode(void)
{
HRESULT hr = S_OK;
IMFSample* pInputSample = NULL;
CDecodeTask* pDecodeTask = NULL;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
// No need to lock, sample queues are thread safe
/***************************************
** Since this in an internal function
** we know m_pInputSampleQueue can never be
** NULL due to InitializeTransform()
***************************************/
hr = m_pInputSampleQueue->GetNextSample(&pInputSample);
if(FAILED(hr))
{
break;
}
hr = CDecodeTask::Create(
m_dwDecodeWorkQueueID,
pInputSample,
(IMFAsyncCallback**)&pDecodeTask);
if(FAILED(hr))
{
break;
}
hr = pDecodeTask->Begin(this);
if(FAILED(hr))
{
break;
}
}while(false);
SAFERELEASE(pInputSample);
SAFERELEASE(pDecodeTask);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
HRESULT CHWMFT::DecodeInputFrame(
IMFSample* pInputSample)
{
HRESULT hr = S_OK;
IMFSample* pOutputSample = NULL;
IMFMediaBuffer* pMediaBuffer = NULL;
IMFMediaEvent* pHaveOutputEvent = NULL;
DWORD dwCurrentSample = 0;
DWORD dwDataLen = 0;
BYTE* pbData = NULL;
UINT64 pun64MarkerID = 0;
LONGLONG llSampleDuration = MFT_DEFAULT_SAMPLE_DURATION;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
/****************************************
** Todo, here's where the MFT transforms
** the input to output samples. In the
** SDK sample, the output is simply a
** numbered frame, so no complicated
** processing is done here. Your MFT
** should reference it's input and output
** types to ensure it does the right thing
** here and modify this function accordingly
** Addionally, your MFT must monitor for
** format changes and act accordly
** See http://msdn.microsoft.com/en-us/library/ee663587(VS.85).aspx
****************************************/
dwCurrentSample = InterlockedIncrement(&m_ulSampleCounter);
hr = MFCreateSample(&pOutputSample);
if(FAILED(hr))
{
break;
}
if(m_bDXVA != FALSE) // Not thread safe!
{
/****************************************
** !!MSFT_TODO: handle dxva!
****************************************/
//MessageBox(NULL, L"TODO: Make MFT Handle DXVA!", L"ERROR!", MB_OK);
hr = E_NOTIMPL;
break;
}
else
{
dwDataLen = (MFT_OUTPUT_WIDTH * MFT_OUTPUT_HEIGHT) * 4; // This is the max needed for the
// biggest supported output type
hr = MFCreateMemoryBuffer(dwDataLen, &pMediaBuffer);
if(FAILED(hr))
{
break;
}
hr = pMediaBuffer->Lock(&pbData, NULL, NULL);
if(FAILED(hr))
{
break;
}
hr = pMediaBuffer->SetCurrentLength(dwDataLen);
if(FAILED(hr))
{
break;
}
hr = pOutputSample->AddBuffer(pMediaBuffer);
if(FAILED(hr))
{
break;
}
}
unsigned char pucColors[10] = {
0,
25,
50,
75,
100,
125,
150,
175,
200,
225
};
memset(pbData, pucColors[dwCurrentSample % 10], dwDataLen); // Fill our buffer with a color correlated to the frame number
// This will show our frames changing
// Now setup the sample
hr = DuplicateAttributes(pOutputSample, pInputSample);
if(FAILED(hr))
{
break;
}
hr = pOutputSample->SetSampleDuration(llSampleDuration);
if(FAILED(hr))
{
break;
}
{
CAutoLock lock(&m_csLock);
LONGLONG llSampleTime = 0;
if(FAILED(pInputSample->GetSampleTime(&llSampleTime)))
{
llSampleTime = m_llCurrentSampleTime;
m_llCurrentSampleTime += llSampleDuration;
}
hr = pOutputSample->SetSampleTime(llSampleTime);
if(FAILED(hr))
{
break;
}
if(m_bFirstSample != FALSE)
{
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Sample @%p is discontinuity", __FUNCTION__, pOutputSample);
hr = pOutputSample->SetUINT32(MFSampleExtension_Discontinuity, TRUE);
if(FAILED(hr))
{
break;
}
m_bFirstSample = FALSE;
}
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Output Sample @%p Created: Duration %I64u, Sample Time %I64d",
__FUNCTION__, pOutputSample, llSampleDuration, m_llCurrentSampleTime);
}
/***************************************
** Since this in an internal function
** we know m_pOutputSampleQueue can never be
** NULL due to InitializeTransform()
***************************************/
hr = m_pOutputSampleQueue->AddSample(pOutputSample);
if(FAILED(hr))
{
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to add sample to output queue (hr=0x%x)", __FUNCTION__, hr);
break;
}
// Now that the sample is in the output queue, send out have output event
hr = MFCreateMediaEvent(METransformHaveOutput, GUID_NULL, S_OK, NULL, &pHaveOutputEvent);
if(FAILED(hr))
{
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to create METransformHaveOutput event (hr=0x%x)", __FUNCTION__, hr);
break;
}
{
CAutoLock lock(&m_csLock);
/***************************************
** Since this in an internal function
** we know m_pEventQueue can never be
** NULL due to InitializeTransform()
***************************************/
hr = m_pEventQueue->QueueEvent(pHaveOutputEvent);
if(FAILED(hr))
{
// If this fails, consider decrementing m_dwHaveOutputCount
TraceString(CHMFTTracing::TRACE_ERROR, L"%S(): Failed to queue METransformHaveOutput event (hr=0x%x)", __FUNCTION__, hr);
break;
}
m_dwHaveOutputCount++;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): HaveOutputCount: %u", __FUNCTION__, m_dwHaveOutputCount);
m_dwStatus |= MYMFT_STATUS_OUTPUT_SAMPLE_READY;
}
if(pInputSample->GetUINT64(MYMFT_MFSampleExtension_Marker, &pun64MarkerID) == S_OK)
{
// This input sample flagged a marker
IMFMediaEvent* pMarkerEvent = NULL;
do
{
hr = MFCreateMediaEvent(METransformMarker, GUID_NULL, S_OK, NULL, &pMarkerEvent);
if(FAILED(hr))
{
break;
}
hr = pMarkerEvent->SetUINT64(MF_EVENT_MFT_CONTEXT, pun64MarkerID);
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(pMarkerEvent);
if(FAILED(hr))
{
break;
}
}while(false);
SAFERELEASE(pMarkerEvent);
if(FAILED(hr))
{
break;
}
}
// Done processing this sample, request another
/*******************************
** Todo: This MFT only has one
** input stream, so RequestSample
** is always called with '0'. If
** your MFT has more than one
** input stream, you will
** have to change this logic
*******************************/
hr = RequestSample(0);
if(FAILED(hr))
{
break;
}
}while(false);
if(pMediaBuffer != NULL)
{
if(pbData != NULL)
{
pMediaBuffer->Unlock();
}
pMediaBuffer->Release();
}
SAFERELEASE(pOutputSample);
SAFERELEASE(pHaveOutputEvent);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}
BOOL CHWMFT::IsLocked(void)
{
/***************************************
** Since this in an internal function
** we know m_pAttributes can never be
** NULL due to InitializeTransform()
***************************************/
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
BOOL bUnlocked = MFGetAttributeUINT32(m_pAttributes,
MF_TRANSFORM_ASYNC_UNLOCK,
FALSE
);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(%s)", __FUNCTION__, (bUnlocked != FALSE) ? L"False" : L"True");
return (bUnlocked != FALSE) ? FALSE : TRUE;
}
BOOL CHWMFT::IsMFTReady(void)
{
/*******************************
** The purpose of this function
** is to ensure that the MFT is
** ready for processing
*******************************/
BOOL bReady = FALSE;
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
CAutoLock lock(&m_csLock);
m_dwStatus &= (~MYMFT_STATUS_INPUT_ACCEPT_DATA);
if(m_pInputMT == NULL)
{
// The Input type is not set
break;
}
if(m_pOutputMT == NULL)
{
// The output type is not set
break;
}
m_dwStatus |= MYMFT_STATUS_INPUT_ACCEPT_DATA; // The MFT is ready for data
bReady = TRUE;
}while(false);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(%s)", __FUNCTION__, bReady ? L"True" : L"False");
return bReady;
}
HRESULT DuplicateAttributes(
IMFAttributes* pDest,
IMFAttributes* pSource)
{
HRESULT hr = S_OK;
GUID guidKey = GUID_NULL;
PROPVARIANT pv = {0};
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Enter", __FUNCTION__);
do
{
if((pDest == NULL) || (pSource == NULL))
{
hr = E_POINTER;
break;
}
PropVariantInit(&pv);
for(UINT32 un32Index = 0; true; un32Index++)
{
PropVariantClear(&pv);
PropVariantInit(&pv);
hr = pSource->GetItemByIndex(un32Index, &guidKey, &pv);
if(FAILED(hr))
{
if(hr == E_INVALIDARG)
{
// all items copied
hr = S_OK;
}
break;
}
hr = pDest->SetItem(guidKey, pv);
if(FAILED(hr))
{
break;
}
}
}while(false);
PropVariantClear(&pv);
TraceString(CHMFTTracing::TRACE_INFORMATION, L"%S(): Exit(hr=0x%x)", __FUNCTION__, hr);
return hr;
}