{"id":402,"date":"2008-07-05T13:31:11","date_gmt":"2008-07-05T11:31:11","guid":{"rendered":"https:\/\/alax.info\/blog\/?p=402"},"modified":"2008-07-18T18:46:20","modified_gmt":"2008-07-18T16:46:20","slug":"how-to-implement-directshow-fitler-using-directx-media-object-part-1","status":"publish","type":"post","link":"https:\/\/alax.info\/blog\/402","title":{"rendered":"How To: Implement DirectShow Filter using DirectX Media Object DMO (Part 1: Starting the Project)"},"content":{"rendered":"<p>This post is starting a step by step tutorial on writing a simple <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783323(VS.85).aspx\">DirectShow<\/a> filter using a simplified <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783356(VS.85).aspx\">DirectX Media Objects (DMO)<\/a> API. From the very scratch, the goal is to make a DirectShow\/DMO video processing filter which implements video brightness and contrast correction.<\/p>\n<p>DirectX Media Objects are <a href=\"http:\/\/www.microsoft.com\/com\/default.mspx\">COM<\/a>-based components. To implement a COM object we will use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/vstudio\/default.aspx\">Visual Studio .NET 2008<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/3ax346b7(VS.80).aspx\">Active Template Library (ATL)<\/a>.<\/p>\n<p>We are starting creating a no thrills ATL DLL project following by adding a no thrills <em>ATL Simple Object Class<\/em>:<\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image001.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-404\" title=\"image001\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image001-300x253.png\" alt=\"ATL DLL Project\" width=\"300\" height=\"253\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image001-300x253.png 300w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image001.png 615w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image002.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-405\" title=\"image002\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image002-300x194.png\" alt=\"ATL Simple Object\" width=\"300\" height=\"194\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image002-300x194.png 300w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image002.png 683w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>The only thing to make sure is to choose &#8220;Both&#8221; Threading Model since DirectX Media Object must function correctly in a free-threaded environment:<\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image003.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-406\" title=\"image003\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image003-300x253.png\" alt=\"ATL Simple Object Threading Model\" width=\"300\" height=\"253\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image003-300x253.png 300w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image003.png 615w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Visual Studio wizard creates a class which implements custom IDispatch-derived dual interface. We will not need it until we get to persistence and property pages.<\/p>\n<p>First of all, we need to reference relevant SDK headers to be able to use DirectShow and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783356(VS.85).aspx\">DMO API<\/a>:<\/p>\n<pre>#include &lt; dshow.h &gt;\r\n#include &lt; dmo.h &gt;\r\n#include &lt; dmodshow.h &gt;\r\n...\r\n#pragma comment(lib, \"strmiids.lib\")\r\n#pragma comment(lib, \"dmoguids.lib\")\r\n#pragma comment(lib, \"msdmo.lib\")<\/pre>\n<p>We reference header files and immediately leave a comment to linker to link library files (to avoid specifying them explicitly in project settings.<\/p>\n<p>From the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783383(VS.85).aspx\">minimum requirements for every DMO<\/a> we implemented aggregation (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/t9adwcde.aspx\">ATL<\/a> provides implementation by default) and threading model:<\/p>\n<blockquote><p>Every DMO should meet the following minimum requirements:<br \/>\n&#8211; It must support aggregation.<br \/>\n&#8211; It must expose the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> interface.<br \/>\n&#8211; The threading model must be &#8216;both&#8217;. DMOs must function correctly in a free-threaded environment.<\/p><\/blockquote>\n<p>We yet need to expose <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> interface and add registration code to expose the object\/filter to DirectShow-enabled applications and software components. While registration step is not necessary, it still allows visual graph construction with the filter being developed using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms787460(VS.85).aspx\">GraphEdit<\/a> utility.<\/p>\n<p>To implement <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a>, we inherit from it the media object class:<\/p>\n<pre>class ATL_NO_VTABLE CBrightnessContrastObject :\r\n    public CComObjectRootEx&lt; CComMultiThreadModel &gt;,\r\n    public CComCoClass&lt; CBrightnessContrastObject, &amp;CLSID_BrightnessContrastObject &gt;,\r\n    public IDispatchImpl&lt; IBrightnessContrastObject &gt;,\r\n<strong>    public IMediaObject<\/strong><\/pre>\n<p>then add the interface into COM MAP:<\/p>\n<pre>BEGIN_COM_MAP(CBrightnessContrastObject)\r\n    <strong>COM_INTERFACE_ENTRY(IMediaObject)<\/strong><\/pre>\n<p>and add <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> methods to the class.<\/p>\n<p>Since <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> contains Lock method, it is confused with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/8hzca2fs.aspx\">CComObjectRootEx<\/a>&#8216;s Lock and breaks project from compilation. To resolve this ambiguity, we add another method to the media object class:<\/p>\n<pre>\/\/ CComObjectRootEx\r\n    VOID Lock()\r\n    {\r\n        CComObjectRootEx::Lock();\r\n    }<\/pre>\n<p>To enable automatic registration of the media object with DirectShow\/DMO infrastructure, we are putting registration as a part of COM registration of the DLL module. This way the object will be automatically exposed to DirectShow software once the DLL is installed and registered with the system.<\/p>\n<p>First of all, we are adding <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/24z8966k.aspx\">GetObjectFriendlyName<\/a> method to provide a friendly name for the object, to be used by both ATL to register the class as COM class and the same name will be available to DirectShow software:<\/p>\n<pre>static LPCTSTR GetObjectFriendlyName() throw()\r\n{\r\n    return _T(\"Alax.Info BrightnessContrast Sample\");\r\n}<\/pre>\n<p>To intercept COM registration and register the object as DMO we are overriding UpdateRegistry method. The implementation for this method is added to th class through <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/w0ey2be3(VS.80).aspx\">DECLARE_REGISTRY_RESOURCEID<\/a> macro. We comment this out and add implementation for this method explicitly:<\/p>\n<p>Except for default handling through <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/fk48ft1t.aspx\">CAtlModule::UpdateRegistryFromResource<\/a>, we will add calls to our <strong>RegisterMediaObject<\/strong> and <strong>UnregisterMediaObject<\/strong> functions which in their turn will use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783385(VS.85).aspx\">DMORegister<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms783388(VS.85).aspx\">DMOUnregister<\/a> API.<\/p>\n<pre>static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\r\n{\r\n    _ATLTRY\r\n    {\r\n        if(!bRegister)\r\n            UnregisterMediaObject();\r\n        ATLASSERT(_pAtlModule);\r\n        _pAtlModule-&gt;UpdateRegistryFromResource(IDR_BRIGHTNESSCONTRASTOBJECT, bRegister);\r\n        if(bRegister)\r\n            RegisterMediaObject();\r\n    }\r\n    _ATLCATCH(Exception)\r\n    {\r\n        return Exception;\r\n    }\r\n    return S_OK;\r\n}<\/pre>\n<p>Our media object will expose one input and one output stream\/pin both with media type MEDIATYPE_Video, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa390521.aspx\">MEDIASUBTYPE_YUY2<\/a>.<\/p>\n<p>Once the project is compiled, COM registration is performed as a part of build task and DMO registration is a subtask. So, the object is already exposed to DirectShow software and applications:<\/p>\n<p><a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image004.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-408\" title=\"GraphEdit Availability\" src=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image004-253x300.png\" alt=\"\" width=\"253\" height=\"300\" srcset=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image004-253x300.png 253w, https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/image004.png 450w\" sizes=\"auto, (max-width: 253px) 100vw, 253px\" \/><\/a><\/p>\n<p>The framework part is done, we are ready to add real implementation for <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> interface and video processing methods.<\/p>\n<p>Source code: <a href=\"https:\/\/alax.info\/blog\/wp-content\/uploads\/2008\/07\/dmobrightnesscontrastsample01.zip\">DmoBrightnessContrastSample.01.zip<\/a><\/p>\n<p>Additional Notes:<\/p>\n<ul>\n<li>Platform SDK provides <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785938(VS.85).aspx\">IMediaObjectImpl<\/a> template class (dmoimpl.h) to inherit from instead of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a>, which offer base implementation for <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms785947(VS.85).aspx\">IMediaObject<\/a> interface.<\/li>\n<li>See also <a href=\"http:\/\/vnet.uh.edu\/vrecord_data\/vclass\/resource\/ATL_Tutorial_9219.doc\">similar tutorial on vnet.uh.edu<\/a><\/li>\n<\/ul>\n<p>Continued by:<\/p>\n<ul>\n<li><a href=\"https:\/\/alax.info\/blog\/412\">Part 2: Video Processing<\/a><\/li>\n<li><a href=\"https:\/\/alax.info\/blog\/433\">Part 3: Persistence, Automation and Property Pages<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This post is starting a step by step tutorial on writing a simple DirectShow filter using a simplified DirectX Media Objects (DMO) API. From the very scratch, the goal is to make a DirectShow\/DMO video processing filter which implements video brightness and contrast correction. DirectX Media Objects are COM-based components. To implement a COM object&hellip; <\/p>\n<p><a class=\"moretag\" href=\"https:\/\/alax.info\/blog\/402\">Read the full article<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,10],"tags":[487,78,83,47],"class_list":["post-402","post","type-post","status-publish","format-standard","hentry","category-atl","category-video","tag-atl","tag-directshow","tag-dmo","tag-howto"],"_links":{"self":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/402","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/comments?post=402"}],"version-history":[{"count":0,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/402\/revisions"}],"wp:attachment":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/media?parent=402"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/categories?post=402"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/tags?post=402"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}