- Author: Space Hero - Published: 2004-7-21 0: 59: 36-- DirectShow System Getting Started Guide Getting Started Guide DirectShow streaming media system, with its complexity and technicality, it has been well received by industry attention. Alternatively with the popularity of the Internet, the wide application of streaming media on the network, how to make the process of streaming simply and have gradually become focus issues. Choose a suitable application plan for half a power. At this point, Microsoft's DirectShow gives us a good choice. DirectShow is a development package provided by Microsoft's streaming of streaming on the Windows platform, which is posted with the DirectX development package. Currently, DirectX is the latest version of 8.1 (Tang: There is DirectX9 now). So what can DirectSHOW? It is also seen that DirectShow provides powerful support for the capture and playback of multimedia streams. Using DirectShow, we can easily capture data from the acquisition card that supports the WDM drive model, and performs corresponding post-processing or even stored in the file. It is widely supported in various media formats, including ASF, MPEG, AVI, DV, MP3, WAVE, etc., making the playback of multimedia data becomes light. In addition, DirectShow also integrates the technology of DirectX, such as DirectDraw, DirectSound, directly supports DVD playback, nonlinear editing of video, and exchange of data with digital cameras. What is more worth mentioning is that DirectShow provides an open development environment, we can customize your components according to your needs. DirectShow uses a model called Filter Graph to manage the processing of the entire data stream; each functional module participating in data processing is called Filter; each filter is connected to a "pipeline" collaborative work in a certain order in Filter Graph. Everyone can see that Filter is roughly divided into three categories: Source Filters, Transform Filters and Rendering Filters. Source filters is responsible for obtaining data, the data source can be a file, an Internet, or a capture card, a digital camera, or the like, then transfer data down; Transform Fitlers is responsible for the format conversion, transmission of data; rendering filter is responsible for data Finally, we can give the data to the sound card, the graphics card for multimedia demonstration, or output to the file for storage. It is worth noting that the three parts are not only one filter to complete the function. On the contrary, each part often has several Fitler synergy. For example, Transform Filters may contain an MPEG decoding filter, as well as convertible Filter, video color space, audio sampling frequency conversion filter, and more. In addition to the large amount of Filter provided by the system, we can customize your own Filter to complete the features we need. The following figure is a typical AVI file playback Filter Graph link: On the DirectShow system, we see, that is, our app. The application is to establish the corresponding Filter Graph in accordance with certain intentions, and then control the entire data processing process via Filter Graph Manager. DirectSHOW can receive a variety of events when Filter Graph run, and send it to our application by messaging.
In this way, the interaction between the application and the DirectShow system is realized. The following figure shows the general process of DirectShow application development: the above brief introduction DirectShow system structure, I hope that everyone has a probably aware of this strong application framework. If you are interested, you can study DirectX's help documentation in detail. DirectShow is a powerful development package; in addition, it is CoM, so some basic knowledge of COM programming is required. For how to learn how to learn the DirectShow application structure, please refer to the author's follow-up article. The author will tell the experience in the actual work from the perspective of programming. From below, we must further explore the application of DirectShow from the perspective of programmers and development of Filter. Prior to this, the author first had to take a FILTER test tool provided by Microsoft - Graphedit, its path in dxsdk // bin // DxUtils // graphedit.exe. (If you haven't installed DirectX SDK yet, please download it on Microsoft's website.) Through this tool, we can visually see the Filter Graph's operation and processing processes, so that we can make program debugging. (If you have a computer in your hand, what are you waiting for, you will experience it: Run your graphedit, perform file-> render media file ... Select a media file; after the Filter Graph builds successfully, press the toolbar's run button; you It can be seen that the media files just selected are played back! See it, write a media player is also the same!) Next, we will talk about the development of Filter. Learn the development of DirectShow Filter, not more than the following ways: see help documents, see example code and see SDK base class source code. See the help documentation should focus on the overall concept of understanding; see the example code should be in synchronization with the research of the base source code, because you write Filter, the key first step is to select a suitable Filter base class and PIN base class . For Filter's grasp, it is generally considered to master the following three aspects: the connection between the Filter PIN connection, the data transfer between the FITER and the random access of the streaming (or the positioning of the stream). The following will be set forth below. The connection between the Filter Pin is actually a negotiation process of the Media Type (media type) between the PIN. The connection always points from the output PIN to the input PIN. To learn more about the specific connection process, you must study the SDK's base source code (located in DXSDK // Samples // MultiMedia // DirectShow // Baseclasses // Amfilter.cpp, CBASepin's Connect method). The approach process of the connection is to connect all media types on the input PIN of enumeration, and use these media types one by one to connect to the output PIN. If the output PIN is also accepted, the connection between the PIN is successful; if All media type output PINs that enumerate on the input PIN do not support, and enumerate all media types on the PIN, and use these media types one by one to connect to the input PIN. If you enter a media type of the PIN accepts, the connection between the PIN also declares successfully; if all media types on the PIN are output, the input PIN does not support, the connection process between the two PINs declares failed .
One thing to note is that the above input PIN is generally not the same filter, typically the previous FILTER (also called Upstream Filter) output PIN is connected next to FILTER (also called DownStream Filter). Enter the PIN. When the connection between the Filter's PIN is completed, that is, the connection between the two parties has obtained a media type that everyone supports by negotiation, and begins to prepare data transmission. In these preparations, the most important thing is that the negotiation of the memory distributor on the PIN is generally initiated by the output PIN. Between DirectShow filters, the data is transmitted through a packet, this packet is called SAMPLE. Sample itself is a COM object with a memory to load data, and SAMPLE is managed by the memory distributor (Allocator). A pair of outputs that have been successfully connected, the input PIN uses the same memory distributor, so the data is transferred from the output PIN to the input PIN is not required to copy. The typical data copy, typically occurs inside the FILTER, after reading data from the input PIN of the FILTER, performs a sense of intent, and then populates the data on the Filter's output PIN, then continue to transfer. Below, we will specifically explain the data transfer between the filter. First, everyone must distinguish between two main data transfer modes of Filter: Push Model and Pull Model. The so-called push mode, that is, the source filter (Source Filter) can generate data, and generally there is a separate sub-thread on its output PIN, which is responsible for sending data, common cases, such as the Live Source Filter of the capture card representing the WDM model; The so-called pull mode, that is, the source filter does not have the ability to send his own data. In this case, the general source filter is tightened with a Parser Filter or Splitter filter, which is generally independent on the input PIN. The sub-thread is responsible for continuously requesting data from the source filter, and then transmits the data after processing, common situations such as file sources. In the push mode, the source filter is active; pulling the mode, the source filter is passive. In fact, if the source filter and splitter filter in the Tula mode appear as another virtual source filter, the data transfer between the following filters is identical to the push mode. So how do data transferred by connecting PIN? First, look at the push mode. On the Filter input PIN behind the source filter, a IMEMINPUTPIN interface must be implemented, and the data is transmitted by calling the previous FILTER calling this interface. It is worth noting that (above has been mentioned), the data is transferred from the output PIN to the input PIN, and there is no memory copy, which is just a "notification" equivalent to the data arrival. Look at the pull mode. On the output PIN of the source FILTER, the output PIN under the pull mode, it must be implemented; the Splitter filter behind it is to obtain data by calling the request method or SyncRead method in this interface. Splitter Filter then calls the next level of Filter Enter the IMEMINPUTPIN Interface Receive method to implement data down transfer.
In-depth understanding of this part, please study the SDK's base source code (located in Dxsdk // Samples // BaseClasses // Source, // BaseClasses // Source.cpp and PULLPIN.CPP). Below, let's talk about a downstream positioning. In Graphedit, we can play it after we successfully build a Filter Graph. In playback, we can see that the progress bar is also advancing accordingly. Of course, we can also achieve random access by dragging progress bars. To do this, you should know how long the application level will play for how long is the current playback, or now, where is the location. So, how is this implementation at the Filter level? We know that several filters consist of Filter Graph through the interconnection of the PIN. This Filter Graph is managed by another COM object Filter Graph Manager. With Filter Graph Manager, we can get an iMediaseEKing interface to achieve the positioning of the convection media. In the Filter level, we can see that Filter Graph Manager begins with the last Filter (Rendere Filter), asks if the previous FILTER output PIN supports the iMediaseEKing interface. If support, return to this interface; if you do not support, continue in the first-level Filter to ask until the source filter. Generally, an iMediaseEKing interface is implemented on the output PIN of the source filter. It tells the caller how long is a total of media content, current playlings, etc. (If it is a file source, this interface is generally implemented in Parser Filter or Splitter Filter.) For Filter developers, if we write the source filter, we must implement the IMEDISEEKING interface on the Filter's output PIN; if written Is the middle transfer filter, only need to pass the user's acquisition interface request to the previous FILTER output PIN; if written is rendere filter, you need to request the user's acquisition interface request Give the previous FILTER output PIN. Further understanding, carefully study the SDK base class source code (in DXSDK // samples // achieve Multimedia // DirectShow // BaseClasses // transfrm.cpp class method implementation and ctlutil.cpp CTransformOutputPin :: NonDelegatingQueryInterface class of CPosPassThru ). We have introduced how to learn DirectShow Filter development, and some preparation knowledge before starting your own Filter. Next, the author will develop Filter's experience, teach you how to write its own filter.
- Author: Space Hero - Published: 2004-7-210: 59: 59-- how to write your own Filter First, VC project from the beginning (to make sure you have configured the DirectX VC development environment ). 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). (Tang: I don't quite understand this, the author is definitely not wrong, it is too low.) When the foundation 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. 1. Locking (LOCK) 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.
(Tang: These I haven't experienced yet, my skills are not enough) 2. Endofstream issues 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. (Tang: These are also what I have not involved. You should look at the source code!) 3. Media Seeking question In general, you only need to implement the NondelegatingQueryInterface method on the Filter's output PIN, when the user applies to get the IID_IMEDIAPSIAPosition interface or When the IID_IMEDIASEEKING interface is passed, the output PIN of the previous FILTER will be requested. 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 for data processing and send, you need to be particulartime, do not let the thread go to cycle, and let the thread process 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. (Do not understand this) 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 input PIN's CompleteConnect method, not In SetMediaType. DirectX Media Objects (DMOS), is another stream of stream data processes COM components provided by Microsoft. Dimo has a lot of similarities compared to DirectShow Filter. Familiar with the principle of Filter, will greatly help you learn from DMO. In addition, DMO is also highly respected due to its simple structure, easy to create and use.
- Author: Space Hero - Published: 2004-7-21 1: 00: 23-- DMO and filter contrast ratio 1. DMO filter function achieved much less, which makes the DMO "volume" is very small; 2. DMO uses more flexible than Filter. The use of DMO does not require Filter Graph, and the application can interact directly with DMO. And DMO can also work in a DirectShow environment through a DMO Wrapper filter; 3. DMO always processes data, unlike Filter's independent data transfer thread, you need to consider multi-threaded programming issues; 4. ACM with traditional codec manager ACM Compared to VCM, the codec development with DMO is based on COM, which is easier to expand. And the DMO supports multiple inputs and multiple outputs; 5. DMO does not need to assign data transfer like Filter, and DMO users are responsible; 6. DMO is a separate functional module, do not need to be connected as filter Link; 7. DMO does not need to "push" data like Filter, the input and output of data is done by the user of DMO; all of these advantages make DMOs become Microsoft's key recommendation modes for Encoder and Decoder development. DirectX 9.0 SDK, Microsoft has separated DMO from DirectShow, and for some transform filters, Microsoft also recommends replacing with DMO. About DMO's use, there are currently two: one is the application directly using DMO, the other is in DirectShow Filter. The latter is relatively simple, just using a DMO Wrapper Filter. In the DirectShow application, DMO is transparent to users, all of which use DMOs are done by DMO Wrapper Filter. See the code below.
// Create the DMO Wrapper filter.IBaseFilter * pFilter; HRESULT hr = CoCreateInstance (CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast