All pastes #821846 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-12-18 10:56 UTC
rendered paste body
#include "StdAfx.h"

#include "SmartCamFilter.h"

// COM global table of objects in this dll

CFactoryTemplate g_Templates[] = {
	{
		SMART_CAM_FILTER_NAME,
		&CLSID_SmartCam,
		CSmartCamFilter::CreateInstance,
		NULL,
		NULL
	}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

// DllEntryPoint
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD  dwReason,
                      LPVOID lpReserved)
{
	return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

// Exported entry points for registration and unregistration
STDAPI DllRegisterServer()
{
	REGPINTYPES  pinMediaTypes[] = {
		{ &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 }
	};

	REGFILTERPINS2 pinRegInfo = {
		REG_PINFLAG_B_OUTPUT,					// dwFlags
		1,										// cInstances
		1,										// nMediaTypes
		pinMediaTypes,							// lpMediaType
		0,										// nMediums
		NULL,									// lpMedium
		&PIN_CATEGORY_CAPTURE					// clsPinCategory
	};

	REGFILTER2 filterRegInfo = {
		2,										// Version 2 (pin mediums or pin category).
		MERIT_NORMAL,							// Merit.
		{
			1,									// Number of pins.
			(const REGFILTERPINS *)&pinRegInfo	// Pointer to pin information.
		}
	};

    HRESULT hr;
    IFilterMapper2 *pFM2 = NULL;

    hr = AMovieDllRegisterServer2(TRUE);
    if (FAILED(hr))
        return hr;

    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);

    if (FAILED(hr))
        return hr;

    hr = pFM2->RegisterFilter(
					CLSID_SmartCam,							// Filter CLSID.
					SMART_CAM_FILTER_NAME,					// Filter name.
					NULL,									// Device moniker.
					&CLSID_VideoInputDeviceCategory,		// Video capture category.
					SMART_CAM_FILTER_NAME,					// Instance data.
					&filterRegInfo);						// Pointer to filter information.
    pFM2->Release();

    return hr;
}

STDAPI DllUnregisterServer()
{
    HRESULT hr = AMovieDllRegisterServer2(FALSE);
    if (FAILED(hr))
    {
        return hr;
    }
    IFilterMapper2 *pFM2 = NULL;
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);
    if (SUCCEEDED(hr))
    {
        hr = pFM2->UnregisterFilter(&CLSID_VideoInputDeviceCategory,
            SMART_CAM_FILTER_NAME, CLSID_SmartCam);
        pFM2->Release();
    }
    return hr;
}

//
// ------------------ CSmartCamFilter ------------------
//

CUnknown * WINAPI CSmartCamFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
    ASSERT(phr);

    CUnknown *punk = new CSmartCamFilter(lpunk, phr);
    if(punk == NULL)
    {
        if(phr)
            *phr = E_OUTOFMEMORY;
    }
    return punk;

}

STDMETHODIMP CSmartCamFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
    if(riid == IID_ISmartCamWriter)
	{
        return GetInterface(static_cast<ISmartCamWriter*>(this), ppv);
    }
    return CSource::NonDelegatingQueryInterface(riid,ppv);
}

CSmartCamFilter::CSmartCamFilter(LPUNKNOWN lpunk, HRESULT *phr)
	:CSource(NAME("SMARTCAM"), lpunk, CLSID_SmartCam)
{
	DbgOutString("CSmartCamFilter()\n");
    ASSERT(phr);
    CAutoLock cAutoLock(&m_cStateLock);

    m_paStreams = (CSourceStream **) new CSmartCamCapturePin*[1];
    if(m_paStreams == NULL)
    {
        if(phr)
            *phr = E_OUTOFMEMORY;
        return;
    }

    m_paStreams[0] = new CSmartCamCapturePin(phr, this, SMART_CAM_CAPTURE_PIN_NAME);
    if(m_paStreams[0] == NULL)
    {
        if(phr)
            *phr = E_OUTOFMEMORY;
    }
}

// ISmartCamWriter methods
STDMETHODIMP CSmartCamFilter::WriteFrame(char* frameBuffer, int size)
{
	return NOERROR;
}

STDMETHODIMP CSmartCamFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State)
{
	switch(m_State)
	{
		case State_Stopped:
		{
			DbgOutString("CSmartCamFilter::GetState() [crtState = State_Stopped]\n");
			break;
		}
		case State_Paused:
		{
			DbgOutString("CSmartCamFilter::GetState() [crtState = State_Paused]\n");
			break;
		}
		case State_Running:
		{
			DbgOutString("CSmartCamFilter::GetState() [crtState = State_Running]\n");
			break;
		}
	}
    CheckPointer(State, E_POINTER);
    *State = m_State;
    if (m_State == State_Paused)
        return VFW_S_CANT_CUE;
    else
        return S_OK;
}

STDMETHODIMP CSmartCamFilter::SetSyncSource(IReferenceClock* pClock)
{
	DbgOutString("SetSyncSource()\n");
	return CBaseFilter::SetSyncSource(pClock);
}

CSmartCamFilter::~CSmartCamFilter(void)
{
	DbgOutString("~CSmartCamFilter()\n");
}

//
// ------------------ CSmartCamCapturePin ------------------
//

CSmartCamCapturePin::CSmartCamCapturePin(HRESULT *phr, CSmartCamFilter *pParent, LPCWSTR pPinName):
	CSourceStream(NAME("SMARTCAM_CAPTURE_PIN"), phr, pParent, pPinName),
	hFileMapping(NULL),
	pSharedMem(NULL),
	//hNewFrameEvt(NULL),
	isMaster(FALSE),
	frameNumber(0),
	sampleTime((LONG) 0)
{
	DbgOutString("CSmartCamCapturePin()\n");
	Initialize();
}

CSmartCamCapturePin::~CSmartCamCapturePin()
{
	DbgOutString("~CSmartCamCapturePin()\n");
	Cleanup();
}

STDMETHODIMP CSmartCamCapturePin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
    if(riid == IID_IAMPushSource)
	{
        return GetInterface(static_cast<IAMPushSource*>(this), ppv);
    }
    if(riid == IID_IAMStreamConfig)
	{
        return GetInterface(static_cast<IAMStreamConfig*>(this), ppv);
    }
    if(riid == IID_IKsPropertySet)
	{
        return GetInterface(static_cast<IKsPropertySet*>(this), ppv);
    }

    return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
}

// IAMStreamConfig methods

STDMETHODIMP CSmartCamCapturePin::GetFormat(AM_MEDIA_TYPE **ppmt)
{
	DbgOutString("CSmartCamCapturePin::GetFormat()\n");

	VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
	*pVih = SmartCamVideoInfoHeader;
	AM_MEDIA_TYPE * pmt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
	*pmt = SmartCamMediaType;
	pmt->pbFormat = (BYTE*) pVih;
	pmt->cbFormat = sizeof(VIDEOINFOHEADER);
	*ppmt = pmt;

	return NOERROR;
}

STDMETHODIMP CSmartCamCapturePin::GetNumberOfCapabilities(int *piCount, int *piSize)
{
	DbgOutString("CSmartCamCapturePin::GetNumberOfCapabilities()\n");
	*piCount = 1;
	*piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
	return NOERROR;
}

STDMETHODIMP CSmartCamCapturePin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC)
{
	DbgOutString("CSmartCamCapturePin::GetStreamCaps()\n");
	if(iIndex < 0)
		return E_INVALIDARG;
	if(iIndex > 0)
		return S_FALSE;
	if(pSCC == NULL)
		return E_POINTER;

	VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
	*pVih = SmartCamVideoInfoHeader;
	AM_MEDIA_TYPE * pmt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
	*pmt = SmartCamMediaType;
	pmt->pbFormat = (BYTE*) pVih;
	pmt->cbFormat = sizeof(VIDEOINFOHEADER);
	*ppmt = pmt;

	VIDEO_STREAM_CONFIG_CAPS* pVidCap = (VIDEO_STREAM_CONFIG_CAPS*) pSCC;
	*pVidCap = SmartCamVideoCfgCaps;

	return S_OK;
}

