www.pudn.com > DS4050src.zip > divxfilter.cpp


/************************************************************************** 
 *                                                                        * 
 * This code has been developed by Andrea Graziani. Those intending to    * 
 * use this software module in hardware or software products are advised  * 
 * that its use may infringe existing patents or copyrights, and any such *  
 * use would be at such party's own risk. The original developer of this  * 
 * software module and his/her company, and subsequent editors and their  * 
 * companies (including Project Mayo), will have no liability for use of  * 
 * this software or modifications or derivatives thereof.                 * 
 *                                                                        * 
 * Project Mayo gives users of the Codec and Filter a license to this     * 
 * software  module or modifications thereof for use in hardware or       * 
 * software products claiming conformance to the MPEG-4 Video Standard    * 
 * as described in the Open DivX license.                                 * 
 *                                                                        * 
 * The complete Open DivX license can be found at                         * 
 * http://www.projectmayo.com/opendivx/license.php                        * 
 *                                                                        * 
 **************************************************************************/ 
/** 
*  Copyright (C) 2001 - Project Mayo 
 * 
 * Andrea Graziani 
 * 
 * DivX Advanced Research Center  
* 
**/ 
// divxfilter.cpp // 
 
#include  
#include  
#include  
#include  
 
#include "decore.h" 
#include "divxuid.h" 
#include "divxfilter.h" 
#include "divxfilterproperties.h" 
 
/** 
 *	declaration of filter information 
**/ 
 
// setup data 
 
const AMOVIESETUP_MEDIATYPE sudPinInTypes[4] = 
{ 
	{ // Type 0 
		&MEDIATYPE_Video,      
		&CLSID_DivX			   
	}, 
	{ // Type 1 
		&MEDIATYPE_Video,      
		&CLSID_DivX_U 
	}, 
	{ // Type 2 
		&MEDIATYPE_Video,      
		&CLSID_DivX_ 
	}, 
	{ // Type 3 
		&MEDIATYPE_Video,      
		&CLSID_DivX__U 
	} 
}; 
 
const AMOVIESETUP_MEDIATYPE sudPinOutTypes[1] = 
{ 
		&MEDIATYPE_Video,      
		&MEDIASUBTYPE_NULL     
}; 
 
const AMOVIESETUP_PIN psudPins[] = 
{ 
  { 
    L"Input",           // String pin name 
    FALSE,              // Is it rendered 
    FALSE,              // Is it an output 
    FALSE,               
    FALSE,               
    &CLSID_NULL,        // Connects to filter 
    L"Output",          // Connects to pin 
    4,                  // Number of types 
    &sudPinInTypes[0]		// The pin details 
	}, 
  {  
		L"Output",          // String pin name 
    FALSE,              // Is it rendered 
    TRUE,               // Is it an output 
    FALSE,               
    FALSE,               
    &CLSID_NULL,        // Connects to filter 
    L"Input",           // Connects to pin 
    1,                  // Number of types 
    &sudPinOutTypes[0]	// The pin details 
  } 
}; 
 
const AMOVIESETUP_FILTER sudDivXReg = 
{ 
	&CLSID_DivX,								// Filter CLSID 
  L"OpenDivX Decoder Filter",	// Filter name 
  MERIT_PREFERRED,						// Its merit 
  2,													// Number of pins 
  psudPins										// Pin details 
}; 
 
/** 
 *	declaration of filter template 
**/ 
 
// 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[2] =  
{ 
	{  
		L"OpenDivX Decoder Filter",	// Filter name 
		&CLSID_DivX,						    // Filter CLSID 
		DivXFilter::CreateInstance,	// Creation function 
		NULL,												//  
		&sudDivXReg							    // Self-registration information 
	}, 
	{ 
    L"OpenDivX Decoder Filter Properties Page", 
    &CLSID_DivXPropertiesPage, 
    DivXFilterProperties::CreateInstance 
	} 
}; 
 
int g_cTemplates = sizeof(g_Templates)/(sizeof(g_Templates[0])); 
 
