Previously on the topic:

The principal task of video processing is done but there are still things mandatory for the filter to be usable. First of all, a custom interface is required to be able to control the filter from higher level application and to adjust brightness and constract correction values on the run time. Additionally, persistence would not hurt at all to be able to store correction settings along with other graph settings in GraphEdit graph file or anywhere else. Additionally, it would also be convenient to have a property page for the filter to be able to adjust the correction settings through GUI, both on graph composition and while the graph is running.

All the mentioned tasks are interconnected and ATL has an answer in implementation of:

Also note that DMO Minimum Requirements mention IPersistStream and ISpecifyPropertyPages as not required but recommended as useful, and these interfaces will be used by DirectShow.

We start with custom IDispatch-derived interface to be used to control filter and for persistence. ATL Project Wizard already prepared empty IBrightnessContrastObject interface as a part of project creation, where we are adding Brightness and Contrast properties (in the IDL definition) and adding implementation of corresponding methods to the filter/DMO class:

interface IBrightnessContrastObject : IDispatch
{
	[propget, id(1)] HRESULT Brightness([out, retval] LONG* pnBrightness);
	[propput, id(1)] HRESULT Brightness([in] LONG nBrightness);
	[propget, id(2)] HRESULT Contrast([out, retval] LONG* pnContrast);
	[propput, id(2)] HRESULT Contrast([in] LONG nContrast);
};
// IBrightnessContrastObject
	STDMETHOD(get_Brightness)(LONG* pnBrightness) throw()
	STDMETHOD(put_Brightness)(LONG nBrightness) throw()
	STDMETHOD(get_Contrast)(LONG* pnContrast) throw()
	STDMETHOD(put_Contrast)(LONG nContrast) throw()

To complete implemetnation of persistence we are to inherit from IPersistStreamInitImpl and also add a property map:

class ATL_NO_VTABLE CBrightnessContrastObject :
	...
	public IPersistStreamInitImpl<CBrightnessContrastObject>,
...
BEGIN_COM_MAP(CBrightnessContrastObject)
	COM_INTERFACE_ENTRY(IPersistStreamInit)
	COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStreamInit)
...
BEGIN_PROP_MAP(CBrightnessContrastObject)
	PROP_ENTRY_TYPE_EX("Brightness", 1, CLSID_NULL, __uuidof(IBrightnessContrastObject), VT_I4)
	PROP_ENTRY_TYPE_EX("Contrast", 2, CLSID_NULL, __uuidof(IBrightnessContrastObject), VT_I4)
END_PROP_MAP()
...
public:
	BOOL m_bRequiresSave;

In the property map we enumerate the persistent properties using PROP_ENTRY_TYPE_EX (a successor of PROP_ENTRY_EX, which is deprecated starting Visual Studio .NET 2008).

Note that ATL implements IPersistStreamInit, however IPersistStream is compatible in method declaration so we can quick-implement this interface through declaring COM_INTERFACE_ENTRY_IID and thus castingĀ IPersistStreamInit to IPersistStream.

Note CLSID_NULL which is a class identifier of the corresponding property page, if any, which we will replace with a non-NULL identifier below as soon as property page is ready.

We also need a m_bRequiresSave variable which is used by IPersist*Impl classes and for this reason it has to be either public or instead we should friend the classes to allow access to the variable.

To ensure automation interface property put accessors are working as expected, let us re-work debug pre-initialization of the correction variables through FinalConstruct method:

#if defined(_DEBUG)
	HRESULT FinalConstruct() throw()
	{
		_ATLTRY
		{
			__C(put_Brightness(-0x0010));
			__C(put_Contrast(0x2000));
		}
		_ATLCATCH(Exception)
		{
			return Exception;
		}
		return S_OK;
	}
#endif // defined(_DEBUG)

The only things remained is a property page, for which we create a new COM object class CGeneralPropertyPage. Luckily, ATL has a wizard-based creation helper for property pages:

We will start needing WTL for convenient GUI implementation. Please refer to Example: Implementing a Property Page on how property page is implemented. Once implementation is complete, we need to inherit from IPersistStreamInitImpl and reference the property page from filter/DMO property map:

class ATL_NO_VTABLE CBrightnessContrastObject :
	...
	public ISpecifyPropertyPagesImpl<CBrightnessContrastObject>,
...
BEGIN_COM_MAP(CBrightnessContrastObject)
	...
	COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
...
BEGIN_PROP_MAP(CBrightnessContrastObject)
	PROP_PAGE(CLSID_GeneralPropertyPage)

Filter’s run time:

Source code: DmoBrightnessContrastSample.03.zip (note that Release build binary is included)

Continued by:

Tags: , , , ,