Made a DirectShow's Filter, turn the RGB video stream into black and white

xiaoxiao2021-03-06  41

This DirectShow of this DirectShow belongs to Transform Filter. In the meantime, refer to the help documentation of DirectShow, an introduction of the foreign language DirectShow book (this book is good, the code inside, although it feels the ingredients of the copy directshow helps the document, but, it is very good), and VC There are two articles in the knowledge base, and these two articles are also very good. If I didn't look at the beginning, I would like a lot of detours.

It has been prepared for a long time to write the Transform Filter of DirectShow. I used to use DirectShow, but it is also a Filter Graph with ready-made Filter, and then Run is OK. Write the Filter as a very difficult thing. It is now found that it is not difficult to write transform filter, of course, it is just as simple as me. However, the speed of processing is indeed a problem.

First, DirectShow Filter is in line with the COM component specification, that is, it is a COM component. To meet the COM specification, you need some functions, but there have been a lot of base classes, just need to inherit, In this way, there is a lot less knowledge involved in the COM component. When writing DirectShow Filter, just find the base class to inherit, then realize the virtual function, write your own control code, you can. Some source code and instructions are given, and the specific explanation will be done later.

This simple Transform Filter consists of three files:

1. TOGRAYFILTER.DEF: Since Filter is a DLL-based COM component, the general Filter wants to implement several portfolios. There are two ways to export the functions in the DLL: one is to use the export keyword __declspec (dllexport) when defining a function, that is, the function is defined in .h file as follows:

Extern "C" __declspec (dllexport) Bool DLREGISTERSERRERVER;, etc.; the second method is to use module definition files, which is also what I use here.

//Togramingfilter.def --------------------------------------------- ----------------------------

//

Library TOGRAYFILTER.AX

Will call this function EXPORTS DllMain PRIVATE // dll entry function, DirectShow is implemented for obtaining dllEntryPoint DllGetClassObject PRIVATE // pointer to the class factory DllCanUnloadNow PRIVATE // the system is idle, it is determined whether the DLL DllRegisterServer PRIVATE // unload assembly com Registering to the Registry DllunregisterServer Private // Delete the registration information of the COM component in the registry is the five exporters necessary for a typical self-registered COM component DLL.

2. TOGRAYFILTER.H

In this file, a C class is declared, which is inherited from one of DirectShow to facilitate the user's base class for the user to write Filter.

//Togramfilter.h--------------------------------- -------------------------------------------------- -------- // # ifndef TOGRAYFILTER_H_ # define TOGRAYFILTER_H _ //// {5F2265B1-A841-4eb7-871F-5556436042AC} DEFINE_GUID (CLSID_ToGrayFilter, 0x5f2265b1, 0xa841, 0x4eb7, 0x87, 0x1f, 0x55, 0x56, 0x43 , 0x60, 0x42, 0xAc);

Class CTOGRAYFILTER: PUBLIC CTRANSFORMFILTER {public: CTOGRAYFILTER (Tchar * PNAME, LPUNKNOWN PUNK, HRESULT * PHR); // Constructor ~ CTOGRAYFILTER (); // Destructor

Public: // static object-code method (for the class factory) // must have // ​​static cunknown * WinAPI CreateInstance (LPunkNown Punk, HRESULT * PHR);

public: // implement the base filter 's method, the following five functions are CTranseformFilter virtual functions must implement the // HRESULT CheckInputType (const CMediaType * pmtIn); HRESULT GetMediaType (int iPosition, CMediaType * pMediaType); HRESULT CheckTransform (const CMediaType * mtIn, const CMediaType * mtOut); HRESULT DecideBufferSize (IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pProp); HRESULT Transform (IMediaSample * pSource, IMediaSample * pDest);

// this method is also in the base filter class, but in the base class it does noting, // implement here just want to get m_VihIn and m_VihOut // HRESULT SetMediaType (PIN_DIRECTION direction, const CMediaType * pmt);

Private: // my own process method, this is my own handler :), in the transform function called // hResult Togray (Byte * Pbinput, Byte * Pboutput); // a help method, Just Copy from Helper Document, this function, eventually did not use in this filter, because I don't know why, // feels some problems, and it should be like this. Finally own direct operations of the void GetVideoInfoParameters (const VIDEOINFOHEADER * pvih, // Pointer to the format header. BYTE * const pbData, // Pointer to the first address in the buffer. Bool bYuv, // Is this a YUV format? ( true = YUV, false = RGB) DWORD * pdwWidth, // Returns the width in pixels. DWORD * pdwHeight, // Returns the height in pixels. LONG * plStrideInBytes, // Add this to a row to get the new row down. Byte ** ppbtop // Returns a Pointer to the first byte in the // top row of pixels.); // Holds the current video format (INPUT), you can use each frame image as a BMP bitmap VideoInfoHeader m_vihout; // Holds The Current Video Format (Output)

// the imformation about every picture, put here just for speed // DWORD m_bytePerLine; // the real numbers of bits in one line, just for handy int m_Width; // the width of the bitmap, to use it, just handy int M_Height; // the height of the bitmap}; # endif

3. TOGRAYFILTER.CPP

// TOGRAYFILTER.CPP: Define the entry point of the DLL application. //

#include "stdafx.h"

// The include file for directshow filter // # include "streams.h" // Using the foundation class of the Filter, you must include the #include // # include # of this header file. INCLUDE

#include "tograyfilter.h"

#pragma Warning (Disable: 4715)

/ / -------------------------------------------------------------------------------------------- --------------------

CTOGRAYFILTER :: CTOGRAYFILTER (tchar * PNAME, LPUNKNOWN PUNK, HRESULT * PHR): CTransformFilter (PNAME, PUNK, CLSID_TOGRAYFILTER) {} ctogram () {}

/ / -------------------------------------------------------------------------------------------- ------------------------------ /// This Method Check This Filter's Input Pin Could Receive Which Kind of Media Type // HRESULT CToGrayFilter :: CheckInputType (const CMediaType * pmtIn) {if ((pmtIn-> majortype! = MEDIATYPE_Video) || (pmtIn-> subtype! = MEDIASUBTYPE_RGB24) || (pmtIn-> formattype! = FORMAT_VideoInfo) || (pmtIn- > cbFormat

VideoInfoHeader * pvih = reinterpret_cast (pmtin-> pbformat);

// everything is good. Return S_OK;

}