//  
// CreateInstance 
// 
CUnknown * WINAPI DivXFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT * phr) 
{ 
	DivXFilter * pNewObject = new DivXFilter(NAME("OpenDivX Decoder Filter"), lpunk, phr); 
	if (pNewObject == NULL) { 
		*phr = E_OUTOFMEMORY; 
	} 
	 
	return pNewObject; 
} // CreateInstance 
 
 
// 
// NonDelegatingQueryInterface 
// 
STDMETHODIMP DivXFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) 
{ 
  if (riid == IID_IDivXFilterInterface) { 
		return GetInterface((IDivXFilterInterface *) this, ppv); 
	} 
	else if (riid == IID_ISpecifyPropertyPages) { 
		return GetInterface((ISpecifyPropertyPages *) this, ppv); 
	}  
	return CTransformFilter::NonDelegatingQueryInterface(riid, ppv); 
 
} // NonDelegatingQueryInterface 
 
 
/** 
 *	implementation of DllRegistrerServer 
**/ 
 
// the dll that export this component must contain this function 
// 
STDAPI DllRegisterServer(void) 
{ 
	HRESULT hr = AMovieDllRegisterServer2(TRUE); 
	if ( FAILED(hr) ) 
		return hr; 
 
	IFilterMapper2 *pFM2 = 0; 
 
	hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, 
		IID_IFilterMapper2, (void **) &pFM2); 
	if ( FAILED(hr) ) 
		return hr; 
 
	REGFILTER2 rf2; 
	rf2.dwVersion = 1; 
	rf2.dwMerit = MERIT_PREFERRED; 
	rf2.cPins = NUMELMS(psudPins); 
	rf2.rgPins = psudPins; 
 
	hr = pFM2->RegisterFilter(CLSID_DivX,  
		L"OpenDivX Decoder Filter", 
		NULL,  
		&CLSID_AVIDec, 
		L"CLSID_DivXDeux", 
		&rf2); 
 
	pFM2->Release(); 
 
	return hr; 
} // DllRegisterServer 
 
 
STDAPI DllUnregisterServer(void) 
{ 
	HRESULT hr = AMovieDllRegisterServer2(FALSE); 
	if ( FAILED(hr) ) 
		return hr; 
 
	IFilterMapper2 * pFM2 = 0; 
 
	hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, 
		IID_IFilterMapper2, (void **) &pFM2); 
	if ( FAILED(hr) ) 
		return hr; 
 
	if (pFM2 != 0) { 
 
		hr = pFM2->UnregisterFilter(&CLSID_AVIDec, 
			NULL, CLSID_DivX); 
 
		pFM2->Release(); 
	} 
 
	return S_OK; 
} // DllUnregisterServer 
 
 
/** 
 *	override of functions 
**/ 
 
