Implemented IGraphBuilder methods: Connect, Render, RenderFile &
AddSourceFilter. Fixed filter name generation in IGraphBuilder::AddFilter.
This commit is contained in:
parent
18988663c2
commit
8db6b0a514
|
@ -31,12 +31,15 @@
|
|||
#include "winuser.h"
|
||||
#include "dshow.h"
|
||||
#include "wine/debug.h"
|
||||
#include "quartz_private.h"
|
||||
#define COM_NO_WINDOWS_H
|
||||
#include "ole2.h"
|
||||
#include "olectl.h"
|
||||
#include "strmif.h"
|
||||
#include "vfwmsgs.h"
|
||||
#include "evcode.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#include "quartz_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
||||
|
||||
|
@ -163,6 +166,7 @@ typedef struct _IFilterGraphImpl {
|
|||
/* IVideoFrameStep */
|
||||
|
||||
ULONG ref;
|
||||
IFilterMapper2 * pFilterMapper2;
|
||||
IBaseFilter ** ppFiltersInGraph;
|
||||
LPWSTR * pFilterNames;
|
||||
int nFilters;
|
||||
|
@ -238,6 +242,7 @@ static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
|
|||
|
||||
ref = --This->ref;
|
||||
if (ref == 0) {
|
||||
IFilterMapper2_Release(This->pFilterMapper2);
|
||||
CloseHandle(This->hEventCompletion);
|
||||
EventsQueue_Destroy(&This->evqueue);
|
||||
HeapFree(GetProcessHeap(), 0, This->ppFiltersInGraph);
|
||||
|
@ -316,7 +321,7 @@ static HRESULT WINAPI Graphbuilder_AddFilter(IGraphBuilder *iface,
|
|||
|
||||
/* Check if the generated name already exists */
|
||||
for(i = 0; i < This->nFilters; i++)
|
||||
if (!strcmpW(This->pFilterNames[i], pName))
|
||||
if (!strcmpW(This->pFilterNames[i], wszFilterName))
|
||||
break;
|
||||
|
||||
/* Compute next index and exit if generated name is suitable */
|
||||
|
@ -335,7 +340,6 @@ static HRESULT WINAPI Graphbuilder_AddFilter(IGraphBuilder *iface,
|
|||
else
|
||||
memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
|
||||
|
||||
|
||||
if (This->nFilters + 1 > This->filterCapacity)
|
||||
{
|
||||
int newCapacity = 2*This->filterCapacity;
|
||||
|
@ -485,23 +489,348 @@ static HRESULT WINAPI Graphbuilder_SetDefaultSyncSource(IGraphBuilder *iface) {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
|
||||
{
|
||||
static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
|
||||
static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
|
||||
IPropertyBag * pPropBagCat = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
VariantInit(pvar);
|
||||
V_VT(pvar) = VT_BSTR;
|
||||
|
||||
hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
|
||||
|
||||
if (pPropBagCat)
|
||||
IPropertyBag_Release(pPropBagCat);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* poutputpin, IPin*** pppins, ULONG* pnb)
|
||||
{
|
||||
HRESULT hr;
|
||||
ULONG nb = 0;
|
||||
|
||||
TRACE("\n");
|
||||
hr = IPin_QueryInternalConnections(poutputpin, NULL, &nb);
|
||||
if (hr == S_OK) {
|
||||
/* Rendered input */
|
||||
} else if (hr == S_FALSE) {
|
||||
*pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
|
||||
hr = IPin_QueryInternalConnections(poutputpin, *pppins, &nb);
|
||||
if (hr != S_OK) {
|
||||
ERR("Error (%lx)\n", hr);
|
||||
}
|
||||
} else if (hr == E_NOTIMPL) {
|
||||
/* Input connected to all outputs */
|
||||
IEnumPins* penumpins;
|
||||
IPin* ppin;
|
||||
int i = 0;
|
||||
TRACE("E_NOTIMPL\n");
|
||||
hr = IBaseFilter_EnumPins(pfilter, &penumpins);
|
||||
if (FAILED(hr)) {
|
||||
ERR("filter Enumpins failed (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
i = 0;
|
||||
/* Count output pins */
|
||||
while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
|
||||
PIN_DIRECTION pindir;
|
||||
IPin_QueryDirection(ppin, &pindir);
|
||||
if (pindir == PINDIR_OUTPUT)
|
||||
i++;
|
||||
else
|
||||
IPin_Release(ppin);
|
||||
}
|
||||
*pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
|
||||
/* Retreive output pins */
|
||||
IEnumPins_Reset(penumpins);
|
||||
i = 0;
|
||||
while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
|
||||
PIN_DIRECTION pindir;
|
||||
IPin_QueryDirection(ppin, &pindir);
|
||||
if (pindir == PINDIR_OUTPUT)
|
||||
(*pppins)[i++] = ppin;
|
||||
else
|
||||
IPin_Release(ppin);
|
||||
}
|
||||
nb = i;
|
||||
if (FAILED(hr)) {
|
||||
ERR("Next failed (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
IEnumPins_Release(penumpins);
|
||||
} else if (FAILED(hr)) {
|
||||
ERR("Cannot get internal connection (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
*pnb = nb;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*** IGraphBuilder methods ***/
|
||||
static HRESULT WINAPI Graphbuilder_Connect(IGraphBuilder *iface,
|
||||
IPin *ppinOut,
|
||||
IPin *ppinIn) {
|
||||
ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
|
||||
HRESULT hr;
|
||||
AM_MEDIA_TYPE* mt;
|
||||
IEnumMediaTypes* penummt;
|
||||
ULONG nbmt;
|
||||
IEnumPins* penumpins;
|
||||
IEnumMoniker* pEnumMoniker;
|
||||
GUID tab[2];
|
||||
ULONG nb;
|
||||
IMoniker* pMoniker;
|
||||
ULONG pin;
|
||||
|
||||
TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, ppinOut, ppinIn);
|
||||
TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
|
||||
|
||||
/* Try direct connection first */
|
||||
TRACE("Try direct connection first\n");
|
||||
hr = IPin_Connect(ppinOut, ppinIn, NULL);
|
||||
if (SUCCEEDED(hr)) {
|
||||
TRACE("Direct connection successfull\n");
|
||||
return S_OK;
|
||||
}
|
||||
TRACE("Direct connection failed, trying to insert other filters\n");
|
||||
|
||||
/* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream
|
||||
* filter to the minor mediatype of input pin of the renderer */
|
||||
hr = IPin_EnumMediaTypes(ppinOut, &penummt);
|
||||
if (FAILED(hr)) {
|
||||
ERR("EnumMediaTypes (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
|
||||
if (FAILED(hr)) {
|
||||
ERR("IEnumMediaTypes_Next (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!nbmt) {
|
||||
ERR("No media type found!\n");
|
||||
return S_OK;
|
||||
}
|
||||
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
|
||||
TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
|
||||
|
||||
/* Try to find a suitable filter that can connect to the pin to render */
|
||||
tab[0] = mt->majortype;
|
||||
tab[1] = mt->subtype;
|
||||
hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to enum filters (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
|
||||
{
|
||||
VARIANT var;
|
||||
GUID clsid;
|
||||
IPin** ppins;
|
||||
IPin* ppinfilter;
|
||||
IBaseFilter* pfilter = NULL;
|
||||
|
||||
hr = GetFilterInfo(pMoniker, &clsid, &var);
|
||||
IMoniker_Release(pMoniker);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to retreive filter info (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to create filter (%lx), trying next one\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to add filter (%lx)\n", hr);
|
||||
IBaseFilter_Release(pfilter);
|
||||
pfilter = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = IBaseFilter_EnumPins(pfilter, &penumpins);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Enumpins (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Next (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
if (pin == 0) {
|
||||
ERR("No Pin\n");
|
||||
goto error;
|
||||
}
|
||||
IEnumPins_Release(penumpins);
|
||||
|
||||
hr = IPin_Connect(ppinOut, ppinfilter, NULL);
|
||||
if (FAILED(hr)) {
|
||||
TRACE("Cannot connect to filter (%lx), trying next one\n", hr);
|
||||
goto error;
|
||||
}
|
||||
TRACE("Successfully connected to filter, follow chain...\n");
|
||||
|
||||
/* Render all output pins of the filter by calling IGraphBuilder_Render on each of them */
|
||||
hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
int i;
|
||||
TRACE("pins to consider: %ld\n", nb);
|
||||
for(i = 0; i < nb; i++) {
|
||||
TRACE("Processing pin %d\n", i);
|
||||
hr = IGraphBuilder_Connect(iface, ppins[0], ppinIn);
|
||||
if (FAILED(hr)) {
|
||||
TRACE("Cannot render pin %p (%lx)\n", ppinfilter, hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(ppins);
|
||||
}
|
||||
break;
|
||||
|
||||
error:
|
||||
if (pfilter) {
|
||||
IGraphBuilder_RemoveFilter(iface, pfilter);
|
||||
IBaseFilter_Release(pfilter);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumMediaTypes_Release(penummt);
|
||||
DeleteMediaType(mt);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI Graphbuilder_Render(IGraphBuilder *iface,
|
||||
IPin *ppinOut) {
|
||||
ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
|
||||
IEnumMediaTypes* penummt;
|
||||
AM_MEDIA_TYPE* mt;
|
||||
ULONG nbmt;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, ppinOut);
|
||||
IEnumMoniker* pEnumMoniker;
|
||||
GUID tab[2];
|
||||
ULONG nb;
|
||||
IMoniker* pMoniker;
|
||||
|
||||
TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
|
||||
|
||||
hr = IPin_EnumMediaTypes(ppinOut, &penummt);
|
||||
if (FAILED(hr)) {
|
||||
ERR("EnumMediaTypes (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
|
||||
if (FAILED(hr)) {
|
||||
ERR("IEnumMediaTypes_Next (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
if (!nbmt)
|
||||
break;
|
||||
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
|
||||
TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
|
||||
|
||||
/* Try to find a suitable renderer with the same media type */
|
||||
tab[0] = mt->majortype;
|
||||
tab[1] = GUID_NULL;
|
||||
hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, TRUE, FALSE, 0, NULL, NULL, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to enum filters (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
|
||||
{
|
||||
VARIANT var;
|
||||
GUID clsid;
|
||||
IPin* ppinfilter;
|
||||
IBaseFilter* pfilter = NULL;
|
||||
IEnumPins* penumpins;
|
||||
ULONG pin;
|
||||
|
||||
hr = GetFilterInfo(pMoniker, &clsid, &var);
|
||||
IMoniker_Release(pMoniker);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to retreive filter info (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to create filter (%lx), trying next one\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to add filter (%lx)\n", hr);
|
||||
IBaseFilter_Release(pfilter);
|
||||
pfilter = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = IBaseFilter_EnumPins(pfilter, &penumpins);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Splitter Enumpins (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Next (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
if (pin == 0) {
|
||||
ERR("No Pin\n");
|
||||
goto error;
|
||||
}
|
||||
IEnumPins_Release(penumpins);
|
||||
|
||||
/* Connect the pin to render to the renderer */
|
||||
hr = IGraphBuilder_Connect(iface, ppinOut, ppinfilter);
|
||||
if (FAILED(hr)) {
|
||||
TRACE("Unable to connect to renderer (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
|
||||
error:
|
||||
if (pfilter) {
|
||||
IGraphBuilder_RemoveFilter(iface, pfilter);
|
||||
IBaseFilter_Release(pfilter);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMediaType(mt);
|
||||
break;
|
||||
}
|
||||
|
||||
IEnumMediaTypes_Release(penummt);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -509,9 +838,134 @@ static HRESULT WINAPI Graphbuilder_RenderFile(IGraphBuilder *iface,
|
|||
LPCWSTR lpcwstrFile,
|
||||
LPCWSTR lpcwstrPlayList) {
|
||||
ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
|
||||
static const WCHAR string[] = {'R','e','a','d','e','r',0};
|
||||
IBaseFilter* preader = NULL;
|
||||
IBaseFilter* psplitter;
|
||||
IPin* ppinreader;
|
||||
IPin* ppinsplitter;
|
||||
IEnumPins* penumpins;
|
||||
ULONG pin;
|
||||
HRESULT hr;
|
||||
IEnumMoniker* pEnumMoniker;
|
||||
GUID tab[2];
|
||||
IPin** ppins;
|
||||
ULONG nb;
|
||||
IMoniker* pMoniker;
|
||||
IFileSourceFilter* pfile = NULL;
|
||||
AM_MEDIA_TYPE mt;
|
||||
WCHAR* filename;
|
||||
|
||||
TRACE("(%p/%p)->(%s (%p), %s (%p)): stub !!!\n", This, iface, debugstr_w(lpcwstrFile), lpcwstrFile, debugstr_w(lpcwstrPlayList), lpcwstrPlayList);
|
||||
TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
|
||||
|
||||
hr = IGraphBuilder_AddSourceFilter(iface, lpcwstrFile, string, &preader);
|
||||
|
||||
/* Retreive file media type */
|
||||
if (SUCCEEDED(hr))
|
||||
hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
|
||||
IFileSourceFilter_Release(pfile);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
tab[0] = mt.majortype;
|
||||
tab[1] = mt.subtype;
|
||||
hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
|
||||
} else {
|
||||
if (preader) {
|
||||
IGraphBuilder_RemoveFilter(iface, preader);
|
||||
IBaseFilter_Release(preader);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
|
||||
{
|
||||
VARIANT var;
|
||||
GUID clsid;
|
||||
|
||||
hr = GetFilterInfo(pMoniker, &clsid, &var);
|
||||
IMoniker_Release(pMoniker);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to retreive filter info (%lx)\n", hr);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&psplitter);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to create filter (%lx), trying next one\n", hr);
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = IGraphBuilder_AddFilter(iface, psplitter, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable add filter (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Connect file source and splitter filters together */
|
||||
/* Make the splitter analyze incoming data */
|
||||
hr = IBaseFilter_EnumPins(preader, &penumpins);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Enumpins (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
hr = IEnumPins_Next(penumpins, 1, &ppinreader, &pin);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Next (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
if (pin == 0) {
|
||||
ERR("No Pin\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
IEnumPins_Release(penumpins);
|
||||
|
||||
hr = IBaseFilter_EnumPins(psplitter, &penumpins);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Splitter Enumpins (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
hr = IEnumPins_Next(penumpins, 1, &ppinsplitter, &pin);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Next (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
if (pin == 0) {
|
||||
ERR("No Pin\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
IEnumPins_Release(penumpins);
|
||||
|
||||
hr = IPin_Connect(ppinreader, ppinsplitter, NULL);
|
||||
if (FAILED(hr)) {
|
||||
IBaseFilter_Release(ppinsplitter);
|
||||
ppinsplitter = NULL;
|
||||
TRACE("Cannot connect to filter (%lx), trying next one\n", hr);
|
||||
break;
|
||||
}
|
||||
TRACE("Successfully connected to filter\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Render all output pin of the splitter by calling IGraphBuilder_Render on each of them */
|
||||
hr = GetInternalConnections(psplitter, ppinsplitter, &ppins, &nb);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
int i;
|
||||
TRACE("pins to consider: %ld\n", nb);
|
||||
for(i = 0; i < nb; i++) {
|
||||
TRACE("Processing pin %d\n", i);
|
||||
hr = IGraphBuilder_Render(iface, ppins[i]);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Cannot render pin %p (%lx)\n", ppins[i], hr);
|
||||
/* FIXME: We should clean created things properly */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(ppins);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -520,9 +974,61 @@ static HRESULT WINAPI Graphbuilder_AddSourceFilter(IGraphBuilder *iface,
|
|||
LPCWSTR lpcwstrFilterName,
|
||||
IBaseFilter **ppFilter) {
|
||||
ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
|
||||
HRESULT hr;
|
||||
IBaseFilter* preader;
|
||||
IFileSourceFilter* pfile = NULL;
|
||||
AM_MEDIA_TYPE mt;
|
||||
WCHAR* filename;
|
||||
|
||||
TRACE("(%p/%p)->(%s (%p), %s (%p), %p): stub !!!\n", This, iface, debugstr_w(lpcwstrFileName), lpcwstrFileName, debugstr_w(lpcwstrFilterName), lpcwstrFilterName, ppFilter);
|
||||
TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
|
||||
|
||||
/* Instantiate a file source filter */
|
||||
hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to create file source filter (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = IGraphBuilder_AddFilter(iface, preader, lpcwstrFilterName);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable add filter (%lx)\n", hr);
|
||||
IBaseFilter_Release(preader);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to get IFileSourceInterface (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Load the file in the file source filter */
|
||||
hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Load (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
|
||||
if (FAILED(hr)) {
|
||||
ERR("GetCurFile (%lx)\n", hr);
|
||||
goto error;
|
||||
}
|
||||
TRACE("File %s\n", debugstr_w(filename));
|
||||
TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
|
||||
TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
|
||||
|
||||
if (ppFilter)
|
||||
*ppFilter = preader;
|
||||
|
||||
return S_OK;
|
||||
|
||||
error:
|
||||
if (pfile)
|
||||
IFileSourceFilter_Release(pfile);
|
||||
IGraphBuilder_RemoveFilter(iface, preader);
|
||||
IBaseFilter_Release(preader);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2413,6 +2919,7 @@ static IMediaEventSinkVtbl IMediaEventSink_VTable =
|
|||
/* This is the only function that actually creates a FilterGraph class... */
|
||||
HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) {
|
||||
IFilterGraphImpl *fimpl;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
|
||||
|
||||
|
@ -2444,6 +2951,12 @@ HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) {
|
|||
fimpl->EcCompleteCount = 0;
|
||||
EventsQueue_Init(&fimpl->evqueue);
|
||||
|
||||
hr = CoCreateInstance(&CLSID_FilterMapper, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2);
|
||||
if (FAILED(hr)) {
|
||||
ERR("Unable to create filter mapper (%lx)\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
*ppObj = fimpl;
|
||||
return S_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue