In the two stories, the author introduces the application principle of DirectShow and some of the preparatory knowledge before developing Filter. This lecture, the author will teach you how to write your own Filter.
First, start from the VC project (please confirm that you have configured the DirectX development environment to VC ). Write your own Filter, the first step is to use VC to build a Filter project. Since DirectX SDK provides a lot of Filter's example items (in the DXSDK / Samples / MultiMedia / DirectShow / Filters directory), the easiest way is to copy one, and then modify on this basis. But if you are a beginner developed by Filter, the author does not agree to do this.
It is also very simple to create a new Filter project. Use the vc wizard to create an empty "Win32 Dynamic-Link Library" project. Note that several files must be: .def file, define four export functions; define the .cpp file and .h file of the Filter class, and define the Filter's registration information in the .cpp file, and the two Filter registration functions. : DllRegisterServer and DllunregisterServer. (Note: Filter's registration information is the content written in the registration table when registering, and the format can refer to the sample code of the SDK, and the Filter-related GUID must use Guidgen.exe.) Next, the project setting (Project-> Settings ...). At this point, you can open an example item for an SDK for comparison, some macro definitions can be copied, and finally pay attention to change the extension of the output file to .ax.
The last talks have been mentioned that before writing Filter, choose a suitable Filter base class is critical. 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.
This is the case in the implementation of the Filter framework. You may also want to know how to implement a custom interface on the Filter, and how to implement the Filter's property page, and so on. Limited to the space, the author does not expand. In fact, these issues can find the answer in the SDK sample project. Others, some questions that should be paid attention to in actual programming, I have organized it for your reference.
Lock problem
The DirectShow application contains at least two threads: one main thread and a data transfer thread. Since it is multi-thread, it will definitely touch the problem of thread synchronization. Filter has two locks: Filter object lock and data lock. Filter object locks are used for Filter levels such as FILTER state transition, Beginflush, Endflush, etc .; data stream locks are used in data processing threads such as Receive, Endofstream, etc. If the two locks don't make it clear, it is easy to generate the deadlock of the program, this is especially reminded. 2. Endofstream problem
When the Filter receives this "message", it means that the data of the previous Filter has been sent. After that, if the receive is received, it should not be ignored. If Filter caching data on the input PIN, ensure that all cached data has been processed after receiving endofstream.
3. Media seeking problem
In general, you only need to implement the NondelegatingQueryInterface method on the Filter's output PIN, and the user requests the previous Filter output PIN when the user is applied. When Filter Graph is Mediaseek, Beginflush, Endflush, and NewSegment are generally invoked. If your Filter caching the data, you have to overload them and make a corresponding process. If your Filter is responsible for sending a timestamp sent out, then you should start from zero after mediaseeping.
4. About using specialized threads
If you use a dedicated thread to process and send, you need to be special, do not let the thread die cycle, and let the thread tension function can check the thread command. It should be ensured that the thread can also end properly when the Filter ends. Sometimes, you turn the Graphedit program, but the Graphedit process is still in memory, often because the data thread is not safe to close this reason.
5. How to get information from the media type
For example, you want to get the wide and higher information of the video image in the media type of the PIN connection, you should implement it in the completed completion in the PIN without in SetMediaType.