Implement your own Algorithm into a DirectShow Filter

A MontiVision Filter SDK DLL contains one function which is provided for the implementation of custom algorithms, the TransformSample()  function. This function is called for every frame passing the filter in a started filter configuration. The function provides two pointers to arrays of bytes, one array contains the input and the other one the output image. The arrays are of the same size. Your new DirectShow filter reads the data from the input image buffer, processes it and writes the resulting data into the output image buffer.To help you navigating through the image, a couple of additional parameters are passed to the function. The iWidth and the iHeight parameters contain the dimension of the image. It is not possible to change the input image to a smaller or larger output image size. The iBytePerPixel parameter defines the number of bytes used per pixel. There are three possible values: 1 (grayscale), 3 (RGB in byte order B G R) or 4 (ARGB in byte order B G R A). The input and output images have the same number of bytes per pixel. It is not possible to change the color depth of the output image. The global variable  g_dwTypes  sets the possible video formats the filter accepts.

Image Organization

Input and output images are stored in a one-dimensional buffer of type BYTE, where a BYTE is an unsigned 8 bit value. Each pixel of the image contains one, three or four bytes. The number of bytes per pixel depends on the color bit depth of the image.

RGB_8 1
RGB_24 3
RGB_32 4


The pixels are encoded as RGB(A) values. The image buffer is organized in lines. In a RGB24 image, the first pixel of the first line of the image is represented in the array as the first three values of the array, the following three values represent the next pixel of the image and so on. Each line of the image is DWORD aligned. The first line in the array is followed by the second line and so on. The first line of the array is the bottom line of the image. This image layout used in DirectShow® is different from the layout used in Windows bitmaps and Windows GDI. The color values for a pixel are stored in the order: blue, green, red, alpha.  

Sample:

The easiest way to understand this is through a diagram. Below you see a 2x2 pixel image in RGB 24 mode.

Image:

RGB
Line 2
Pixel 1
RGB
Line 2
Pixel 2
RGB
Line 1
Pixel 1
RGB
Line 1
Pixel 2

Array:

image[0] image[1] image[2] image[3] image[4] image[5] image[6] image[7] image[8] image[9] image[10] image[11] image[12] image[13] image[14] image[15]
Blue value
Pixel 1
Line 1
Green value
Pixel 1
Line 1
Red value
Pixel 1
Line 1
Blue value
Pixel 2
Line 1
Green value
Pixel 2
Line 1
Red value
Pixel 2
Line 1

padding
for
DWORD alignment

padding
for
DWORD alignment

Blue value
Pixel 1
Line 2
Green value
Pixel 1
Line 2
Red value
Pixel 1
Line 2
Blue value
Pixel 2
Line 2
Green value
Pixel 2
Line 2
Red value
Pixel 2
Line 2
padding
for
DWORD allignment
padding
for
DWORD
allignment

Because of the DWORD alignment one line of the image is stored in 8 bytes. The iPitch parameter of the TransformSample function is set to 8.

Sample

This is a working TransformSample() function. It reads a parameter from the parameter structure (*pSavePointer) which was initialized in the function  InitDLL() . Three "for" loops go through the input image and copy the bytes of every pixel to the output image.

STDAPI TransformSample( BYTE*        pInBuffer, 
                        BYTE*        pOutBuffer, 
                        int          iWidth, 
                        int          iHeight, 
                        int          iBytePerPixel,
                        int          iPitch
                        void*        pSavePointer,
                        void*        pTempPointer, 
                        PVOID        pIOInBuffer, 
                        int          iIOInBufferSize, 
                        PVOID        pIOOutBuffer, 
                        int          iIOOutBufferSize, 
                        SAMPLE_TIMES times)
{   
    int i, j;
    int iParam = 0; 
    int iTemp  = 0;

    iParam = ((FILTER_PARAMETER*)pSavePointer)->iParam; 
    iTemp  = ++((FILTER_TEMP_DATA*)pTempPointer)->iTemp;

    // Sample for IO_UINT8 I/O input pin type 
    BYTE invalue;
    if((pIOInBuffer != 0L) && (iIOInBufferSize >= sizeof(BYTE)))   
    {
        invalue = *((BYTE*)pIOInBuffer);
    } 
     
    for( i=0; i<iHeight; i++ )
    { 
        for( j=0; j<iPitch; j++ )
        { 
            *pOutBuffer++ = *pInBuffer++;
        } 
    }

    // Sample for IO_STRING I/O output pin type 
    char* outvalue;
    if((pIOOutBuffer != 0L) && (iIOOutBufferSize >= 256))
    {
        outvalue = (char*)pIOOutBuffer; 
        StringCchPrintf(outvalue, "Input Value: 0x%02X, frame %d", invalue, iTemp);
    }  

    return S_OK;
}