VC + DirectShow for image processing II

Source: Internet
Author: User
Download the source code of this Article

Please read this article first: One of VC + DirectShow Image Processing for videos

  Develop videorenderer Filter

Filter to do the following: accept the 24-bit RGB format image, which is obtained by the upper-level filter dismember the video, and process it into a 32-bit argb image, and then pass it to the external function for further processing.

The reason I want to filter is that almost all video filters accept the 24bit RGB format, so I don't have to worry about connection failure. 32bit argb can support MMX acceleration well, if MMX is used, I will introduce MMX in this article. However, it is basic to the same level as me. Calling external functions provides more flexibility, you don't have to worry about encapsulating the image processing function in the filter. You can add new processing functions when writing a program with higher capabilities and levels, and ensure timely processing.

How about filter? It's very easy to do. Similarly, writing a filter is easier than imagined. Let's look at it step by step.

Create a simple DLL project, set the name to VR, and delete VR. add vr to the dllmain function in CPP. H and VR. def two files, in VR. add the following code to Def to complete function export.

Library Vr

Exports

Dllmain private

Dllgetclassobject private

Dllcanunloadnow private

Dllregisterserver private

Dllunregisterserver private

Let's do something uncreative-filter registration, class factory definition, etc. Add it to VR. cpp. I copied it from the filter example of DirectShow, and then added and modified it.

# Include "stdafx. H"
# Include "Vr. H"
# Pragma comment (Lib, "strmbase. lib ")
# Pragma comment (Lib, "winmm. lib ")

// Setup data

Const amoviesetup_mediatype sudippintypes =
{
& Mediatype_video, // majortype
& Mediasubtype_null // minortype
};

Const amoviesetup_pin sudippin =
{
L "input", // The pins name
False, // is rendered
False, // is an output pin
False, // allowed none
False, // allowed enabled
& Clsid_null, // connects to filter
Null, // connects to pin
1, // number of types
& Sudippintypes // pin details
};

Const amoviesetup_filter sudvrax =
{
& Clsid_lwvideorenderer, // filter CLSID /**/
L "lwvideorenderer", // string name /**/
Merit_normal, // filter merit
1, // Number of pins
& Sudippin // pin details
};

// List of class IDs and creator functions for the class factory. This
// Provides the link between the OLE entry point in the DLL and an object
// Being created. The class factory will call the static createinstance
// Function when it is asked to create a clsid_videorenderer object

Cfactorytemplate g_templates [] = {
{L "lwvideorenderer "/**/
, & Clsid_lwvideorenderer /**/
, Cvideorenderer: createinstance
, Null
, & Sudvrax },
};

Int g_ctemplates = sizeof (g_templates)/sizeof (g_templates [0]);
// Dllregisterserver
// Used to register and unregister the filter
Stdapi dllregisterserver ()
{
Return amoviedllregisterserver2 (true );
} // Dllregisterserver

// Dllunregisterserver

Stdapi dllunregisterserver ()
{
Return amoviedllregisterserver2 (false );
} // Dllunregisterserver

Extern "C" bool winapi dllentrypoint (hinstance, ulong, lpvoid );

// Dllmain

Bool apientry dllmain (handle hmodule, DWORD dwreason, lpvoid lpreserved)
{
Return dllentrypoint (hinstance) (hmodule), dwreason, lpreserved );
} // Dllmain

After some replication, some simple business logic needs to be added. Let's first complete the definition of the filter class, and derive a new class from cbasevideorendeer. Rewrite the four functions to lay the basic function of the filter, as shown below, and add it to VR. h.

# Include <streams. h>

// Callback class definition

Class funcls

{Public: Virtual void procfun (bitmapinfo * pbmpinfo, byte * pb) {return ;};
};

// Callback function pointer Definition

Typedef void (callback * pprocfun) (bitmapinfo * pbmpinfo, byte * pb );

// {F81331DB-2E46-43e7-8709-BE57205D8914} Global identifier of the filter

Static const guid clsid_lwvideorenderer =
{0xf81331db, 0x2e46, 0x43e7, {0x87, 0x9, 0xbe, 0x57, 0x20, 0x5d, 0x89, 0x14 }};
// Filter class definition
Class cvideorenderer: Public cbasevideorenderer
{
Public:
// Create a process.
Static cunknown * winapi createinstance (lpunknown, hresult *);
// Constructor and constructor
Cvideorenderer (lpunknown punk, hresult * phr );
~ Cvideorenderer ();
Public:
// Check whether data in acceptable format is available
Hresult checkmediatype (const cmediatype * PMT );
// Set the specific data format, such as the width and height of the video image
Hresult setmediatype (const cmediatype * PMT );
// Submit the data to display and present the data
Hresult dorendersample (imediasample * pmediasample );
PRIVATE:
Bitmapinfo m_bmp Info; // Image Information
Byte * m_pcopybuffer; // copy the buffer
Uint m_pixelnum; // number of pixels
Funcls * m_pfuncls; // callback class pointer
Pprocfun m_ppf; // callback function pointer
};

I mentioned above that an external function is called for processing when new data is received in the filter, So I defined a callback class (what I call) and a callback function pointer. In this way, the callback class can be used as a base class of the MFC View class to conveniently use the member variables in the MFC View class. The callback function pointer can be used to play multiple video files and use multiple cameras at the same time. This is what I felt necessary in use and was later modified to make the use of filter flexible enough. The following describes the specific implementation of functions in the filter class.

// ================================================ ==================================
// Create a process.

Cunknown * winapi cvideorenderer: createinstance (lpunknown punk, hresult * phr)
{
Return new cvideorenderer (punk, PHR );
}

// ================================================ ==================================
// Constructor

Cvideorenderer: cvideorenderer (lpunknown punk, hresult * phr): cbasevideorenderer (clsid_lwvideorenderer, "LW video Renderer", punk, PHR)
{
M_pcopybuffer = NULL;
M_pfuncls = NULL;
M_ppf = NULL;
M_pixelnum = 0;
}

// ================================================ ==================================
// Destructor

Cvideorenderer ::~ Cvideorenderer ()
{
If (this-> m_pcopybuffer ){
Delete [] m_pcopybuffer;
}
}

// ================================================ ==================================
// Check the media type

Hresult cvideorenderer: checkmediatype (const cmediatype * PMT)
{
Videoinfo * PVI;
// Only accept videos
If (* PMT-> formattype ()! = Format_videoinfo ){
Return e_invalidarg;
}
// Only accept the rgb24 format, that is, 1 byte for R, G, and B
PVI = (videoinfo *) PMT-> Format ();
If (isequalguid (* PMT-> type (), mediatype_video) & isequalguid (* PMT-> subtype (), mediasubtype_rgb24 )){
Return s_ OK;
}
Return e_invalidarg;
}

// ================================================ ==================================
// Set the media type to obtain various information (width and height) of the image, which must be used to process the image

Hresult cvideorenderer: setmediatype (const cmediatype * PMT)
{
Videoinfo * pvibmp; // bitmap info Header
Pvibmp = (videoinfo *) PMT-> Format ();
Memset (& m_bmp info, 0, sizeof (bitmapinfo); // Reset
M_bmp info.bmiheader = pvibmp-> bmiheader;
// Change to 32bit because I will process it as 32bit
M_bmp info.bmiheader.bibitcount = 32;
// Of course, the buffer size also changes
M_bmp info.bmiheader.bisizeimage = m_bmp info.bmiheader.bisizeimage * 4/3;
// Create a buffer for the new 32bit Image
If (m_pcopybuffer) {Delete [] m_pcopybuffer ;}
M_pcopybuffer = new byte [m_bmp info.bmiheader.bisizeimage];
M_pixelnum = m_bmp info.bmiheader.biwidth * m_bmp info.bmiheader.biheight;
Return s_ OK;
}

// ================================================ ==================================
// Process media sampling

Hresult cvideorenderer: dorendersample (imediasample * pmediasample)
{
// Obtain the sampled data area pointer, that is, the data area pointer of the 24bit Image
Byte * pb = NULL;
Pmediasample-> getpointer (& Pb );
If (! PB ){
Return e_fail;
}
// Lock! Lock the data area I want to operate on to prevent errors caused by interruptions when half of the data is processed.
// It is actually the type of the critical section that is often used in multi-threaded programming,
// Use constructor and constructor to enter and exit the critical section
// M_rendererlock is a member of cbasevideorenderer and can be inherited.
Cautolock (& this-> m_rendererlock );
// Process a 24bit image into a 32bit Image
Byte * pb32 = m_pcopybuffer; // pointer to the 32bit Buffer
For (uint I = 0; I <m_pixelnum; I ++ ){
Pb32 [0] = Pb [0];
Pb32 [1] = Pb [1];
Pb32 [2] = Pb [2];
Pb32 [3] = 0xff; // 0xff is 255
Pb + = 3;
Pb32 + = 4;
}
// If a callback class exists, perform callback processing.
If (m_pfuncls ){
M_pfuncls-> procfun (& m_bmp info, m_pcopybuffer );
}
// If a callback function exists, process it.
If (m_ppf ){
M_ppf (& m_bmp info, m_pcopybuffer );
}
Return s_ OK;
}

So far, a simple filter is complete, and the compilation is successful. Then, you can use regsvr32.exe for registration and go to graphedit.exe for testing. However, if you want to use it in a program, you will find that you cannot set a callback function or callback class. This filter is so useless that we don't get anything useful except the basic functions of the ibasefilter interface. Therefore, you have to write an interface for it so that we can set something. Writing an interface is not difficult. As long as there is an interface Example, anyone can compare and write one, And I copied one. Create an ivrcontrol. h file and add the following code.

// {244df760-7e93-4cf0-92f4-dcb79f646b7e} interface guid

Static const guid iid_ivrcontrol = {0x244df760, 0x7e93, 0x4cf0, {0x92, 0xf4, 0xdc, 0xb7, 0x9f, 0x64, 0x6b, 0x7e }};

// Interface Definition

Declare_interface _ (ivrcontrol, iunknown)
{
Stdmethod (getbmp info) (This _ // Method 1: Get Image Information
Bitmapinfo ** ppbmp info) pure;

Stdmethod (getpointer) (This _ // Method 2: Get the buffer pointer
Byte ** ppb // pointer of the buffer pointer) pure;

Stdmethod (setfuncls) (This _ // method 3: Set the callback class
Funcls * pfuncls // callback class pointer) pure;

Stdmethod (setfun) (This _ // Method 4: Set the callback function
Pprocfun PPF) pure;
};

After writing the interface, you need to implement it. Add # include "ivrcontrol. H" to VR. H, and use the interface as a base class of the filter class, as shown in the following figure:

Class cvideorenderer: Public cbasevideorenderer, public ivrcontrol

Add interface functions and query interface functions to the cvideorenderer class:

// The query interface, which is generally not required, but the interface needs to be used here and is also reloaded
Stdmethodimp nondelegatingqueryinterface (refiid riid, void ** GMM );
// Interface function
Declare_iunknown;
Stdmethodimp getbmp Info (bitmapinfo ** ppbmp info );
Stdmethodimp getpointer (byte ** ppb );
Stdmethodimp setfuncls (funcls * pfuncls );
Stdmethodimp setfun (pprocfun PPF );

Then add the specific implementation code of the above function to VR. cpp:

// ================================================ ==================================
// Query interface

Stdmethodimp cvideorenderer: nondelegatingqueryinterface (refiid riid, void ** bp)
{
Checkpointer (GMM, e_pointer );
If (riid = iid_ivrcontrol ){
// Return interface. Here is the details: When an interface is returned, the reference count of the filter will be added, so the external program will release the interface after it is used up.
Return getinterface (ivrcontrol *) This, GMM );
} Else {
Return cbasevideorenderer: nondelegatingqueryinterface (riid, GMM );
}
}

// ================================================ ==================================
// The specific implementation of the interface function is as follows, but the assignment is simple.

Stdmethodimp cvideorenderer: getbmp Info (bitmapinfo ** ppbmp info)
{
* Ppbmp info = & this-> m_bmp Info;
Return s_ OK;
}

Stdmethodimp cvideorenderer: getpointer (byte ** ppb)
{
* Ppb = m_pcopybuffer;
Return s_ OK;
}

Stdmethodimp cvideorenderer: setfuncls (funcls * pfuncls)
{
M_pfuncls = pfuncls;
Return s_ OK;
}

Stdmethodimp cvideorenderer: setfun (pprocfun PPF)
{
M_ppf = PPF;
Return s_ OK;
}

I don't know if you have noticed that the interface is actually a virtual base class. Classes are everywhere in modern programming languages such as C ++, and there is nothing to be surprised about, but it is helpful for better understanding. Another, seemingly powerful interface may be easily implemented. It depends on the object, and its complexity may be hidden in the object.

We can see that the callback class and callback function pointer definitions are also used in the interface definition, So I move them together with the definition of filter CLSID to ivrcontrol. h file. When this filter is used, only ivrcontrol is enabled. h. Just include this file.

Good, we have written the filters in our imagination step by function. We have successfully completed the filter and compiled it in the release mode with more than 80 K, after UPX compression, it is more than 30 kb. In this way, the code looks like a lot, but I don't think it at all when I think about the code, because every function does very little, follow the logic rules, step by step to take a photo of the very easy.

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.