Develop your own Filter with DirectShow
Learning DirectShow has been a few days. He will write your own experience and hope to help others.
Filter is a COM component, so you should have a little understanding of COM before learning development of Filter. The essence of the COM component is a C object that implements a pure virtual pointer interface. There are not many talks about COM.
1 Configuring the development environment of DSHOW to VC
Whether developing Filter or developing DSHOW applications to configure a development environment, it is true to include the header file and dynamic library for DSHOW. Select the Options below the Tools menu. The Option dialog box is configured as follows;
Add header file
Select dynamic library file to add to the project
2 Creating an engineering and port entry functions
Create project
In general, create a Filter using a normal Win32 DLL project. Moreover, general Filter projects do not use MFC. At this time, the application passes the COCREATEINSTANCE function Filter instance; Filter and the application collaborate in binary levels. Another method can also create a Filter in the MFC's application project.
New project in VC, select Win32 dynamic library, as shown below;
This generates a simple DLL, only one DLLMAIN entry function.
Below I want to add an entry function to this Filter.
FILTER is a DLL-based COM component, so the general Filter must implement the following portfolios.
Dllmain
DllgetClassObject
DllcanunloadNow
DllRegisterServer
DllunregisterServer
First define the export function
To export these functions, there are two ways. Use the export function keyword_declspec (DLLEXPORT) to create myDLL.dll is the definition function in .h file is as follows,
Extern "C" _Declspec (DLLEXPORT) BOOL DLLREGISTERSERVER; etc.
In order to create a DLL with the .def file, add a text file to this project, name mydll.def, add the following code in this file:
Library myfilter.ax
Exports
Dllmain Private
DllgetClassObject Private
DllcanunloadNow Private
DllregisterServer Private
DllunregisterServer Private
Where the library statement indicates that the DEF file is a corresponding DLL, the exports statement lists the function name to be exported. We can add @n, such as max @ 1, min @ 2, indicating that the function sequence to be exported is explicitly used in the export function to export. After the DLL is successful, open the Debug directory in the project, and you will also see the mydll.dll and mydll.lib files.
Then define these functions, in fact, these work DSHOW's base class has been done for us. If we have to do it, it is, the most important three functions are generally as follows.
Stdapi DllregisterServer ()
{
Return AmoviedllRegisterServer2 (TRUE);
}
Stdapi DllunregisterServer ()
{
Return AmoviedllregisterServer2 (false);
Extern "C" BOOL WINAPI DLLENTRYPOINT (Hinstance, Ulong, LPVOID);
Bool Apientry Dllmain (Handle Hmodule, DWORD DWREASON, LPVOID LPRESERVED)
{
Return DllenTryPoint (HMODULE) (HMODULE), DWREASON, LPRESERVED;
}
Where DLLLENTRYPOINT is defined in C: / DX90SDK / SampleClasses / DLlentry.cpp, if you are interested, we can take a look at its definition.
The amoviedllregisterServer2 function is below
C: / DX90SDK / Samples / C / DirectShow / BaseClasses / dllsetup.cpp This file is defined, and the specific implementation can take yourself.
Here you are here, I am afraid to do something, or set up your project environment, otherwise I am afraid that you have compiled it, because you use some things in the base class, so you have to define your DSHOW base class definition and library The file contains it.
First include
#include
Second, configure your own Filter output name and connection LIB file under the Project -Setting menu.
The dynamic library included in the library modules is as follows
c: / DX90SDK / Samples / C / DirectShow / BaseClasses / debug / strmbasd.lib msvcrtd.lib quartz.lib vfw32.lib winmm.lib kernel32.lib advapi32.lib version.lib largeint.lib user32.lib gdi32.lib comctl32. Lib ole32.lib olepro32.lib oleaut32.lib uuid.lib
At this time, you compile it, it seems to be not, it prompts a global variable for implementing the COM interface, no definition, not anxious, let's start implementing the Filter's COM interface.
3 How to implement Filter's class factory object
This section is to talk about how the Filter implements the COM interface, which is different from other COM implementations.
We know that a Filter is a COM component, so its COM features is actually implemented in its base class, such as the iUnknown interface, after we send our Filter directly from the base class, it supports the COM interface, it is a COM components.
All COM components In order to implement binary packages, even the created interfaces are encapsulated, so each COM object has a class object (also called class factory object, it is also a COM object, used to create COM components) to create COM Component.
Here is a test process of COM components, which involve several functions.
1 When the client wants to create a COM component, it uses SCM's service through the underlying COM API function COGETCLASSOBJECT (), this function, please SCM bind a pointer to the class object of the client request,
In fact, in COGETCLASSObject (), it loads the DLL library, through the DLL export function dllgetClassObject (); DllgetClassObject returns a pointer to the COM component class object based on the COM component ClassID provided by the client. The creation of the COM component below is not related to SCM. 2 Clients Create a COM component using the IclassFactory :: CreateInstance method of the class object (class object).
FILTER uses a class factory template class here to use as a Filter class factory object.
Let's take a look at how the class is working in dshow.
The class object is also a COM component. Originally DllgetClassObject is a function we wrote by our own, in DirectShow has been completed, we don't have to do it yourself. Its function is to find class millions in this DLL to see if there is a class object that meets the client request.
The DLL declares an array of global classes. When the DllgetClassObject requests a class factory object, it searches for this array to see if there is a class object that matches the CLSID. When it finds a matching CLSID, it creates a class factory object, then the class fleet is returned to COGETCLASSOBJECT, and the client can call the iClassFactory :: createInstance method to create components according to the returned class factory pointer, and the class is based on The method defined in the array creates a COM component.
Factory Template contains the following variables:
Const wchar * m_name; // name
Const CLSID * m_clsid; // CLSID
LPFNNNEWCOMOBJECT M_LPFNNEW; // Function To // Create An Instance of The Component
LPFNITROUTINE M_LPFNINIT; // Initialization Function (optional)
Const Amoviesetup_filter * m_pamoviesetup_filter; // set-up information (for filter)
The two function pointer M_LPFNNEW and M_LPFNIT use the definition below
Typedef coknown * (Callback * lpfnnewcomobject) (HRESULT * PHR);
TypeDef void (Callback * lpfninitRoutine) (Bool Bloading, Const CLSID * RCLSID);
You can define your class factories in the following way.
If the following is your COM component creation function,
Cunknown * WinAPI CMYFILTER :: CreateInstance (LPunkNown Punk, HRESULT * PHR)
{
CMYFILTER * PFILTER = New CMYFILTER (Name ("My Filter", PUNK, PHR);
IF (pfilter == null)
{
* pHR = E_OUTOFMEMORY;
}
Return Pfilter;
}
You can declare that your own class is as follows: If you have multiple Filter in this COM component, you can continue to add in this array.
CFactoryTemplate G_Templates [1] =
{
{
L "my filter", // name & clsid_myfilter, // clsid
CMYFILTER :: CreateInstance, //Method to create an instance of mycomponent
Null, // Initialization function
& Sudinftee // Set-Up Information (for filter)
}
}
INT g_ctemplates = sizeof (g_templates) / sizeof (g_templates [0]);
4 How to implement your own Filter
Here, you must talk about how to create your own Filter. Here we write a CTransformFilter as an example.
1 Select a base class to declare your class
Creating a Filter is very simple, you only need to choose a different base class Filter to send his own Filter according to your needs, and it has supported the COM feature.
Logically consider, selecting a suitable Filter base class is critical before writing Filter. To do this, you must have a considerable understanding of several Filter's base classes. In practical applications, Filter's base class does not always choose CBASEFILTER. Instead, because most of us written is the middle transfer filter (Transform Filter, the base class selects CTransformFilter and CTransinplaceFilter). If we write the source filter, we can choose CSource as a base class; if it is renderer filter, you can choose CBASERENDERER or CBASEVIDEORERERER. In short, it is important to choose the base class of Filter. Of course, the base class for selecting Filter is also very flexible, there is no absolute standard. Filter that can be implemented through CTRANSFORMFILTER can of course achieve step by step from CBasefilter. Below, the author will put forward some suggestions for the Choice of the Filter base class from the actual experience. First, you must clarify what kind of feature to complete this filter, that is, to analyze the Filter project. Please try to keep the Filter's single functionality. If necessary, you can decompose demand, single (or more) features a single filter to implement the total functional requirements. Second, you should clarify this Filter from the entire Filter Graph's location, this filter input is what data, what is the data, there are several inputs, and several output PIN, etc. You can draw a sketch of this Filter. It is very important to figure out this, which will directly determine which "model" of "model" you use. For example, if Filter has only one input PIN and an output PIN, and the media type of one place is the same, CTRANSINPLACEFILTER is generally used as a base class of the filter; if the media type is different, the CTransformFilter is generally selected as the base class. Furthermore, consider some data transmission, processing specialty requirements. The SAMPLE, such as the input and output of the FILTER is not one, which generally wants to perform data on the input PIN, and performs data processing using a special thread on the output PIN. In this case, the Filter's base class selects csource as suitable (although this filter is not a source filter). When the base class of the Filter is selected, the base class of the PIN will be selected accordingly. Next, it is implemented in Filter and PIN. One thing to note is that from the perspective of software design, your logical class code should be separated from the filter code. Below, let's take a look at the implementation of the PIN. You need to achieve all pure virtual functions of the base class, such as Checkmediatype, etc. In Checkmediatype, you can check the media type to see if it is what you expect. Because most Filter uses push mode transmission data, the Receive method is generally implemented on the input PIN. Some base classes have already implemented Receive, and a pure virtual function is left on the Filter class for data processing. In this case, there is generally no need to overload the Receive method unless the realization of the base class does not meet your actual requirements. And if you overrupt the Receive method, you generally overload the following three functions endofstream, beginflush, and endflush. Let's take a look at the implementation of the output PIN.
Under normal circumstances, you have to implement all the pure virtual functions of the base class, except for the media type check, usually there is DecideBuffersize to determine the size of the memory using memory, GetMediaType provides supported media types. Finally, let's take a look at the implementation of the FILTER class. First of all, all pure virtual functions of the base class must be implemented. In addition, Filter also implements CREATEINSTANCE to provide COM's entrance to implement NondelegatingQueryInterface to expose supported interfaces. If we have created a custom input, output PIN, usually we also overload two functions of getPinCount and getpin.
Here I mainly for example, so Simple written Filter does not have a PIN interface, but in my demo, it is an Out PIN and an Input Pin.
The definition of my Filter class is as follows:
Class CMYFILTER: PUBLIC CCRITSEC, Public CBASEFILTER
{
PUBLIC:
CMYFILTER (TCHAR * PNAME, LPUNKNOWN PUNK, HRESULT * HR);
Virtual ~ CMYFILTER ();
Static Cunknown * WinAPI CreateInstance (LPunknown Punk, HRESULT * PHR);
CBasepin * getpin (int N);
INT getpincount ();
}
Note: Because the base class is a purely virtual base class, you must derive a pure virtual function in your Filter, otherwise your derived class is also a pure virtual class, you are creating this COM component object When you are, you can't create an object.
2 Generate a CLSID for your own Filter
You can generate a 128-bit ID number with GUIDgen or uuidgen to generate a 128-bit ID number, then use the define_guid macro to declare the Filter's CLSID;
[myfilter.h]
// {1915C5C7-02AA-415F-890F-76D94C85AAF1}
Define_guid (CLSID_MYFILTER,
0x1915c5c7, 0x2aa, 0x415f, 0x89, 0x1, 0x76, 0x29, 0x4c, 0x85, 0xaa, 0xf1);
This CLSID_MYFILTER is used in the class factory, and it is also used when registering the Filter.
3 Simple implementation of CMYFILTER class
This class is purely for demonstration, so it is especially simple. You can refer to my Demo, which is more written by Filter.
CMYFILTER :: CMYFILTER (Tchar * PNAME, LPUNKNOWN PUNK, HRESULT * HR)
: CBASEFILTER ("My Filter", Punk, this, CLSID_MYFILTER)
{}
CMYFILTER :: ~ CMYFILTER ()
{}
// Public Method That Returns A New Instance.
Cunknown * WinAPI CMYFILTER :: CreateInstance (LPunkNown Punk, HRESULT * PHR)
{
CMYFILTER * PFILTER = New CMYFILTER (Name ("My Filter", PUNK, PHR);
IF (pfilter == null)
{
* pHR = E_OUTOFMEMORY;
}
Return Pfilter;
}
CBasepin * CMYFILTER :: getpin (int N)
{
Return NULL;
}
Int CMYFILTER :: getpincount ()
{
Return 0;
}
This is basically implemented, but this filter does not contact it, but the basic process of implementing Filter is like a logical thing, such as how Filter and PIN are connected, how the data flow is flowing You have to look at SDK, follow these steps you can write a Filter framework.
Below we summarize it to write a Filter requires at least those things.
1 Filter implementation class
Here is the CMYFILTER class, you can implement your own logical features in this class, including define your Filter's feature, give your Filter equipped with a PIN interface, etc.
2 COM components lead functions
Five full bureau functions
Entrance function of Dllmain // DLL
DllgetClassObject // Get Class Factory of COM Components
DllcanunloadNow // COM components can be uninstalled
DllRegisterServer // Register COM components
DllunregisterServer // Uninstall COM components
Where DllgetClassObject has completed yourself by the base class, you can do three functions, Dllmain, DllregisterServer, DllunregisterServer.
3 COM components class factory object
The class object is used to generate a Filter object, and the template class used to define a global template class object, and the general format is as follows.
CFactoryTemplate G_Templates [1] =
{
{
L "my filter", // name
& Clsid_myfilter, // Filter's CLSID
CMYFILTER :: CREATEINSTANCE, // Create a Filter method
Null, // Initialization function
& Sudinftee // Filter information (a structure)
}
}
INT g_ctemplates = sizeof (g_templates) / sizeof (g_templates [0]);
4 Information about your own defined Filter and PIN information
These are a global structural variable for describing your Filter and your defined PIN, which will be used when registering Filter, as follows
AMOVIESETUP_FILTER Description a Filter
Amoviesetup_pin Description Pin
AMOVIESETUP_MEDIATYPE Description Data Type
The following code describes a Filter with an Output Pin
Static const wchar g_wszname [] = l "some filter";
Amoviesetup_mediatype sududiatypes [] = {
{& Mediatype_video, & mediasubtype_rgb24},
{& Mediatype_video, & mediasubtype_rgb32},
}
Amoviesetup_pin sudoutputpin = {
L "", // obsolete, not used.
False, // is this pin rendered?
True, // is it an output pin? False, // can the filter create Zero Instances?
FALSE, / / DOES THE FILTER CREATE MULTIPLE INSTANCES?
& Guid_null, // Obsolete.
NULL, // Obsolete.
2, // Number of Media Types.
Sudmediatypes // Pointer to Media Types.
}
Amoviesetup_filter sudfilterReg = {
& Clsid_somefilter, // filter clsid.
g_wszname, // filter name.
MERIT_NORMAL, // Merit.
1, // Number of Pin Types.
& Sudoutputpin // Pointer to Pin Information.
}
Finally, SudfilterReg will be used in an array of class factory objects.
CFactoryTemplate G_Templates [1] =
{
{
L "my filter", // name
& Clsid_myfilter, // CLSID
CMYFILTER :: CreateInstance, //Method to create an instance of mycomponent
Null, // Initialization function
& SudfilterReg // Set-Up Information (for filters)
}
}
Finally, if you still debug, see if you contain the header file below.
#include
#include
Wisdom of fish Aoosang 2004-09-01