www.pudn.com > VirtualVCR-src-v2.6.9.zip > Histogram.cpp


/* 
	Virtual VCR 
    Copyright (C) 2002  Shaun Faulds 
 
    This program is free software; you can redistribute it and/or modify 
    it under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2 of the License, or 
    (at your option) any later version. 
 
    This program is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details. 
 
    You should have received a copy of the GNU General Public License 
    along with this program; if not, write to the Free Software 
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 
	Acknowledgments: 
	This application and associated filters are based on the examples 
	from the Microsoft DirectX DirectShow SDK. 
*/ 
 
#include  
#include  
#include  
 
#if (1100 > _MSC_VER) 
#include  
#else 
#include  
#endif 
 
#include "HistogramUIDs.h" 
#include "iHistogram.h" 
#include "HistogramProp.h" 
#include "Histogram.h" 
#include "resource.h" 
#include "../Common/Filter/iFilterProperties.h" 
 
#include "Histogram.version" 
#include "colourFormats.h" 
 
// Setup information 
 
const AMOVIESETUP_MEDIATYPE sudPinTypes = 
{ 
    &MEDIATYPE_Video,       // Major type 
    &MEDIASUBTYPE_NULL      // Minor type 
}; 
 
const AMOVIESETUP_PIN sudpPins[] = 
{ 
    { L"Input",             // Pins string name 
      FALSE,                // Is it rendered 
      FALSE,                // Is it an output 
      FALSE,                // Are we allowed none 
      FALSE,                // And allowed many 
      &CLSID_NULL,          // Connects to filter 
      NULL,                 // Connects to pin 
      1,                    // Number of types 
      &sudPinTypes          // Pin information 
    }, 
    { L"Output",            // Pins string name 
      FALSE,                // Is it rendered 
      TRUE,                 // Is it an output 
      FALSE,                // Are we allowed none 
      FALSE,                // And allowed many 
      &CLSID_NULL,          // Connects to filter 
      NULL,                 // Connects to pin 
      1,                    // Number of types 
      &sudPinTypes          // Pin information 
    } 
}; 
 
const AMOVIESETUP_FILTER sudHistogram = 
{ 
    &CLSID_Histogram,         // Filter CLSID 
    L"Colour Histogram",       // String name 
    MERIT_DO_NOT_USE,       // Filter merit 
    2,                      // Number of pins 
    sudpPins                // Pin information 
}; 
 
 
// 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 
 
CFactoryTemplate g_Templates[] = { 
    { L"Colour Histogram" 
    , &CLSID_Histogram 
    , CHistogram::CreateInstance 
    , NULL 
    , &sudHistogram } 
  , 
    { L"Colour Histogram" 
    , &CLSID_HistogramPropertyPage 
    , CHistogramProperties::CreateInstance } 
}; 
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); 
 
 
// 
// DllRegisterServer 
// 
// Handles sample registry and unregistry 
// 
STDAPI DllRegisterServer() 
{ 
    return AMovieDllRegisterServer2( TRUE ); 
 
} // DllRegisterServer 
 
 
// 
// DllUnregisterServer 
// 
STDAPI DllUnregisterServer() 
{ 
    return AMovieDllRegisterServer2( FALSE ); 
 
} // DllUnregisterServer 
 
 
// 
// Constructor 
// 
CHistogram::CHistogram(TCHAR *tszName, 
                   LPUNKNOWN punk, 
                   HRESULT *phr) : 
    CTransformFilter(tszName, punk, CLSID_Histogram) 
{ 
 
	Channels = true; 
	ChannelSelection = 7; 
 
	output_width = 268; 
	output_height = 210; 
 
	inputColourFormat = 0; 
 
	channel01 = new LONG[256]; 
	channel02 = new LONG[256]; 
	channel03 = new LONG[256]; 
 
} // (Constructor) 
 
// 
// Constructor 
// 
CHistogram::~CHistogram() 
{ 
	// Delete the pixel arrays from the heap 
	delete[] channel01; 
	delete[] channel02; 
	delete[] channel03; 
} 
 
// 
// CreateInstance 
// 
// Provide the way for COM to create a EZrgb24 object 
// 
CUnknown *CHistogram::CreateInstance(LPUNKNOWN punk, HRESULT *phr) 
{ 
    CHistogram *pNewObject = new CHistogram(NAME("Colour Histogram"), punk, phr); 
    if (pNewObject == NULL) 
	{ 
        *phr = E_OUTOFMEMORY; 
    } 
    return pNewObject; 
 
} // CreateInstance 
 
 
// 
// NonDelegatingQueryInterface 
// 
// Reveals IIPEffect and ISpecifyPropertyPages 
// 
STDMETHODIMP CHistogram::NonDelegatingQueryInterface(REFIID riid, void **ppv) 
{ 
    CheckPointer(ppv,E_POINTER); 
 
    if (riid == IID_IHistogram) 
	{ 
        return GetInterface((IHistogram *) this, ppv); 
    } 
	else if (riid == IID_IFilterProperties) 
	{ 
		return GetInterface((IFilterProperties *) this, ppv); 
	} 
	else if (riid == IID_ISpecifyPropertyPages) 
	{ 
        return GetInterface((ISpecifyPropertyPages *) this, ppv); 
    } 
	else 
	{ 
        return CTransformFilter::NonDelegatingQueryInterface(riid, ppv); 
    } 
 
} // NonDelegatingQueryInterface 
 
 
// 
// Transform 
// 
HRESULT CHistogram::Transform(IMediaSample *pIn, IMediaSample *pOut) 
{ 
	// 
	// Perpare output sample. 
	// Use the local method to copy sample times etc 
	// from input sample to the output sample 
	// 
	HRESULT result = S_OK; 
	//result = this->PrepareOutputSample(pIn, pOut); 
	if (result != S_OK) return result; 
 
	int output_size = output_height * output_width * 24; 
	pOut->SetActualDataLength(output_size); 
 
	// Zero all the data in the colour arrays 
	memset(channel01, 0, 256*sizeof(channel01[0])); 
	memset(channel02, 0, 256*sizeof(channel02[0])); 
	memset(channel03, 0, 256*sizeof(channel03[0])); 
 
	LONG maxRGB = CountPixels(pIn, channel01, channel02, channel03); 
 
	if(inputColourFormat == 1) 
		result = DrawHistogramRGB(pOut, maxRGB, channel01, channel02, channel03); 
	else if(inputColourFormat == 2) 
		result = DrawHistogramLUM(pOut, maxRGB, channel01, channel02, channel03); 
 
    return NOERROR; 
 
} // Transform 
 
 
//////////////////////////////////////////////////////////// 
// Take the information from the pixel arrays and draw it 
// to an output media sample to be rendered to a video 
// render filter 
//////////////////////////////////////////////////////////// 
 
