视频捕获增加color space converter + Transform Filter
其它不解释,贴是代码:
ipfilter.h
[html]
//
// sample directshow in-place transform filter that accepts data for use in application
//
#include <streams.h>
// this is an example transform filter that is created within
// the application, and not by cocreateinstance
class capptransform : public ctransformfilter
{
public:
capptransform(lpunknown punkouter, hresult *phr);
hresult checkinputtype(const cmediatype* mtin);
hresult transform(imediasample *pin, imediasample *pout);
hresult checktransform(const cmediatype *mtin,const cmediatype *mtout);
hresult decidebuffersize(imemallocator *palloc,
allocator_properties *pproperties);
hresult getmediatype(int iposition, cmediatype *pmediatype);
private:
hresult copy(imediasample *psource, imediasample *pdest) const;
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;
dword m_dwobjecttable;
icapturegraphbuilder2 *m_pbuild;
igraphbuilder *m_pgraph;
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);
hresult initcapturegraphbuilder(igraphbuilder **ppgraph,icapturegraphbuilder2 **ppbuild);
hresult enumeratedevices(refguid category, ienummoniker **ppenum);
void displaydeviceinformation(ienummoniker *penum, imoniker** pmoniker);
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
[html] view plaincopy
//
// sample directshow transform filter that accepts data for use in application
//
#include "stdafx.h"
#include "ipfilter.h"
////////////////////////////////////////////////////////////////////////////////
capptransform::capptransform(lpunknown punkouter, hresult *phr) :
ctransformfilter(name("app transform"), punkouter, guid_null)
{
}
//
// checktransform
//
// to be able to transform the formats must be identical
//
hresult capptransform::checktransform(const cmediatype *mtin,const cmediatype *mtout)
{
checkpointer(mtin,e_pointer);
checkpointer(mtout,e_pointer);
hresult hr;
if(failed(hr = checkinputtype(mtin)))
{
return hr;
}
// format must be a videoinfoheader
if(*mtout->formattype() != format_videoinfo)
{
return e_invalidarg;
}
// formats must be big enough
if(mtin->formatlength() < sizeof(videoinfoheader) ||
mtout->formatlength() < sizeof(videoinfoheader))
return e_invalidarg;
videoinfo *pinput = (videoinfo *) mtin->format();
videoinfo *poutput = (videoinfo *) mtout->format();
if(memcmp(&pinput->bmiheader,&poutput->bmiheader,sizeof(bitmapinfoheader)) == 0)
{
return noerror;
}
return e_invalidarg;
} // checktransform
//
// decidebuffersize
//
// tell the output pin's allocator what size buffers we
// require. can only do this when the input is connected
//
hresult capptransform::decidebuffersize(imemallocator *palloc,allocator_properties *pproperties)
{
checkpointer(palloc,e_pointer);
checkpointer(pproperties,e_pointer);
// is the input pin connected
if(m_pinput->isconnected() == false)
{
return e_unexpected;
}
hresult hr = noerror;
pproperties->cbuffers = 1;
pproperties->cbbuffer = m_pinput->currentmediatype().getsamplesize();
assert(pproperties->cbbuffer);
// if we don't have fixed sized samples we must guess some size
if(!m_pinput->currentmediatype().bfixedsizesamples)
{
if(pproperties->cbbuffer < 100000)
{
// nothing more than a guess!!
pproperties->cbbuffer = 100000;
}
}
// 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
// we must be connected to support the single output type
//
hresult capptransform::getmediatype(int iposition, cmediatype *pmediatype)
{
// is the input pin connected
if(m_pinput->isconnected() == false)
{
return e_unexpected;
}
// this should never happen
if(iposition < 0)
{
return e_invalidarg;
}
// do we have more items to offer
if(iposition > 0)
{
return vfw_s_no_more_items;
}
checkpointer(pmediatype,e_pointer);
*pmediatype = m_pinput->currentmediatype();
return noerror;
}
hresult capptransform::copy(imediasample *psource, imediasample *pdest) const
{
checkpointer(psource,e_pointer);
checkpointer(pdest,e_pointer);
// copy the sample data
byte *psourcebuffer, *pdestbuffer;
long lsourcesize = psource->getactualdatalength();
#ifdef debug
long ldestsize = pdest->getsize();
assert(ldestsize >= lsourcesize);
#endif
psource->getpointer(&psourcebuffer);
pdest->getpointer(&pdestbuffer);
copymemory((pvoid) pdestbuffer,(pvoid) psourcebuffer,lsourcesize);
// copy the sample times
reference_time timestart, timeend;
if(noerror == psource->gettime(×tart, &timeend))
{
pdest->settime(×tart, &timeend);
}
longlong mediastart, mediaend;
if(psource->getmediatime(&mediastart,&mediaend) == noerror)
{
pdest->setmediatime(&mediastart,&mediaend);
}
// copy the sync point property
hresult hr = psource->issyncpoint();
if(hr == s_ok)
{
pdest->setsyncpoint(true);
}
else if(hr == s_false)
{
pdest->setsyncpoint(false);
}
else
{ // an unexpected error has occured...
return e_unexpected;
}
// copy the media type
am_media_type *pmediatype;
psource->getmediatype(&pmediatype);
pdest->setmediatype(pmediatype);
deletemediatype(pmediatype);
// copy the preroll property
hr = psource->ispreroll();
if(hr == s_ok)
{
pdest->setpreroll(true);
}
else if(hr == s_false)
{
pdest->setpreroll(false);
}
else
{ // an unexpected error has occured...
return e_unexpected;
}
// copy the discontinuity property
hr = psource->isdiscontinuity();
if(hr == s_ok)
{
pdest->setdiscontinuity(true);
}
else if(hr == s_false)
{
pdest->setdiscontinuity(false);
}
else
{ // an unexpected error has occured...
return e_unexpected;
}
// copy the actual data length
long ldatalength = psource->getactualdatalength();
pdest->setactualdatalength(ldatalength);
return noerror;
} // copy
//
// transform
//
// copy the input sample into the output sample
// then transform the output sample 'in place'
//
hresult capptransform::transform(imediasample *pin, imediasample *pout)
{
hresult hr = copy(pin, pout);
if (failed(hr)) {
return hr;
}
return transform(pout);
} // transform
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=prgb->rgbtblue=prgb->rgbtgreen=(prgb->rgbtred+prgb->rgbtblue+prgb->rgbtgreen)/3;
}
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)*/
if (pmt->majortype == mediatype_video &&
(pmt->subtype == mediasubtype_rgb24))
{
return noerror;
}
return e_fail;
}
// --- graph building (examples) ---------
cappgraphbuilder::cappgraphbuilder() :
m_pbuild(null),
m_pgraph(null),
m_pfilter(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;
m_pbuild->release();
m_pbuild = null;
}
if (m_pfilter)
{
m_pfilter->release();
m_pfilter = null;
}
}
hresult cappgraphbuilder::initcapturegraphbuilder(
igraphbuilder **ppgraph, // receives the pointer.
icapturegraphbuilder2 **ppbuild // receives the pointer.
)
{
if (!ppgraph || !ppbuild)
{
return e_pointer;
}
igraphbuilder *pgraph = null;
icapturegraphbuilder2 *pbuild = null;
// create the capture graph builder.
hresult hr = cocreateinstance(clsid_capturegraphbuilder2, null,
clsctx_inproc_server, iid_icapturegraphbuilder2, (void**)&pbuild );
if (succeeded(hr))
{
// create the filter graph manager.
hr = cocreateinstance(clsid_filtergraph, 0, clsctx_inproc_server,
iid_igraphbuilder, (void**)&pgraph);
if (succeeded(hr))
{
// initialize the capture graph builder.
pbuild->setfiltergraph(pgraph);
// return both interface pointers to the caller.
*ppbuild = pbuild;
*ppgraph = pgraph; // the caller must release both interfaces.
return s_ok;
}
else
{
pbuild->release();
}
}
return hr; // failed
}
hresult cappgraphbuilder::enumeratedevices(refguid category, ienummoniker **ppenum)
{
icreatedevenum *pdevenum = null;
// create the system device enumerator.
hresult hr = cocreateinstance(clsid_systemdeviceenum, null,
clsctx_inproc_server, iid_icreatedevenum,
reinterpret_cast<void**>(&pdevenum));
if (succeeded(hr))
{
// create an enumerator for the video capture category.
hr = pdevenum->createclassenumerator(
clsid_videoinputdevicecategory,
ppenum, 0);
}
return hr;
}
void cappgraphbuilder::displaydeviceinformation(ienummoniker *penum, imoniker** pmoniker)
{
hwnd hlist; // handle to the list box.
while (penum->next(1, pmoniker, null) == s_ok)
{
ipropertybag *ppropbag;
hresult hr = (*pmoniker)->bindtostorage(0, 0, iid_ipropertybag,
(void**)(&ppropbag));
if (failed(hr))
{
(*pmoniker)->release();
continue; // skip this one, maybe the next one will work.
}
// find the description or friendly name.
variant varname;
variantinit(&varname);
hr = ppropbag->read(l"description", &varname, 0);
if (failed(hr))
{
hr = ppropbag->read(l"friendlyname", &varname, 0);
}
if (succeeded(hr))
{
// add it to the application's list box.
uses_conversion;
/*(long)sendmessage(hlist, lb_addstring, 0,
(lparam)ole2t(varname.bstrval));*/
variantclear(&varname);
}
ppropbag->release();
(*pmoniker)->release();
}
}
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();
imoniker* pmoniker;
imediaevent *pevent;
initcapturegraphbuilder(&m_pgraph,&m_pbuild);
hresult hr = m_pgraph->queryinterface(iid_imediaevent, (void **)&pevent);
addtoobjecttable();
ibasefilter *pcap; // video capture filter.
ienummoniker *penum;
hr = enumeratedevices(clsid_videoinputdevicecategory, &penum);
displaydeviceinformation(penum, &pmoniker);
hr = pmoniker->bindtoobject(0, 0, iid_ibasefilter, (void**)&pcap);
if (succeeded(hr))
{
hr = m_pgraph->addfilter(pcap, l"capture filter");
}
hr = m_pbuild->renderstream(&pin_category_preview, &mediatype_video, pcap, null, null);
ibasefilter *pmux;
hr = m_pbuild->setoutputfilename(&mediasubtype_avi,l"d:\\example.avi",&pmux,null);
hr = m_pbuild->renderstream(&pin_category_capture,&mediatype_video,pcap,null,pmux);
// 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;
}
}
调用:
[html]
lpcwstr wchfile=l"d:\\example.avi";
m_graph.buildfromfile(wchfile);
m_graph.makechild(getsafehwnd());
m_graph.run();
作者:luckyboy101