STDMETHODIMP CSmartCamCapturePin::SetFormat(AM_MEDIA_TYPE *pmt)
{
	DbgOutString("CSmartCamCapturePin::SetFormat()\n");
    CAutoLock cAutoLock(m_pFilter->pStateLock());

	if(pmt == NULL)
		return E_POINTER;

    // Pass the call up to the base class
	CMediaType MediaType = *pmt;
    return CSourceStream::SetMediaType(&MediaType);
}

// IKsPropertySet methods

STDMETHODIMP CSmartCamCapturePin::Set(
		REFGUID guidPropSet,
		DWORD dwPropID,
		LPVOID pInstanceData,
		DWORD cbInstanceData,
		LPVOID pPropData,
		DWORD cbPropData
		)
{
	DbgOutString("CSmartCamCapturePin::Set()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::Get(
		REFGUID guidPropSet,
		DWORD dwPropID,
		LPVOID pInstanceData,
		DWORD cbInstanceData,
		LPVOID pPropData,
		DWORD cbPropData,
		DWORD *pcbReturned
		)
{
	DbgOutString("CSmartCamCapturePin::Get()\n");
    if (guidPropSet != AMPROPSETID_Pin)
        return E_PROP_SET_UNSUPPORTED;
    if (dwPropID != AMPROPERTY_PIN_CATEGORY)
        return E_PROP_ID_UNSUPPORTED;
    if (pPropData == NULL && pcbReturned == NULL)
        return E_POINTER;
    if (pcbReturned)
        *pcbReturned = sizeof(GUID);
    if (pPropData == NULL)  // Caller just wants to know the size.
	{
		DbgOutString("CSmartCamCapturePin::Get() [ (SIZE QUERY) OK !!! ]\n");
        return S_OK;
	}
    if (cbPropData < sizeof(GUID)) // The buffer is too small.
        return E_UNEXPECTED;
    *(GUID *)pPropData = PIN_CATEGORY_CAPTURE;
	DbgOutString("CSmartCamCapturePin::Get() [ OK !!! ]\n");
    return S_OK;
}

STDMETHODIMP CSmartCamCapturePin::QuerySupported(
		REFGUID guidPropSet,
		DWORD dwPropID,
		DWORD *pTypeSupport
		)
{
	DbgOutString("CSmartCamCapturePin::QuerySupported()\n");
    if (guidPropSet != AMPROPSETID_Pin)
        return E_PROP_SET_UNSUPPORTED;
    if (dwPropID != AMPROPERTY_PIN_CATEGORY)
        return E_PROP_ID_UNSUPPORTED;
    if (pTypeSupport)
        // We support getting this property, but not setting it.
        *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    return S_OK;
}

// IAMPushSource
STDMETHODIMP CSmartCamCapturePin::GetMaxStreamOffset(REFERENCE_TIME *prtMaxOffset)
{
	DbgOutString("CSmartCamCapturePin::GetMaxStreamOffset()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::GetPushSourceFlags(ULONG *pFlags)
{
	DbgOutString("CSmartCamCapturePin::GetPushSourceFlags()\n");
	*pFlags = AM_PUSHSOURCECAPS_INTERNAL_RM;
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::GetStreamOffset(REFERENCE_TIME *prtOffset)
{
	DbgOutString("CSmartCamCapturePin::GetStreamOffset()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::SetMaxStreamOffset(REFERENCE_TIME rtMaxOffset)
{
	DbgOutString("CSmartCamCapturePin::SetMaxStreamOffset()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::SetPushSourceFlags(ULONG Flags)
{
	DbgOutString("CSmartCamCapturePin::SetPushSourceFlags()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::SetStreamOffset(REFERENCE_TIME rtOffset)
{
	DbgOutString("CSmartCamCapturePin::SetStreamOffset()\n");
	return E_NOTIMPL;
}

STDMETHODIMP CSmartCamCapturePin::GetLatency(REFERENCE_TIME *prtLatency)
{
	DbgOutString("CSmartCamCapturePin::GetLatency()\n");
	return E_NOTIMPL;
}

// CBasePin methods
HRESULT CSmartCamCapturePin::SetMediaType(const CMediaType *pMediaType)
{
	DbgOutString("CSmartCamCapturePin::SetMediaType()\n");
    CAutoLock cAutoLock(m_pFilter->pStateLock());

    // Pass the call up to the base class
    return CSourceStream::SetMediaType(pMediaType);
}

HRESULT CSmartCamCapturePin::GetMediaType(int iPosition, CMediaType* pMediaType)
{
	DbgLog((LOG_ERROR, 0, TEXT("CSmartCamCapturePin::GetMediaType( iPosition = %d )\n"), iPosition));
    CheckPointer(pMediaType,E_POINTER);

    CAutoLock cAutoLock(m_pFilter->pStateLock());
    if(iPosition < 0)
    {
        return E_INVALIDARG;
    }
    // Have we run off the end of types?
    if(iPosition > 0)
    {
        return VFW_S_NO_MORE_ITEMS;
    }

	*pMediaType = SmartCamMediaType;
    VIDEOINFOHEADER* pVih =
		(VIDEOINFOHEADER*) pMediaType->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
    if(pVih == NULL)
	{
		DbgOutString("CSmartCamCapturePin::GetMediaType(iPosition) - Format allocation failed !\n");
        return(E_OUTOFMEMORY);
	}
	*pVih = SmartCamVideoInfoHeader;

	DbgOutString("CSmartCamCapturePin::GetMediaType(iPosition) - OK! -\n");
	return NOERROR;
}

HRESULT CSmartCamCapturePin::GetMediaType(CMediaType *pMediaType)
{
	DbgOutString("CSmartCamCapturePin::GetMediaType()\n");
	return GetMediaType(0, pMediaType);
}

HRESULT CSmartCamCapturePin::CheckMediaType(const CMediaType *pMediaType)
{
	DbgOutString("CSmartCamCapturePin::CheckMediaType()\n");
    CheckPointer(pMediaType,E_POINTER);

	const GUID* Type = pMediaType->Type();
    if (Type == NULL)
        return E_INVALIDARG;
    if((*Type != MEDIATYPE_Video) ||		// we only output video
       !(pMediaType->IsFixedSize()))		// in fixed size samples
    {
        return E_INVALIDARG;
    }

    // Check for the RGB24 subtype we support
    const GUID* SubType = pMediaType->Subtype();
    if (SubType == NULL)
        return E_INVALIDARG;
    if(*SubType != MEDIASUBTYPE_RGB24)
    {
        return E_INVALIDARG;
    }

    // Get the format area of the media type
    VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) pMediaType->Format();
    if(pVih == NULL)
        return E_INVALIDARG;

    // Check the image size
    if((pVih->bmiHeader.biWidth > FRAME_WIDTH) || (abs(pVih->bmiHeader.biHeight) > FRAME_HEIGHT) ||
	   (pVih->bmiHeader.biSizeImage != GetBitmapSize(&pVih->bmiHeader)))
    {
        return E_INVALIDARG;
    }

	// Check the color depth and compression
	if((pVih->bmiHeader.biBitCount != 24) || (pVih->bmiHeader.biCompression != BI_RGB))
    {
        return E_INVALIDARG;
    }

	DbgOutString("CSmartCamCapturePin::CheckMediaType() - OK! -\n");
    return S_OK;  // This format is acceptable.
}

HRESULT CSmartCamCapturePin::FillBuffer(IMediaSample *pMediaSample)
{
	DbgOutString("CSmartCamCapturePin::FillBuffer()\n");
	CAutoLock cAutoLock(m_pFilter->pStateLock());
    CheckPointer(pMediaSample, E_POINTER);

	DWORD crtFrameNumber = *((DWORD*) pSharedMem);
	if(crtFrameNumber == SC_END_OF_STREAM)
		return S_FALSE;

	BYTE* pData = NULL;
    pMediaSample->GetPointer(&pData);
    long lDataLen = pMediaSample->GetSize();
	BYTE* pSharedFrame = (BYTE*) pSharedMem + FRAME_NUMBER_SIZE;
	RtlCopyMemory(pData, pSharedFrame, lDataLen);

	CRefTime rtStart = sampleTime;
	sampleTime += CRefTime(MILLISECONDS_TO_100NS_UNITS(AVG_FRAME_TIME_MS));

	pMediaSample->SetTime((REFERENCE_TIME *)&rtStart, (REFERENCE_TIME *)&sampleTime);
	Sleep(AVG_FRAME_TIME_MS);
	return S_OK;
}

HRESULT CSmartCamCapturePin::DecideBufferSize(
	IMemAllocator *pIMemAlloc,
    ALLOCATOR_PROPERTIES *pProperties)
{
	DbgOutString("CSmartCamCapturePin::DecideBufferSize()\n");

    CheckPointer(pIMemAlloc, E_POINTER);
    CheckPointer(pProperties, E_POINTER);

    CAutoLock cAutoLock(m_pFilter->pStateLock());
    HRESULT hr = NOERROR;

    VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) m_mt.Format();
    pProperties->cBuffers = 1;
    pProperties->cbBuffer = pVih->bmiHeader.biSizeImage;

    ASSERT(pProperties->cbBuffer);

    // Ask the allocator to reserve us some sample memory, NOTE the function
    // can succeed (that is return NOERROR) but still not have allocated the
    // memory that we requested, so we must check we got whatever we wanted

    ALLOCATOR_PROPERTIES Actual;
    hr = pIMemAlloc->SetProperties(pProperties,&Actual);
    if(FAILED(hr))
    {
        return hr;
    }

    // Is this allocator unsuitable

    if(Actual.cbBuffer < pProperties->cbBuffer)
    {
        return E_FAIL;
    }

    // Make sure that we have only 1 buffer (we erase the ball in the
    // old buffer to save having to zero a 200k+ buffer every time
    // we draw a frame)

    ASSERT(Actual.cBuffers == 1);
	DbgOutString("CSmartCamCapturePin::DecideBufferSize() - OK! -\n");
    return NOERROR;
}

HRESULT CSmartCamCapturePin::OnThreadCreate()
{
	DbgOutString("CSmartCamCapturePin::OnThreadCreate()\n");
	return CSourceStream::OnThreadCreate();
}

HRESULT CSmartCamCapturePin::OnThreadDestroy()
{
	DbgOutString("CSmartCamCapturePin::OnThreadDestroy()\n");
	return NOERROR;
}

STDMETHODIMP CSmartCamCapturePin::Notify(IBaseFilter * pSelf , Quality  q)
{
	return E_NOTIMPL;
	//return CSourceStream::Notify(pSelf, q);
}

STDMETHODIMP CSmartCamCapturePin::SetSink(IQualityControl * piqc)
{
	return E_NOTIMPL;
	//return CSourceStream::SetSink(piqc);
}


HRESULT CSmartCamCapturePin::Initialize()
{
	Util::CreateSharedMem(&hFileMapping, &pSharedMem);
	//Util::CreateOpenNewFrameEvt(&hNewFrameEvt);

	char procFullFileName[MAX_PROC_FILE_NAME], dllFullFileName[MAX_PROC_FILE_NAME];
	GetModuleFileName(GetModuleHandle(SMART_CAM_FILTER_FILE_NAME), dllFullFileName, MAX_PROC_FILE_NAME);
	GetModuleFileName(NULL, procFullFileName, MAX_PROC_FILE_NAME);
	string installDir, procDir, procFileName;
	Util::ParseFileName(dllFullFileName, &installDir, NULL);
	Util::ParseFileName(procFullFileName, &procDir, &procFileName);

	isMaster = (procDir == installDir) && (procFileName == MASTER_APP_FILE_NAME);
	if(!isMaster)
	{
		HWND hMasterWnd = FindWindow(SMARTCAM_CLASSNAME, SMARTCAM_CAPTION);
		if(hMasterWnd == NULL)
		{
			string masterAppFullFileName = installDir + MASTER_APP_FILE_NAME;
			STARTUPINFO si;
			ZeroMemory(&si, sizeof(STARTUPINFO));
			si.dwFlags = STARTF_USESHOWWINDOW;
			si.wShowWindow = SW_MINIMIZE;
			PROCESS_INFORMATION pi;
			CreateProcess(masterAppFullFileName.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
		}
	}
	return S_OK;
}

void CSmartCamCapturePin::Cleanup()
{
	// Close the shared memory
	// Unmap shared memory from the process's address space.
	UnmapViewOfFile(pSharedMem);
	// Close the process's handle to the file-mapping object.
	CloseHandle(hFileMapping);
	// Close the handle to the synchronization event object
	//CloseHandle(hNewFrameEvt);
}


void CSmartCamCapturePin::GetVideoInfoParameters(
    const VIDEOINFOHEADER *pvih, // Pointer to the format header
    BYTE  * const pbData,        // Pointer to first address in buffer
    DWORD *pdwWidth,         // Returns the width in pixels
    DWORD *pdwHeight,        // Returns the height in pixels
    LONG  *plStrideInBytes,  // Add this to a row to get the new row down
    BYTE **ppbTop,           // Pointer to first byte in top row of pixels
    bool bYuv
    )
{
    LONG lStride;

    //  For 'normal' formats, biWidth is in pixels. 
    //  Expand to bytes and round up to a multiple of 4.
    if (pvih->bmiHeader.biBitCount != 0 &&
        0 == (7 & pvih->bmiHeader.biBitCount)) 
    {
        lStride = (pvih->bmiHeader.biWidth * 
            (pvih->bmiHeader.biBitCount / 8) + 3) & ~3;
    } 
    else   // Otherwise, biWidth is in bytes.
    {
        lStride = pvih->bmiHeader.biWidth;
    }

    //  If rcTarget is empty, use the whole image.
    if (IsRectEmpty(&pvih->rcTarget)) 
    {
        *pdwWidth = (DWORD)pvih->bmiHeader.biWidth;
        *pdwHeight = (DWORD)(abs(pvih->bmiHeader.biHeight));
        
        if (pvih->bmiHeader.biHeight < 0 || bYuv)   // Top-down bitmap
        {
            *plStrideInBytes = lStride; // Stride goes "down"
            *ppbTop           = pbData; // Top row is first
        } 
        else  // Bottom-up bitmap
        {
            *plStrideInBytes = -lStride;    // Stride goes "up"
            *ppbTop = pbData + lStride * 
                (*pdwHeight - 1);  // Bottom row is first
        }
    } 
    else   // rcTarget is NOT empty. Use a sub-rectangle in the image.
    {
        *pdwWidth = (DWORD)(pvih->rcTarget.right - pvih->rcTarget.left);
        *pdwHeight = (DWORD)(pvih->rcTarget.bottom - pvih->rcTarget.top);
        
        if (pvih->bmiHeader.biHeight < 0 || bYuv)   // Top-down bitmap
        {
            // Same stride as above, but first pixel is modified down
            // and over by the target rectangle.
            *plStrideInBytes = lStride;
            *ppbTop = pbData +
                     lStride * pvih->rcTarget.top +
                     (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
        } 
        else  // Bottom-up bitmap
        {
            *plStrideInBytes = -lStride;
            *ppbTop = pbData +
                     lStride * (pvih->bmiHeader.biHeight - 
                     pvih->rcTarget.top - 1) +
                     (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
        }
    }
}