直接在MFC中用Directshow Transform filter

直接在MFC中用Directshow Transform filter_第1张图片

IPFilter.h

//
// Sample DirectShow In-Place Transform Filter that accepts data for use in application
//

#include <streams.h>

// This is an example in-place transform filter that is created within
// the application, and not by CoCreateInstance
class CAppTransform : public CTransInPlaceFilter
{
public:
    CAppTransform(LPUNKNOWN pUnkOuter, HRESULT *phr);

    HRESULT CheckInputType(const CMediaType* mtIn);
    HRESULT Transform(IMediaSample *pSample);
};


// DirectShow graph management sample code:
// This builds a playback graph using RenderFile
// and then inserts a transform filter on the uncompressed video.
class CAppGraphBuilder
{
private:
	CAppTransform*   m_pFilter;
    IGraphBuilder*   m_pGraph;
	DWORD		     m_dwObjectTable; 

public:
    CAppGraphBuilder();
    ~CAppGraphBuilder();

    void DestroyGraph(void);

    HRESULT BuildFromFile(LPCWSTR pszFile);
    HRESULT Run(void);
    HRESULT MakeChild(HWND hwnd);
    HRESULT ResizeVideoWindow(RECT* prc);

private:
	void CreateAppFilter(void);
	HRESULT FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter);
	HRESULT ConnectUpstreamOf(IBaseFilter* pFilter, IBaseFilter* pTransform);
	HRESULT NextUpstream(IBaseFilter* pFilter, IBaseFilter** ppNext);   

	IPin* GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest);
	// Helper methods
	IPin* InputPinOf(IBaseFilter* pFilter) 
	{
		return GetPin(pFilter, PINDIR_INPUT);
	}
	IPin* OutputPinOf(IBaseFilter* pFilter) 
	{
		return GetPin(pFilter, PINDIR_OUTPUT);
	}

	void AddToObjectTable(void) ;
	void RemoveFromObjectTable(void);
};


IPFilter.cpp

//
// Sample DirectShow In-Place Transform Filter that accepts data for use in application
//

#include "stdafx.h"
#include "IPFilter.h"

////////////////////////////////////////////////////////////////////////////////
CAppTransform::CAppTransform(LPUNKNOWN pUnkOuter, HRESULT *phr) : 
CTransInPlaceFilter(NAME("App Transform"), pUnkOuter, GUID_NULL, phr)
{
}

HRESULT CAppTransform::Transform(IMediaSample *pSample)
{
	// Override to do something inside the application
	// Such as grabbing a poster frame...
	// ...
	BYTE *pData;                // Pointer to the actual image buffer
	long lDataLen;              // Holds length of any given sample
	int iPixel;                 // Used to loop through the image pixels
	tagRGBQUAD *prgb;            // Holds a pointer to the current pixel

	AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
	VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat;
	ASSERT(pvi);

	CheckPointer(pSample,E_POINTER);
	pSample->GetPointer(&pData);
	lDataLen = pSample->GetSize();

	// Get the image properties from the BITMAPINFOHEADER

	int cxImage    = pvi->bmiHeader.biWidth;
	int cyImage    = pvi->bmiHeader.biHeight;
	int numPixels  = cxImage * cyImage;

	// int iPixelSize = pvi->bmiHeader.biBitCount / 8;
	// int cbImage    = cyImage * cxImage * iPixelSize;


	prgb = (tagRGBQUAD*) pData;
	for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {
		prgb->rgbRed=255;
	}
    return S_OK;
}

// Check if we can support this specific proposed type and format
HRESULT CAppTransform::CheckInputType(const CMediaType *pmt) 
{
	// We accept a series of raw media types
	if (pmt->majortype == MEDIATYPE_Video &&
		(pmt->subtype == MEDIASUBTYPE_RGB32 ||
		pmt->subtype == MEDIASUBTYPE_RGB24 ||
		pmt->subtype == MEDIASUBTYPE_RGB565 ||
		pmt->subtype == MEDIASUBTYPE_RGB555 ||
		pmt->subtype == MEDIASUBTYPE_UYVY ||
		pmt->subtype == MEDIASUBTYPE_YUY2)||
		pmt->subtype==MEDIASUBTYPE_NV12)
	{
		return NOERROR;
	}
	return E_FAIL;
}