// determine if the proposed input is valid 
// 
HRESULT DivXFilter::CheckInputType(const CMediaType * pmtIn) 
{ 
	DbgLog((LOG_TRACE, 2, TEXT("DivXFilter::CheckInputType"))); 
	if ( (*pmtIn->Type() != MEDIATYPE_Video) ) 
		return E_INVALIDARG; 
 
	VIDEOINFO * pvi = (VIDEOINFO *) pmtIn->Format(); 
 
	m_DecParam.y_dim = (pvi->bmiHeader.biHeight > 0) ?  
		pvi->bmiHeader.biHeight : -pvi->bmiHeader.biHeight; 
	m_DecParam.x_dim = pvi->bmiHeader.biWidth; 
 
	return S_OK; 
} // CheckInputType 
 
 
HRESULT DivXFilter::StartStreaming() 
{ 
	return S_OK; 
} // StartStreaming 
 
 
HRESULT DivXFilter::StopStreaming() 
{ 
	return S_OK; 
} // StopStreaming 
 
 
// performs my desired transformation on input media  
// 
HRESULT DivXFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) 
{ 
	if (m_iInitialized == 0)  
	{ 
		decore(1, DEC_OPT_MEMORY_REQS, &m_DecParam, &m_DecMemReqs); 
 
		m_DecParam.buffers.mp4_edged_ref_buffers = malloc(m_DecMemReqs.mp4_edged_ref_buffers_size); 
		m_DecParam.buffers.mp4_edged_for_buffers = malloc(m_DecMemReqs.mp4_edged_for_buffers_size); 
		m_DecParam.buffers.mp4_display_buffers = malloc(m_DecMemReqs.mp4_display_buffers_size); 
		m_DecParam.buffers.mp4_state = malloc(m_DecMemReqs.mp4_state_size); 
		m_DecParam.buffers.mp4_tables = malloc(m_DecMemReqs.mp4_tables_size); 
		m_DecParam.buffers.mp4_stream = malloc(m_DecMemReqs.mp4_stream_size); 
 
		memset(m_DecParam.buffers.mp4_state, 0, m_DecMemReqs.mp4_state_size); 
		memset(m_DecParam.buffers.mp4_tables, 0, m_DecMemReqs.mp4_tables_size); 
		memset(m_DecParam.buffers.mp4_stream, 0, m_DecMemReqs.mp4_stream_size); 
 
		decore((long) this, DEC_OPT_INIT, &m_DecParam, NULL); 
 
		put_PPLevel(90); 
 
		m_iInitialized = 1; 
	} 
 
	DEC_FRAME dec_frame; 
 
	BYTE * input_buffer, * output_buffer; 
	if (pIn->GetPointer(&input_buffer) != S_OK) 
		return S_OK; // not valid pointer, forgot it! 
	if (pOut->GetPointer(&output_buffer) != S_OK) 
		return S_OK;  
 
	dec_frame.length = pIn->GetSize(); 
	dec_frame.render_flag = 1; 
	dec_frame.bitstream = (char *) input_buffer; 
	dec_frame.bmp = (char *) output_buffer; 
	dec_frame.stride = m_DecParam.x_dim; 
 
	decore((long) this, 0, &dec_frame, NULL); 
 
	return S_OK; 
} // Transform 
 
 
HRESULT DivXFilter::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt) 
{ 
	if (pmt->subtype != m_CURRENTSubType) 
	{ 
		if (pmt->subtype == MEDIASUBTYPE_RGB32) { 
			m_DecParam.output_format = DEC_RGB32; 
		} 
		else if (pmt->subtype == MEDIASUBTYPE_RGB24) { 
			m_DecParam.output_format = DEC_RGB24; 
		} 
		else if (pmt->subtype == MEDIASUBTYPE_RGB555) { 
			m_DecParam.output_format = DEC_RGB555; 
		} 
		else if (pmt->subtype == MEDIASUBTYPE_RGB565) { 
			m_DecParam.output_format = DEC_RGB565; 
		} 
		else if (pmt->subtype == MEDIASUBTYPE_YUY2) { 
			m_DecParam.output_format = DEC_YUV2; 
		} 
		/*** [Ag] Thanks to Martin for this patch! 
 
		else if (pmt->subtype == MEDIASUBTYPE_YV12) { 
			m_DecParam.output_format = YUV12; 
		} 
 
		***/ 
		else { 
			/*** 
			MessageBox(NULL, "Output format not supported\nCheck your monitor settings\n", 
				"Error", MB_ICONEXCLAMATION); 
			***/ 
			m_iInitialized = 0; 
			return E_INVALIDARG; 
		} 
		if (m_iInitialized == 1) 
			decore((long) this, DEC_OPT_SETOUT, &m_DecParam, NULL); 
 
		m_CURRENTSubType = pmt->subtype; 
	} 
 
	if (pmt->FormatType() == &FORMAT_VideoInfo2) { 
		VIDEOINFOHEADER2 * videoinfo = (VIDEOINFOHEADER2 *) pmt->Format(); 
	} 
	else { 
		VIDEOINFOHEADER2 * videoinfo = (VIDEOINFOHEADER2 *) pmt->Format(); 
	} 
 
	return S_OK; 
} 
 
 
// check if input and output media types are compatibles 
// 
HRESULT DivXFilter::CheckTransform(const CMediaType * pmtIn, const CMediaType * pmtOut) 
{ 
	VIDEOINFOHEADER2 * pvi = (VIDEOINFOHEADER2 *) pmtIn->Format(); 
	VIDEOINFOHEADER2 * pvo = (VIDEOINFOHEADER2 *) pmtOut->Format(); 
 
	if ( (*pmtIn->Type() != MEDIATYPE_Video) || (*pmtOut->Type() != MEDIATYPE_Video) ) 
		return E_FAIL; 
 
	if ( (pvo->rcSource.right != 0) || (pvo->rcSource.left != 0) ||  
		(pvo->rcSource.bottom != 0) || (pvo->rcSource.top != 0 ) ) 
		return E_FAIL; 
 
	return S_OK; 
} // CheckTransform 
 
 
// tell the output pin's allocator what buffer is required 
// 
HRESULT DivXFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) 
{ 
	HRESULT hr; 
	ALLOCATOR_PROPERTIES Actual; 
 
  // Is the input pin connected 
  if (m_pInput->IsConnected() == FALSE) { 
      return E_UNEXPECTED; 
  } 
 
	pProperties->cBuffers = 1; 
	pProperties->cbBuffer = m_DecParam.x_dim * m_DecParam.y_dim * 4; 
 
	hr = pAlloc->SetProperties(pProperties, &Actual); 
	if (FAILED(hr)) { 
		return hr; 
	} 
 
	// verify that the allocator is able to allocate what requested 
	if (Actual.cbBuffer < pProperties->cbBuffer) { 
		return E_FAIL; 
	} 
 
  return S_OK; 
} // DecideBufferSize 
 
 
// retrieve the preferred media type for the output pin 
// 
HRESULT DivXFilter::GetMediaType(int iPos, CMediaType * pmtOut) 
{ 
	VIDEOINFOHEADER * pvih = (VIDEOINFOHEADER *) pmtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER)); 
 
	if (pvih == NULL)	{ 
		return E_OUTOFMEMORY; 
	} 
	ZeroMemory(pvih, sizeof (VIDEOINFOHEADER)); 
 
	// common bitmap info 
	pvih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
	pvih->bmiHeader.biWidth	= m_DecParam.x_dim; 
	pvih->bmiHeader.biHeight = m_DecParam.y_dim; 
	pvih->bmiHeader.biPlanes = 1; 
	pvih->bmiHeader.biClrImportant = 0; 
	pvih->bmiHeader.biClrUsed = 0; 
 
	pvih->rcSource.top = 0; 
	pvih->rcSource.left = 0; 
	pvih->rcSource.bottom = 0; 
	pvih->rcSource.right = 0; 
 
	pvih->rcTarget.top = 0; 
	pvih->rcTarget.left = 0; 
	pvih->rcTarget.bottom = 0; 
	pvih->rcTarget.right = 0; 
 
  // is the input pin connected 
  if (m_pInput->IsConnected() == FALSE) { 
		return E_UNEXPECTED; 
  } 
 
	// check position number limit 
	if (iPos < 0) 
		return E_INVALIDARG; 
	if (iPos > 5) 
		return VFW_S_NO_MORE_ITEMS; 
 
	// common media type info 
	pmtOut->SetType(&MEDIATYPE_Video); 
	pmtOut->SetFormatType(&FORMAT_VideoInfo); 
	pmtOut->SetTemporalCompression(TRUE); 
 
	/*** [Ag] Thanks to Martin for this patch! 
 
	if (iPos == 0)  
	{ 
		FOURCCMap * pFourCC = new FOURCCMap(&MEDIASUBTYPE_YV12); 
		pvih->bmiHeader.biCompression	 = pFourCC->GetFOURCC(); 
 
		pvih->bmiHeader.biBitCount = 12; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_YV12); 
		pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); 
 
		delete pFourCC; 
	} 
 
	***/ 
	if (iPos == 0) 
	{ 
		FOURCCMap *pFourCC = new FOURCCMap(&MEDIASUBTYPE_YUY2); 
		pvih->bmiHeader.biCompression	 = pFourCC->GetFOURCC(); 
 
		pvih->bmiHeader.biBitCount = 16; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_YUY2); 
		pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); 
 
		delete pFourCC; 
	}  
	else if (iPos == 1) 
	{ 
		FOURCCMap *pFourCC = new FOURCCMap(&MEDIASUBTYPE_UYVY); 
		pvih->bmiHeader.biCompression	 = pFourCC->GetFOURCC(); 
 
		pvih->bmiHeader.biBitCount = 16; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_UYVY); 
		pvih->bmiHeader.biSizeImage = GetBitmapSize(&pvih->bmiHeader); 
 
		delete pFourCC; 
	}  
	else if (iPos == 2)  
	{ 
		pvih->bmiHeader.biCompression	= BI_RGB;  
		 
		pvih->bmiHeader.biBitCount = 32; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_RGB32); 
		pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); 
	}  
	else if (iPos == 3) 
	{ 
		pvih->bmiHeader.biCompression	= BI_RGB;  
 
		pvih->bmiHeader.biBitCount = 24; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_RGB24); 
		pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); 
	} 
	else if (iPos == 4) 
	{ 
		pvih->bmiHeader.biCompression	= BI_RGB;  
 
		pvih->bmiHeader.biBitCount = 16; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_RGB555);  
		pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); 
	} 
	else if (iPos == 5) 
	{ 
		pvih->bmiHeader.biCompression	= BI_RGB;  
 
		pvih->bmiHeader.biBitCount = 16; 
 
		pmtOut->SetSubtype(&MEDIASUBTYPE_RGB565);  
		pmtOut->SetSampleSize(pvih->bmiHeader.biSizeImage); 
	}  
 
	ConvertVideoInfoToVideoInfo2(pmtOut); 
 
  return NOERROR; 
 
} // GetMediaType 
 
 
/** 
 *	interface methods 
**/ 
 
