www.pudn.com > colortracker.rar > MPColorTrackerFilter.cpp


//==========================================================================; 
//  MPColorTrackerFilter 
//  This is intended to be a very fast face tracker.  
//  It is based on very primitive color, shape and motion information. 
//  This allows it to do its job very fast. However it will get confused 
//  by things that look like a flesh-colored blob and move. 
//  In applications the system should be complemented by a 
//  template/feature based face detection module  
// 
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  Original version developed by Boris E. Shpungin at UCSD's Machine Perception Lab 
//  Under the supersvision of Javier R. Movellan 
//  Copyright (c) Machine Perception Laboratory, UCSD 
//  Licensed under the GNU GPL agreement  
//--------------------------------------------------------------------------; 
 
//#include  
#include  
#include  
#if (1100 > _MSC_VER) 
#include  
#else 
#include  
#endif 
#include "DirectShow/MPUFilter_uids.h" 
#include "iMPColorTrackerFilter.h" 
//#include "MPColorTrackerFilter_prop.h" 
#include "MPColorTrackerFilter.h" 
#include "resource.h" 
#include  
 
// ================================================================ 
 
// Setup information 
const AMOVIESETUP_MEDIATYPE sudPinTypes = 
{ 
	&MEDIATYPE_Video,      // Major type 
		&MEDIASUBTYPE_NULL      // Minor type 
}; 
 
// ================================================================ 
 
const AMOVIESETUP_PIN sudpPins[] = 
{ 
	{ L"Input",            // Pins string name 
		FALSE,                // Is it rendered 
		FALSE,                // Is it an output 
		FALSE,                // Are we allowed none 
		FALSE,                // And allowed many 
		&CLSID_NULL,          // Connects to filter 
		NULL,                // Connects to pin 
		1,                    // Number of types 
		&sudPinTypes          // Pin information   
	}, 
	{ L"Output",            // Pins string name 
	FALSE,                // Is it rendered 
	TRUE,                // Is it an output 
	FALSE,                // Are we allowed none 
	FALSE,                // And allowed many 
	&CLSID_NULL,          // Connects to filter 
	NULL,                // Connects to pin 
	1,                    // Number of types 
	&sudPinTypes          // Pin information 
	} 
}; 
 
// ================================================================ 
 
const AMOVIESETUP_FILTER sudMPColorTrackerFilter = 
{ 
	&CLSID_MPColorTrackerFilter, // Filter CLSID 
		L"MPColorTrackerFilter",      // String name 
		MERIT_DO_NOT_USE,      // Filter merit 
		2,                      // Number of pins 
		sudpPins                // Pin information 
}; 
 
// ================================================================ 
 
// List of class IDs and creator functions for the class factory. This 
// provides the link between the OLE entry point in the DLL and an object 
// being created. The class factory will call the static CreateInstance 
CFactoryTemplate g_Templates[] = { 
	{ L"MPLab Color Tracker Filter" 
		, &CLSID_MPColorTrackerFilter 
		, MPColorTrackerFilter::CreateInstance 
		, NULL 
		, &sudMPColorTrackerFilter }, 
//	{ L"MPLab Color Tracker Fiter Properties" 
//	, &CLSID_MPColorTrackerFilterPropertyPage } 
}; 
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); 
 
// ================================================================ 
 
// 
// DllRegisterServer 
// 
// Handles sample registry and unregistry 
// 
STDAPI DllRegisterServer() 
{ 
	return AMovieDllRegisterServer2( TRUE ); 
	 
} // DllRegisterServer 
 
// ================================================================ 
 
// 
// DllUnregisterServer 
// 
STDAPI DllUnregisterServer() 
{ 
	return AMovieDllRegisterServer2( FALSE ); 
} // DllUnregisterServer 
 
// ================================================================ 
 
// 
// Constructor 
// 
MPColorTrackerFilter::MPColorTrackerFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)  
: CTransformFilter(tszName, punk, CLSID_MPColorTrackerFilter) 
, m_effect(IDC_RED) 
, m_lBufferRequest(1) 
, CPersistStream(punk, phr) 
{ 
	char sz[60]; 
	GetProfileStringA("Adaptability", "ResetInterval", "30.0", sz, 60); 
	m_resetInterval = COARefTime(atof(sz)); 
	 
	m_currentTime = COARefTime(0.0);      
	m_lastValidTime = COARefTime(0.0); 
	 
	////////////////////// 
	 
	srand( (unsigned)time( NULL ) ); 
} // (Constructor) 
 
// ================================================================ 
 
// 
// CreateInstance 
// 
// Provide the way for COM to create a MPColorTrackerFilter object 
// 
CUnknown *MPColorTrackerFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr) 
{ 
	MPColorTrackerFilter *pNewObject = new MPColorTrackerFilter(NAME("Face Tracker MPLab"), punk, phr); 
	if (pNewObject == NULL) 
		*phr = E_OUTOFMEMORY; 
	return pNewObject; 
} // CreateInstance 
 
// ================================================================ 
 
// 
// NonDelegatingQueryInterface 
// 
// Reveals IIPEffect and ISpecifyPropertyPages 
// 
STDMETHODIMP MPColorTrackerFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv) 
{ 
	CheckPointer(ppv,E_POINTER); 
	if (riid == IID_IIPEffect) { 
		return GetInterface((IIPEffect *) this, ppv); 
	} else if (riid == IID_ISpecifyPropertyPages) { 
		return GetInterface((ISpecifyPropertyPages *) this, ppv); 
	} else { 
		return CTransformFilter::NonDelegatingQueryInterface(riid, ppv); 
	} 
} // NonDelegatingQueryInterface 
 
// ================================================================ 
 
HRESULT MPColorTrackerFilter::StartStreaming(){ 
//	m_colortracker.InitStreaming(); 
	return S_OK; 
} 
 
// ================================================================ 
 
HRESULT MPColorTrackerFilter::StopStreaming(){ 
//	m_colortracker.EndStreaming(); 
	return S_OK; 
} 
 
// ================================================================ 
 
// 
// Transform 
// 
// Copy the input sample into the output sample - then transform the output 
// sample 'in place'. If we have all keyframes, then we shouldn't do a copy 
// If we have cinepak or indeo and are decompressing frame N it needs frame 
// decompressed frame N-1 available to calculate it, unless we are at a 
// keyframe. So with keyframed codecs, you can't get away with applying the 
// transform to change the frames in place, because you'll screw up the next 
// frames decompression. The runtime MPEG decoder does not have keyframes in 
// the same way so it can be done in place. We know if a sample is key frame 
// as we transform because the sync point property will be set on the sample 
// 
HRESULT MPColorTrackerFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) 
{ 
	// Copy the properties across 
	HRESULT hr = Copy(pIn, pOut); 
	if (FAILED(hr)) { 
		return hr; 
	} 
	 
	CRefTime temp; 
	pIn->GetTime((REFERENCE_TIME *) &m_currentTime, (REFERENCE_TIME *)&temp); 
	 
	return Transform(pOut); 
	 
} // Transform 
 
// ================================================================ 
 
// 
// Copy 
// 
// Make destination an identical copy of source 
// 
HRESULT MPColorTrackerFilter::Copy(IMediaSample *pSource, IMediaSample *pDest) 
{ 
	// Copy the sample data 
	 
	BYTE *pSourceBuffer, *pDestBuffer; 
	long lSourceSize = pSource->GetActualDataLength(); 
	long lDestSize  = pDest->GetSize(); 
	 
	ASSERT(lDestSize >= lSourceSize); 
	 
	pSource->GetPointer(&pSourceBuffer); 
	pDest->GetPointer(&pDestBuffer); 
	 
	m_interface.printFrame((RGBTRIPLE*)pSourceBuffer, m_imgWidth, m_imgHeight); 
	CopyMemory( (PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize); 
	 
	// Copy the sample times 
	 
	REFERENCE_TIME TimeStart, TimeEnd; 
	if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) { 
		pDest->SetTime(&TimeStart, &TimeEnd); 
	} 
	 
	LONGLONG MediaStart, MediaEnd; 
	if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { 
		pDest->SetMediaTime(&MediaStart,&MediaEnd); 
	} 
	 
	// Copy the Sync point property 
	 
	HRESULT hr = pSource->IsSyncPoint(); 
	if (hr == S_OK) { 
		pDest->SetSyncPoint(TRUE); 
	} 
	else if (hr == S_FALSE) { 
		pDest->SetSyncPoint(FALSE); 
	} 
	else {  // an unexpected error has occured... 
		return E_UNEXPECTED; 
	} 
	 
	// Copy the media type 
	 
	AM_MEDIA_TYPE *pMediaType; 
	pSource->GetMediaType(&pMediaType); 
	pDest->SetMediaType(pMediaType); 
	DeleteMediaType(pMediaType); 
	 
	// Copy the preroll property 
	 
	hr = pSource->IsPreroll(); 
	if (hr == S_OK) { 
		pDest->SetPreroll(TRUE); 
	} 
	else if (hr == S_FALSE) { 
		pDest->SetPreroll(FALSE); 
	} 
	else {  // an unexpected error has occured... 
		return E_UNEXPECTED; 
	} 
	 
	// Copy the discontinuity property 
	hr = pSource->IsDiscontinuity(); 
	 
	if (hr == S_OK) 
		pDest->SetDiscontinuity(TRUE); 
	 
	else if (hr == S_FALSE) 
		pDest->SetDiscontinuity(FALSE); 
	 
	else  
		return E_UNEXPECTED; // an unexpected error has occured... 
	 
	// Copy the actual data length 
	long lDataLength = pSource->GetActualDataLength(); 
	pDest->SetActualDataLength(lDataLength); 
	 
	return NOERROR; 
} // Copy 
 
// ================================================================ 
 
// ////////////////////////////////////////////////////////////////////  
//  This is where the MPColorTrackerFilter and tracking algorithm is implemented 
//  This is intended to be a very fast face tracker.  
//  It is based on very primitive color, shape and motion information. 
//  This allows it to do its job very fast. However it will get confused 
//  by things that look like a flesh-colored blob and move. 
//  In applications the system should be complemented by a 
//  template/feature based face detection module  
// 
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  Original version developed by Boris E. Shpungin at UCSD's Machine Perception Lab 
//  Under the supersvision of Javier R. Movellan 
//  Copyright (c) Machine Perception Laboratory, UCSD 
//  Licensed under the GNU GPL agreement  
//////////////////////////////////////////////////////////////////////// 
HRESULT MPColorTrackerFilter::Transform(IMediaSample *pMediaSample) 
{ 
	AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType(); 
	VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat; 
	 
	BYTE *pData;                // Pointer to the actual image buffer 
	pMediaSample->GetPointer(&pData); 
	 
	// Get the image properties from the BITMAPINFOHEADER 
 
	m_imgWidth = pvi->bmiHeader.biWidth; 
	m_imgHeight = pvi->bmiHeader.biHeight; 
 
	m_interface.runInterface(pData, m_imgWidth, m_imgHeight); 
 
	return NOERROR; 
} 
 
// ================================================================ 
 
// Check the input type is OK - return an error otherwise 
HRESULT MPColorTrackerFilter::CheckInputType(const CMediaType *mtIn) 
{ 
	// check this is a VIDEOINFOHEADER type 
	if (*mtIn->FormatType() != FORMAT_VideoInfo) 
		return E_INVALIDARG; 
	// Can we transform this type 
	if (CanPerformMPColorTrackerFilter(mtIn))  
		return NOERROR; 
	return E_FAIL; 
} 
 
// ================================================================ 
 
// 
// Checktransform 
// 
// Check a transform can be done between these formats 
// 
HRESULT MPColorTrackerFilter::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) 
{ 
	if (CanPerformMPColorTrackerFilter(mtIn)) { 
		if (*mtIn == *mtOut) 
			return NOERROR;    
	} 
	return E_FAIL; 
} // CheckTransform 
 
// ================================================================ 
 
// 
// DecideBufferSize 
// 
// Tell the output pin's allocator what size buffers we 
// require. Can only do this when the input is connected 
// 
HRESULT MPColorTrackerFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) 
{ 
	// Is the input pin connected 
	if (m_pInput->IsConnected() == FALSE) 
		return E_UNEXPECTED; 
	ASSERT(pAlloc); 
	ASSERT(pProperties); 
	HRESULT hr = NOERROR; 
	pProperties->cBuffers = 1; 
	pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize(); 
	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 = pAlloc->SetProperties(pProperties,&Actual); 
	if (FAILED(hr)) 
		return hr; 
	ASSERT( Actual.cBuffers == 1 ); 
	if (pProperties->cBuffers > Actual.cBuffers || 
		pProperties->cbBuffer > Actual.cbBuffer) { 
		return E_FAIL;   
	} 
	return NOERROR; 
} // DecideBufferSize 
 
// ================================================================ 
 
