Create a filter instance (transform filter)

Source: Internet
Author: User

 

Create a filter instance (transform filter)

1. Select the purpose of the filter to be created and select the base class accordingly. The base class can be selected from ctransformfilter, ctransinplacefilter, cvideotransformfilter, and cbasefilter.
(1) Ctransinplacefilter provides a mechanism for processing samples locally(Sample can be considered to store the structure of a video frame.) When a trans-in-place filter receives a sample, you can reload its transform () function to modify the data. The trans-in-place filter will pass the sample directly to the next filter after the transform () function is executed.
(2) The function of ctransformfilter is the same as that of ctransinplacefilter, The difference is that ctransformfilter always copies the sample passed by the upstream filter and passes the copied sample to the next filter.. Of course, you can control this process by reloading the transform () function, including modifying the data (this is also the reason for writing the filter by yourself ).
(3) cvideotransformfilter is the same as ctransformfilter, Added quality control functions.
(4) All the above three filters inherit from cbasefilter.So if you want to control the filter more, you need to inherit it directly from the cbasefilter, but you have to do the most.
In this example, I chose ctransformfilter because the ctransinplacefilter is too simple. In the dx9sdk example, nullnull is a complete ctransinplacefilter framework, and it is only a framework, and nothing is done, if you want to use it, you can directly modify it.
2. Select Win32 DLL in VC and create a DLL. The name can be obtained at will. Here, I select splitfilter and select null DLL. 3. Create a class csplitfilter that inherits from ctransformfilter. select public. 4. Generate a CLSID for the filter. You can use guidgen. It is used to create guidgen in the command line, and press enter to run guidgen, click new guid to generate a new guid. Click copy to copy the new guid to the clipboard. Then paste it in the splitfilter. h file, and finally it looks like this:
//////////////////////////////////////// //////////////////////////////
// Guid
//////////////////////////////////////// //////////////////////////////
// {3dcd790f-b7a0-429a-b9e1-3ce3255d8d1c}
Define_guid (<Name>,
0x3dcd790f, 0xb7a0, 0x429a, 0xb9, 0xe1, 0x3c, 0xe3, 0x25, 0x5d, 0x8d, 0x1c );

