Dynamic reconstruction technology of Filter Graph

xiaoxiao2021-03-05  24

Author: Lu Qiming published in the "Chinese Information - Program Spring" 2003.9

From http://hqtech.nease.net/Article/ds_dynamicbuilding.htm Keyword DirectShow Dynamic Graph Building Filter Chain For any reason: (1) The application wants to insert into one in the process of playing a video Video Effect Filter; (2) Source Filter Changes Media Type during operation, you need to access a new decoding filter; (3) Application wants to join another video stream in Filter Graph; we need to have A Filter Graph is modified. The usual practice is to stop the Filter Graph and then restart after modification. So, is there a way to implement the reconstruction of Filter Graph while you can follow the Filter Graph running status? The answer is yes. Reconstruction of Filter Graph, including the following scenarios: MEDIA TYPE connected between the FILTER; increasing or deleting FILTER, re-performing a connection between the relevant FILTER (FILTER CHAIN). Below, we will discuss them separately. First see the first situation: MEDIA TYPE dynamic changes. Everyone knows that when two PIN connections are completed, there will be a two parties agreed to Media Type, which is used to describe the data formats transmitted between the two connection PINs. In general, this Media Type will not change during the entire process of Filter Graph. But in some special occasions, this MEDIA TYPE is required. How does DirectSHOW support? We also discuss the situation. 1. From the top down, Media Type changes, but the buffer of transmitting data does not need to be increased: as the above figure, the change of Media Type is initiated by the Output PiN of Filter A. First, Filter A calls IPIN :: QueryAccept or ipinconnection :: DynamicQueryAccept on Filter B, see if Filter B supports new Media Type. If support, Filter A calls IMEMALLOCATOR :: getBuffer to get an empty Sample, connect the new Media Type with Sample by iMediaSample :: setMediatype. Then, FILTER A can then transfer Sample to Filter B. When Filter B receives new Sample, you can get new Media Type by calling iMediaMple :: getMediaType. In general, FILTER B should have the ability to change the Media Type; this is what we should take into account when we write your own Filter. Filter A typically call QueryAccept to determine if the file b's INPUT PIN supports new Media Type. We can see from the implementation of CBasepin :: QueryAccept, it is just a checkmediatype method that calls the PIN. So QueryAccept returns S_OK and does not guarantee that Media Type can change success in Graph operation. Another reliable method is that if the INPUT PIN of Filter B supports the ipinconnection interface, call the DynamicQueryAccept method for this interface.

For Filter developers, we also need to pay attention to the implementation of CBaseInputpin :: Receive. We can see that this method first calls CheckStream to check the Filter's running status, followed by reading the attribute of the SAMPLE (saved to member variable am_props), and determine if the Media Type has changed. If Media Type changes, check calkmediatype is recalled. This is the DirectShow SDK base class to provide us, only, "immune ability" for MEDIA TYPE dynamic changes. In fact, for the support of Media Type dynamic changes, we also need to handle more details. This varies depending on the specific Filter task. 2. The Media Type changes from the bottom up, but the buffer that transmits data does not need to be increased: as the above figure, the change in Media Type is initiated by the Input Pin of Filter B. Note that there is a prerequisite here, that is, Filter B must have its own allocator (if Filter A has allocator, Filter B will not change Media Type). First FILTER B calls the QueryAccept of the Output PIN of Filter A to see if new Media Type is supported. If supported, the Filter B is included in the private way to change the next empty SAMPE MEDIA TYPE (because allocator is created by Filter B, so Filter B has a way to call iMediasample :: setMediatype for the next empty Sample :: SETMEDIATYPE without the need to pass public Interface method IMEMALLOCATOR :: getBuffer first takes the next empty Sample). Next, when Filter A calls iMallocator :: getBuffer to get a null Sample, you can get new Media Type via iMediaMple :: getMediatype. At this point, FILTER A must generate Sample data according to the new Media Type, and then pass it to Filter B. Filter B is confirmed by the MEDIA TYPE when receiving SAMPLE. Note that if Filter A can accept new Media Type, it should also be capable of restore to the original Media Type. This MEDIA TYPE dynamic changes are most common on Video Renderer Filter. Everyone may have discovered that the Media Type used in Video Rendere is RGB, but it sometimes has become YUV after running, and its working principle is as described above. Video Rendrer first uses RGB's Media Type connection, which is to take into account the application of GDI functions. For high efficiency, when you can use DirectDraw, Video Rendrer will require the last FILTER to output YUV format; DirectDraw Surface may be lost in the middle, and Video Rendrer will request the last level Filter to recover the RGB format to use the GDI function to draw. 3. Output Pin requires new Media Type, and requires a larger buffer to deliver new Sample: The above three cases, although Media Type changes, but Sample's buffer size does not need to be expanded.

When the new Media Type requires a larger buffer to transfer data, the last level of Filter must process: First, call the next level filter in IPIN :: ReceiveConnection; if successful returns, then call up in Output Pin IMEMALLOCATOR :: SetProperties Change the size of the buffer and reassign the memory. Then then call the ImeminputPin :: NotifyAllocator in Input PIN to use the new allocator. Note: Before making the above changes, be sure that all the old Media Type's SAMPLE is sent out. Look at the second situation: dynamically delete or increase the Filter. As shown above, we want to move Filter 2 to move. There are two necessary conditions: (1) Filter 3 (PIN D) must support the ipinconnection interface (this interface ensures that the Filter can also be re-connected in non-stopped state); (2) Filter is not allowed The data is transmitted, so blocking the data thread. If "reconnected" is initiated by Filter 1 (completed inside the FILTER), Filter 1 To synchronize this data sending thread; if "reconnect" is completed by the application, require Filter 1 (PIN A) to implement the IPInflowControl interface. . The general steps of dynamic reunion are as follows: (1) Blocking the data stream thread on Filter 1 (PIN A). IPINFLOWCONTROL :: Block can work in two modes of synchronization and asynchronous. Do not use the synchronization mode of the BLOCK function under the application main thread, as this may cause thread dead locks. Either use a Worker Thread or use the expiogram of the Block function. Below: // Create an eventHANDLE hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); if (hEvent = NULL!) {// Block the data flow.hr = pFlowControl-> Block (AM_PIN_FLOW_CONTROL_BLOCK, hEvent); if (SUCCEEDED (hr)) {// Wait for the pin to finish.dword dwres = WaitForsingleObject (HEVENT, DWMILLILLISECONDS);}} (2) Re-connect PIN A and PIN D, insert a new Filter if necessary. Here PIN's reunion can use IGraphConfig :: Reconnect or IgraphConfig :: Reconfigure (IGraphConfig interface can be obtained from Filter Graph Manager). Reconnect is simpler than Reconfigure, it is as follows: put the filter 2 in the stopped status, then remove it; add new Filter; reconnect the relevant PIN; place newly added Filter in paused Or Running Status to synchronize with the Filter Graph.

转载请注明原文地址:https://www.9cbs.com/read-36871.html

New Post(0)