One area I was unsure of is passing parameters to filters as specified in
the PARAM node. Where a FILTER element has a PARAM element with a src
attribute e.g.
<FILTER ID="VOB_Source_0" clsid="{E436EBB5-524F-11CE-9F53-0020AF0BA770}">
<PARAM name="src" value="C:\vts_02_4.vob"/>
</FILTER>
I have used IGraphBuilder::AddSourceFilter, but maybe this is incorrect.
If anyone would like to suggest changes or enhancements I would be very
grateful.
<!-- GraphEditToCpp.xsl -->
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<![CDATA[
#include <dshow.h>
#include <comdef.h>
#include <atlbase.h>
#include <iostream>
inline void TESTHR(HRESULT hr)
{
if(FAILED(hr))
{
_com_raise_error(hr);
}
}
void main(void)
{
CoInitialize(NULL);
try
{
]]>
<xsl:apply-templates select="GRAPH"/>
<![CDATA[
}
catch(_com_error &e)
{
const char *errMsg = e.ErrorMessage();
const char *errDesc = e.Description();
std::cout << "Error: ";
if(errMsg != NULL)
{
std::cout << errMsg << std::endl;
}
if(errDesc != NULL)
{
std::cout << errDesc << std::endl;
}
}
catch(...)
{
std::cout << "Error: no details";
}
}
]]>
</xsl:template>
<xsl:template match="GRAPH">
<![CDATA[
CComPtr<IGraphBuilder> pGraph;
CComPtr<IMediaControl> pMediaControl;
CComPtr<IMediaEvent> pEvent;
TESTHR(pGraph.CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER));
TESTHR(pGraph->QueryInterface(IID_IMediaControl, (void
**)&pMediaControl));
TESTHR(pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent));
]]>
CLSID clsid;
<xsl:apply-templates select="FILTER">
<xsl:sort select="position()" order="descending"/>
</xsl:apply-templates>
<xsl:apply-templates select="connect"/>
<![CDATA[
pMediaControl->Run();
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
]]>
</xsl:template>
<xsl:template match="FILTER">
<!-- Create filter -->
CComPtr<IBaseFilter> <xsl:apply-templates select="@ID"/>;
TESTHR(CLSIDFromString(L"<xsl:value-of select="@clsid"/>",
&clsid));
TESTHR(<xsl:apply-templates select="@ID"/>.CoCreateInstance(clsid, NULL,
CLSCTX_INPROC_SERVER));
pGraph->AddFilter(<xsl:apply-templates select="@ID"/>,
L"<xsl:value-of select="@ID"/>");
</xsl:template>
<xsl:template match="FILTER[PARAM/@name='src']">
<!-- Create source filter -->
<xsl:variable name="FileName" select="translate(PARAM/@value, '\', '/')"/>
CComPtr<IBaseFilter> <xsl:apply-templates select="@ID"/>;
pGraph->AddSourceFilter(L"<xsl:value-of
select="$FileName"/>", L"<xsl:value-of select="$FileName"/>",
&<xsl:apply-templates select="@ID"/>);
</xsl:template>
<xsl:template match="connect">
<!-- Connec filters -->
CComPtr<IPin> pSrcPin<xsl:value-of select="position()"/>,
pDestPin<xsl:value-of select="position()"/>;
<xsl:apply-templates select="@src"/>->FindPin(L"<xsl:value-of
select="@srcpin"/>", &pSrcPin<xsl:value-of select="position()"/>);
<xsl:apply-templates select="@dest"/>->FindPin(L"<xsl:value-of
select="@destpin"/>", &pDestPin<xsl:value-of
select="position()"/>);
TESTHR(pGraph->ConnectDirect(pSrcPin<xsl:value-of select="position()"/>,
pDestPin<xsl:value-of select="position()"/>, NULL));
</xsl:template>
<xsl:template match="@ID | @src | @dest">
<!-- Make a valid C++ variable name (not very strict) -->
<xsl:value-of select="translate(.,
'ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvqxyz1234567890_/- ',
'ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvqxyz1234567890____')"/>
</xsl:template>
</xsl:stylesheet>
> I have made an attempt at creating an XSLT stylesheet to transform
> a GraphEdit XML (XGR) filter graph into C++. I don't know how
> useful it will be in practice but it might help as a starting
> point.
>
> One area I was unsure of is passing parameters to filters as
> specified in the PARAM node. Where a FILTER element has a PARAM
> element with a src attribute e.g.
>
><FILTER ID="VOB_Source_0"
><clsid="{E436EBB5-524F-11CE-9F53-0020AF0BA770}">
> <PARAM name="src" value="C:\vts_02_4.vob"/>
></FILTER>
>
That's cool!
I think you are fine using IGraphBuilder::AddSourceFilter to add this
filter. The 'src' attribute probably indicates a filter which
implements IFileSourceFilter. Therefore you can either use
IGraphBuilder::AddSourceFilter or create the filter, QI for
IFileSourceFilter and call IFileSourceFilter::Load to specify the
input file name.
If the filter does not support IFileSourceFilter, then you will
probably have to handle it like you do a 'data' PARAM element except
you will load the stream from a structured storage file and then call
IPersistStream::Load on the filter.
HTH,
Bill
--
Bill Arnette
Signalscape, Inc.
bi...@MAPSONsignalscape.com
www.signalscape.com
"Bill Arnette" <bi...@MAPSONsignalscape.com> wrote in
message
news:Xns93035D3F3E8CCbi...@207.46.248.16...
"Alessandro Angeli [MVP::DigitalMedia]" <a.angel...@sogetelREMOVE.it>
wrote in message news:uBCWln#uCHA.2060@TK2MSFTNGP11...
BTW I'm using the command-line utility msxsl.exe to transform the XML. It is
available for download here
http://download.microsoft.com/download/xml/Utility/2.0/NT5XP/EN-US/msxsl.exe
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
void main(void)
{
CoInitialize(NULL);
TESTHR(pGraph.CoCreateInstance(CLSID_FilterGraph));
TESTHR(pGraph.QueryInterface(&pMediaControl));
TESTHR(pGraph.QueryInterface(&pEvent));
]]>
CLSID clsid;
<xsl:apply-templates select="FILTER">
<xsl:sort select="position()" order="descending"/>
</xsl:apply-templates>
<xsl:apply-templates select="connect"/>
<![CDATA[
TESTHR(pMediaControl->Run());
long evCode;
TESTHR(pEvent->WaitForCompletion(INFINITE, &evCode));
]]>
</xsl:template>
<xsl:template match="FILTER">
<!-- Create filter -->
CComPtr<IBaseFilter> <xsl:apply-templates select="@ID"/>;
TESTHR(CLSIDFromString(L"<xsl:value-of select="@clsid"/>",
&clsid));
TESTHR(<xsl:apply-templates select="@ID"/>.CoCreateInstance(clsid));
<xsl:apply-templates select="PARAM"/>
TESTHR(pGraph->AddFilter(<xsl:apply-templates select="@ID"/>,
L"<xsl:value-of select="@ID"/>"));
</xsl:template>
<xsl:template match="connect">
<!-- Connect filters -->
CComPtr<IPin> pSrcPin<xsl:value-of select="position()"/>,
pDestPin<xsl:value-of select="position()"/>;
TESTHR(<xsl:apply-templates
select="@src"/>->FindPin(L"<xsl:value-of select="@srcpin"/>",
&pSrcPin<xsl:value-of select="position()"/>));
TESTHR(<xsl:apply-templates
select="@dest"/>->FindPin(L"<xsl:value-of select="@destpin"/>",
&pDestPin<xsl:value-of select="position()"/>));
<xsl:choose>
<xsl:when test="@direct = 'yes'">
TESTHR(pGraph->ConnectDirect(pSrcPin<xsl:value-of select="position()"/>,
pDestPin<xsl:value-of select="position()"/>, NULL));
</xsl:when>
<xsl:otherwise>
TESTHR(pGraph->Connect(pSrcPin<xsl:value-of select="position()"/>,
pDestPin<xsl:value-of select="position()"/>, NULL));
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@ID | @src | @dest">
<!-- Make a valid-ish C++ variable name -->
<xsl:value-of select="translate(.,
'ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvqxyz1234567890_/- ',
'ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvqxyz1234567890____')"/>
</xsl:template>
<xsl:template match="PARAM">
<xsl:choose>
<xsl:when test="@name='src'">
CComPtr<IFileSourceFilter> pFileSource;
TESTHR(<xsl:apply-templates
select="../@ID"/>.QueryInterface(&pFileSource));
TESTHR(pFileSource->Load(L"<xsl:value-of select="translate(@value,
'\', '/')"/>", NULL));
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I think you could create the code section like this (untested):
CComQIPtr<IPersistStream> ps = pFilter;
if (ps)
{
BYTE *pBuf;
DWORD bufLen;
// Decode the data string using a global function
CComPtr<IStream> pStream;
DecodeDataStringToStream("<value-of select="@value"/>", &pStream)
if (pStream)
{
// Load the filter state from the stream
ps->Load(pStream);
}
}
The above code would go in the PARAM tag template and the global
function DecodeDataStringToStream would either be a part of the /
template or it could be linked in. Either way
DecodeDataStringToStream would be implemented something like:
HRESULT DecodeDataStringToStream(LPCSTR pDataString, IStream
**pStream)
{
DWORD bufLen = 0;
// Get the required decode buffer length
DecodeDataString(pData, NULL, &bufLen);
// Allocate a buffer to decode to
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, bufLen);
BYTE *pDecoded = GlobalLock(hMem);
// Decode the buffer
DecodeDataString(pDataString, pDecoded, &bufLen);
// Return a stream with the decoded data, allow the
// memory to be freed when the stream is finally
// released
return CreateStreamOnHGlobal(hMem, TRUE, pStream);
}
DWORD DecodeDataString(LPCSTR pStr, LPBYTE pDecodeBuf, DWORD pBufLen)
{
// Calculate the buffer size needed for the decoded data
// if *pBufLen < decodeLen, set pBufLen to the size needed and
// return
*pBufLen = decodedLen;
if (pDecodeBuf)
{
// Actually decode the string into the buffer pointed
// to by pDecodeBuf
}
return decodedLen;
}
cheers,
Bill
"TomJ" <tjulie...@hotmail.com> wrote in
news:b04k6f$lin$1...@newsg1.svr.pol.co.uk:
--
How do you get access to the "data" to persist a non-source filter? I
am referring to the "data" like you see in an xgr file where <PARAM
name="data"> appears. I would love to see some code that accesses this
persistence data, stores it to a file, then later reloads it from a
file and restores the filters settings.
- Jeff Dodson
=== saving and restoring filter state ===
http://groups.google.com/groups?th=7175230925fbe08c
=== saving and restoring AVI compressor state ===
http://groups.google.com/groups?th=908728ad897d423
http://groups.google.com/groups?th=df9eb79ac6e9589d
http://groups.google.com/groups?th=abe9c147f73bca8c
http://groups.google.com/groups?th=cdef9149a22f830d
=== saving and restoring filter state using
ISpecifyPropertyPages ===
http://groups.google.com/groups?th=1c62d3ecc1eee33f
=== how to use ISpecifyPropertyPages ===
http://groups.google.com/groups?th=8719df7c358cb03a
http://groups.google.com/groups?th=ecfdb3f3451d1a6d
"Jeff" <jef...@netzero.net> wrote in message
news:8d8014d2.03011...@posting.google.com...