Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
May 2005
- 145 participants
- 348 discussions
I realized today that we can't compile man pages outside the source directory,
c2man complains about being unable to find .c files.
I modified a line in dlls/Makedll.in:
$(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext)
-R$(TOPOBJDIR) -S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %)
$(SPEC_SRCS16:%=-w
%) $(C_SRCS) $(C_SRCS16)
so that it becomes:
cd $(SRCDIR) && $(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext)
-R$(TOPOBJDIR) -S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %)
$(SPEC_SRCS16:%=-w
%) $(C_SRCS) $(C_SRCS16)
Then, because documentation/man3w should be in the build directory, we have to
modify TOPSRCDIR and TOPOBJDIR for the makefiles. I modified them to:
TOPSRCDIR = @abs_top_srcdir@
TOPOBJDIR = @abs_top_builddir@
Is this correct? I'm testing it (my machine's slow) to see if it breaks
anything.
I've just done
for i in `find -name Makefile.in`
do
cat $i | sed \
-e s/TOPSRCDIR = .*/TOPSRCDIR = @abs_top_srcdir@/ \
-e s/TOPOBJDIR = .*/TOPOBJDIR = @abs_top_builddir@/ \
> $i.new
cat $i.new > $i
rm $i.new
done
and the patch is quite large, about 130k, so maybe I won't post it here
(straight to wine-patches if it's ok). Just the first 2:
Index: Makefile.in
===================================================================
RCS file: /home/wine/wine/Makefile.in,v
retrieving revision 1.161
diff -u -p -r1.161 Makefile.in
--- Makefile.in 2 Mar 2005 12:18:55 -0000 1.161
+++ Makefile.in 4 May 2005 10:19:18 -0000
@@ -17,8 +17,8 @@
# Directories
-TOPSRCDIR = @top_srcdir@
-TOPOBJDIR = .
+TOPSRCDIR = @abs_top_srcdir@
+TOPOBJDIR = @abs_top_builddir@
SRCDIR = @srcdir@
VPATH = @srcdir@
LIBEXT = @LIBEXT@
Index: dlls/Makedll.rules.in
===================================================================
RCS file: /home/wine/wine/dlls/Makedll.rules.in,v
retrieving revision 1.71
diff -u -p -r1.71 Makedll.rules.in
--- dlls/Makedll.rules.in 8 Mar 2005 16:55:26 -0000 1.71
+++ dlls/Makedll.rules.in 4 May 2005 10:19:18 -0000
@@ -61,13 +61,13 @@ $(MAINSPEC).c: $(MAINSPEC) $(RC_SRCS:.rc
# Rules for auto documentation
man: $(C_SRCS)
- $(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext) -R$(TOPOBJDIR)
-S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS)
$(C_SRCS16)
+ cd $(SRCDIR) && $(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext)
-R$(TOPOBJDIR) -S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %)
$(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
doc-html: $(C_SRCS)
- $(C2MAN) -o $(TOPOBJDIR)/documentation/html -R$(TOPSRCDIR) $(INCLUDES) -Th
$(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
+ cd $(SRCDIR) && $(C2MAN) -o $(TOPOBJDIR)/documentation/html -R$(TOPSRCDIR)
$(INCLUDES) -Th $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
doc-sgml: $(C_SRCS)
- $(C2MAN) -o $(TOPOBJDIR)/documentation/api-guide -R$(TOPSRCDIR) $(INCLUDES)
-Ts $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
+ cd $(SRCDIR) && $(C2MAN) -o $(TOPOBJDIR)/documentation/api-guide
-R$(TOPSRCDIR) $(INCLUDES) -Ts $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %)
$(C_SRCS) $(C_SRCS16)
.PHONY: man doc-html doc-sgml
William Poetra Yoga Hadisoeseno
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
2
3
--- Paul van Schayck <polleke(a)gmail.com> wrote:
> We do need this for winecfg. If you want to setup virtual drive you do
> want to see the full unix fs. Winecfg needs to have to unix paths.
> Putting conversion code in winecfg was not really acceptable, an
> extension to was.
>
> This extension will become even more valuable because we want winecfg
> (or wine in particular) to start without having any virtual drive.
> People might have removed all drives (with winecfg).
>
> Paul
>
But surely, for this particular winecfg program we don't need to add extensions
to all of wine, right? I mean, if we extend the API this way, more will come.
And it's actually easier to extend than to trim down, so I say we'd better not
add this extension.
About winecfg, why not have a unix, text-based version of winecfg? More like
Linux's make config IMO. Then when the drives are already set up, we can run
the 'real' winecfg.
William Poetra Yoga Hadisoeseno
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
1
0
When i run Electronic work bench exe with wine i get this:
]$ wine WEWB32.EXE
Loading required GL library /usr/X11R6/lib/libGL.so.1.2
fixme:ntdll:TIME_GetTZAsStr Can't match system time zone name "WEST", bias=-60
and dst=1 to an entry in TZ_INFO. Please add appropriate entry to TZ_INFO and
submit as patch to wine-patches
fixme:font:WineEngRemoveFontResourceEx :stub
And when using it, if i click in some icon then it stays black.
Any help?
Note: im using last wine release
--
Zé
Linux user #378762
1
0
Hi Jesse,
The failures you see are only whitespace changes.
Either make patch skip whitespace changes, or apply the following patch
to Olivier's patch prior to apply it to your tree.
Vincent
3
6
Kees Cook <kees(a)outflux.net> writes:
> ChangeLog:
> Black-box implementation of CryptProtectData/CryptUnprotectData
>
> This is a resend, since it looks like current patches are making their
> way into CVS now. :) It was reviewed last week by several people, and
> includes docs, tests, etc.
I don't understand while you come up with such an elaborate scheme of
storing things in the registry when it's clearly not the way this
thing is supposed to work. If you can't figure out what Windows does,
then just xoring the data with 0xdeadbeef or something like this would
be at least as secure as your solution, and would actually be much
closer to the proper behavior.
--
Alexandre Julliard
julliard(a)winehq.org
3
8
Please send all presentations/PDFs/whatever to ivanleo(a)gmail.com and
I'll upload them to the server that will be providing the wineconf
videos.
Ivan.
2
1
Hello,
Right now, each time I make a modification (even one line) I do a
'make' followed by a 'make install'.
Is there a faster way ?
Thanks
David Hemmo
4
5
The application of this patch causes a menu item to not be
displayed.
In appplication TablEdit Demo available at
http://www.tabledit.com/download/tabled32.exe
there is under the "File" entry of the menubar a submenu
entry for both "Import" and "Export" which are both present when run
under WINE before this patch is applied. After application the
"Import" submenu is no longer present.
The loss of this submenu persists into the current 20050405 release.
I am running Slackware 10.0 on a AMD K6 500Mhz with self-compiled
binaries from CVS as per regression testing procedure on winehq.com.
--
Timm Reasbeck
3
2
04 May '05
I thought I'd move it around a little and put it in qcap, where I
*think* it should reside, I know CaptureGraphBuilder has to, so I moved
it to
I had to copy some files from quartz for it though
media.c is enummedia.c in quartz
pin.c is a diet version of quartz' pin.c
regsvr.c is meant to register the vfwcapture and the capturegraphbuilder
class, also copied from quartz
qcap_main.c is basically a modified version of quartz' main.c
vfwcapture related files:
vfwcapture.c - front-end com interface
v4l.c - Does the magic between /dev/video and vfwcapture
null.c - NULL renderer, in case v4l isn't available the functions get
enabled
capture.h - headers that are used for null.c/v4l.c/vfwcapture.c
Current todo list:
- Implement YUV formats (If anyone has some documentation on it I would
be grateful, if you want to write the renderers yourself (Should be
easy) I would be eternal grateful)
- Add resizing (Help me!!! Fix my Resize function (24 bits to 24 bits)
and send the results to me), currently resizing (Clipping and flipping
image horizontal) should crash when format < 320x240
- Find a way for devenum to keep /dev/video* apart (I have a vague idea
on how to do it)
- Fix Capture_SetMediaType function to try to adjust size
I'll do the last thing of my TODO list myself, but if you're interested
in helping you're free to do so :)
If your webcam isn't detected in msn messenger there could be several
reasons:
1. Make sure you use the BUILTIN devenum,quartz and qcap
2. Make sure you regsvr32'd the *BUILTIN* qcap and quartz (regsvr32 qcap)
3. Delete HKEY_CURRENT_USER/Software/Microsoft/ActiveMovie
4. Check permissions for /dev/video*
5. Adjust #define VIDEODEVICE (in dlls/qcap/vfwcapture.c) to get the
right video device..
6. Try starting up msn with WINEDEBUG=-all,+qcap_v4l and check for
output, especially the ERR lines
You could get something like:
err:qcap_v4l:Capture_Initialise /dev/video1: (Some explanation why the
initialisation failed here)
in that case it should be obvious why it wouldn't work and how you can
fix it :)
If it can't render your webcam, write a renderer for it and give me a
copy of it.
If it your image gets clipped, dig into msdn and write a proper resize
function and pass me a copy.
If you're too lazy to apply my quartz fixes patch, native quartz will
work too.. (I tested it).. but I offer no guarantees on it..
If something else happens, tell me the results, and I'll look at it..
(If not covered by the above ;))
At this point, it is not recommended to use this in msn but you're free
to try, you will need a native msvfw32.dll, because a function msn uses
is not implemented in the builtin
This patch will only work for wine-cvs, since it uses some patches that
are for now only in the wine cvs tree
Devices I tested this on:
A creative usb webcam (zc030x driver), images looked distorted because
of driver issues, not because of bugs on my side
bttv, worked perfect, because for some reason it initialised with a
resolution of 320x240, so I didn't need to touch it
Index: dlls/quartz/enummedia.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/enummedia.c,v
retrieving revision 1.5
diff -u -p -r1.5 enummedia.c
--- dlls/quartz/enummedia.c 6 Jan 2005 19:36:47 -0000 1.5
+++ dlls/quartz/enummedia.c 1 May 2005 00:10:56 -0000
@@ -27,6 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
{
memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
+ if (!pSrc->pbFormat) return S_OK;
if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
return E_OUTOFMEMORY;
memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
@@ -45,6 +46,7 @@ void DeleteMediaType(AM_MEDIA_TYPE * pMe
IUnknown_Release(pMediaType->pUnk);
pMediaType->pUnk = NULL;
}
+ CoTaskMemFree(pMediaType);
}
BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
@@ -90,7 +92,11 @@ HRESULT IEnumMediaTypesImpl_Construct(co
pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
for (i = 0; i < pDetails->cMediaTypes; i++)
- pEnumMediaTypes->enumMediaDetails.pMediaTypes[i] = pDetails->pMediaTypes[i];
+ if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]))) {
+ while (--i > 0) CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes[i].pbFormat);
+ CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes);
+ return E_OUTOFMEMORY;
+ }
*ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
return S_OK;
}
@@ -136,12 +142,14 @@ static ULONG WINAPI IEnumMediaTypesImpl_
if (!refCount)
{
+ int i;
+ for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
+ if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
+ CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
CoTaskMemFree(This);
- return 0;
}
- else
- return refCount;
+ return refCount;
}
static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
@@ -159,7 +167,13 @@ static HRESULT WINAPI IEnumMediaTypesImp
ULONG i;
*ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
for (i = 0; i < cFetched; i++)
- (*ppMediaTypes)[i] = This->enumMediaDetails.pMediaTypes[This->uIndex + i];
+ if (FAILED(CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]))) {
+ while (--i)
+ CoTaskMemFree((*ppMediaTypes)[i].pbFormat);
+ CoTaskMemFree(*ppMediaTypes);
+ *ppMediaTypes = NULL;
+ return E_OUTOFMEMORY;
+ }
}
if ((cMediaTypes != 1) || pcFetched)
Index: dlls/quartz/filtergraph.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filtergraph.c,v
retrieving revision 1.27
diff -u -p -r1.27 filtergraph.c
--- dlls/quartz/filtergraph.c 24 Mar 2005 21:01:37 -0000 1.27
+++ dlls/quartz/filtergraph.c 1 May 2005 00:10:58 -0000
@@ -245,6 +245,9 @@ static ULONG Filtergraph_Release(IFilter
TRACE("(%p)->(): new ref = %ld\n", This, ref);
if (ref == 0) {
+ int i;
+ for (i = 0; i < This->nFilters; i++)
+ IBaseFilter_Release(This->ppFiltersInGraph[i]);
IFilterMapper2_Release(This->pFilterMapper2);
CloseHandle(This->hEventCompletion);
EventsQueue_Destroy(&This->evqueue);
@@ -556,8 +559,7 @@ static HRESULT GetInternalConnections(IB
IPin_QueryDirection(ppin, &pindir);
if (pindir == PINDIR_OUTPUT)
i++;
- else
- IPin_Release(ppin);
+ IPin_Release(ppin);
}
*pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
/* Retrieve output pins */
@@ -605,10 +607,8 @@ static HRESULT WINAPI Graphbuilder_Conne
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 successful\n");
return S_OK;
}
TRACE("Direct connection failed, trying to insert other filters\n");
@@ -648,7 +648,7 @@ static HRESULT WINAPI Graphbuilder_Conne
VARIANT var;
GUID clsid;
IPin** ppins;
- IPin* ppinfilter;
+ IPin* ppinfilter = NULL;
IBaseFilter* pfilter = NULL;
hr = GetFilterInfo(pMoniker, &clsid, &var);
@@ -677,6 +677,7 @@ static HRESULT WINAPI Graphbuilder_Conne
ERR("Enumpins (%lx)\n", hr);
goto error;
}
+
hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
if (FAILED(hr)) {
ERR("Next (%lx)\n", hr);
@@ -703,17 +704,22 @@ static HRESULT WINAPI Graphbuilder_Conne
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);
+ hr = IGraphBuilder_Connect(iface, ppins[i], ppinIn);
if (FAILED(hr)) {
- TRACE("Cannot render pin %p (%lx)\n", ppinfilter, hr);
- return hr;
+ TRACE("Cannot render pin %p (%lx)\n", ppinfilter, hr);
}
+ IPin_Release(ppins[i]);
+ if (SUCCEEDED(hr)) break;
}
+ while (++i < nb) IPin_Release(ppins[i]);
CoTaskMemFree(ppins);
+ IBaseFilter_Release(pfilter);
+ IPin_Release(ppinfilter);
+ break;
}
- break;
error:
+ if (ppinfilter) IPin_Release(ppinfilter);
if (pfilter) {
IGraphBuilder_RemoveFilter(iface, pfilter);
IBaseFilter_Release(pfilter);
@@ -1167,7 +1173,9 @@ static HRESULT WINAPI Mediacontrol_Invok
return S_OK;
}
-static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, REFERENCE_TIME tStart)
+typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *);
+
+static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter)
{
HRESULT hr;
IPin* pInputPin;
@@ -1176,7 +1184,8 @@ static HRESULT ExploreGraph(IFilterGraph
ULONG i;
PIN_INFO PinInfo;
- TRACE("%p %p %lld\n", pGraph, pOutputPin, tStart);
+ TRACE("%p %p\n", pGraph, pOutputPin);
+ PinInfo.pFilter = NULL;
hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
@@ -1201,20 +1210,33 @@ static HRESULT ExploreGraph(IFilterGraph
/* Explore the graph downstream from this pin
* FIXME: We should prevent exploring from a pin more than once. This can happens when
* several input pins are connected to the same output (a MUX for instance). */
- ExploreGraph(pGraph, ppPins[i], tStart);
+ ExploreGraph(pGraph, ppPins[i], FoundFilter);
+ IPin_Release(ppPins[i]);
}
CoTaskMemFree(ppPins);
}
- TRACE("Run filter %p\n", PinInfo.pFilter);
- IBaseFilter_Run(PinInfo.pFilter, tStart);
+ TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
+ FoundFilter(PinInfo.pFilter);
}
+ if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
return hr;
}
-/*** IMediaControl methods ***/
-static HRESULT WINAPI Mediacontrol_Run(IMediaControl *iface) {
+static HRESULT WINAPI SendRun(IBaseFilter *pFilter) {
+ return IBaseFilter_Run(pFilter, 0);
+}
+
+static HRESULT WINAPI SendPause(IBaseFilter *pFilter) {
+ return IBaseFilter_Pause(pFilter);
+}
+
+static HRESULT WINAPI SendStop(IBaseFilter *pFilter) {
+ return IBaseFilter_Stop(pFilter);
+}
+
+static HRESULT WINAPI SendTheFilterAMessage(IMediaControl *iface, fnFoundFilter FoundFilter) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
int i;
IBaseFilter* pfilter;
@@ -1223,19 +1245,10 @@ static HRESULT WINAPI Mediacontrol_Run(I
IPin* pPin;
LONG dummy;
PIN_DIRECTION dir;
-
TRACE("(%p/%p)->()\n", This, iface);
- EnterCriticalSection(&This->cs);
-
- if (This->state == State_Running)
- {
- LeaveCriticalSection(&This->cs);
- return S_OK;
- }
-
- /* Explorer the graph from source filters to renderers, determine renderers number and
- * run filters from renderers to source filters */
+ /* Explorer the graph from source filters to renderers, determine renderers
+ * number and run filters from renderers to source filters */
This->nRenderers = 0;
ResetEvent(This->hEventCompletion);
@@ -1253,6 +1266,7 @@ static HRESULT WINAPI Mediacontrol_Run(I
while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
{
IPin_QueryDirection(pPin, &dir);
+ IPin_Release(pPin);
if (dir == PINDIR_INPUT)
{
source = FALSE;
@@ -1266,34 +1280,56 @@ static HRESULT WINAPI Mediacontrol_Run(I
while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
{
/* Explore the graph downstream from this pin */
- ExploreGraph(This, pPin, 0);
+ ExploreGraph(This, pPin, FoundFilter);
+ IPin_Release(pPin);
}
- IBaseFilter_Run(pfilter, 0);
+ FoundFilter(pfilter);
}
IEnumPins_Release(pEnum);
}
- This->state = State_Running;
+ return S_FALSE;
+}
+
+/*** IMediaControl methods ***/
+static HRESULT WINAPI Mediacontrol_Run(IMediaControl *iface) {
+ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
+ TRACE("(%p/%p)->()\n", This, iface);
+
+ if (This->state == State_Running) return S_OK;
+ EnterCriticalSection(&This->cs);
+ SendTheFilterAMessage(iface, SendRun);
+ This->state = State_Running;
LeaveCriticalSection(&This->cs);
-
return S_FALSE;
}
static HRESULT WINAPI Mediacontrol_Pause(IMediaControl *iface) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
+ TRACE("(%p/%p)->()\n", This, iface);
- TRACE("(%p/%p)->(): stub !!!\n", This, iface);
+ if (This->state == State_Paused) return S_OK;
- return S_OK;
+ EnterCriticalSection(&This->cs);
+ SendTheFilterAMessage(iface, SendPause);
+ This->state = State_Paused;
+ LeaveCriticalSection(&This->cs);
+ return S_FALSE;
}
static HRESULT WINAPI Mediacontrol_Stop(IMediaControl *iface) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
+ TRACE("(%p/%p)->()\n", This, iface);
- TRACE("(%p/%p)->(): stub !!!\n", This, iface);
+ if (This->state == State_Stopped) return S_OK;
- return S_OK;
+ EnterCriticalSection(&This->cs);
+ if (This->state == State_Running) SendTheFilterAMessage(iface, SendPause);
+ SendTheFilterAMessage(iface, SendStop);
+ This->state = State_Stopped;
+ LeaveCriticalSection(&This->cs);
+ return S_FALSE;
}
static HRESULT WINAPI Mediacontrol_GetState(IMediaControl *iface,
Index: dlls/quartz/pin.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/pin.c,v
retrieving revision 1.13
diff -u -p -r1.13 pin.c
--- dlls/quartz/pin.c 2 Mar 2005 10:12:12 -0000 1.13
+++ dlls/quartz/pin.c 1 May 2005 00:10:59 -0000
@@ -49,7 +49,6 @@ static void Copy_PinInfo(PIN_INFO * pDes
strcpyW(pDest->achName, pSrc->achName);
pDest->dir = pSrc->dir;
pDest->pFilter = pSrc->pFilter;
- IBaseFilter_AddRef(pDest->pFilter);
}
/* Function called as a helper to IPin_Connect */
@@ -311,6 +310,7 @@ HRESULT WINAPI IPinImpl_QueryPinInfo(IPi
TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
Copy_PinInfo(pInfo, &This->pinInfo);
+ IBaseFilter_AddRef(pInfo->pFilter);
return S_OK;
}
diff -Nru wine-old/dlls/qcap/capturegraph.c wine-new/dlls/qcap/capturegraph.c
--- wine-old/dlls/qcap/capturegraph.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capturegraph.c 2005-04-29 00:31:34.000000000 +0200
@@ -0,0 +1,196 @@
+/* Capture Graph Builder, Minimal edition..
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * TODO: Implement CaptureGraphBuilder2, and make all calls from
+ * CaptureGraphBuilder forward to it..
+ */
+
+#include "config.h"
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "evcode.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl;
+
+typedef struct CaptureGraphImpl
+{
+ const ICaptureGraphBuilderVtbl * lpVtbl;
+ IGraphBuilder *mygraph;
+
+ ULONG refCount;
+ CRITICAL_SECTION csFilter;
+} CaptureGraphImpl;
+
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+ CaptureGraphImpl * pCapture;
+ TRACE("(%p, %p)\n", pUnkOuter, ppv);
+ *ppv = NULL;
+ if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+ pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
+ pCapture->lpVtbl = &Builder_Vtbl;
+ pCapture->refCount = 1;
+ pCapture->mygraph = NULL;
+ InitializeCriticalSection(&pCapture->csFilter);
+ *ppv = (LPVOID)pCapture;
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface, REFIID riid, LPVOID * ppv)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ TRACE("(%p/%p)->(%s, %p)\n", This, iface, qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
+ *ppv = (LPVOID)This;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
+{
+ CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+ return refCount;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
+{
+ CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+
+ if (!refCount) {
+ TRACE("Destroying everything..\n");
+ DeleteCriticalSection(&This->csFilter);
+ if (This->mygraph != NULL)
+ IGraphBuilder_Release((IGraphBuilder *)This->mygraph);
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else return refCount;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder *pfg)
+{
+/* The graph builder will automatically create a filter graph if you don't call this method. If you call this method after the graph builder has created its own filter graph, the call will fail. */
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ if (This->mygraph != NULL) return E_NOTIMPL;
+ This->mygraph = pfg;
+ IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+ TRACE("%p: %p\n", iface, pfg);
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_GetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder **pfg)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ FIXME("%p: Make our own filtergraph if we haven't got one already - stub\n", iface);
+ if (This->mygraph == NULL) return E_NOTIMPL;
+
+ *pfg = This->mygraph;
+ IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+
+ TRACE("%p: %p\n", iface, *pfg);
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface, const GUID *pType, LPCOLESTR lpstrFile,IBaseFilter **ppf, IFileSinkFilter **ppSink)
+{
+ FIXME("%p: %p, %p, %p, %p - stub\n", iface, pType, lpstrFile, *ppf, *ppSink);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pf, REFIID riid, void **ppint)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ FIXME("%p: %s %p %s %p - unwanted partial stub!\n", This, qcdebugstr_guid(pCategory), pf, qcdebugstr_guid(riid), *ppint);
+ return IBaseFilter_QueryInterface(pf, riid, ppint);
+ /* Looks for the specified interface on the filter, upstream and
+ * downstream from the filter, and, optionally, only on the output
+ * pin of the given category.
+ */
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IUnknown *pSource, IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pFilter, REFERENCE_TIME *pstart, REFERENCE_TIME *pstop, WORD wStartCookie, WORD wStopCookie)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface, LPCOLESTR lpstr, DWORDLONG dwlSize)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface, LPOLESTR lpwstrOld, LPOLESTR lpwstrNew, int fAllowEscAbort, IAMCopyCaptureFileProgress *pCallback)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl =
+{
+ CaptureGraphBuilder_QueryInterface,
+ CaptureGraphBuilder_AddRef,
+ CaptureGraphBuilder_Release,
+ CaptureGraphBuilder_SetFilterGraph,
+ CaptureGraphBuilder_GetFilterGraph,
+ CaptureGraphBuilder_SetOutputFileName,
+ CaptureGraphBuilder_FindInterface,
+ CaptureGraphBuilder_RenderStream,
+ CaptureGraphBuilder_ControlStream,
+ CaptureGraphBuilder_AllocCapFile,
+ CaptureGraphBuilder_CopyCaptureFile
+};
+
diff -Nru wine-old/dlls/qcap/capture.h wine-new/dlls/qcap/capture.h
--- wine-old/dlls/qcap/capture.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capture.h 2005-05-01 01:51:50.000000000 +0200
@@ -0,0 +1,35 @@
+/* DirectShow private capture header (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __CAPTURE_H__
+#define __CAPTURE_H__
+
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card);
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT);
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT);
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Destroy(void * pBox);
+
+#endif /* __CAPTURE_H__ */
+
diff -Nru wine-old/dlls/qcap/enumpins.c wine-new/dlls/qcap/enumpins.c
--- wine-old/dlls/qcap/enumpins.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/enumpins.c 2005-04-29 13:40:15.000000000 +0200
@@ -0,0 +1,183 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+typedef struct IEnumPinsImpl
+{
+ const IEnumPinsVtbl * lpVtbl;
+ ULONG refCount;
+ ENUMPINDETAILS enumPinDetails;
+ ULONG uIndex;
+} IEnumPinsImpl;
+
+static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum)
+{
+ IEnumPinsImpl * pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
+ TRACE("()\n");
+ if (!pEnumPins)
+ {
+ *ppEnum = NULL;
+ return E_OUTOFMEMORY;
+ }
+ pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
+ pEnumPins->refCount = 1;
+ pEnumPins->uIndex = 0;
+ CopyMemory(&pEnumPins->enumPinDetails, pDetails, sizeof(ENUMPINDETAILS));
+ *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
+{
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)iface;
+ else if (IsEqualIID(riid, &IID_IEnumPins))
+ *ppv = (LPVOID)iface;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+ return E_NOINTERFACE;
+}
+static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("() -> %lu\n", refCount);
+
+ return refCount;
+}
+
+static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("() -> %lu\n", refCount);
+
+ if (!refCount)
+ {
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else
+ return refCount;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
+{
+ ULONG cFetched;
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("()\n");
+
+ cFetched = min(This->enumPinDetails.cPins, This->uIndex + cPins) - This->uIndex;
+
+ TRACE("(%lu, %p, %p)\n", cPins, ppPins, pcFetched);
+
+ if (cFetched > 0)
+ {
+ ULONG i;
+ for (i = 0; i < cFetched; i++) {
+ IPin_AddRef(This->enumPinDetails.ppPins[This->uIndex + i]);
+ ppPins[i] = This->enumPinDetails.ppPins[This->uIndex + i];
+ }
+ }
+
+ if ((cPins != 1) || pcFetched)
+ *pcFetched = cFetched;
+
+ This->uIndex += cFetched;
+
+ if (cFetched != cPins)
+ return S_FALSE;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("(%lu)\n", cPins);
+
+ if (This->uIndex + cPins < This->enumPinDetails.cPins)
+ {
+ This->uIndex += cPins;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("IEnumPinsImpl::Reset()\n");
+
+ This->uIndex = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
+{
+ HRESULT hr;
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("(%p)\n", ppEnum);
+
+ hr = IEnumPinsImpl_Construct(&This->enumPinDetails, ppEnum);
+ if (FAILED(hr))
+ return hr;
+ return IEnumPins_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
+{
+ IEnumPinsImpl_QueryInterface,
+ IEnumPinsImpl_AddRef,
+ IEnumPinsImpl_Release,
+ IEnumPinsImpl_Next,
+ IEnumPinsImpl_Skip,
+ IEnumPinsImpl_Reset,
+ IEnumPinsImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/Makefile.in wine-new/dlls/qcap/Makefile.in
--- wine-old/dlls/qcap/Makefile.in 2004-05-14 23:37:32.000000000 +0200
+++ wine-new/dlls/qcap/Makefile.in 2005-05-01 01:56:42.000000000 +0200
@@ -3,8 +3,19 @@
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = qcap.dll
+IMPORTS = ole32 kernel32 advapi32 user32
+EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE)
-C_SRCS = qcap_main.c
+C_SRCS = \
+ capturegraph.c \
+ enumpins.c \
+ media.c \
+ null.c \
+ pin.c \
+ qcap_main.c \
+ regsvr.c \
+ v4l.c \
+ vfwcapture.c
RC_SRCS = version.rc
diff -Nru wine-old/dlls/qcap/media.c wine-new/dlls/qcap/media.c
--- wine-old/dlls/qcap/media.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/media.c 2005-05-01 01:48:09.000000000 +0200
@@ -0,0 +1,229 @@
+/*
+ * Implementation of IEnumMediaTypes Interface
+ *
+ * Copyright 2003 Robert Shearman
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "qcap_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
+{
+ memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
+ if (!pDest->pbFormat) return S_OK;
+ if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
+ return E_OUTOFMEMORY;
+ memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
+ return S_OK;
+}
+
+void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
+{
+ if (pMediaType->pbFormat)
+ {
+ CoTaskMemFree(pMediaType->pbFormat);
+ pMediaType->pbFormat = NULL;
+ }
+ if (pMediaType->pUnk)
+ {
+ IUnknown_Release(pMediaType->pUnk);
+ pMediaType->pUnk = NULL;
+ }
+ CoTaskMemFree(pMediaType);
+}
+
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
+{
+ TRACE("pmt1: ");
+ dump_AM_MEDIA_TYPE(pmt1);
+ TRACE("pmt2: ");
+ dump_AM_MEDIA_TYPE(pmt2);
+ return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
+ ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
+}
+
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
+{
+ if (!pmt)
+ return;
+ TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qcdebugstr_guid(&pmt->majortype), qcdebugstr_guid(&pmt->subtype), qcdebugstr_guid(&pmt->formattype));
+}
+
+typedef struct IEnumMediaTypesImpl
+{
+ const IEnumMediaTypesVtbl * lpVtbl;
+ ULONG refCount;
+ ENUMMEDIADETAILS enumMediaDetails;
+ ULONG uIndex;
+} IEnumMediaTypesImpl;
+
+static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
+
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum)
+{
+ ULONG i;
+ IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
+
+ if (!pEnumMediaTypes)
+ {
+ *ppEnum = NULL;
+ return E_OUTOFMEMORY;
+ }
+ pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
+ pEnumMediaTypes->refCount = 1;
+ pEnumMediaTypes->uIndex = 0;
+ pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
+ pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
+ for (i = 0; i < pDetails->cMediaTypes; i++)
+ CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]);
+ *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
+{
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)iface;
+ else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
+ *ppv = (LPVOID)iface;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("()\n");
+
+ return refCount;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("()\n");
+
+ if (!refCount)
+ {
+ int i;
+ for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
+ if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
+ CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
+ CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else
+ return refCount;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
+{
+ ULONG cFetched;
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
+
+ TRACE("(%lu, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched);
+ TRACE("Next uIndex: %lu, cFetched: %lu\n", This->uIndex, cFetched);
+
+ if (cFetched > 0)
+ {
+ ULONG i;
+ *ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
+ for (i = 0; i < cFetched; i++)
+ CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]);
+ }
+
+ if ((cMediaTypes != 1) || pcFetched)
+ *pcFetched = cFetched;
+
+ This->uIndex += cFetched;
+
+ if (cFetched != cMediaTypes)
+ return S_FALSE;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("(%lu)\n", cMediaTypes);
+
+ if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
+ {
+ This->uIndex += cMediaTypes;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("()\n");
+
+ This->uIndex = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
+{
+ HRESULT hr;
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("(%p)\n", ppEnum);
+ hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum);
+
+ if (FAILED(hr))
+ return hr;
+ return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
+{
+ IEnumMediaTypesImpl_QueryInterface,
+ IEnumMediaTypesImpl_AddRef,
+ IEnumMediaTypesImpl_Release,
+ IEnumMediaTypesImpl_Next,
+ IEnumMediaTypesImpl_Skip,
+ IEnumMediaTypesImpl_Reset,
+ IEnumMediaTypesImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/null.c wine-new/dlls/qcap/null.c
--- wine-old/dlls/qcap/null.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/null.c 2005-05-01 01:49:06.000000000 +0200
@@ -0,0 +1,84 @@
+/* DirectShow capture services (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the part of the vfw capture interface that
+ * does the actual capturing stuff required for capturing
+ * and setting/getting media format..
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Why on earth am I writing a copyright notice for a NULL renderer???
+ */
+
+#include "config.h"
+#ifndef HAVE_LINUX_VIDEODEV_H
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card)
+{
+ ERR("No DirectShow Video for Wine Capture support compiled\n");
+ return E_FAIL;
+}
+
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Destroy(void * pBox)
+{
+ return E_FAIL;
+}
+
+#endif
+
diff -Nru wine-old/dlls/qcap/pin.c wine-new/dlls/qcap/pin.c
--- wine-old/dlls/qcap/pin.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.c 2005-04-30 18:44:10.000000000 +0200
@@ -0,0 +1,411 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1))
+#define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary)
+
+static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
+{
+ /* Tempting to just do a memcpy, but the name field is
+ 128 characters long! We will probably never exceed 10
+ most of the time, so we are better off copying
+ each field manually */
+ strcpyW(pDest->achName, pSrc->achName);
+ pDest->dir = pSrc->dir;
+ pDest->pFilter = pSrc->pFilter;
+}
+
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+/* TRACE("(%p)\n", ppPin);*/
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ *ppPin = This->pConnectedTo;
+ IPin_AddRef(*ppPin);
+ hr = S_OK;
+ }
+ else
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ CopyMediaType(pmt, &This->mtCurrent);
+ hr = S_OK;
+ }
+ else
+ {
+ ZeroMemory(pmt, sizeof(*pmt));
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
+
+ Copy_PinInfo(pInfo, &This->pinInfo);
+ IBaseFilter_AddRef(pInfo->pFilter);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
+
+ *pPinDir = This->pinInfo.dir;
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, Id);
+
+ *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
+ if (!Id)
+ return E_OUTOFMEMORY;
+
+ strcpyW(*Id, This->pinInfo.achName);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ if (!This->fnQueryAccept) return S_OK;
+
+ return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
+}
+
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
+
+ return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
+}
+
+/* Function called as a helper to IPin_Connect */
+/* specific AM_MEDIA_TYPE - it cannot be NULL */
+/* NOTE: not part of standard interface */
+static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ OutputPin *This = (OutputPin *)iface;
+ HRESULT hr;
+ IMemAllocator * pMemAlloc = NULL;
+ ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
+
+ TRACE("(%p, %p)\n", pReceivePin, pmt);
+ dump_AM_MEDIA_TYPE(pmt);
+
+ /* FIXME: call queryacceptproc */
+
+ This->pin.pConnectedTo = pReceivePin;
+ IPin_AddRef(pReceivePin);
+ CopyMediaType(&This->pin.mtCurrent, pmt);
+
+ hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
+
+ /* get the IMemInputPin interface we will use to deliver samples to the
+ * connected pin */
+ if (SUCCEEDED(hr))
+ {
+ hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
+
+ if (SUCCEEDED(hr))
+ hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
+
+ if (hr == VFW_E_NO_ALLOCATOR)
+ {
+ /* Input pin provides no allocator, use standard memory allocator */
+ hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
+
+ if (pMemAlloc)
+ IMemAllocator_Release(pMemAlloc);
+
+ /* break connection if we couldn't get the allocator */
+ if (FAILED(hr))
+ IPin_Disconnect(pReceivePin);
+ }
+
+ if (FAILED(hr))
+ {
+ IPin_Release(This->pin.pConnectedTo);
+ This->pin.pConnectedTo = NULL;
+ DeleteMediaType(&This->pin.mtCurrent);
+ }
+
+ TRACE(" -- %lx\n", hr);
+ return hr;
+}
+
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
+{
+ TRACE("\n");
+
+ /* Common attributes */
+ pPinImpl->pin.refCount = 1;
+ pPinImpl->pin.pConnectedTo = NULL;
+ pPinImpl->pin.fnQueryAccept = pQueryAccept;
+ pPinImpl->pin.pUserData = pUserData;
+ pPinImpl->pin.pCritSec = pCritSec;
+ Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
+
+ /* Output pin attributes */
+ pPinImpl->pMemInputPin = NULL;
+ pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
+ if (props)
+ {
+ memcpy(&pPinImpl->allocProps, props, sizeof(pPinImpl->allocProps));
+ if (pPinImpl->allocProps.cbAlign == 0)
+ pPinImpl->allocProps.cbAlign = 1;
+ }
+ else
+ ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
+
+ return S_OK;
+}
+
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ HRESULT hr;
+ OutputPin *This = (OutputPin *)iface;
+
+ TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
+ dump_AM_MEDIA_TYPE(pmt);
+
+ /* If we try to connect to ourself, we will definitely deadlock.
+ * There are other cases where we could deadlock too, but this
+ * catches the obvious case */
+ assert(pReceivePin != iface);
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ /* if we have been a specific type to connect with, then we can either connect
+ * with that or fail. We cannot choose different AM_MEDIA_TYPE */
+ if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
+ hr = This->pConnectSpecific(iface, pReceivePin, pmt);
+ else
+ {
+ /* negotiate media type */
+
+ IEnumMediaTypes * pEnumCandidates;
+ AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
+
+ if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
+ {
+ hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+ /* try this filter's media types first */
+ while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+ {
+ if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+ (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+ {
+ hr = S_OK;
+ TRACE("o_o\n");
+ DeleteMediaType(pmtCandidate);
+ break;
+ }
+ DeleteMediaType(pmtCandidate);
+ }
+ IEnumMediaTypes_Release(pEnumCandidates);
+ }
+
+ /* then try receiver filter's media types */
+ if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
+ {
+ hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+ while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+ {
+ if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+ (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+ {
+ hr = S_OK;
+ DeleteMediaType(pmtCandidate);
+ break;
+ }
+ DeleteMediaType(pmtCandidate);
+ } /* while */
+ IEnumMediaTypes_Release(pEnumCandidates);
+ } /* if not found */
+ } /* if negotiate media type */
+ } /* if succeeded */
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ TRACE(" -- %lx\n", hr);
+ return hr;
+}
+
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
+
+ return E_UNEXPECTED;
+}
+
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
+{
+ HRESULT hr;
+ OutputPin *This = (OutputPin *)iface;
+
+ TRACE("()\n");
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (This->pMemInputPin)
+ {
+ IMemInputPin_Release(This->pMemInputPin);
+ This->pMemInputPin = NULL;
+ }
+ if (This->pin.pConnectedTo)
+ {
+ IPin_Release(This->pin.pConnectedTo);
+ This->pin.pConnectedTo = NULL;
+ hr = S_OK;
+ }
+ else
+ hr = S_FALSE;
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ return hr;
+}
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags)
+{
+ HRESULT hr;
+
+ TRACE("(%p, %p, %p, %lx)\n", ppSample, tStart, tStop, dwFlags);
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (!This->pin.pConnectedTo)
+ hr = VFW_E_NOT_CONNECTED;
+ else
+ {
+ IMemAllocator * pAlloc = NULL;
+
+ hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_GetBuffer(pAlloc, ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop, dwFlags);
+
+ if (SUCCEEDED(hr))
+ hr = IMediaSample_SetTime(*ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+ }
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ return hr;
+}
+
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
+{
+ HRESULT hr = S_OK;
+ IMemInputPin * pMemConnected = NULL;
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (!This->pin.pConnectedTo || !This->pMemInputPin)
+ hr = VFW_E_NOT_CONNECTED;
+ else
+ {
+ /* we don't have the lock held when using This->pMemInputPin,
+ * so we need to AddRef it to stop it being deleted while we are
+ * using it. */
+ pMemConnected = This->pMemInputPin;
+ IMemInputPin_AddRef(pMemConnected);
+ }
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ if (SUCCEEDED(hr))
+ {
+ /* NOTE: if we are in a critical section when Receive is called
+ * then it causes some problems (most notably with the native Video
+ * Renderer) if we are re-entered for whatever reason */
+ hr = IMemInputPin_Receive(pMemConnected, pSample);
+ IMemInputPin_Release(pMemConnected);
+ }
+
+ return hr;
+}
+
diff -Nru wine-old/dlls/qcap/pin.h wine-new/dlls/qcap/pin.h
--- wine-old/dlls/qcap/pin.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.h 2005-04-29 14:01:43.000000000 +0200
@@ -0,0 +1,81 @@
+/*
+ * IPin function declarations to allow inheritance
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* This function will process incoming samples to the pin.
+ * Any return value valid in IMemInputPin::Receive is allowed here
+ */
+typedef HRESULT (* SAMPLEPROC)(LPVOID userdata, IMediaSample * pSample);
+
+/* This function will determine whether a type is supported or not.
+ * It is allowed to return any error value (within reason), as opposed
+ * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE.
+ */
+typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt);
+
+/* This function is called prior to finalizing a connection with
+ * another pin and can be used to get things from the other pin
+ * like IMemInput interfaces.
+ */
+typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin);
+
+typedef struct IPinImpl
+{
+ const struct IPinVtbl * lpVtbl;
+ ULONG refCount;
+ LPCRITICAL_SECTION pCritSec;
+ PIN_INFO pinInfo;
+ IPin * pConnectedTo;
+ AM_MEDIA_TYPE mtCurrent;
+ ENUMMEDIADETAILS enumMediaDetails;
+ QUERYACCEPTPROC fnQueryAccept;
+ LPVOID pUserData;
+} IPinImpl;
+
+typedef struct OutputPin
+{
+ /* inheritance C style! */
+ IPinImpl pin;
+
+ IMemInputPin * pMemInputPin;
+ HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt);
+ ALLOCATOR_PROPERTIES allocProps;
+} OutputPin;
+
+/*** Initializers ***/
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+
+/* Common */
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin);
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo);
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir);
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id);
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum);
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin);
+
+/* Output Pin */
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface);
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags);
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample);
+
diff -Nru wine-old/dlls/qcap/qcap_main.c wine-new/dlls/qcap/qcap_main.c
--- wine-old/dlls/qcap/qcap_main.c 2004-05-21 22:54:48.000000000 +0200
+++ wine-new/dlls/qcap/qcap_main.c 2005-05-01 01:53:20.000000000 +0200
@@ -1,7 +1,10 @@
-/*
- * Qcap implementation
+/* DirectShow Capture Base Functions (QCAP.DLL)
*
- * Copyright (C) 2003 Dominik Strasser
+ * Copyright 2002 Lionel Ulmer
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,26 +21,206 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
#include "wine/debug.h"
-#include "winerror.h"
+#include "qcap_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+static DWORD dll_ref = 0;
+
+/* For the moment, do nothing here. */
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
+{
+ switch(fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hInstDLL);
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+/******************************************************************************
+ * DirectShow ClassFactory
+ */
+typedef struct {
+ IClassFactory ITF_IClassFactory;
+
+ DWORD ref;
+ HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+} IClassFactoryImpl;
+
+struct object_creation_info
+{
+ const CLSID *clsid;
+ HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+};
+
+static const struct object_creation_info object_creation[] =
+{
+ { &CLSID_VfwCapture, &VfwCapture_create },
+ { &CLSID_CaptureGraphBuilder, &CaptureGraphBuilder_create }
+};
+
+static HRESULT WINAPI
+DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ if (IsEqualGUID(riid, &IID_IUnknown)
+ || IsEqualGUID(riid, &IID_IClassFactory))
+ {
+ IClassFactory_AddRef(iface);
+ *ppobj = This;
+ return S_OK;
+ }
+
+ WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ if (ref == 0)
+ HeapFree(GetProcessHeap(), 0, This);
+
+ return ref;
+}
+
+
+static HRESULT WINAPI DSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
+ REFIID riid, LPVOID *ppobj)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ HRESULT hres;
+ LPUNKNOWN punk;
+
+ TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
+
+ *ppobj = NULL;
+ hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
+ if (SUCCEEDED(hres)) {
+ hres = IUnknown_QueryInterface(punk, riid, ppobj);
+ IUnknown_Release(punk);
+ }
+ return hres;
+}
+
+static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ FIXME("(%p)->(%d),stub!\n",This,dolock);
+ return S_OK;
+}
+
+static IClassFactoryVtbl DSCF_Vtbl =
+{
+ DSCF_QueryInterface,
+ DSCF_AddRef,
+ DSCF_Release,
+ DSCF_CreateInstance,
+ DSCF_LockServer
+};
+
+/*******************************************************************************
+ * DllGetClassObject [QCAP.@]
+ * Retrieves class object from a DLL object
+ *
+ * NOTES
+ * Docs say returns STDAPI
+ *
+ * PARAMS
+ * rclsid [I] CLSID for the class object
+ * riid [I] Reference to identifier of interface for class object
+ * ppv [O] Address of variable to receive interface pointer for riid
+ *
+ * RETURNS
+ * Success: S_OK
+ * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
+ * E_UNEXPECTED
+ */
+DWORD WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ unsigned int i;
+ IClassFactoryImpl *factory;
+
+ TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+ if ( !IsEqualGUID( &IID_IClassFactory, riid )
+ && ! IsEqualGUID( &IID_IUnknown, riid) )
+ return E_NOINTERFACE;
+
+ for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
+ {
+ if (IsEqualGUID(object_creation[i].clsid, rclsid))
+ break;
+ }
+
+ if (i == sizeof(object_creation)/sizeof(object_creation[0]))
+ {
+ FIXME("%s: no class found.\n", debugstr_guid(rclsid));
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
+ if (factory == NULL) return E_OUTOFMEMORY;
+
+ factory->ITF_IClassFactory.lpVtbl = &DSCF_Vtbl;
+ factory->ref = 1;
+
+ factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
+
+ *ppv = &(factory->ITF_IClassFactory);
+ return S_OK;
+}
+
/***********************************************************************
- * DllRegisterServer (QCAP.@)
+ * DllCanUnloadNow (QCAP.@)
*/
-HRESULT WINAPI QCAP_DllRegisterServer()
+HRESULT WINAPI QCAP_DllCanUnloadNow()
{
- FIXME("(): stub\n");
- return 0;
+ return dll_ref != 0 ? S_FALSE : S_OK;
}
+
+#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } , #name },
+
+static struct {
+ const GUID riid;
+ const char *name;
+} InterfaceDesc[] =
+{
+#include "uuids.h"
+ { { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }, NULL }
+};
+
/***********************************************************************
- * DllGetClassObject (QCAP.@)
+ * qcdebugstr_guid (internal)
+ *
+ * Gives a text version of QCap Guids
*/
-HRESULT WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+const char * qcdebugstr_guid( const GUID * id )
{
- FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
- return CLASS_E_CLASSNOTAVAILABLE;
+ int i;
+ char * name = NULL;
+
+ for (i=0;InterfaceDesc[i].name && !name;i++) {
+ if (IsEqualGUID(&InterfaceDesc[i].riid, id)) return InterfaceDesc[i].name;
+ }
+ return debugstr_guid(id);
}
+
diff -Nru wine-old/dlls/qcap/qcap_private.h wine-new/dlls/qcap/qcap_private.h
--- wine-old/dlls/qcap/qcap_private.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/qcap_private.h 2005-04-29 00:27:34.000000000 +0200
@@ -0,0 +1,64 @@
+/* Quartz Capture private interfaces (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __QCAP_PRIVATE_INCLUDED__
+#define __QCAP_PRIVATE_INCLUDED__
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "dshow.h"
+
+#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv);
+
+typedef struct tagENUMPINDETAILS
+{
+ ULONG cPins;
+ IPin ** ppPins;
+} ENUMPINDETAILS;
+
+typedef struct tagENUMEDIADETAILS
+{
+ ULONG cMediaTypes;
+ AM_MEDIA_TYPE * pMediaTypes;
+} ENUMMEDIADETAILS;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum);
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum);
+
+extern const char * qcdebugstr_guid(const GUID * id);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc);
+void DeleteMediaType(AM_MEDIA_TYPE * pmt);
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
+
+#endif /* __QCAP_PRIVATE_INCLUDED__ */
diff -Nru wine-old/dlls/qcap/qcap.spec wine-new/dlls/qcap/qcap.spec
--- wine-old/dlls/qcap/qcap.spec 2003-07-30 05:48:55.000000000 +0200
+++ wine-new/dlls/qcap/qcap.spec 2005-04-28 23:07:08.000000000 +0200
@@ -1,4 +1,4 @@
-@ stub DllCanUnloadNow
+@ stdcall -private DllCanUnloadNow() QCAP_DllCanUnloadNow
@ stdcall -private DllGetClassObject(ptr ptr ptr) QCAP_DllGetClassObject
@ stdcall -private DllRegisterServer() QCAP_DllRegisterServer
-@ stub DllUnregisterServer
+@ stdcall -private DllUnregisterServer() QCAP_DllUnregisterServer
diff -Nru wine-old/dlls/qcap/regsvr.c wine-new/dlls/qcap/regsvr.c
--- wine-old/dlls/qcap/regsvr.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/regsvr.c 2005-04-29 00:28:39.000000000 +0200
@@ -0,0 +1,940 @@
+/*
+ * self-registerable dll functions for qcap.dll
+ *
+ * Copyright (C) 2003 John K. Hohm
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define COBJMACROS
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "uuids.h"
+#include "strmif.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+/*
+ * Near the bottom of this file are the exported DllRegisterServer and
+ * DllUnregisterServer, which make all this worthwhile.
+ */
+
+/***********************************************************************
+ * interface for self-registering
+ */
+struct regsvr_interface
+{
+ IID const *iid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ IID const *base_iid; /* can be NULL to omit */
+ int num_methods; /* can be <0 to omit */
+ CLSID const *ps_clsid; /* can be NULL to omit */
+ CLSID const *ps_clsid32; /* can be NULL to omit */
+};
+
+static HRESULT register_interfaces(struct regsvr_interface const *list);
+static HRESULT unregister_interfaces(struct regsvr_interface const *list);
+
+struct regsvr_coclass
+{
+ CLSID const *clsid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ LPCSTR ips; /* can be NULL to omit */
+ LPCSTR ips32; /* can be NULL to omit */
+ LPCSTR ips32_tmodel; /* can be NULL to omit */
+ LPCSTR progid; /* can be NULL to omit */
+ LPCSTR viprogid; /* can be NULL to omit */
+ LPCSTR progid_extra; /* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+struct regsvr_mediatype_parsing
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ LPCSTR line[11]; /* NULL for end of list */
+};
+
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+
+struct regsvr_mediatype_extension
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ LPCSTR extension;
+};
+
+struct mediatype
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ DWORD fourcc;
+};
+
+struct pin
+{
+ DWORD flags; /* 0xFFFFFFFF for end of list */
+ struct mediatype mediatypes[11];
+};
+
+struct regsvr_filter
+{
+ CLSID const *clsid; /* NULL for end of list */
+ CLSID const *category;
+ WCHAR name[50];
+ DWORD merit;
+ struct pin pins[11];
+};
+
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+
+static HRESULT register_filters(struct regsvr_filter const *list);
+static HRESULT unregister_filters(struct regsvr_filter const *list);
+
+/***********************************************************************
+ * static string constants
+ */
+static WCHAR const interface_keyname[10] = {
+ 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
+static WCHAR const base_ifa_keyname[14] = {
+ 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
+ 'e', 0 };
+static WCHAR const num_methods_keyname[11] = {
+ 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
+static WCHAR const ps_clsid_keyname[15] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', 0 };
+static WCHAR const ps_clsid32_keyname[17] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', '3', '2', 0 };
+static WCHAR const clsid_keyname[6] = {
+ 'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+ 'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const ips_keyname[13] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ 0 };
+static WCHAR const ips32_keyname[15] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+ 'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+ 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+ 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+ 0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+static WCHAR const mediatype_name[11] = {
+ 'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
+static WCHAR const subtype_valuename[8] = {
+ 'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
+static WCHAR const sourcefilter_valuename[14] = {
+ 'S', 'o', 'u', 'r', 'c', 'e', ' ', 'F', 'i', 'l', 't', 'e', 'r', 0 };
+static WCHAR const extensions_keyname[11] = {
+ 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 0 };
+
+/***********************************************************************
+ * static helper functions
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+ WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+ char const *value);
+static LONG register_progid(WCHAR const *clsid,
+ char const *progid, char const *curver_progid,
+ char const *name, char const *extra);
+static LONG recursive_delete_key(HKEY key);
+static LONG recursive_delete_keyA(HKEY base, char const *name);
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
+
+/***********************************************************************
+ * register_interfaces
+ */
+static HRESULT register_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+ HKEY iid_key;
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_interface_key;
+
+ if (list->name) {
+ res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->base_iid) {
+ register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (0 <= list->num_methods) {
+ static WCHAR const fmt[3] = { '%', 'd', 0 };
+ HKEY key;
+
+ res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+
+ wsprintfW(buf, fmt, list->num_methods);
+ res = RegSetValueExW(key, NULL, 0, REG_SZ,
+ (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid) {
+ register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid32) {
+ register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ error_close_iid_key:
+ RegCloseKey(iid_key);
+ }
+
+error_close_interface_key:
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_interfaces
+ */
+static HRESULT unregister_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
+ KEY_READ | KEY_WRITE, &interface_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = recursive_delete_keyW(interface_key, buf);
+ }
+
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+ HKEY clsid_key;
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->name) {
+ res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips) {
+ res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips32) {
+ HKEY ips32_key;
+
+ res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL,
+ &ips32_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)list->ips32,
+ lstrlenA(list->ips32) + 1);
+ if (res == ERROR_SUCCESS && list->ips32_tmodel)
+ res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+ (CONST BYTE*)list->ips32_tmodel,
+ strlen(list->ips32_tmodel) + 1);
+ RegCloseKey(ips32_key);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->progid) {
+ res = register_key_defvalueA(clsid_key, progid_keyname,
+ list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->progid, NULL,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->viprogid) {
+ res = register_key_defvalueA(clsid_key, viprogid_keyname,
+ list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->viprogid, list->progid,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ error_close_clsid_key:
+ RegCloseKey(clsid_key);
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+ KEY_READ | KEY_WRITE, &coclass_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = recursive_delete_keyW(coclass_key, buf);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->progid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+
+ if (list->viprogid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_mediatypes_parsing
+ */
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY mediatype_key;
+ WCHAR buf[39];
+ int i;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ HKEY majortype_key = NULL;
+ HKEY subtype_key = NULL;
+
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegCreateKeyExW(mediatype_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &majortype_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = RegCreateKeyExW(majortype_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &subtype_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+ res = RegSetValueExW(subtype_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ for(i = 0; list->line[i]; i++) {
+ char buffer[3];
+ wsprintfA(buffer, "%d", i);
+ res = RegSetValueExA(subtype_key, buffer, 0, REG_SZ, (CONST BYTE*)list->line[i],
+ lstrlenA(list->line[i]));
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+ }
+
+error_close_keys:
+ if (majortype_key)
+ RegCloseKey(majortype_key);
+ if (subtype_key)
+ RegCloseKey(subtype_key);
+ }
+
+ RegCloseKey(mediatype_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_mediatypes_extension
+ */
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY mediatype_key;
+ HKEY extensions_root_key = NULL;
+ WCHAR buf[39];
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ res = RegCreateKeyExW(mediatype_key, extensions_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &extensions_root_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ HKEY extension_key;
+
+ res = RegCreateKeyExA(extensions_root_key, list->extension, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &extension_key, NULL);
+ if (res != ERROR_SUCCESS) break;
+
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegSetValueExW(extension_key, mediatype_name, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = RegSetValueExW(extension_key, subtype_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+ StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+ res = RegSetValueExW(extension_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+error_close_key:
+ RegCloseKey(extension_key);
+ }
+
+error_return:
+ RegCloseKey(mediatype_key);
+ if (extensions_root_key)
+ RegCloseKey(extensions_root_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_mediatypes_parsing
+ */
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+ LONG res;
+ HKEY mediatype_key;
+ HKEY majortype_key;
+ WCHAR buf[39];
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+ KEY_READ | KEY_WRITE, &mediatype_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegOpenKeyExW(mediatype_key, buf, 0,
+ KEY_READ | KEY_WRITE, &majortype_key);
+ if (res == ERROR_FILE_NOT_FOUND) {
+ res = ERROR_SUCCESS;
+ continue;
+ }
+ if (res != ERROR_SUCCESS) break;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = recursive_delete_keyW(majortype_key, buf);
+ if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+
+ /* Removed majortype key if there is no more subtype key */
+ res = RegDeleteKeyW(majortype_key, 0);
+ if (res == ERROR_ACCESS_DENIED) res = ERROR_SUCCESS;
+
+ RegCloseKey(majortype_key);
+ }
+
+ RegCloseKey(mediatype_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_mediatypes_extension
+ */
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+ LONG res;
+ HKEY mediatype_key;
+ HKEY extensions_root_key = NULL;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+ KEY_READ | KEY_WRITE, &mediatype_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ res = RegOpenKeyExW(mediatype_key, extensions_keyname, 0,
+ KEY_READ | KEY_WRITE, &extensions_root_key);
+ if (res == ERROR_FILE_NOT_FOUND)
+ res = ERROR_SUCCESS;
+ else if (res == ERROR_SUCCESS)
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ res = recursive_delete_keyA(extensions_root_key, list->extension);
+ if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+ }
+
+ RegCloseKey(mediatype_key);
+ if (extensions_root_key)
+ RegCloseKey(extensions_root_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_filters
+ */
+static HRESULT register_filters(struct regsvr_filter const *list)
+{
+ HRESULT hr;
+ IFilterMapper2* pFM2 = NULL;
+
+ CoInitialize(NULL);
+ hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+ if (SUCCEEDED(hr)) {
+ for (; SUCCEEDED(hr) && list->clsid; ++list) {
+ REGFILTER2 rf2;
+ REGFILTERPINS2* prfp2;
+ int i;
+
+ for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) ;
+ rf2.dwVersion = 2;
+ rf2.dwMerit = list->merit;
+ rf2.u.s1.cPins2 = i;
+ rf2.u.s1.rgPins2 = prfp2 = (REGFILTERPINS2*) CoTaskMemAlloc(i*sizeof(REGFILTERPINS2));
+ if (!prfp2) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) {
+ REGPINTYPES* lpMediatype;
+ CLSID* lpClsid;
+ int j, nbmt;
+
+ for (nbmt = 0; list->pins[i].mediatypes[nbmt].majortype; nbmt++) ;
+ /* Allocate a single buffer for regpintypes struct and clsids */
+ lpMediatype = (REGPINTYPES*) CoTaskMemAlloc(nbmt*(sizeof(REGPINTYPES) + 2*sizeof(CLSID)));
+ if (!lpMediatype) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ lpClsid = (CLSID*) (lpMediatype + nbmt);
+ for (j = 0; j < nbmt; j++) {
+ (lpMediatype + j)->clsMajorType = lpClsid + j*2;
+ memcpy(lpClsid + j*2, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+ (lpMediatype + j)->clsMinorType = lpClsid + j*2 + 1;
+ if (list->pins[i].mediatypes[j].subtype)
+ memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].subtype, sizeof(CLSID));
+ else {
+ /* Subtype are often a combination of major type + fourcc/tag */
+ memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+ *(DWORD*)(lpClsid + j*2 + 1) = list->pins[i].mediatypes[j].fourcc;
+ }
+ }
+ prfp2[i].dwFlags = list->pins[i].flags;
+ prfp2[i].cInstances = 0;
+ prfp2[i].nMediaTypes = j;
+ prfp2[i].lpMediaType = lpMediatype;
+ prfp2[i].nMediums = 0;
+ prfp2[i].lpMedium = NULL;
+ prfp2[i].clsPinCategory = NULL;
+ }
+
+ if (FAILED(hr)) {
+ ERR("failed to register with hresult 0x%lx\n", hr);
+ CoTaskMemFree(prfp2);
+ break;
+ }
+
+ hr = IFilterMapper2_RegisterFilter(pFM2, list->clsid, list->name, NULL, list->category, NULL, &rf2);
+
+ while (i) {
+ CoTaskMemFree((REGPINTYPES*)prfp2[i-1].lpMediaType);
+ i--;
+ }
+ CoTaskMemFree(prfp2);
+ }
+ }
+
+ if (pFM2)
+ IFilterMapper2_Release(pFM2);
+
+ CoUninitialize();
+
+ return hr;
+}
+
+/***********************************************************************
+ * unregister_filters
+ */
+static HRESULT unregister_filters(struct regsvr_filter const *list)
+{
+ HRESULT hr;
+ IFilterMapper2* pFM2;
+
+ CoInitialize(NULL);
+
+ hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+ if (SUCCEEDED(hr)) {
+ for (; SUCCEEDED(hr) && list->clsid; ++list)
+ hr = IFilterMapper2_UnregisterFilter(pFM2, list->category, NULL, list->clsid);
+ IFilterMapper2_Release(pFM2);
+ }
+
+ CoUninitialize();
+
+ return hr;
+}
+
+/***********************************************************************
+ * regsvr_key_guid
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
+{
+ WCHAR buf[39];
+
+ StringFromGUID2(guid, buf, 39);
+ return register_key_defvalueW(base, name, buf);
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+ HKEY base,
+ WCHAR const *name,
+ WCHAR const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ (lstrlenW(value) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+ HKEY base,
+ WCHAR const *name,
+ char const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ lstrlenA(value) + 1);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_progid
+ */
+static LONG register_progid(
+ WCHAR const *clsid,
+ char const *progid,
+ char const *curver_progid,
+ char const *name,
+ char const *extra)
+{
+ LONG res;
+ HKEY progid_key;
+
+ res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &progid_key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+
+ if (name) {
+ res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)name, strlen(name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (clsid) {
+ res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (curver_progid) {
+ res = register_key_defvalueA(progid_key, curver_keyname,
+ curver_progid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (extra) {
+ HKEY extra_key;
+
+ res = RegCreateKeyExA(progid_key, extra, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &extra_key, NULL);
+ if (res == ERROR_SUCCESS)
+ RegCloseKey(extra_key);
+ }
+
+error_close_progid_key:
+ RegCloseKey(progid_key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_key
+ */
+static LONG recursive_delete_key(HKEY key)
+{
+ LONG res;
+ WCHAR subkey_name[MAX_PATH];
+ DWORD cName;
+ HKEY subkey;
+
+ for (;;) {
+ cName = sizeof(subkey_name) / sizeof(WCHAR);
+ res = RegEnumKeyExW(key, 0, subkey_name, &cName,
+ NULL, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
+ res = ERROR_SUCCESS; /* presumably we're done enumerating */
+ break;
+ }
+ res = RegOpenKeyExW(key, subkey_name, 0,
+ KEY_READ | KEY_WRITE, &subkey);
+ if (res == ERROR_FILE_NOT_FOUND) continue;
+ if (res != ERROR_SUCCESS) break;
+
+ res = recursive_delete_key(subkey);
+ RegCloseKey(subkey);
+ if (res != ERROR_SUCCESS) break;
+ }
+
+ if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyA
+ */
+static LONG recursive_delete_keyA(HKEY base, char const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyW
+ */
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * coclass list
+ */
+static struct regsvr_coclass const coclass_list[] = {
+ { &CLSID_VfwCapture,
+ "Video input for wine",
+ NULL,
+ "qcap.dll",
+ "Both"
+ },
+ { &CLSID_CaptureGraphBuilder,
+ "Capture Graph Builder",
+ NULL,
+ "qcap.dll",
+ "Both"
+ },
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * interface list
+ */
+
+static struct regsvr_interface const interface_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * mediatype list
+ */
+
+static struct regsvr_mediatype_parsing const mediatype_parsing_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * mediatype list
+ */
+
+static struct regsvr_mediatype_extension const mediatype_extension_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * filter list
+ */
+
+static struct regsvr_filter const filter_list[] = {
+ { &CLSID_VfwCapture,
+ &CLSID_VideoInputDeviceCategory,
+ { 'V','i','d','e','o',' ','4',' ','w','i','n','e',0 },
+ 0x400000,
+ { { 0xFFFFFFFF } }
+ },
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * DllRegisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllRegisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = register_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = register_interfaces(interface_list);
+ if (SUCCEEDED(hr))
+ hr = register_mediatypes_parsing(mediatype_parsing_list);
+ if (SUCCEEDED(hr))
+ hr = register_mediatypes_extension(mediatype_extension_list);
+ if (SUCCEEDED(hr))
+ hr = register_filters(filter_list);
+ return hr;
+}
+
+/***********************************************************************
+ * DllUnregisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllUnregisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = unregister_filters(filter_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_interfaces(interface_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_mediatypes_parsing(mediatype_parsing_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_mediatypes_extension(mediatype_extension_list);
+ return hr;
+}
diff -Nru wine-old/dlls/qcap/v4l.c wine-new/dlls/qcap/v4l.c
--- wine-old/dlls/qcap/v4l.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/v4l.c 2005-05-01 02:08:03.000000000 +0200
@@ -0,0 +1,667 @@
+/* DirectShow capture services (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the part of the vfw capture interface that
+ * does the actual Video4Linux(1/2) stuff required for capturing
+ * and setting/getting media format..
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#ifdef HAVE_LINUX_VIDEODEV_H
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <asm/types.h>
+#include <linux/videodev.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "winnls.h"
+#include "capture.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap_v4l);
+
+/* NOTE: Currently the V4L2 is unsupported and I'm not working on it,
+ * I have undefined HAVE_V4L2 so that I could leave the code in place
+ * without having to update it..
+ */
+#undef HAVE_V4L2
+
+struct CaptureBox;
+
+typedef void (* Renderer)(struct CaptureBox *, LPBYTE bufferin, LPBYTE stream);
+
+typedef struct CaptureBox {
+/* Dunno what to put in here? */
+ UINT width, height, bitDepth, fps;
+ UINT outputwidth, outputheight;
+
+ CRITICAL_SECTION CritSect;
+
+ IPin *pOut;
+ int fd, isV4l2, mmap;
+ int iscommitted, stopped;
+
+/* mmap (V4l1) */
+ struct video_mmap *grab_buf;
+ struct video_mbuf gb_buffers;
+ void *pmap;
+ int buffers, palette;
+
+/* read (V4l1) */
+ int imagesize;
+ char * grab_data;
+
+ int curframe;
+
+ HANDLE thread;
+ Renderer renderer;
+} CaptureBox;
+
+struct renderlist {
+ int depth;
+ char* name;
+ Renderer renderer;
+};
+
+static void renderer_RGB24(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream);
+static void renderer_RGB32(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream);
+
+static const struct renderlist renderlist_V4l[] = {
+ { 0, "NULL renderer", NULL },
+ { 8, "Gray scales", NULL }, /* 1, Intentional not suported */
+ { 0, "High 240 cube (BT848)", NULL }, /* 2, Intentional not supported */
+ { 16, "16 bit RGB (565)", NULL }, /* 3, Intentional not supported */
+ { 24, "24 bit RGB values", renderer_RGB24 }, /* 4, Supported, and tested */
+ { 32, "32 bit RGB values", renderer_RGB32 }, /* 5, Supported, and tested */
+ { 16, "15 bit RGB (555)", NULL }, /* 6, Intentional not supported */
+ { 16, "YUV 422 (Not P)", NULL }, /* 7, Should be supported */
+ { 16, "YUYV (Not P)", NULL }, /* 8, Should be supported */
+ { 16, "UYVY (Not P)", NULL }, /* 9, Should be supported */
+ { 12, "YUV 420 (Not P)", NULL }, /* 10, Should be supported */
+ { 0, "Raw capturing (BT848)", NULL }, /* 11, Intentional not supported */
+ { 16, "YUV 422 (Planar)", NULL }, /* 12, Should be supported */
+ { 12, "YUV 411 (Planar)", NULL }, /* 13, Should be supported */
+ { 12, "YUV 420 (Planar)", NULL }, /* 14, Should be supported */
+ { 10, "YUV 410 (Planar)", NULL }, /* 15, Should be supported */
+ { 0, NULL, NULL },
+};
+
+const int fallback_V4l[] = { 4, 5, 7, 8, 9, 12, 13, 14, 15, 10 };
+/* Fallback: First try raw formats, then yuv, then yuv with a color channel missing */
+
+static int xioctl(int fd, int request, void * arg)
+{
+ int r;
+
+ do r = ioctl (fd, request, arg);
+ while (-1 == r && EINTR == errno);
+
+ return r;
+}
+
+HRESULT Capture_Initialise(void ** pointer, IPin * pOut, USHORT card)
+{
+ CaptureBox * capBox = CoTaskMemAlloc(sizeof(CaptureBox));
+ char device[128];
+ struct stat st;
+#ifdef HAVE_V4L2
+ struct v4l2_capability caps;
+#endif
+ struct video_capability capa;
+ struct video_picture pict;
+ struct video_window window;
+
+ /* Because I don't want to change every return failure,
+ I'll let VfwCapture clean up if *pointer != NULL
+ and the call failed..
+ */
+
+ *pointer = NULL; /* Until we're succesful */
+
+ if (!capBox) {
+ ERR("Out of memory\n");
+ return E_OUTOFMEMORY;
+ }
+
+ sprintf(device, "/dev/video%i", card);
+
+ FIXME("(): Allow use of more then 1 video adapter, like I did in avicap\n");
+
+ if (stat (device, &st) == -1) {
+ ERR("%s: %s\n", device, strerror(errno));
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ if (!S_ISCHR (st.st_mode)) {
+ ERR("%s: Not a device\n", device);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ capBox->fd = open(device, O_RDWR | O_NONBLOCK);
+ if (capBox->fd == -1) {
+ ERR("%s: Failed to open: %s\n", device, strerror(errno));
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+#ifdef HAVE_V4L2
+ if (xioctl(capBox->fd, VIDIOC_QUERYCAP, &caps) >= 0) {
+ capBox->isV4l2 = 1;
+/* There are 5 reasons I don't add V4l2 support
+ * 1. Webcams don't use it
+ * 2. It is more complicated then V4l and more complicated then it needs to be
+ * 3. V4l2 devices can fall back to V4l
+ * 4. No one really misses it if I leave it out..
+ * 5. (MAIN REASON) *I* don't miss it, if you do, write V4l2 support yourself!
+ */
+ ERR("Tinkerer detected? Thou shalt not define HAVE_V4L2\n");
+ CoTaskMemFree(capBox);
+ close(capBox->fd);
+ return E_FAIL;
+ } else
+#endif /* HAVE_V4L2 */
+ {
+ capBox->isV4l2 = 0;
+ memset(&capa, 0, sizeof(capa));
+
+ if (xioctl(capBox->fd, VIDIOCGCAP, &capa) == -1) {
+ if (errno != EINVAL && errno != 515) ERR("%s: Querying failed: %s\n", device, strerror(errno));
+ else ERR("%s: Querying failed: Not a V4L compatible device", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ if (!(capa.type & VID_TYPE_CAPTURE)) {
+ ERR("%s: This is not a video capture device\n", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+ TRACE("Amount of inputs on %s: %d\n", capa.name, capa.channels);
+
+ if (xioctl(capBox->fd, VIDIOCGPICT, &pict) == -1) {
+ ERR("%s: Acquiring picture properties failed, this shouldn't happen..\n", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ TRACE("%s: Suggested picture depth: %d, suggested picture palette: %d\n", device, pict.depth, pict.palette);
+ TRACE("%s: Hue %d, Color %d, Contrast %d\n", device, pict.hue,pict.colour,pict.contrast);
+/* This will most likely fail, and if it does we will fall back to 32 bits,
+ of which each first bit will be nothing but rubble, waste of bandwidth */
+ TRACE("%s: Suggested format: \"%s\"\n", device, renderlist_V4l[pict.palette].name);
+ if (!renderlist_V4l[pict.palette].renderer)
+ {
+ int palet = pict.palette, formatenum;
+ WARN("No renderer available for \"%s\", trying to fall back to defaults\n", renderlist_V4l[pict.palette].name);
+ capBox->renderer = NULL;
+ for (formatenum = 0; formatenum < (sizeof(fallback_V4l) / sizeof(int)); formatenum++) {
+ int currentrender = fallback_V4l[formatenum];
+ if (renderlist_V4l[currentrender].renderer == NULL) continue;
+ pict.depth = renderlist_V4l[currentrender].depth;
+ pict.palette = currentrender;
+ if (xioctl(capBox->fd, VIDIOCSPICT, &pict) == -1) {
+ TRACE("%s: Could not render with \"%s\"\n (%d)", device, renderlist_V4l[currentrender].name, currentrender);
+ continue;
+ }
+ TRACE("%s: Found a suitable renderer: \"%s\" (%d)\n", device, renderlist_V4l[currentrender].name, currentrender);
+ capBox->renderer = renderlist_V4l[currentrender].renderer;
+ break;
+ }
+ if (!capBox->renderer) {
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ ERR("%s: This device wants to use \"%s\", but this format isn't available, and it didn't accept one of our other formats, GIVING UP!\n\n", device, renderlist_V4l[palet].name);
+ return E_FAIL;
+ }
+ } else {
+ TRACE("Using the suggested format\n");
+ capBox->renderer = renderlist_V4l[pict.palette].renderer;
+ }
+
+ memset(&window, 0, sizeof(window));
+ if (xioctl(capBox->fd, VIDIOCGWIN, &window) == -1) {
+ ERR("%s: Getting resolution failed.. (%s), giving up\n", device, strerror(errno));
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ capBox->height = window.height;
+ capBox->width = window.width;
+ capBox->bitDepth = 24;
+/* Try mmap */
+
+ if (xioctl(capBox->fd, VIDIOCGMBUF, &capBox->gb_buffers) != -1 && capBox->gb_buffers.frames) {
+ capBox->mmap = 1;
+ capBox->buffers = capBox->gb_buffers.frames;
+ if (capBox->gb_buffers.frames > 2) {
+ TRACE("%s: %d buffers granted, but only using 2 anyway\n", device, capBox->gb_buffers.frames);
+ capBox->buffers = 2;
+ } else if (capBox->gb_buffers.frames == 1) {
+ TRACE("%s: Only 1 buffer granted, which is below the tested 2\n", device);
+ } else {
+ TRACE("%s: Using %d buffers\n", device, capBox->gb_buffers.frames);
+ }
+ capBox->pmap = mmap(0, capBox->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, capBox->fd, 0);
+ if (capBox->pmap != MAP_FAILED) {
+ int i;
+ capBox->grab_buf = CoTaskMemAlloc(sizeof(struct video_mmap) * capBox->buffers);
+ if(!capBox->grab_buf) {
+ ERR("Out of memory?\n");
+ munmap(capBox->pmap, capBox->gb_buffers.size);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_OUTOFMEMORY;
+ }
+
+ /* Setup mmap capture buffers. */
+ for (i = 0; i < capBox->buffers; i++) {
+ capBox->grab_buf[i].format = pict.palette;
+ capBox->grab_buf[i].frame = i;
+ capBox->grab_buf[i].width = capBox->width;
+ capBox->grab_buf[i].height = capBox->height;
+ if (xioctl(capBox->fd, VIDIOCMCAPTURE, &capBox->grab_buf[i]) == -1)
+ {
+ ERR("%s: Error setting up capture IOCTL: %s\n", device, strerror(errno));
+ Capture_Destroy(capBox);
+ return E_FAIL;
+ }
+ }
+ } else capBox->mmap = 0;
+ }
+ if (!capBox->mmap) {
+ capBox->buffers = 1;
+ capBox->imagesize = renderlist_V4l[pict.palette].depth * capBox->height * capBox->width / 8;
+ capBox->grab_data = CoTaskMemAlloc(capBox->imagesize);
+ if (!capBox->grab_data)
+ {
+ ERR("%s: Out of memory?\n", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_OUTOFMEMORY;
+ }
+ }
+ }
+
+ capBox->pOut = pOut;
+ capBox->fps = 3;
+ capBox->stopped = 0;
+ capBox->curframe = 0;
+ InitializeCriticalSection(&capBox->CritSect);
+ *pointer = capBox;
+
+/* I had to set output to 320x240 for pin connection, the builtin filtergraph reconnect doesn't work
+ * we will try to change to this format later anyway, in Capture_SetFormat */
+ capBox->outputwidth = 320;
+ capBox->outputheight = 240;
+ capBox->iscommitted = 0;
+ TRACE("Using format: %d bits - %d x %d\n", capBox->bitDepth, capBox->width, capBox->height);
+ return S_OK;
+}
+
+HRESULT Capture_Destroy(void * pBox)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+/* Destroy file handlers etc? This function can't fail.. */
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+/* We should destroy V4l2 stuff here but we don't use it */
+ } else
+#endif
+ if (capBox->mmap) {
+ munmap(capBox->pmap, capBox->gb_buffers.size);
+ CoTaskMemFree(capBox->grab_buf);
+ } else CoTaskMemFree(capBox->grab_data);
+ close(capBox->fd);
+ DeleteCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p\n", capBox);
+ if (((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biBitCount != 24 ||
+ ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biCompression != BI_RGB)
+ {
+ ERR("Invalid media type suggested\n");
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+/* We should do V4l2 resizing here but V4l2 is not really supported.. */
+ } else
+#endif
+ {
+ struct video_window window;
+
+ }
+
+ capBox->outputwidth = ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biWidth;
+ capBox->outputheight = ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biHeight;
+
+ FIXME("%p -> (%p) - %d %d\n", capBox, mT, capBox->outputwidth, capBox->outputheight);
+ return S_OK;
+}
+
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p\n", capBox);
+ VIDEOINFOHEADER *vi;
+ mT[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+ if (!mT[0]) return E_OUTOFMEMORY;
+ vi = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
+ mT[0]->cbFormat = sizeof(VIDEOINFOHEADER);
+ if (!vi)
+ {
+ CoTaskMemFree(mT[0]);
+ return E_OUTOFMEMORY;
+ }
+ memcpy(&mT[0]->majortype, &MEDIATYPE_Video, sizeof(GUID));
+ memcpy(&mT[0]->subtype, &MEDIASUBTYPE_RGB24, sizeof(GUID));
+ memcpy(&mT[0]->formattype, &FORMAT_VideoInfo, sizeof(GUID));
+ mT[0]->bFixedSizeSamples = TRUE;
+ mT[0]->bTemporalCompression = FALSE;
+ mT[0]->pUnk = NULL;
+ mT[0]->lSampleSize = capBox->outputwidth * capBox->outputheight * capBox->bitDepth / 8;
+ TRACE("Output format: %d x %d - %d bits = %lu KB\n", capBox->outputwidth, capBox->outputheight, capBox->bitDepth, mT[0]->lSampleSize/1024);
+ vi->rcSource.left = 0; vi->rcSource.top = 0;
+ vi->rcTarget.left = 0; vi->rcTarget.top = 0;
+ vi->rcSource.right = capBox->width; vi->rcSource.bottom = capBox->height;
+ vi->rcTarget.right = capBox->outputwidth; vi->rcTarget.bottom = capBox->outputheight;
+ vi->dwBitRate = capBox->fps * mT[0]->lSampleSize;
+ vi->dwBitErrorRate = 0;
+ vi->AvgTimePerFrame = (LONGLONG)10000000.0 / (LONGLONG)capBox->fps;
+ vi->bmiHeader.biSize = 40;
+ vi->bmiHeader.biWidth = capBox->outputwidth;
+ vi->bmiHeader.biHeight = capBox->outputheight;
+ vi->bmiHeader.biPlanes = 1;
+ vi->bmiHeader.biBitCount = 24;
+ vi->bmiHeader.biCompression = BI_RGB;
+ vi->bmiHeader.biSizeImage = mT[0]->lSampleSize;
+ vi->bmiHeader.biClrUsed = vi->bmiHeader.biClrImportant = 0;
+ vi->bmiHeader.biXPelsPerMeter = 100;
+ vi->bmiHeader.biYPelsPerMeter = 100;
+ mT[0]->pbFormat = (void *)vi;
+ dump_AM_MEDIA_TYPE(mT[0]);
+ return S_OK;
+}
+
+static void renderer_RGB24(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream)
+{
+ int size = capBox->height * capBox->width * 3;
+ TRACE("%p\n", capBox);
+ memcpy(bufferin, stream, size);
+}
+
+static void renderer_RGB32(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream)
+{
+ int size = capBox->height * capBox->width * 4;
+ int pointer = 0, offset = 1;
+ TRACE("()\n");
+
+ /* I guess it's easier - but slower to do this per byte.. */
+
+ while (pointer + offset <= size) {
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ offset++;
+ }
+}
+
+#define CHECKRANGE(a) (a > 255 ? 255 : (a < 0 ? 0 : a))
+
+static void Resize(CaptureBox * capBox, LPBYTE output, LPBYTE input)
+{
+/* outputheight < height */
+/* outputwidth < width */
+ int depth = capBox->bitDepth / 8;
+ int inoffset = 0, outoffset = (capBox->outputheight-1) * capBox->outputwidth * depth;
+ int ow = capBox->outputwidth * depth;
+ while (outoffset) {
+ outoffset -= ow;
+ int x;
+ for (x = 0; x < ow; x++)
+ output[outoffset + x] = input[inoffset + x];
+ inoffset += capBox->width * depth;
+ }
+}
+
+static void Capture_GetFrame(CaptureBox * capBox, LPBYTE * pInput)
+{
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ if (capBox->mmap) {
+ if (xioctl(capBox->fd, VIDIOCSYNC, &capBox->grab_buf[capBox->curframe]) == -1)
+ TRACE("Syncing ioctl failed: %s\n", strerror(errno));
+ *pInput = ((char *)capBox->pmap) + capBox->gb_buffers.offsets[capBox->curframe];
+ } else {
+ int retval;
+ while ((retval = read(capBox->fd, capBox->grab_data, capBox->imagesize)) == -1)
+ if (errno != EAGAIN) break;
+ if (retval == -1)
+ ERR("Error occured while reading from device: %s\n", strerror(errno));
+ *pInput = capBox->grab_data;
+ }
+}
+
+static void Capture_FreeFrame(CaptureBox * capBox)
+{
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ if (capBox->mmap) {
+ if (xioctl(capBox->fd, VIDIOCMCAPTURE, &capBox->grab_buf[capBox->curframe]) == -1)
+ TRACE("Freeing frame for capture failed: %s\n", strerror(errno));
+ }
+ if (++capBox->curframe == capBox->buffers) capBox->curframe = 0;
+}
+
+static DWORD WINAPI ReadThread(LPVOID lParam) {
+ CaptureBox * capBox = lParam;
+ HRESULT hr;
+ IMediaSample *pSample = NULL;
+ unsigned long framecount = 0;
+ LPBYTE pTarget, pInput, pOutput;
+ pOutput = CoTaskMemAlloc(capBox->width * capBox->height * 3);
+
+ while (1) {
+ EnterCriticalSection(&capBox->CritSect);
+ if (capBox->stopped) break;
+ hr = OutputPin_GetDeliveryBuffer((OutputPin *)capBox->pOut, &pSample, NULL, NULL, 0);
+ if (SUCCEEDED(hr)) {
+ IMediaSample_SetActualDataLength(pSample, capBox->outputheight * capBox->outputwidth * capBox->bitDepth / 8);
+ IMediaSample_GetPointer(pSample, &pTarget);
+ /* TODO: Check return values.. */
+ Capture_GetFrame(capBox, &pInput);
+ capBox->renderer(capBox, pOutput, pInput);
+ Resize(capBox, pTarget, pOutput);
+ hr = OutputPin_SendSample((OutputPin *)capBox->pOut, pSample);
+ FIXME("%p -> Frame %lu: %lx\n", capBox, ++framecount, hr);
+ IMediaSample_Release(pSample);
+ Capture_FreeFrame(capBox);
+ }
+ LeaveCriticalSection(&capBox->CritSect);
+ if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED) {
+ ERR("Received error: %lx\n", hr);
+ }
+ }
+ LeaveCriticalSection(&capBox->CritSect);
+ CoTaskMemFree(pOutput);
+
+ return 0x0;
+}
+
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ HANDLE thread;
+ HRESULT hr;
+
+ TRACE("%p -> (%p)\n", capBox, state);
+
+ if (*state == State_Running) return S_OK;
+
+ EnterCriticalSection(&capBox->CritSect);
+
+ capBox->stopped = 0;
+
+ if (*state == State_Stopped)
+ {
+ *state = State_Running;
+ if (!capBox->iscommitted++) {
+ IMemAllocator * pAlloc = NULL;
+ ALLOCATOR_PROPERTIES ap, actual;
+ ap.cBuffers = 3;
+ ap.cbBuffer = capBox->outputwidth * capBox->outputheight * capBox->bitDepth / 8;
+ ap.cbAlign = 1;
+ ap.cbPrefix = 0;
+
+ hr = IMemInputPin_GetAllocator(((OutputPin *)capBox->pOut)->pMemInputPin, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_SetProperties(pAlloc, &ap, &actual);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_Commit(pAlloc);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+
+ TRACE("Committing allocator: %lx\n", hr);
+ }
+
+ thread = CreateThread(NULL, 0, ReadThread, capBox, 0, NULL);
+ if (thread) {
+ capBox->thread = thread;
+ SetThreadPriority(thread, THREAD_PRIORITY_IDLE);
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+ }
+ ERR("Creating thread failed.. %lx\n", GetLastError());
+ LeaveCriticalSection(&capBox->CritSect);
+ return E_FAIL;
+ }
+
+ ResumeThread(capBox->thread);
+ *state = State_Running;
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p -> (%p)\n", capBox, state);
+ if (*state == State_Paused) return S_OK;
+ if (*state == State_Stopped) Capture_Run(pBox, state);
+ EnterCriticalSection(&capBox->CritSect);
+ *state = State_Paused;
+ SuspendThread(capBox->thread);
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p -> (%p)\n", capBox, state);
+ if (*state == State_Stopped) return S_OK;
+
+ EnterCriticalSection(&capBox->CritSect);
+
+ if (capBox->thread) {
+ if (*state == State_Paused)
+ ResumeThread(capBox->thread);
+ *state = State_Stopped;
+ capBox->stopped = 1;
+ capBox->thread = 0;
+ if (capBox->iscommitted) {
+ HRESULT hr;
+ IMemInputPin *pMem = NULL;
+ IMemAllocator * pAlloc = NULL;
+ IPin *pConnect = NULL;
+
+ capBox->iscommitted = 0;
+
+ hr = IPin_ConnectedTo(capBox->pOut, &pConnect);
+
+ if (SUCCEEDED(hr))
+ hr = IPin_QueryInterface(pConnect, &IID_IMemInputPin, (void **) &pMem);
+
+ if (SUCCEEDED(hr))
+ hr = IMemInputPin_GetAllocator(pMem, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_Decommit(pAlloc);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+
+ if (pMem)
+ IMemInputPin_Release(pMem);
+
+ if (pConnect)
+ IPin_Release(pConnect);
+
+ if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
+ ERR("Decommitting allocator: %lx\n", hr);
+ }
+ }
+
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+#endif /* HAVE_LINUX_VIDEODEV_H */
+
diff -Nru wine-old/dlls/qcap/vfwcapture.c wine-new/dlls/qcap/vfwcapture.c
--- wine-old/dlls/qcap/vfwcapture.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/vfwcapture.c 2005-05-01 01:59:57.000000000 +0200
@@ -0,0 +1,614 @@
+/* Video For Windows Steering structure
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Ugh, Now I can't tell what's worser, COM or the bugs in filtergraph, pins, enummedia and devenum..
+ * This file is only compiled if we found a working videodev.h
+ * If it doesn't exist, null.c will be compiled instead
+ */
+
+/* /dev/videoX where X = videodevice, will look at a more legal way later..
+ * So here we use /dev/video0 */
+#define VIDEODEVICE 0
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "config.h"
+#include "qcap_private.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#include "pin.h"
+#include "capture.h"
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+static const IBaseFilterVtbl VfwCapture_Vtbl;
+static const IAMStreamConfigVtbl IAMStreamConfig_VTable;
+static const IPinVtbl VfwPin_Vtbl;
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
+
+typedef struct VfwCapture
+{
+ const struct IBaseFilterVtbl * lpVtbl;
+ const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;
+
+ LPVOID myCap;
+ ULONG refCount;
+ FILTER_INFO filterInfo;
+ FILTER_STATE state;
+ CRITICAL_SECTION csFilter;
+
+ IPin * pOutputPin;
+} VfwCapture;
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+ OutputPin pin;
+
+ LPVOID myCap;
+ IKsPropertySetVtbl * KSP_VT;
+} VfwPinImpl;
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+ VfwCapture *pVfwCapture;
+ HRESULT hr;
+
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+
+ pVfwCapture = CoTaskMemAlloc(sizeof(VfwCapture));
+
+ if (!pVfwCapture)
+ return E_OUTOFMEMORY;
+
+ pVfwCapture->lpVtbl = &VfwCapture_Vtbl;
+ pVfwCapture->IAMStreamConfig_vtbl = &IAMStreamConfig_VTable;
+ pVfwCapture->refCount = 1;
+ pVfwCapture->filterInfo.achName[0] = '\0';
+ pVfwCapture->filterInfo.pGraph = NULL;
+ pVfwCapture->state = State_Stopped;
+ InitializeCriticalSection(&pVfwCapture->csFilter);
+ hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl, &pVfwCapture->csFilter, &pVfwCapture->pOutputPin);
+ if (!SUCCEEDED(hr))
+ {
+ CoTaskMemFree(pVfwCapture);
+ return E_OUTOFMEMORY;
+ } else {
+ hr = Capture_Initialise(&pVfwCapture->myCap, pVfwCapture->pOutputPin, VIDEODEVICE);
+ ((VfwPinImpl *)pVfwCapture->pOutputPin)->myCap = pVfwCapture->myCap;
+ if (FAILED(hr)) {
+ if (pVfwCapture->myCap)
+ CoTaskMemFree(pVfwCapture->myCap);
+ IPin_Release((IPin *)pVfwCapture->pOutputPin);
+ CoTaskMemFree(pVfwCapture);
+ return hr;
+ }
+ }
+ *ppv = (LPVOID)pVfwCapture;
+ TRACE("-- created at %p\n", pVfwCapture);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IPersist))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IMediaFilter))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IBaseFilter))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IAMStreamConfig))
+ *ppv = (LPVOID)&(This->IAMStreamConfig_vtbl);
+
+ if (*ppv)
+ {
+ TRACE("Returning %s interface\n", qcdebugstr_guid(riid));
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+ return refCount;
+}
+
+static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+ TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+ if (!refCount)
+ {
+ TRACE("(): Destroying everything!\n");
+ if (This->state != State_Stopped)
+ Capture_Stop(This->myCap, &This->state);
+ Capture_Destroy(This->myCap);
+ CoTaskMemFree(This->myCap);
+ if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL)
+ {
+ IPin_Disconnect(((IPinImpl *)This->pOutputPin)->pConnectedTo);
+ IPin_Disconnect(This->pOutputPin);
+ }
+ IPin_Release(This->pOutputPin);
+ DeleteCriticalSection(&This->csFilter);
+ This->lpVtbl = NULL;
+ CoTaskMemFree(This);
+ }
+ return refCount;
+}
+
+/** IPersist methods **/
+
+static HRESULT WINAPI VfwCapture_GetClassID(IBaseFilter * iface, CLSID * pClsid)
+{
+ TRACE("(%p)\n", pClsid);
+ *pClsid = CLSID_VfwCapture;
+ return S_OK;
+}
+
+/** IMediaFilter methods **/
+
+static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("()\n");
+ return Capture_Stop(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("()\n");
+ return Capture_Pause(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("(%lx%08lx)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
+ return Capture_Run(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("(%lu, %p)\n", dwMilliSecsTimeout, pState);
+ *pState = This->state;
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
+{
+ TRACE("(%p)\n", pClock);
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
+{
+ TRACE("(%p)\n", ppClock);
+ return S_OK;
+}
+
+/** IBaseFilter methods **/
+
+static HRESULT WINAPI VfwCapture_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
+{
+ ENUMPINDETAILS epd;
+ VfwCapture *This = (VfwCapture *)iface;
+
+ TRACE("(%p)\n", ppEnum);
+
+ epd.cPins = 1;
+ epd.ppPins = &This->pOutputPin;
+ return IEnumPinsImpl_Construct(&epd, ppEnum);
+}
+
+static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
+{
+ FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VfwCapture_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+
+ TRACE("(%p)\n", pInfo);
+
+ strcpyW(pInfo->achName, This->filterInfo.achName);
+ pInfo->pGraph = This->filterInfo.pGraph;
+
+ if (pInfo->pGraph)
+ IFilterGraph_AddRef(pInfo->pGraph);
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+
+ TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
+
+ if (pName)
+ strcpyW(This->filterInfo.achName, pName);
+ else
+ *This->filterInfo.achName = 0;
+ This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
+
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
+{
+ FIXME("(%p) - stub\n", pVendorInfo);
+ return E_NOTIMPL;
+}
+
+static const IBaseFilterVtbl VfwCapture_Vtbl =
+{
+ VfwCapture_QueryInterface,
+ VfwCapture_AddRef,
+ VfwCapture_Release,
+ VfwCapture_GetClassID,
+ VfwCapture_Stop,
+ VfwCapture_Pause,
+ VfwCapture_Run,
+ VfwCapture_GetState,
+ VfwCapture_SetSyncSource,
+ VfwCapture_GetSyncSource,
+ VfwCapture_EnumPins,
+ VfwCapture_FindPin,
+ VfwCapture_QueryFilterInfo,
+ VfwCapture_JoinFilterGraph,
+ VfwCapture_QueryVendorInfo
+};
+
+/* AMStreamConfig interface, we only need to implement {G,S}etFormat */
+static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig * iface, REFIID riid, LPVOID * ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IAMStreamConfig))
+ {
+ *ppv = (LPVOID)iface;
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig * iface)
+{
+ ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+ TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+ return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig * iface)
+{
+ ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+ TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+ return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI AMStreamConfig_SetFormat(IAMStreamConfig *iface,
+ AM_MEDIA_TYPE *pmt) {
+ HRESULT hr;
+ ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+
+ TRACE("(%p): %p->%p\n", iface, pmt, pmt->pbFormat);
+
+ if (This->state != State_Stopped)
+ {
+ TRACE("Returning not stopped error\n");
+ return VFW_E_NOT_STOPPED;
+ }
+
+ dump_AM_MEDIA_TYPE(pmt);
+
+ if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+ hr = IPin_QueryAccept(((IPinImpl *)This->pOutputPin)->pConnectedTo, pmt);
+ TRACE("Would accept: %ld\n", hr);
+ if (hr == S_FALSE)
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+
+ hr = Capture_SetMediaType(This->myCap, pmt);
+ if (SUCCEEDED(hr) && This->filterInfo.pGraph != NULL &&
+ ((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+ hr = IFilterGraph_Reconnect(This->filterInfo.pGraph, This->pOutputPin);
+ if (SUCCEEDED(hr))
+ TRACE("Reconnection completed, with new media format..\n");
+ }
+ TRACE("Returning: %ld\n", hr);
+ return hr;
+}
+
+static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface,
+ AM_MEDIA_TYPE **pmt) {
+ ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface);
+
+ TRACE("%p -> (%p)\n", iface, pmt);
+ return Capture_GetMediaType(This->myCap, pmt);
+}
+
+static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, int *piCount, int *piSize)
+{
+ FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize);
+ return E_NOTIMPL; /* Not implemented for this interface */
+}
+
+static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
+int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)
+{
+ FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC);
+ return E_NOTIMPL; /* Not implemented for this interface */
+}
+
+static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
+{
+ AMStreamConfig_QueryInterface,
+ AMStreamConfig_AddRef,
+ AMStreamConfig_Release,
+ AMStreamConfig_SetFormat,
+ AMStreamConfig_GetFormat,
+ AMStreamConfig_GetNumberOfCapabilities,
+ AMStreamConfig_GetStreamCaps
+};
+
+/* IKsPropertySet interface */
+static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, LPVOID * ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IKsPropertySet))
+ {
+ *ppv = (LPVOID)iface;
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
+{
+ ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
+ TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
+ return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
+{
+ ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
+ TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
+ return IUnknown_Release((IUnknown *)This);
+}
+
+static HRESULT WINAPI KSP_Set(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI KSP_Get(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned)
+{
+ TRACE("()\n");
+ if (!IsEqualIID(guidPropSet, &ROPSETID_Pin))
+ return E_PROP_SET_UNSUPPORTED;
+ if (pPropData == NULL && pcbReturned == NULL)
+ return E_POINTER;
+ if (pcbReturned)
+ *pcbReturned = sizeof(GUID);
+ if (pPropData == NULL)
+ return S_OK;
+ if (cbPropData < sizeof(GUID))
+ return E_UNEXPECTED;
+ *(GUID *)pPropData = PIN_CATEGORY_PREVIEW;
+ FIXME("() Not adding a pin with PIN_CATEGORY_CAPTURE for a reason..\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI KSP_QuerySupported(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static IKsPropertySetVtbl KSP_VTable =
+{
+ KSP_QueryInterface,
+ KSP_AddRef,
+ KSP_Release,
+ KSP_Set,
+ KSP_Get,
+ KSP_QuerySupported
+};
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+ ALLOCATOR_PROPERTIES ap;
+ VfwPinImpl * pPinImpl;
+ PIN_INFO piOutput;
+
+ pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+ if (!pPinImpl)
+ return E_OUTOFMEMORY;
+
+ ap.cBuffers = 3;
+ ap.cbBuffer = 230400;
+ ap.cbAlign = 1;
+ ap.cbPrefix = 0;
+
+ piOutput.dir = PINDIR_OUTPUT;
+ piOutput.pFilter = pBaseFilter;
+ strcpyW(piOutput.achName, wszOutputPinName);
+
+ if (SUCCEEDED(OutputPin_Init(&piOutput, &ap, pBaseFilter, NULL, pCritSec, &pPinImpl->pin)))
+ {
+ pPinImpl->KSP_VT = &KSP_VTable;
+ pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl;
+ *ppPin = (IPin *)(&pPinImpl->pin.pin.lpVtbl);
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
+{
+ VfwPinImpl *This = (VfwPinImpl *)iface;
+ TRACE("%s %p\n", qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IPin))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IKsPropertySet))
+ *ppv = (LPVOID)&(This->KSP_VT);
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwPin_AddRef(IPin * iface)
+{
+ VfwPinImpl *This = (VfwPinImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->pin.pin.refCount);
+
+ TRACE("() -> new refcount: %lu\n", refCount);
+
+ return refCount;
+}
+
+static ULONG WINAPI VfwPin_Release(IPin * iface)
+{
+ VfwPinImpl *This = (VfwPinImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
+ TRACE("() -> new refcount: %lu\n", refCount);
+
+ if (!refCount)
+ {
+ CoTaskMemFree(This);
+ return 0;
+ }
+ return refCount;
+}
+
+static HRESULT WINAPI VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+ ENUMMEDIADETAILS emd;
+ AM_MEDIA_TYPE *pmt;
+ HRESULT hr;
+
+ VfwPinImpl *This = (VfwPinImpl *)iface;
+ emd.cMediaTypes = 1;
+ hr = Capture_GetMediaType(This->myCap, &pmt);
+ emd.pMediaTypes = pmt;
+ if (SUCCEEDED(hr)) hr = IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+ TRACE("%p -- %lx\n", This, hr);
+ DeleteMediaType(pmt);
+ return hr;
+}
+
+static HRESULT WINAPI VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+ TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VfwPin_EndOfStream(IPin * iface)
+{
+ TRACE("()\n");
+ return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_BeginFlush(IPin * iface)
+{
+ TRACE("(%p)->()\n", iface);
+ return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_EndFlush(IPin * iface)
+{
+ TRACE("(%p)->()\n", iface);
+ return E_UNEXPECTED;
+}
+
+static HRESULT WINAPI VfwPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+ TRACE("(%p)->(%lx%08lx, %lx%08lx, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
+ return E_UNEXPECTED;
+}
+
+static const IPinVtbl VfwPin_Vtbl =
+{
+ VfwPin_QueryInterface,
+ VfwPin_AddRef,
+ VfwPin_Release,
+ OutputPin_Connect,
+ OutputPin_ReceiveConnection,
+ OutputPin_Disconnect,
+ IPinImpl_ConnectedTo,
+ IPinImpl_ConnectionMediaType,
+ IPinImpl_QueryPinInfo,
+ IPinImpl_QueryDirection,
+ IPinImpl_QueryId,
+ IPinImpl_QueryAccept,
+ VfwPin_EnumMediaTypes,
+ VfwPin_QueryInternalConnections,
+ VfwPin_EndOfStream,
+ VfwPin_BeginFlush,
+ VfwPin_EndFlush,
+ VfwPin_NewSegment
+};
+
2
1
I'm having a look at the public beta of Notes 7 with a view to making this
work but I get quite a few MSI errors. How do I override the built in msi.
Bob
2
1