HRESULT CHistogram::DrawHistogramRGB( 
								IMediaSample *pOutput, 
								LONG rgbMax, 
								LONG *pixel01, 
								LONG *pixel02, 
								LONG *pixel03) 
{ 
 
    BYTE *pData; 
    pOutput->GetPointer(&pData); 
	RGBTRIPLE *prgb; 
	prgb = (RGBTRIPLE*) pData; 
 
	// offset the Histogram in output window 
	int offsetX = 5; 
	int offsetY = 5; 
 
	LONG maxRGBValue = rgbMax; 
 
    for (int y = 0; y < 200; y++) 
	{ 
		for (int x = 0; x < 256; x++) 
		{ 
			PlotPixel(0, 0, 0, 0, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
 
			if(Channels) 
			{ 
				if((ChannelSelection & 1) == 1) 
				{ 
					if(pixel01[x] > ((maxRGBValue * (200-y)) / 200)) 
					{ 
						PlotPixel(250, 0, 0, 50, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
					} 
				} 
 
				if((ChannelSelection & 2) == 2) 
				{ 
					if(pixel02[x] > ((maxRGBValue * (200-y)) / 200)) 
					{ 
						PlotPixel(0, 250, 0, 50, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
					} 
				} 
 
				if((ChannelSelection & 4) == 4) 
				{ 
					if(pixel03[x] > ((maxRGBValue * (200-y)) / 200)) 
					{ 
						PlotPixel(0, 0, 250, 50, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
					} 
				} 
 
			} 
			else 
			{ 
				LONG lum = 0; 
 
				// Use r%22 g%71 b%7 as the calculation 
				lum = ((pixel01[x] * 22) + (pixel02[x] * 71) + (pixel03[x] * 7)) / 100; 
 
				if(lum > ((maxRGBValue * (200-y)) / 200)) 
					PlotPixel(250, 250, 250, 50, x+offsetX, y+offsetY, prgb, output_width, output_height); 
			} 
 
			// Draw the box around the histogram 
//			if(x == 0) 
//				PlotPixel(255, 255, 255, 0, (x + offsetX - 1), (y + offsetY), prgb, output_width, output_height); 
//			if(x == 255) 
//				PlotPixel(255, 255, 255, 0, (x + offsetX + 1), (y + offsetY), prgb, output_width, output_height); 
			if(y == 0 || y == 199) 
				PlotPixel(255, 255, 255, 0, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
		} 
	} 
 
	return NOERROR; 
} 
 
HRESULT CHistogram::DrawHistogramLUM( 
								IMediaSample *pOutput, 
								LONG rgbMax, 
								LONG *pixel01, 
								LONG *pixel02, 
								LONG *pixel03) 
{ 
 
    BYTE *pData; 
    pOutput->GetPointer(&pData); 
	RGBTRIPLE *prgb; 
	prgb = (RGBTRIPLE*) pData; 
 
	// offset the Histogram in output window 
	int offsetX = 5; 
	int offsetY = 5; 
 
	LONG maxRGBValue = rgbMax; 
 
    for (int y = 0; y < 200; y++) 
	{ 
		for (int x = 0; x < 256; x++) 
		{ 
			PlotPixel(0, 0, 0, 0, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
 
			if(pixel01[x] > ((maxRGBValue * (200-y)) / 200)) 
			{ 
				PlotPixel(200, 200, 200, 0, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
			} 
 
			if(y == 0 || y == 199) 
				PlotPixel(255, 255, 255, 0, (x + offsetX), (y + offsetY), prgb, output_width, output_height); 
		} 
	} 
 
	return NOERROR; 
} 
 
 
////////////////////////////////////////////////////// 
// Count the pixel colour numbers for building the Histogram 
////////////////////////////////////////////////////// 
 
LONG CHistogram::CountPixels(IMediaSample *pMediaSample, 
							LONG *pixelArray01, 
							LONG *pixelArray02, 
							LONG *pixelArray03) 
{ 
    BYTE *pData; 
//    long lDataLen; 
	LONG maxValue = 0;     
 
    pMediaSample->GetPointer(&pData); 
//    lDataLen = pMediaSample->GetSize(); 
 
    int cxImage    = input_width; 
    int cyImage    = input_height; 
    int numPixels  = cxImage * cyImage; 
 
	if(inputColourFormat == 1) // RGB24 colour format 
	{ 
		RGBTRIPLE *prgb; 
		prgb = (RGBTRIPLE*) pData; 
 
		for (int iPixel = 0; iPixel < numPixels; iPixel++, prgb++) 
		{ 
			//Count all the occurances of the colours to work out frequency for each colour 
			pixelArray01[prgb->rgbtRed]++; 
			if(pixelArray01[prgb->rgbtRed] > maxValue) maxValue = pixelArray01[prgb->rgbtRed]; 
 
			pixelArray02[prgb->rgbtGreen]++; 
			if(pixelArray02[prgb->rgbtGreen] > maxValue) maxValue = pixelArray02[prgb->rgbtGreen]; 
			 
			pixelArray03[prgb->rgbtBlue]++; 
			if(pixelArray03[prgb->rgbtBlue] > maxValue) maxValue = pixelArray03[prgb->rgbtBlue]; 
		} 
	} 
 
	else if(inputColourFormat == 2) // YUY2 colour format 
	{ 
		YUY2 *pyuy2; 
		pyuy2 = (YUY2*) pData; 
 
		for (int iPixel = 0; iPixel < numPixels; iPixel += 2, pyuy2++) 
		{ 
		   // YUY2 colour format 
		   // Y0 V0 Y1 U0 
		   // pixel 1 = Y0 U V 
		   // pixel 2 = Y1 U V 
		   // Y is brightness or luminesces 
		   // U is the colour difference from main luminesces for blue 
		   // V is the colour difference from main luminesces for red 
		   // Green is calculated 
/* 
Here are some test conversion for YUV to RGB 
Very slow at the moment need to MMX them 
 
			int red1 = (int)((double)pyuy2->Y0 + (double)((double)1.403 * (double)(pyuy2->V0-128))); 
			int green1 = pyuy2->Y0 - (0.344 * (double)(pyuy2->U0-128)) - (0.714 * (double)(pyuy2->V0-128)); 
			int blue1 = pyuy2->Y0 + (1.770 * (double)(pyuy2->U0-128)); 
 
			int red2 = pyuy2->Y1 + (1.403 * (double)pyuy2->V0); 
			int green2 = pyuy2->Y1 - (0.344 * (double)(pyuy2->U0-128)) - (0.714 * (double)(pyuy2->V0-128)); 
			int blue2 = pyuy2->Y1 + (1.770 * (double)(pyuy2->U0-128)); 
 
			if(red1 < 0) red1 = 0; 
			if(red1 > 255) red1 = 255; 
 
			if(green1 < 0) green1 = 0; 
			if(green1 > 255) green1 = 255; 
 
			if(blue1 < 0) blue1 = 0; 
			if(blue1 > 255) blue1 = 255; 
 
			//Count all the occurances of the colours to work out frequency for each colour 
			pixelArray01[red1]++; 
			if(pixelArray01[red1] > maxValue) maxValue = pixelArray01[red1]; 
 
			pixelArray02[green1]++; 
			if(pixelArray02[green1] > maxValue) maxValue = pixelArray02[green1]; 
			 
			pixelArray03[blue1]++; 
			if(pixelArray03[blue1] > maxValue) maxValue = pixelArray03[blue1]; 
*/ 
			// First Pixel Lumanence 
			pixelArray01[pyuy2->Y0]++; 
			if(pixelArray01[pyuy2->Y0] > maxValue) maxValue = pixelArray01[pyuy2->Y0]; 
 
			// Second Pixel Lumanence 
			pixelArray01[pyuy2->Y1]++; 
			if(pixelArray01[pyuy2->Y1] > maxValue) maxValue = pixelArray01[pyuy2->Y1]; 
 
		} 
	} 
 
	return maxValue; 
} 
 
////////////////////////////////////////////////////////////// 
// Plot a pixel to an array of RGB triples, this is raw output 
// data in a Media Sample 
////////////////////////////////////////////////////////////// 
 
HRESULT CHistogram::PlotPixel(int red, int green, int blue, int alpha, int x, int y, RGBTRIPLE *pixel, int width, int height) 
{ 
	y = height - y - 1; 
 
	pixel += x + (width * y); 
 
	red = ((red * (255-alpha)) / 255) + ((pixel->rgbtRed * alpha) / 255); 
	blue = ((blue * (255-alpha)) / 255) + ((pixel->rgbtGreen * alpha) / 255); 
	green = ((green * (255-alpha)) / 255) + ((pixel->rgbtGreen * alpha) / 255); 
 
	pixel->rgbtRed = red; 
	pixel->rgbtGreen = green; 
	pixel->rgbtBlue = blue; 
 
	return NOERROR; 
} 
 
// Check the input type is OK - return an error otherwise 
 
HRESULT CHistogram::CheckInputType(const CMediaType *mtIn) 
{ 
    // check this is a VIDEOINFOHEADER type 
	// allow any video format for input 
	// If this filter does not know how to process 
	// it it will just give a blnak histogram 
 
    if (*mtIn->FormatType() != FORMAT_VideoInfo) 
	{ 
        return E_INVALIDARG; 
    } 
 
	return S_OK; 
} 
 
 
// 
// Checktransform 
// 
// Check a transform can be done between these formats 
// 
HRESULT CHistogram::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) 
{ 
 
	// Only connect with a valid input and output format 
	// In this case any video input but only RGB24 video output 
 
    if (IsEqualGUID(*mtIn->Type(), MEDIATYPE_Video) && 
		IsEqualGUID(*mtOut->Type(), MEDIATYPE_Video) && 
		IsEqualGUID(*mtOut->Subtype(), MEDIASUBTYPE_RGB24)) 
	{ 
        return S_OK; 
    } 
    return E_FAIL; 
 
} // CheckTransform 
 
 
// 
// DecideBufferSize 
// 
// Tell the output pin's allocator what size buffers we 
// require. Can only do this when the input is connected 
// 
HRESULT CHistogram::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) 
{ 
    // Is the input pin connected 
 
    if (m_pInput->IsConnected() == FALSE) 
	{ 
        return E_UNEXPECTED; 
    } 
 
    ASSERT(pAlloc); 
    ASSERT(pProperties); 
    HRESULT hr = NOERROR; 
 
    pProperties->cBuffers = 1; 
    pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize(); 
    ASSERT(pProperties->cbBuffer); 
 
    // Ask the allocator to reserve us some sample memory, NOTE the function 
    // can succeed (that is return NOERROR) but still not have allocated the 
    // 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; 
 
} // DecideBufferSize 
 
 
// 
// GetMediaType 
// 
// I support one type, namely the type of the input pin 
// This type is only available if my input is connected 
// 
HRESULT CHistogram::GetMediaType(int iPosition, CMediaType *pMediaType) 
{ 
	 
    if (iPosition < 0) 
	{ 
        return E_INVALIDARG; 
    } 
 
    // Have we run off the end of types 
 
    if (iPosition > 0) 
	{ 
        return VFW_S_NO_MORE_ITEMS; 
    } 
 
    VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->AllocFormatBuffer(sizeof(VIDEOINFO)); 
 
    if (NULL == pvi) 
	{ 
		return(E_OUTOFMEMORY); 
    } 
 
    ZeroMemory(pvi, sizeof(VIDEOINFO)); 
 
	// Set for 24 bit RGB 
	pvi->bmiHeader.biCompression = BI_RGB; 
	pvi->bmiHeader.biBitCount    = 24; 
 
    pvi->bmiHeader.biSize		= sizeof(BITMAPINFOHEADER); 
    pvi->bmiHeader.biWidth		= output_width; 
    pvi->bmiHeader.biHeight		= output_height; 
    pvi->bmiHeader.biPlanes		= 1; 
    pvi->bmiHeader.biSizeImage		= GetBitmapSize(&pvi->bmiHeader); 
    pvi->bmiHeader.biClrImportant	= 0; 
 
    SetRectEmpty(&(pvi->rcSource));	// we want the whole image area rendered. 
    SetRectEmpty(&(pvi->rcTarget));	// no particular destination rectangle 
 
    pMediaType->SetType(&MEDIATYPE_Video); 
    pMediaType->SetFormatType(&FORMAT_VideoInfo); 
    pMediaType->SetTemporalCompression(FALSE); 
 
    // Work out the GUID for the subtype from the header info. 
    const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader); 
    pMediaType->SetSubtype(&SubTypeGUID); 
    pMediaType->SetSampleSize(pvi->bmiHeader.biSizeImage); 
 
    return NOERROR; 
 
} // GetMediaType 
 
// 
// GetPages 
// 
// Returns the clsid's of the property pages we support 
// 
STDMETHODIMP CHistogram::GetPages(CAUUID *pPages) 
{ 
    pPages->cElems = 1; 
    pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID)); 
    if (pPages->pElems == NULL) 
	{ 
        return E_OUTOFMEMORY; 
    } 
 
    *(pPages->pElems) = CLSID_HistogramPropertyPage; 
 
    return NOERROR; 
 
} // GetPages 
 
 
// Interfave Methods to get set the colour analisys options 
 
STDMETHODIMP CHistogram::get_Channel(BOOL *Channel) 
{ 
	*Channel = Channels; 
 
	return NOERROR; 
} 
 
STDMETHODIMP CHistogram::set_Channel(BOOL Channel) 
{ 
 
	Channels = Channel; 
	return NOERROR; 
} 
 
STDMETHODIMP CHistogram::get_RGBmask(int *mask) 
{ 
	*mask = ChannelSelection; 
	return NOERROR; 
} 
 
STDMETHODIMP CHistogram::set_RGBmask(int mask) 
{ 
 
	ChannelSelection = mask; 
	return NOERROR; 
} 
 
//This is for the common interface IFilterProperties 
// 
// Gets the data properties 
// 
STDMETHODIMP CHistogram::get_Prop(char*& data) 
{ 
	char filterData[1024]; 
	wsprintf(filterData, "none"); 
 
	data = filterData; 
	return NOERROR; 
} 
 
// 
// Sets the Data for properties 
// 
STDMETHODIMP CHistogram::set_Prop(char* data) 
{ 
 
	return NOERROR; 
} 
 
STDMETHODIMP CHistogram::get_Version(char *data) 
{ 
	wsprintf(data, "%s", MAIN_VERSION); 
 
	return NOERROR; 
} 
 
///////////////////////////////////////////////////////////////////////// 
// Media type setup functions 
// 
// SetMediaType is called on the base filter when pins are connected 
// the pin direction and a media type object ointer are passed to it. 
// 
// The GetInputMediaType type is called when the input pin is connected. 
// The SetOutputMediaType is called when the output pin is connected. 
// 
///////////////////////////////////////////////////////////////////////// 
 
// 
// Informs when the media type is established for the connection.  
// This then calls the SetInputMediaType and SetOutputMediaType 
// for each pin direction. 
// 
HRESULT CHistogram::SetMediaType(PIN_DIRECTION direction, const CMediaType* mediaType) 
{ 
	// assertion 
	CheckPointer (mediaType, E_POINTER); 
 
	HRESULT result = 0; 
 
	// Call super method, pass it what we got here. 
//	result = this->CTransformFilter::SetMediaType(direction, mediaType); 
 
	if (result != S_OK) 
	{ 
		return result; 
	} 
 
	// get the input pin media type 
	if (direction == PINDIR_INPUT) 
	{ 
		this->GetInputMediaType(mediaType); 
	} 
 
	// set media type for the output pin 
	else if (direction == PINDIR_OUTPUT) 
	{ 
		this->SetOutputMediaType(mediaType); 
	} 
 
	// unrecognized pin direction 
	else 
	{ 
		return E_FAIL; 
	} 
 
	return S_OK; 
} 
 
// 
// Gets the input media type, this is called when SetMediaType 
// is called with a pin direction of INPUT 
// This is a helper function and not part of the base Transform filter 
// 
HRESULT CHistogram::GetInputMediaType(const CMediaType* mediaType) 
{ 
 
	//MsgBOX(TEXT("GetInputMediaType")); 
 
	if(IsEqualGUID(*mediaType->Subtype(), MEDIASUBTYPE_RGB24)) 
	{ 
		inputColourFormat = 1; 
		//MsgBOX(TEXT("MEDIASUBTYPE_RGB24")); 
	} 
	else if(IsEqualGUID(*mediaType->Subtype(), MEDIASUBTYPE_YUY2)) 
	{ 
		inputColourFormat = 2; 
		//MsgBOX(TEXT("MEDIASUBTYPE_YUY2")); 
	} 
	else 
	{ 
		inputColourFormat = 0; 
	} 
		 
 
	int width = 0; 
	int height = 0; 
	int bitsPerPixel = 0; 
 
	if (*mediaType->FormatType () == FORMAT_VideoInfo) 
	{ 
		VIDEOINFOHEADER* header = reinterpret_cast (mediaType->Format ()); 
 
		if ( header == 0 ) 
			return E_FAIL; 
 
		input_width = (int)(header->bmiHeader.biWidth); 
		input_height = (int)(header->bmiHeader.biHeight); 
		bitsPerPixel = (int)(header->bmiHeader.biBitCount); 
		pixel_length_bytes = bitsPerPixel / 8; 
	} 
	else 
	{	 
		return E_FAIL; 
	} 
 
	//Reconnect the output pins to pass the new size downstream 
//	ReconnectOutputPins(); 
 
	//MsgBOX(TEXT("Pixel Depth %d width %d height %d"), bitsPerPixel, width, height); 
 
	return S_OK; 
} 
 
// 
// Sets the output media type, this is called when SetMediaType 
// is called with a pin direction of OUTPUT 
// This is a helper function and not part of the base Transform filter 
// 
HRESULT CHistogram::SetOutputMediaType(const CMediaType* mediaType) 
{ 
//	// copy media type 
//	this->outputMediaType = *mediaType; 
/* 
	MsgBOX(TEXT("SetOutputMediaType")); 
 
	if(IsEqualGUID(*mediaType->Type(), MEDIATYPE_Video)) 
		MsgBOX(TEXT("MEDIATYPE_Video")); 
 
	if(IsEqualGUID(*mediaType->Subtype(), MEDIASUBTYPE_RGB24)) 
		MsgBOX(TEXT("MEDIASUBTYPE_RGB24")); 
*/ 
	// setup format info 
 
	if (*mediaType->FormatType () == FORMAT_VideoInfo) 
	{ 
		VIDEOINFOHEADER* pvi = reinterpret_cast (mediaType->Format());		 
 
		if (NULL == pvi) 
		{ 
			return(E_OUTOFMEMORY); 
		} 
 
		// Set for 24 bit RGB 
		pvi->bmiHeader.biCompression = BI_RGB; 
		pvi->bmiHeader.biBitCount    = 24; 
 
		pvi->bmiHeader.biSize		= sizeof(BITMAPINFOHEADER); 
		pvi->bmiHeader.biWidth		= output_width; 
		pvi->bmiHeader.biHeight		= output_height; 
		pvi->bmiHeader.biPlanes		= 1; 
		pvi->bmiHeader.biSizeImage		= GetBitmapSize(&pvi->bmiHeader); 
		pvi->bmiHeader.biClrImportant	= 0; 
 
		SetRectEmpty(&(pvi->rcSource));	// we want the whole image area rendered. 
		SetRectEmpty(&(pvi->rcTarget));	// no particular destination rectangle 
 
	} 
	else 
		return E_FAIL; 
 
	return S_OK; 
} 
 
// 
// Prepares the output sample. 
// This copies the property from the 
// input sample to the output sample. 
// 
HRESULT CHistogram::PrepareOutputSample (IMediaSample* inSample, IMediaSample* outSample) 
{ 
	// assertions 
	CheckPointer(inSample, E_POINTER); 
	CheckPointer(outSample, E_POINTER);	 
 
	//.1 
	// set media type 
	// 
    // Copy the media type 
	//outSample->SetMediaType(&this->outputMediaType); 
 
	//.2 
	// copy the sample times 
	// 
	REFERENCE_TIME timeStart = 0; 
	REFERENCE_TIME timeEnd = 0; 
	if (inSample->GetTime (&timeStart, &timeEnd) == S_OK) 
	{ 
		outSample->SetTime (&timeStart, &timeEnd); 
	} 
 
	LONGLONG mediaStart = 0; 
	LONGLONG mediaEnd = 0; 
	if (inSample->GetMediaTime (&mediaStart, &mediaEnd) == S_OK) 
	{ 
			outSample->SetMediaTime (&mediaStart,&mediaEnd); 
	} 
 
	//.3 
	// copy the sync point property 
	// 
	HRESULT result = inSample->IsSyncPoint (); 
	if (result == S_OK) 
	{ 
		outSample->SetSyncPoint (TRUE); 
	} 
	else if (result == S_FALSE) 
	{ 
		outSample->SetSyncPoint (FALSE); 
	} 
	else 
	{ 
		return E_UNEXPECTED; 
	} 
 
	//.4 
	// copy the preroll property 
	// 
	result = inSample->IsPreroll (); 
	if (result == S_OK) 
	{ 
		outSample->SetPreroll (TRUE); 
	} 
	else if (result == S_FALSE) 
	{ 
		outSample->SetPreroll (FALSE); 
	} 
	else 
	{ 
		return E_UNEXPECTED; 
	} 
 
	//.5 
	// copy the discontinuity property 
	// 
	result = inSample->IsDiscontinuity (); 
	if (result == S_OK) 
	{ 
		outSample->SetDiscontinuity (TRUE); 
	} 
	else if (result == S_FALSE) 
	{ 
		outSample->SetDiscontinuity(FALSE); 
	} 
	else 
	{ 
		return E_UNEXPECTED; 
	} 
 
	return S_OK; 
} 
 
// 
//Reconnect the output pins to pass the new size down the stream 
// 
BOOL CHistogram::ReconnectOutputPins() 
{ 
 
	FILTER_INFO filerInfo; 
	HRESULT hr = this->QueryFilterInfo(&filerInfo); 
 
	if(filerInfo.pGraph) 
	{ 
		IPin *pP; 
		ULONG u; 
		IEnumPins *pins = NULL; 
 
		PIN_INFO pininfo; 
		hr = this->EnumPins(&pins); 
		pins->Reset(); 
 
		while(hr == NOERROR) 
		{ 
	 
			hr = pins->Next(1, &pP, &u);				 
 
			if(hr == S_OK && pP) 
			{ 
				hr = pP->QueryPinInfo(&pininfo); 
 
				if(hr == NOERROR) 
				{ 
					if(pininfo.dir == PINDIR_OUTPUT) 
					{ 
						filerInfo.pGraph->Reconnect(pP); 
					} 
 
					if(pininfo.pFilter) 
						pininfo.pFilter->Release(); 
				} 
 
				pP->Release(); 
			} 
		} 
 
		if(pins) 
			pins->Release(); 
	} 
	 
	if(filerInfo.pGraph) 
		filerInfo.pGraph->Release(); 
	filerInfo.pGraph = NULL; 
 
	return (hr == S_OK); 
} 
 
 
////////////////////////////////////////////////////////////// 
// 
// Method to display a message box to show data 
// 
int CHistogram::MsgBOX(LPTSTR sz,...)  
{ 
    static TCHAR tach[2000]; 
    va_list va; 
 
    va_start(va, sz); 
    wvsprintf(tach, sz, va); 
    va_end(va); 
    MessageBox(HWND_DESKTOP, tach, "Filter Message Box", MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL); 
    return FALSE; 
}