您的位置:首页 > 编程语言 > PHP开发

视频播放器增加color space converter + In-Place Transform Filter

2012-08-06 17:07 471 查看
http://blog.csdn.net/luckyboy101/article/details/7832179

讲了直接在MFC中用Directshow Transform filter,但是在运行中发现,视频的彩色空间(color space,可以由格式工厂软件查看)通常是YUV,而我们对视频编辑通常是在RGB空间,所以需要增加一个color space converter把YUV彩色空间转换为RGB24彩色空间。

这样就需要在video render之前增加两个filter color space converter + transform filter, 发现一次增加1个filter无法连接,所以要同时一次性把两个filter加入链路,代码如下:

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*pColor, IBaseFilter* pTransform);
HRESULT NextUpstream(IBaseFilter* pFilter, IBaseFilter** ppNext);
HRESULT CAppGraphBuilder::AddFilterByCLSID(IGraphBuilder *pGraph,const GUID& clsid,LPCWSTR wszName,IBaseFilter **ppF);

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
tagRGBTRIPLE *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 = (tagRGBTRIPLE*) pData;
for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {
prgb->rgbtRed=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_RGB24))
{
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::AddFilterByCLSID(
IGraphBuilder *pGraph,  // Pointer to the Filter Graph Manager.
const GUID& clsid,      // CLSID of the filter to create.
LPCWSTR wszName,        // A name for the filter.
IBaseFilter **ppF)      // Receives a pointer to the filter.
{
if (!pGraph || ! ppF) return E_POINTER;
*ppF = 0;
IBaseFilter *pF = 0;
HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, reinterpret_cast<void**>(&pF));
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pF, wszName);
if (SUCCEEDED(hr))
*ppF = pF;
else
pF->Release();
}
return hr;
}
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();

// Add Color Space Convert
IBaseFilter *pColor;
hr=AddFilterByCLSID(m_pGraph, CLSID_Colour, L"Color Space Converter", &pColor);

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

//pColor->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*pColor,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* pPinInCor = InputPinOf(pColor);
hr = m_pGraph->Connect(pPinOut, pPinInCor);
pPinInCor->Release();
}
if (SUCCEEDED(hr))
{
IPin* pPinInXfm = InputPinOf(pTransform);
IPin* pPinOutCor = OutputPinOf(pColor);
hr = m_pGraph->Connect(pPinOutCor, pPinInXfm);
pPinInXfm->Release();
pPinOutCor->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;
}
}




程序在graphedit里的连接情况看上图,在app Transform后面自动增加了一个color space converter
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息