// the downstream filter check this filter's output pin, then the method will be used // now because the media type has not been changed, so only return the media type of // this filter's input pin // HRESULT CToGrayFilter :: GetMediaType ( INT iposition, cmediatype * pmediatype) {// The Output Pin Calls this Method Only if The Input Pin IS Connected. Assert (m_pinput-> iSconnected ());

//////Wwn {return (iposition <0) {return e_invalidarg;} else if (iposition == 0) {// this maybe ok now return m_pinput-> connectionMediatype PMEDiaType);} return vfw_s_no_more_items;

}

// this method checks if a proposed output type is compatible with the current input type.//The method is also called if the input pin reconnects after the output pin connects. // HRESULT CToGrayFilter :: CheckTransform (const CMediaType * mtIn, const CMEDiatype * mtout) {// check the major type. // if (mtout-> majortype! = Mediatype_video) {return vfw_e_type_not_accepted;} // check the subtype and format type. //

// Make sure the subtypes match // if (mtIn-> subtype = mtOut-> subtype!) {Return VFW_E_TYPE_NOT_ACCEPTED;} if ((mtOut-> formattype = FORMAT_VideoInfo) || (mtOut-> cbFormat

. // Compare the bitmap information against the input type // ASSERT (mtIn-> formattype == FORMAT_VideoInfo); BITMAPINFOHEADER * pBmiOut = HEADER (mtOut-> pbFormat); BITMAPINFOHEADER * pBmiIn = HEADER (mtIn-> pbFormat);

IF ((pBMIOUT-> BIWIDTH <= pbmiin-> biwidth) && (pbmiout-> biheight == ABS (PBMIIN-> Biheight))) {return s_ok;} returnifw_e_type_not_accepted;

}

// this method is used during the output pin connection process.//the output pin is responsible for negotiating the allocation of data stream buffers // during the pin connection process, // even if this allocation is actually done by the input pin of the downstream filter.//HRESULT CToGrayFilter :: DecideBufferSize (IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pProp) {// Make sure the input pin is connected // if {return E_UNEXPECTED. (m_pInput-> IsConnected ()!);}

// Our strategy here is to use the upstream allocator as the guideline, // but also defer to the downstream filter's request // when it's compatible with us.// First, find the upstream allocator ... ALLOCATOR_PROPERTIES InputProps;

IMEMALLOCATOR * Pallocinput = 0; HRESULT HR = m_pinput-> getAllocator (& PallocinPut);

IF (Failed (HR)) {Return HR;}

// ... Now get the profment-> getproperties (& Inputprops); Pallocinput-> Release ();

IF (Failed (HR)) {Return HR;}

// Buffer alignment shop be non-zero [Zero Alignment Makes No Sense!]. If (pprop-> cbalign == 0) {pprop-> cbAlign = 1;}

// Number of buffers must be non-zero. If (pprop-> cbbuffer == 0) {pprop-> cbuffers = 1;}

// for buffer size, find the maximum of the Upstream size and /////stream filter's request. Pprop-> cbbuffer = max (inputprops.cbbuffer, pprop-> cbuffer);

// NOW SET The Properties on The Allocator That Was Given To US. Allocator_Properties Actual; HR = Palloc-> SetProperties (PPROP, & Actual); IF (Failed (HR)) {Return HR;}

}

HRESULT CToGrayFilter :: Transform (IMediaSample * pSource, IMediaSample * pDest) {// Get pointers to the underlying buffers // BYTE * pBufferIn, * pBufferOut;. HRESULT hr; hr = pSource-> GetPointer (& pBufferIn); if (FAILED ( HR)) {RETURN HR;} HR = PDEST-> GetPointer (& PBufferout); if (Failed (HR)) {Return HR;}

// process the data. // TOGRAY (PBUFFERIN, PBUFFEROUT);

}

/ / -------------------------------------------------------------------------------------------- ------------------------------ // this Method Is Also in The Base Filter Class, But in The Base Class It Does Noting , // implement here just want to get m_VihIn and m_VihOut // HRESULT CToGrayFilter :: SetMediaType (PIN_DIRECTION direction, const CMediaType * pmt) {if (direction == PINDIR_INPUT) {ASSERT (pmt-> formattype == FORMAT_VideoInfo); VIDEOINFOHEADER * PVIH = (VideoInfoHeader *) PMT-> PBFORMAT;

// WARNING! In general you can not just copy a VIDEOINFOHEADER // struct, because the BITMAPINFOHEADER member may be followed by // random amounts of palette entries or color masks. (See VIDEOINFO // structure in the DShow SDK docs.) Here it's Ok Because We Just // Want The Information That In The VideoInfoHeader Struct Itself.

CopyMemory (& M_VIHIN, PVIH, SIZEOF (VIDEOINFOHEADER);

} Else // output pin {assert (Direction == PINDIR_OUTPUT); assert (pmt-> formattype == format_videoInfo); VideoInfoHeader * PVIH = (VideoInfoHeader *) PMT-> PBFormat;

CopyMemory (& M_VIHOUT, PVIH, SIZEOF (VideoInfoHeader);

/ / -------------------------------------------------------------------------------------------- /// // DWord M_BYTEPERLINE; // THE REAL NUMBERS OF BITS INE LINE, JUST for Handy // Int M_Width; // The Width of The Bitmap, To Use IT, Just Handy // Int M_Height; // The Height of The bitmap m_width = m_vihin.bmiheader.biwidth; m_height = m_vihin.bmiheader.biheight; m_byteperline = (24 * m_width 31) / 32 * 4;

Return S_OK;

/ / -------------------------------------------------------------------------------------------- ---------------------------------- // My OWN Process Method, To change the data to gray // hresult CToGrayFilter :: ToGray (BYTE * pbInput, BYTE * pbOutput) {DWORD dwWidth, dwHeight; // Width and height in pixels (input) DWORD dwWidthOut, dwHeightOut; // Width and height in pixels (output) LONG lStrideIn, lStrideOut; / / Stride in bytes bytes byte * pbsource, * pbtarget; // first byte first row, Source & target // There is no use, because this function is quirky, and finally, it is to get the method of processing BMP bitmaps. data

// GetVideoInfoParameters (& m_VihIn, pbInput, false, & dwWidth, & dwHeight, // & lStrideIn, & pbSource); // GetVideoInfoParameters (& m_VihOut, pbOutput, false, & dwWidthOut, & dwHeightOut, // & lStrideOut, & pbTarget);

// Formats Should Match (Except Maybe Stride). // assert (dwwidth == dwwidth); // assert (abs (dwheight) == ABS (dwheightout);

// Here to process the data // / * for (dWord y = 0; y

/ / The following is the processing of RGB32, so if this is done, there will be problems.

// rgbquad * ppixeltarget = (rgbquad *) PBTARGET; // Rgbquad * ppixelsource = (RGBQUAD *) PBSource; // for (DWORD X = 0; x

// can also be here, when each frame image is coming, it is recalculated, but it is not necessary, and it will affect speed // dword m_byteperline; // the real number of bits in one line, Just for handy // int m_width; // the width of the bitmap, to use it, just handy // int m_height; // the height of the bitmap //m_width=m_vihin.bmiheader.biwidth; // m_height = m_vihin. Bmiheader.biheight; // m_byteperline = (24 * m_width 31) / 32 * 4;

Byte rcolor, gcolor, bcolor, changecolor; for (int i = 0; i

ChangeColor = (rcolor gcolor bcolor) / 3;

* (PBOUT (M_HEIGHT-I-1) * m_byteperline j * 3) = ChangeColor; * (Pboutput (M_HEIGHT-I-1) * m_byteperline j * 3 1) = ChangeColor; * (Pboutput (M_HEight-I- 1) * m_byteperline j * 3 2) = changecolor;}}

Return S_OK;

}

// The following function is from the function of COPY in the help document, but it doesn't feel anything. In fact, it doesn't use it in this filter I wrote ~ -------------- -------------------------------------------------- ------------ // A helper function, not write by me, just copy from the help docoment // void ctographfilter :: getVideoInfoParaseters (const videofoheader * pvih, // pointer to the format header. BYTE * CONST PBDATA, / / ​​POINTER TO THE FIRST Address in the buffer. Bool BYUV, // IS this a yuv format? (True = yuv, false = RGB) DWORD * PDWWIDTH, // Returns the width in pixels. DWORD * PDWHEIGHT, // Returns The Height In Pixels. Long * PlstrideinBytes, // Add this to a row to get the new row down. Byte ** PPBTOP // Returns a Poin TOP OF PIXELS. ) {Long lstride;

// for 'Normal' Formats, Biwidth Is In Pixels. // Expand to Bytes and Round Up to a Multiple of 4. IF ((PVIH-> Bmiheader.biBitcount! = 0) && (0 == (7 & PVIH- > bmiheader.biBitcount)) {lstride = (pvih-> bmiheader.biwidth * (pvih-> bmiheader.biBitcount / 8) 3) & ~ 3;} else // Otherwise, biwidth is in bytes. {lstride = PVIH -> bmiheader.biwidth;}

// if rctarget is Empty, use the whole image. If (isRectempty (& PVIH-> Rctarget) {* pdwwidth = (dword) PVIH-> bmiheader.biwidth; * pdwheight = (dword) (ABS (PVIH-> Bmiheader. Biheight); if (pvih-> bmiheader.biheight <0 || BYUV) // top-down bitmap. {* plstrideinBytes = lstride; // Stride Goes "down". * ppbtop = pbdata; // Top Row is First Else // bottom-up bitmap. {* PlstrideinBytes = -lstride; // Stride Goes "Up". // bottom row is first. * Ppbtop = pbdata lstride * (* pdwheight - 1);}} else / / RCTARGET IS Not Empty. Use a sub-rectangle in The Image. {* pdwwidth = (dword) (PVIH-> Rctarget.right - pvih-> rctarget.left); * pdwheight = (dword) (PVIH-> Rctarget. Bottom - PVIH-> RCTARGET.TOP); IF (PVIH-> Bmiheader.biheight <0 || BYUV) // Top-Down Bitmap. {// Same Stride As Above, But First P ixel is modified down // and over by the target rectangle * plStrideInBytes = lStride;. * ppbTop = pbData lStride * pvih-> rcTarget.top (pvih-> bmiHeader.biBitCount * pvih-> rcTarget.left) / 8; } else // Bottom-up bitmap {* plStrideInBytes = -lStride;. * ppbTop = pbData lStride * (pvih-> bmiHeader.biHeight - pvih-> rcTarget.top - 1) (pvih-> bmiHeader.biBitCount * pvih -> rctarget.left / 8;}}}

/ / -------------------------------------------------------------------------------------------- ----------------------------------------------- // Cunknown * WINAPI CToGrayFilter :: CreateInstance (LPUNKNOWN pUnk, HRESULT * pHr) {CToGrayFilter * pFilter = new CToGrayFilter (NAME ( "To Gray Filter"), pUnk, pHr); if (pFilter == NULL) {* pHr = E_OUTOFMEMORY;} Return pfilter;

Extern "C" BOOL WINAPI DLLENTRYPOINT (Hinstance, DWORD, LPVOID);

Bool Apientry Dllmain (Handle Hmodule, DWORD DWRES, LPVOID PV) {Return DLLENTRYPOINT ((Hinstance) HMODULE, DWRES, PV);

HRESULT WINAPI DLLREGISTERSERSERRERVER () {Return AmoviedllRegisterServer2 (TRUE);} HRESULT WINAPI DLLUNREGISTERSERSERRERVER () {Return AmoviedllRegisterServer2 (false);

/ / -------------------------------------------------------------------------------------------- --- // AMOVIESETUP_FILTER FilterInfo = {& CLSID_ToGrayFilter, // CLSID L "To Gray Filter", // Name MERIT_DO_NOT_USE, // Merit 0, // Number of AMOVIESETUP_PIN structs NULL // Pin registration information};

CfactoryTemplate g_templates [] = {{L "to gray filter", & clsid_togram :: CreateInstance, 0, & filterinfo,}

}; int g_ctemplates = sizeof (g_templates) / sizeof (g_templates [0]);

The above is all source code for my program. This is just an example program, there are many things in it, in fact, the transform filter inherited from CTransformFilter inherited is completely reused, which is the most of the things that are almost like this. The code is simple. Really your own implementation is just a function, it is just the value of the pixel, and then conversion. That is, the TransformFilter has a shelf, which is only the operation of the pixel.

It's now in a hurry. In fact, there are still a lot of places that have not mentioned, but now the mood is suddenly bad, and then add it.

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

New Post(0)