// --- graph building (examples) --------- 
CAppGraphBuilder::CAppGraphBuilder() : 
m_pFilter(NULL),
m_pGraph(NULL),
m_dwObjectTable(0)
{
    CoInitialize(NULL);
}

CAppGraphBuilder::~CAppGraphBuilder()
{
    DestroyGraph();
    CoUninitialize();
}
    
void CAppGraphBuilder::DestroyGraph(void)
{
    if (m_pGraph) 
	{
		RemoveFromObjectTable();
        // ensure graph window is not child of ours
        IVideoWindow* pVW = NULL;
        HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW);
        if (SUCCEEDED(hr)) 
		{
            pVW->put_Visible(OAFALSE);
            pVW->put_Owner(NULL);
            pVW->put_MessageDrain(NULL);
            pVW->Release();
        }
        m_pGraph->Release();
        m_pGraph = NULL;
    }

    if (m_pFilter) 
	{
		m_pFilter->Release();
        m_pFilter = NULL;
    }
}

HRESULT CAppGraphBuilder::BuildFromFile(LPCWSTR pszFile)
{
	DestroyGraph();

	// Build a filter graph
	HRESULT hr = CoCreateInstance(
			CLSID_FilterGraph,
			NULL,
			CLSCTX_INPROC,
			IID_IGraphBuilder,
			(void**)&m_pGraph);
	if (FAILED(hr))
	{
		return hr;
	}
	AddToObjectTable();

	// render the file to build the initial graph
	hr = m_pGraph->RenderFile(pszFile, NULL);
	if (FAILED(hr)) 
	{
		return hr;
	}

	// Try to find the video renderer, by looking for IVideoWindow
	IBaseFilter* pVR;
	hr = FindFilterByInterface(IID_IVideoWindow, &pVR);
	if (FAILED(hr)) 
	{
		return hr;
	}

	// Find the media type on the input pin of the Video Renderer
	// to check for overlay connection where no actual data is passed
	IPin* pPin = InputPinOf(pVR);
	AM_MEDIA_TYPE mt;
	pPin->ConnectionMediaType(&mt);
	pPin->Release();
	CMediaType mtIn = mt;
	FreeMediaType(mt);

	if (mtIn.subtype == MEDIASUBTYPE_Overlay) 
	{
		// This connection may be a overlay mixer 
		// need to move upstream one place
		IBaseFilter* pOvMix = NULL;
		hr = NextUpstream(pVR, &pOvMix);
		pVR->Release();
		if (FAILED(hr)) 
		{
			return hr;
		}
		pVR = pOvMix;
	}

	// Create the transform and insert in graph
	CreateAppFilter();

	// Try to insert our transform filter
	hr = ConnectUpstreamOf(pVR, m_pFilter);
	pVR->Release();

	return hr;
}

// Start the graph
HRESULT CAppGraphBuilder::Run(void)
{
    IMediaControl* pControl = NULL;
    HRESULT hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
    if (SUCCEEDED(hr)) 
	{
		hr = pControl->Run();
		pControl->Release();
    }
    return hr;
}