Replace <Name> with the name you set, as shown below:
// {3dcd790f-b7a0-429a-b9e1-3ce3255d8d1c}
Define_guid (clsid_splitfilter,
0x3dcd790f, 0xb7a0, 0x429a, 0xb9, 0xe1, 0x3c, 0xe3, 0x25, 0x5d, 0x8d, 0x1c); then in splitfilter. # include <initguid. h> modify the constructor in the following format:
Csplitfilter: csplitfilter (): ctransformfilter (name ("splitfilter"), 0, clsid_splitfilter)
{
} 5. Media Processing type
First, you must understand that, Two filters are connected, that is, the output pin and input pin of the two filters are connected. This operation is initiated by the output pin and the input pin is used to check whether the media type matches, and decide whether to accept the connection.In ctransformfilter, it is done by ctransformfilter to negotiate the media type. This work should have been done by the pin, however, the pin in ctransformfilter simply calls the corresponding function in ctransformfilter. All our work is to overload the three virtual functions in ctransformfilter: (1) Implement checkinputtype (const cmediatype * mtin) This function is called by the input pin., When the upstream output pin is to be connected, The input pin of the filter calls this function to check whether the media type of the output pin is supported.The cmediatype class encapsulates the am_media_type structure. am_media_type contains the relevant media types. For details, see the dxsdk documentation. I will write a framework here to demonstrate it for you. The function is just to pass the sample, and there is no modification to the data, so any format is acceptable, so no matter what format we should return OK, the actual function is as follows:
Hresult csplitfilter: checkinputtype (const cmediatype * mtin)
{
// Everything is good.
Return s_ OK;
} (2) Implement getmediatype (INT iposition, cmediatype * pmediatype)
We have already talked about the function used when the PIN is input to accept the connection. This function is used when the PIN is input for the connection, the output pin must first have a list of supported media types for connection. This function is used to generate this list. In fact, we can also directly return an OK message, but this is a bit too irresponsible. Although we do not do anything, we still need to finish the routine check, in this way, the boss (filter graph) will be very satisfied when he sees it. Do you agree very well?
First, we need to determine whether the input pin is connected. If the input pin is not connected, it makes no sense to connect to the following filter, because no data is transmitted from the upstream, what do we get for the filter? The pie cannot satisfy your hunger :)
Assert (m_pinput-> isconnected (); then, check whether the pin position is correct.
If (iposition <0)
{
Return e_invalidarg;
}
The final result of this function is as follows:
Hresult csplitfilter: getmediatype (INT iposition, cmediatype * pmediatype)
{
// Is the Input Pin connected
If (m_pinput-> isconnected () = false)
{
Return e_unexpected;
}

// This shoshould never happen

If (iposition <0)
{
Return e_invalidarg;
}

// Do we have more items to offer
If (iposition> 0)
{
Return vfw_s_no_more_items;
}

Checkpointer (pmediatype, e_pointer );

* Pmediatype = m_pinput-> currentmediatype ();
Return noerror;
}(3) Implement checktransform (const cmediatype * mtin, const cmediatype * mtout)
Although the input and output pin media types have been negotiated, it is still unknown whether our filter can complete the conversion of the two media types. Therefore, we need to call checktransform.Determine whether our filter supports the conversion of these two media types. Here I choose to directly Return OK. 6. Set the distributor
Although we have completed media type matching, but the filter connection is not complete, Our pin must also select Allocator for the connection and set Allocator attributes, such as the buffer size and quantity.. You do not need to enter a pin, because by default, it only needs to agree to output the Allocator provided by the pin,However, the Allocator output of the pin should be handled by ourselves.
If the following filter provides an allocator, the output pin can use this allocator. Otherwise, a new allocator is created.This requires the decidebuffersize (imemallocator * palloc, allocator_properties * pprop) of ctransformfilter. palloc is a Allocator pointer, and pprop is a allocator_properties struct, representing the Allocator attribute required by the filter.In this function, we can set the attributes of Allocator based on the needs of our own filter and the needs of the following filter,You can use the imemallocator: setproperties function to set Allocator attributes.
The most important thing here is to set the buffer size.
Generally, it is determined by the size of the Input Pin media type. If there is no fixed size from here, we have to guess the buffer size.
The final function is as follows:
Hresult csplitfilter: decidebuffersize (imemallocator * palloc, allocator_properties * pproperties)
{
Checkpointer (palloc, e_pointer );
Checkpointer (pproperties, e_pointer );

// Is the Input Pin connected
If (m_pinput-> isconnected () = false)
{
Return e_unexpected;
}

Hresult hR = noerror;
Pproperties-> cbuffers = 1;
Pproperties-> cbbuffer = m_pinput-> currentmediatype (). getsamplesize ();

Assert (pproperties-> cbbuffer );
// If we don't have fixed sized samples we must guess some size
If (! M_pinput-> currentmediatype (). bfixedsizesamples)
{
If (pproperties-> cbbuffer <100000)
{
// Nothing more than a guess !!
Pproperties-> cbbuffer = 100000;
}
}

// Ask the allocator to reserve us some sample memory, note the Function
// Can succeed (that is return noerror) but still not have allocated
// Memory that we requested, so we must check we got whatever we wanted

Allocator_properties actual;

HR = palloc-> setproperties (pproperties, & Actual );
If (failed (HR ))
{
Return hr;
}

Assert (Actual. cbuffers = 1 );

If (pproperties-> cbuffers> Actual. cbuffers |
Pproperties-> cbbuffer> Actual. cbbuffer)
{
Return e_fail;
}

Return noerror;
}
7. Process Data
Finally, we can start to process the data,We reload the transform (imediasample * psource, imediasample * pdest) to process the data.We can literally see the meaning of the two samples, because we do nothing here, so we only need to copy the source sample to the target sample. This function is as follows:
Hresult csplitfilter: Transform (imediasample * pin, imediasample * pout)
{
Hresult hR =Copy (pin, pout );
Return hr;
}
The function copy is used, and the code is as follows:
Hresult csplitfilter: Copy (imediasample * psource, imediasample * pdest) const
{
Checkpointer (psource, e_pointer );
Checkpointer (pdest, e_pointer );

// Copy the sample data
Byte * psourcebuffer, * pdestbuffer;
Long lsourcesize = psource-> getactualdatalength ();

# Ifdef debug
Long ldestsize = pdest-> getsize ();
Assert (ldestsize> = lsourcesize );
# Endif

Psource-> getpointer (& psourcebuffer );
Pdest-> getpointer (& pdestbuffer );

Copymemory (pvoid) pdestbuffer, (pvoid) psourcebuffer, lsourcesize );

// Copy the sample times

Reference_time timestart, timeend;
If (noerror = psource-> gettime (& timestart, & timeend ))
{
Pdest-> settime (& timestart, & timeend );
}

Longlong mediastart, mediaend;
If (psource-> getmediatime (& mediastart, & mediaend) = noerror)
{
Pdest-> setmediatime (& mediastart, & mediaend );
}

// Copy the sync point Property

Hresult hR = psource-> issyncpoint ();
If (hR = s_ OK)
{
Pdest-> setsyncpoint (true );
}
Else if (hR = s_false)
{
Pdest-> setsyncpoint (false );
}
Else
{// An unexpected error has occured...
Return e_unexpected;
}

// Copy the media type

Am_media_type * pmediatype;
Psource-> getmediatype (& pmediatype );
Pdest-> setmediatype (pmediatype );
Deletemediatype (pmediatype );

// Copy the preroll Property

HR = psource-> ispreroll ();
If (hR = s_ OK)
{
Pdest-> setpreroll (true );
}
Else if (hR = s_false)
{
Pdest-> setpreroll (false );
}
Else
{// An unexpected error has occured...
Return e_unexpected;
}

// Copy the discontinuity Property

HR = psource-> isdiscontinuity ();

If (hR = s_ OK)
{
Pdest-> setdiscontinuity (true );
}
Else if (hR = s_false)
{
Pdest-> setdiscontinuity (false );
}
Else
{// An unexpected error has occured...
Return e_unexpected;
}

// Copy the actual data length

Long ldatalength = psource-> getactualdatalength ();
Pdest-> setactualdatalength (ldatalength );

Return noerror;
}
8. Added support for com.
Because filter is a COM component, it must comply with the COM specification.
Because ctransformfilter is inherited from cunknown, you do not need to implement addref and release by yourself,If weIf you have an interface defined by yourself, you must implement QueryInterface by yourself,Fortunately, this filter does not implement its own defined interface, so we don't have to worry about it.
Okay, let's talk a little bit and start:
First, create a static method to return an instance of our filter.The name of this method can be specified at will, but it is generally called createinstance. Then we can take this name. The parameters of this function are as follows (including the General Code ):
Cunknown * winapi csplitfilter: createinstance (lpunknown punk, hresult * phr)
{
Csplitfilter * pfilter = new csplitfilter ();
If (pfilter = NULL)
{
* Phr = e_outofmemory;
}
Return pfilter;

}