// 
// GetMediaType 
// 
// I support one type, namely the type of the input pin 
// This type is only available if my input is connected 
// 
HRESULT MPColorTrackerFilter::GetMediaType(int iPosition, CMediaType *pMediaType) 
{ 
	// Is the input pin connected 
	if (m_pInput->IsConnected() == FALSE)  
		return E_UNEXPECTED; 
	// This should never happen 
	if (iPosition < 0)  
		return E_INVALIDARG; 
	// Do we have more items to offer 
	if (iPosition > 0) 
		return VFW_S_NO_MORE_ITEMS; 
	*pMediaType = m_pInput->CurrentMediaType(); 
	return NOERROR; 
} // GetMediaType 
 
// ================================================================ 
 
// 
// CanPerformMPColorTrackerFilter 
// 
// Check if this is a RGB24 true colour format 
// 
BOOL MPColorTrackerFilter::CanPerformMPColorTrackerFilter(const CMediaType *pMediaType) const 
{ 
	if (IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Video)) { 
		if (IsEqualGUID(*pMediaType->Subtype(), MEDIASUBTYPE_RGB24)) { 
			VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pMediaType->Format(); 
			return (pvi->bmiHeader.biBitCount == 24); 
		}  
	} 
	return FALSE; 
} // CanPerformMPColorTrackerFilter 
 
// ================================================================ 
 
#define WRITEOUT(var) hr = pStream->Write(&var, sizeof(var), NULL); \ 
if (FAILED(hr)) return hr; 
 
#define READIN(var)   hr = pStream->Read(&var, sizeof(var), NULL); \ 
if (FAILED(hr)) return hr; 
 
// ================================================================ 
 
// 
// GetClassID 
// 
// This is the only method of IPersist 
// 
STDMETHODIMP MPColorTrackerFilter::GetClassID(CLSID *pClsid) 
{ 
	return CBaseFilter::GetClassID(pClsid); 
} // GetClassID 
 
// ================================================================ 
 
// 
// ScribbleToStream 
// 
// Overriden to write our state into a stream 
// 
HRESULT MPColorTrackerFilter::ScribbleToStream(IStream *pStream) 
{ 
	HRESULT hr; 
	WRITEOUT(m_effect); 
	return NOERROR; 
} // ScribbleToStream 
 
// ================================================================ 
 
// 
// ReadFromStream 
// 
// Likewise overriden to restore our state from a stream 
// 
HRESULT MPColorTrackerFilter::ReadFromStream(IStream *pStream) 
{ 
	HRESULT hr; 
	READIN(m_effect); 
	return NOERROR; 
} // ReadFromStream 
 
// ================================================================ 
 
// 
// GetPages 
// 
// Returns the clsid's of the property pages we support 
// 
STDMETHODIMP MPColorTrackerFilter::GetPages(CAUUID *pPages) 
{ 
	pPages->cElems = 1; 
	pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)); 
	if (pPages->pElems == NULL) 
		return E_OUTOFMEMORY;  
//	*(pPages->pElems) = CLSID_MPColorTrackerFilterPropertyPage; 
	return NOERROR; 
} // GetPages 
 
// ================================================================ 
 
// 
// get_IPEffect 
// 
// Return the current effect selected 
// 
STDMETHODIMP MPColorTrackerFilter::get_IPEffect(int *IPEffect) //,REFTIME *start,REFTIME *length) 
{ 
	CAutoLock cAutolock(&m_MPColorTrackerFilterLock); 
	CheckPointer(IPEffect,E_POINTER); 
	//    CheckPointer(start,E_POINTER); 
	//    CheckPointer(length,E_POINTER); 
	*IPEffect = m_effect; 
	//    *start = COARefTime(m_effectStartTime); 
	//    *length = COARefTime(m_effectTime); 
	return NOERROR; 
} // get_IPEffect 
 
// ================================================================ 
 
// 
// put_IPEffect 
// 
// Set the required video effect 
// 
STDMETHODIMP MPColorTrackerFilter::put_IPEffect(int IPEffect) //,REFTIME start,REFTIME length) 
{ 
	CAutoLock cAutolock(&m_MPColorTrackerFilterLock); 
	m_effect = IPEffect; 
	//    m_effectStartTime = COARefTime(start); 
	//    m_effectTime = COARefTime(length); 
	SetDirty(TRUE); 
	return NOERROR; 
} // put_IPEffect 
 
// ================================================================ 
 
MPColorTrackerFilter::~MPColorTrackerFilter() {} 
 
// ================================================================ 
 
/* 
 *  
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 
 *  
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
 *    3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
 *  
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 *  
 */