// Make the video window a child of this app
HRESULT CAppGraphBuilder::MakeChild(HWND hwnd)
{
    if (!m_pGraph) 
	{
        return E_FAIL;
    }

    IVideoWindow* pVW = NULL;
    HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW);
    if (SUCCEEDED(hr)) 
	{
		HWND hwndOld;
		pVW->get_Owner((LONG*)&hwndOld);
		if (hwndOld != hwnd)
		{
			pVW->put_AutoShow(OAFALSE);
			pVW->put_Visible(OAFALSE);
			
			long    WindowStyle = 0;
			// Tweak the video's window style to get rid of the caption and frame:
			hr = pVW->get_WindowStyle(&WindowStyle);
			if (SUCCEEDED(hr)) 
			{
				WindowStyle &= ~WS_OVERLAPPEDWINDOW; // No frame junk
				WindowStyle |= WS_CHILD;             // Needs to be child
				hr = pVW->put_WindowStyle(WindowStyle);
			}

			pVW->put_Owner((LONG)hwnd);
			pVW->put_MessageDrain((LONG)hwnd);

            if (hwnd != NULL) 
			{
				RECT rc;
				GetClientRect(hwnd, &rc);
				pVW->SetWindowPosition(
						rc.left,
						rc.top,
						rc.right - rc.left,
						rc.bottom - rc.top);
				pVW->put_Visible(OATRUE);
            }
		}
		pVW->Release();
    }

    return hr;
}

// Resize the video window
HRESULT CAppGraphBuilder::ResizeVideoWindow(RECT* prc)
{
    if (!m_pGraph) 
	{
        return E_FAIL;
    }

    IVideoWindow* pVW = NULL;
    HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW);
    if (SUCCEEDED(hr)) 
	{
        hr = pVW->SetWindowPosition(
                        prc->left,
                        prc->top,
                        prc->right - prc->left,
                        prc->bottom - prc->top);
        pVW->Release();
    }
    return hr;
}

// Create the app-based filter and insert into graph (unconnected)
void CAppGraphBuilder::CreateAppFilter(void)
{
	if (m_pFilter) 
	{
		m_pFilter->Release();
		m_pFilter = NULL;
	}

	HRESULT hr = S_OK;
	m_pFilter = new CAppTransform(NULL, &hr);
	// Make the initial refcount 1 to match COM creation!!!
	m_pFilter->AddRef();

	// Add to graph -- nb need to Query properly for the
	// right interface before giving that to the graph object
	IBaseFilter* pFilter = NULL;
	hr = m_pFilter->QueryInterface(IID_IBaseFilter, (void**)&pFilter);
	if (SUCCEEDED(hr)) 
	{
		hr = m_pGraph->AddFilter(pFilter, L"App Transform");
		pFilter->Release();
	}
}

// Locate a filter within the graph by searching (from renderers upstream)
// looking for a specific interface on the filter
HRESULT CAppGraphBuilder::FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter)
{
    *ppFilter = NULL;

    IEnumFilters* pEnum;
    HRESULT hr = m_pGraph->EnumFilters(&pEnum);
    if (FAILED(hr)) 
	{
		return hr;
    }

    IBaseFilter* pFilter = NULL;
    while (pEnum->Next(1, &pFilter, NULL) == S_OK) 
	{
		// Check for required interface
		IUnknown* pUnk;
		HRESULT hrQuery = pFilter->QueryInterface(riid, (void**)&pUnk);
		if (SUCCEEDED(hrQuery)) 
		{
			pUnk->Release();
			pEnum->Release();
			*ppFilter = pFilter;
			return S_OK;
		}
		pFilter->Release();
    }
    pEnum->Release();

    return E_FAIL;
}


// Connect the filter pTransform upstream of pFilter by reconnecting pins.
// Assumes that pTransform has only one input and one output, and
// that pFilter has only one input.
HRESULT CAppGraphBuilder::ConnectUpstreamOf(IBaseFilter* pFilter, IBaseFilter* pTransform)
{
	IPin* pPinIn = InputPinOf(pFilter);
	if (!pPinIn) 
	{
		return E_FAIL;
	}

	// Get the peer output pin
	IPin* pPinOut = NULL;
	HRESULT hr = pPinIn->ConnectedTo(&pPinOut);
	if (FAILED(hr)) 
	{
		pPinIn->Release();
		return hr;
	}

	// Disconnect the current connection
	hr = m_pGraph->Disconnect(pPinOut);
	if (SUCCEEDED(hr)) 
	{
		hr = m_pGraph->Disconnect(pPinIn);
	}

	// Insert pTransform filter by connecting its input pin and output pin
	if (SUCCEEDED(hr)) 
	{
		IPin* pPinInXfm = InputPinOf(pTransform);
		hr = m_pGraph->Connect(pPinOut, pPinInXfm);
		pPinInXfm->Release();
	}
	if (SUCCEEDED(hr)) 
	{
		IPin* pPinOutXfm = OutputPinOf(pTransform);
		hr = m_pGraph->Connect(pPinOutXfm, pPinIn);
		pPinOutXfm->Release();
	}

	pPinIn->Release();
	pPinOut->Release();
	return hr;
}