Then, declare a global cfactorytemplate class ArrayThe name is g_templates. Each cfactorytemplate instance contains the registration information of a filter or our defined interface, because we only have one filter and no custom interface, so there is only one item in the array.
Cfactorytemplate g_templates [] =
{
{
L "splitfilter ",
& Clsid_splitfilter,
Csplitfilter: createinstance,
Null,
Null
}
};
Int g_ctemplates = sizeof (g_templates)/sizeof (g_templates [0]); Finally, implement the DLL registration function
Stdapi dllregisterserver ()
{
Return amoviedllregisterserver2 (true );
}
Stdapi dllunregisterserver ()
{
Return amoviedllregisterserver2 (false );
}

Plus # include <streams. h>
Introduce static library strmbasd. Lib msvcrtd. Lib winmm. Lib
 Finally, create the exported file splitfilter. Def., The content is as follows:
Library splitfilter. Ax

Exports
Dllmain private
Dllgetclassobject private
Dllcanunloadnow private
Dllregisterserver private
Dllunregisterserver private

In this way, we can establish a basic filter framework.

Of course, if you want to play HD videos, you can increase the memory size if the memory allocated on the distributor is insufficient, that is, try to increase the memory size at first, I reported an error when I tested 2732X768, but I added 0 to the allocated memory.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.