// required for ISpecifyPropertyPages 
// 
STDMETHODIMP DivXFilter::GetPages(CAUUID * pPages) 
{ 
	pPages->cElems = 1; 
 
	// allocate enough memory to hold thieir GUIDs 
	pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)); 
	if (pPages->pElems == NULL) { 
		return E_OUTOFMEMORY; 
	} 
	pPages->pElems[0] = CLSID_DivXPropertiesPage; 
 
	return S_OK; 
} 
 
 
STDMETHODIMP DivXFilter::FreePages(CAUUID * pPages) 
{ 
	CoTaskMemFree(pPages->pElems); 
 
	return S_OK; 
} 
 
 
// return the current postprocessing level 
// 
STDMETHODIMP DivXFilter::get_PPLevel(int * PPLevel) 
{ 
  * PPLevel = m_iPPLevel; 
 
  return S_OK; 
} // get_ContrastLevel 
 
 
// set the postprocessing level 
// 
STDMETHODIMP DivXFilter::put_PPLevel(int PPLevel) 
{ 
  m_iPPLevel = PPLevel; 
 
	// call decore API to set postprocessing level 
	DEC_SET dec_set; 
	dec_set.postproc_level = m_iPPLevel; 
 
	decore((long) this, DEC_OPT_SETPP, &dec_set, NULL); 
 
  return S_OK; 
} // put_ContrastLevel 
 
 
// set the default postprocessing level 
// 
STDMETHODIMP DivXFilter::put_DefaultPPLevel() 
{ 
  m_iPPLevel = m_iDefaultPPLevel; 
 
  return S_OK; 
} // put_DefaultContrastLevel 
 
 
/** 
 *	constructor/denstructor 
**/ 
 
DivXFilter::DivXFilter(TCHAR * pName, LPUNKNOWN lpUnk, HRESULT *pHr) : 
	CVideoTransformFilter(pName, lpUnk, CLSID_DivX), 
  m_iDefaultPPLevel(0), 
  m_iPPLevel(m_iDefaultPPLevel), 
  m_iPrevPPLevel(m_iPPLevel), 
	m_iInitialized(0), 
	m_CURRENTSubType(GUID_NULL) 
{ 
  ASSERT(pName); 
  ASSERT(pHr); 
} // DivXFilter 
 
DivXFilter::~DivXFilter() 
{ 
	decore((long) this, DEC_OPT_RELEASE, NULL, NULL); 
} // ~DivXFilter