// Find the first pin of a specific direction on a given filter
IPin* CAppGraphBuilder::GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest)
{
	IPin * foundPin = NULL;

    IEnumPins* pEnum = NULL;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (SUCCEEDED(hr)) 
	{
		IPin* pPin = NULL;
        while (!foundPin && pEnum->Next(1, &pPin, 0) == S_OK) 
		{
			PIN_DIRECTION dir;
			pPin->QueryDirection(&dir);
			if (dir == dirRequest) 
			{
				foundPin = pPin;
			}
			else
			{
				pPin->Release();
			}
		}
		pEnum->Release();
    }
    return foundPin;
}

// Follow the pin connections to return the filter that is 
// connected to the first input pin of pFilter
HRESULT CAppGraphBuilder::NextUpstream(IBaseFilter* pFilter, IBaseFilter** ppNext)
{
    IPin* pPin = InputPinOf(pFilter);
    if (!pPin) 
	{
		return E_FAIL;
    }

	// Get the peer output pin
    IPin* pPinOut = NULL;
    HRESULT hr = pPin->ConnectedTo(&pPinOut);
    pPin->Release();
    if (FAILED(hr)) 
	{
		return hr;
    }

    PIN_INFO info;
    pPinOut->QueryPinInfo(&info);
	pPinOut->Release();
    *ppNext = info.pFilter;
    
    return S_OK;
}



//////////////////////// For GraphEdit Dubug purpose /////////////////////////////
void CAppGraphBuilder::AddToObjectTable(void)
{
	IMoniker * pMoniker = 0;
    IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
	{
		WCHAR wsz[256];
		wsprintfW(wsz, L"FilterGraph %08p pid %08x", (DWORD_PTR)m_pGraph, GetCurrentProcessId());
		HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
		if (SUCCEEDED(hr)) 
		{
			hr = objectTable->Register(0, m_pGraph, pMoniker, &m_dwObjectTable);
			pMoniker->Release();
		}
		objectTable->Release();
	}
}

void CAppGraphBuilder::RemoveFromObjectTable(void)
{
	IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
	{
        objectTable->Revoke(m_dwObjectTable);
        objectTable->Release();
		m_dwObjectTable = 0;
    }
}

然后建一个MFC 单文档添加成员:

CAppGraphBuilder m_Graph;

实现:

void CtestView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch(nChar) 
	{ 
		case VK_F1: 
			{
				CString    strFilter = _T("AVI File (*.avi)|*.avi|");
				strFilter += _T("MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|");
				strFilter += _T("All Files (*.*)|*.*|");
				CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, 
					strFilter, this);
				if (IDOK != dlgOpen.DoModal()) 
				{
					return;
				}

				WCHAR wchFile[MAX_PATH];
				wcscpy(wchFile,dlgOpen.GetPathName());
				//MultiByteToWideChar(CP_ACP, 0, dlgOpen.GetPathName(), -1, wchFile, MAX_PATH);

				m_Graph.BuildFromFile(wchFile);
				m_Graph.MakeChild(GetSafeHwnd());
				m_Graph.Run();
			}
			break;
		default:
			break;
	}
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}



你可能感兴趣的:(直接在MFC中用Directshow Transform filter)