Added NtLoadDriver and NtUnloadDriver stubs.
[wine] / dlls / quartz / avidec.c
1 /*
2  * AVI Decompressor (VFW decompressors wrapper)
3  *
4  * Copyright 2004 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
27 #include "uuids.h"
28 #include "aviriff.h"
29 #include "mmreg.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "strmif.h"
36 #include "vfwmsgs.h"
37 #include "evcode.h"
38 #include "vfw.h"
39 /* #include "fourcc.h" */
40 /* #include "avcodec.h" */
41
42 #include <assert.h>
43
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
48
49 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
50 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
51
52 static const IBaseFilterVtbl AVIDec_Vtbl;
53 static const IPinVtbl AVIDec_InputPin_Vtbl;
54 static const IMemInputPinVtbl MemInputPin_Vtbl; 
55 static const IPinVtbl AVIDec_OutputPin_Vtbl;
56
57 typedef struct AVIDecImpl
58 {
59     const IBaseFilterVtbl * lpVtbl;
60
61     ULONG refCount;
62     CRITICAL_SECTION csFilter;
63     FILTER_STATE state;
64     REFERENCE_TIME rtStreamStart;
65     IReferenceClock * pClock;
66     FILTER_INFO filterInfo;
67
68     IPin ** ppPins;
69
70     HIC hvid;
71     BITMAPINFOHEADER* pBihIn;
72     BITMAPINFOHEADER* pBihOut;
73     int init;
74 } AVIDecImpl;
75
76 static DWORD AVIDec_SendSampleData(AVIDecImpl* This, LPBYTE data, DWORD size)
77 {
78     VIDEOINFOHEADER* format;
79     AM_MEDIA_TYPE amt;
80     HRESULT hr;
81     DWORD res;
82     IMediaSample* pSample = NULL;
83     DWORD cbDstStream;
84     LPBYTE pbDstStream;
85
86     hr = IPin_ConnectionMediaType(This->ppPins[0], &amt);
87     if (FAILED(hr)) {
88         ERR("Unable to retrieve media type\n");
89         goto error;
90     }
91     format = (VIDEOINFOHEADER*)amt.pbFormat;
92
93     /* Update input size to match sample size */
94     This->pBihIn->biSizeImage = size;
95
96     hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->ppPins[1], &pSample, NULL, NULL, 0);
97     if (FAILED(hr)) {
98         ERR("Unable to get delivery buffer (%lx)\n", hr);
99         goto error;
100     }
101     
102     hr = IMediaSample_SetActualDataLength(pSample, 0);
103     assert(hr == S_OK);
104
105     hr = IMediaSample_GetPointer(pSample, &pbDstStream);
106     if (FAILED(hr)) {
107         ERR("Unable to get pointer to buffer (%lx)\n", hr);
108         goto error;
109     }
110     cbDstStream = IMediaSample_GetSize(pSample);
111     if (cbDstStream < This->pBihOut->biSizeImage) {
112         ERR("Sample size is too small %ld < %ld\n", cbDstStream, This->pBihOut->biSizeImage);
113         hr = E_FAIL;
114         goto error;
115     }
116
117     res = ICDecompress(This->hvid, 0, This->pBihIn, data, This->pBihOut, pbDstStream);
118     if (res != ICERR_OK)
119         ERR("Error occurred during the decompression (%lx)\n", res);
120
121     hr = OutputPin_SendSample((OutputPin*)This->ppPins[1], pSample);
122     if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) {
123         ERR("Error sending sample (%lx)\n", hr);
124         goto error;
125     }
126
127 error:
128     if (pSample)
129         IMediaSample_Release(pSample);
130
131     return hr;
132 }
133
134 static HRESULT AVIDec_Sample(LPVOID iface, IMediaSample * pSample)
135 {
136     AVIDecImpl *This = (AVIDecImpl *)iface;
137     LPBYTE pbSrcStream = NULL;
138     long cbSrcStream = 0;
139     REFERENCE_TIME tStart, tStop;
140     HRESULT hr;
141
142     TRACE("%p %p\n", iface, pSample);
143     
144     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
145     if (FAILED(hr))
146     {
147         ERR("Cannot get pointer to sample data (%lx)\n", hr);
148         return hr;
149     }
150
151     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
152     if (FAILED(hr))
153         ERR("Cannot get sample time (%lx)\n", hr);
154     
155     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
156
157     TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
158
159 #if 0 /* For debugging purpose */
160     {
161         int i;
162         for(i = 0; i < cbSrcStream; i++)
163         {
164             if ((i!=0) && !(i%16))
165                 DPRINTF("\n");
166             DPRINTF("%02x ", pbSrcStream[i]);
167         }
168         DPRINTF("\n");
169     }
170 #endif
171     
172     AVIDec_SendSampleData(This, pbSrcStream, cbSrcStream);
173
174     return S_OK;
175 }
176
177 static HRESULT AVIDec_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
178 {
179     AVIDecImpl* pAVIDec = (AVIDecImpl*)iface;
180     TRACE("%p\n", iface);
181     dump_AM_MEDIA_TYPE(pmt);
182
183     if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) &&
184         (!memcmp(((char*)&pmt->subtype)+4, ((char*)&MEDIATYPE_Video)+4, sizeof(GUID)-4)) && /* Check root (GUID w/o FOURCC) */
185         (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)))
186     {
187         HIC drv;
188         VIDEOINFOHEADER* format = (VIDEOINFOHEADER*)pmt->pbFormat;
189         drv = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, &format->bmiHeader, NULL, ICMODE_DECOMPRESS);
190         if (drv)
191         {
192             AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent;
193             const CLSID* outsubtype;
194             DWORD bih_size;
195
196             switch(format->bmiHeader.biBitCount)
197             {
198                 case 32: outsubtype = &MEDIASUBTYPE_RGB32; break;
199                 case 24: outsubtype = &MEDIASUBTYPE_RGB24; break;
200                 case 16: outsubtype = &MEDIASUBTYPE_RGB565; break;
201                 case 8:  outsubtype = &MEDIASUBTYPE_RGB8; break;
202                 default:
203                     FIXME("Depth %d not supported\n", format->bmiHeader.biBitCount);
204                     ICClose(drv);
205                     return S_FALSE;
206             }
207             CopyMediaType( outpmt, pmt);
208             outpmt->subtype = *outsubtype;
209             pAVIDec->hvid = drv;
210
211             /* Copy bitmap header from media type to 1 for input and 1 for output */
212             if (pAVIDec->pBihIn) {
213                 CoTaskMemFree(pAVIDec->pBihIn);
214                 CoTaskMemFree(pAVIDec->pBihOut);
215             }
216             bih_size = format->bmiHeader.biSize + format->bmiHeader.biClrUsed * 4;
217             pAVIDec->pBihIn = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
218             if (!pAVIDec->pBihIn)
219             {
220                 ICClose(drv);
221                 return E_OUTOFMEMORY;
222             }
223             pAVIDec->pBihOut = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
224             if (!pAVIDec->pBihOut)
225             {
226                 CoTaskMemFree(pAVIDec->pBihIn);
227                 pAVIDec->pBihIn = NULL;
228                 ICClose(drv);
229                 return E_OUTOFMEMORY;
230             }
231             memcpy(pAVIDec->pBihIn, &format->bmiHeader, bih_size);
232             memcpy(pAVIDec->pBihOut, &format->bmiHeader, bih_size);
233
234             /* Update output format as non compressed bitmap */
235             pAVIDec->pBihOut->biCompression = 0;
236             pAVIDec->pBihOut->biSizeImage = pAVIDec->pBihOut->biWidth * pAVIDec->pBihOut->biHeight * pAVIDec->pBihOut->biBitCount / 8;
237
238             /* Update buffer size of media samples in output */
239             ((OutputPin*)pAVIDec->ppPins[1])->allocProps.cbBuffer = pAVIDec->pBihOut->biSizeImage;
240             
241             pAVIDec->init = 1;
242             TRACE("Connection accepted\n");
243             return S_OK;
244         }
245         TRACE("Unable to find a suitable VFW decompressor\n");
246     }
247     
248     TRACE("Connection refused\n");
249     return S_FALSE;
250 }
251
252
253 static HRESULT AVIDec_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
254 {
255     AVIDecImpl* pAVIDec = (AVIDecImpl*)iface;
256     AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent;
257     TRACE("%p\n", iface);
258
259     if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype))
260         return S_OK;
261     return S_FALSE;
262 }
263
264 static HRESULT AVIDec_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
265 {
266     InputPin * pPinImpl;
267
268     *ppPin = NULL;
269
270     if (pPinInfo->dir != PINDIR_INPUT)
271     {
272         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
273         return E_INVALIDARG;
274     }
275
276     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
277
278     if (!pPinImpl)
279         return E_OUTOFMEMORY;
280     TRACE("QA : %p %p\n", pQueryAccept, AVIDec_Input_QueryAccept);
281     if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
282     {
283         pPinImpl->pin.lpVtbl = &AVIDec_InputPin_Vtbl;
284         pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
285         
286         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
287         return S_OK;
288     }
289     return E_FAIL;
290 }
291
292 HRESULT AVIDec_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
293 {
294     OutputPin * pPinImpl;
295
296     *ppPin = NULL;
297
298     if (pPinInfo->dir != PINDIR_OUTPUT)
299     {
300         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
301         return E_INVALIDARG;
302     }
303
304     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
305
306     if (!pPinImpl)
307         return E_OUTOFMEMORY;
308
309     if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
310     {
311         pPinImpl->pin.lpVtbl = &AVIDec_OutputPin_Vtbl;
312         
313         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
314         return S_OK;
315     }
316     return E_FAIL;
317 }
318
319 HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv)
320 {
321     HRESULT hr;
322     PIN_INFO piInput;
323     PIN_INFO piOutput;
324     AVIDecImpl * pAVIDec;
325
326     TRACE("(%p, %p)\n", pUnkOuter, ppv);
327
328     *ppv = NULL;
329
330     if (pUnkOuter)
331         return CLASS_E_NOAGGREGATION;
332     
333     pAVIDec = CoTaskMemAlloc(sizeof(AVIDecImpl));
334
335     pAVIDec->lpVtbl = &AVIDec_Vtbl;
336     
337     pAVIDec->refCount = 1;
338     InitializeCriticalSection(&pAVIDec->csFilter);
339     pAVIDec->state = State_Stopped;
340     pAVIDec->pClock = NULL;
341     pAVIDec->pBihIn = NULL;
342     pAVIDec->pBihOut = NULL;
343     pAVIDec->init = 0;
344     ZeroMemory(&pAVIDec->filterInfo, sizeof(FILTER_INFO));
345
346     pAVIDec->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
347
348     /* construct input pin */
349     piInput.dir = PINDIR_INPUT;
350     piInput.pFilter = (IBaseFilter *)pAVIDec;
351     strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
352     piOutput.dir = PINDIR_OUTPUT;
353     piOutput.pFilter = (IBaseFilter *)pAVIDec;
354     strncpyW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
355
356     hr = AVIDec_InputPin_Construct(&piInput, AVIDec_Sample, (LPVOID)pAVIDec, AVIDec_Input_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[0]);
357
358     if (SUCCEEDED(hr))
359     {
360         ALLOCATOR_PROPERTIES props;
361         props.cbAlign = 1;
362         props.cbPrefix = 0;
363         props.cbBuffer = 0; /* Will be updated at connection time */
364         props.cBuffers = 2;
365         
366         hr = AVIDec_OutputPin_Construct(&piOutput, &props, NULL, AVIDec_Output_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[1]);
367
368         if (FAILED(hr))
369             ERR("Cannot create output pin (%lx)\n", hr);
370         
371         *ppv = (LPVOID)pAVIDec;
372     }
373     else
374     {
375         CoTaskMemFree(pAVIDec->ppPins);
376         DeleteCriticalSection(&pAVIDec->csFilter);
377         CoTaskMemFree(pAVIDec);
378     }
379
380     return hr;
381 }
382
383 static HRESULT WINAPI AVIDec_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
384 {
385     AVIDecImpl *This = (AVIDecImpl *)iface;
386     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
387
388     *ppv = NULL;
389
390     if (IsEqualIID(riid, &IID_IUnknown))
391         *ppv = (LPVOID)This;
392     else if (IsEqualIID(riid, &IID_IPersist))
393         *ppv = (LPVOID)This;
394     else if (IsEqualIID(riid, &IID_IMediaFilter))
395         *ppv = (LPVOID)This;
396     else if (IsEqualIID(riid, &IID_IBaseFilter))
397         *ppv = (LPVOID)This;
398
399     if (*ppv)
400     {
401         IUnknown_AddRef((IUnknown *)(*ppv));
402         return S_OK;
403     }
404
405     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
406
407     return E_NOINTERFACE;
408 }
409
410 static ULONG WINAPI AVIDec_AddRef(IBaseFilter * iface)
411 {
412     AVIDecImpl *This = (AVIDecImpl *)iface;
413     ULONG refCount = InterlockedIncrement(&This->refCount);
414
415     TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
416
417     return refCount;
418 }
419
420 static ULONG WINAPI AVIDec_Release(IBaseFilter * iface)
421 {
422     AVIDecImpl *This = (AVIDecImpl *)iface;
423     ULONG refCount = InterlockedDecrement(&This->refCount);
424
425     TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
426
427     if (!refCount)
428     {
429         ULONG i;
430
431         DeleteCriticalSection(&This->csFilter);
432         IReferenceClock_Release(This->pClock);
433         
434         for (i = 0; i < 2; i++)
435             IPin_Release(This->ppPins[i]);
436         
437         HeapFree(GetProcessHeap(), 0, This->ppPins);
438         This->lpVtbl = NULL;
439
440         if (This->hvid)
441             ICClose(This->hvid);
442         
443         if (This->pBihIn) {
444             CoTaskMemFree(This->pBihIn);
445             CoTaskMemFree(This->pBihOut);
446         }
447             
448         TRACE("Destroying AVI Decompressor\n");
449         CoTaskMemFree(This);
450         
451         return 0;
452     }
453     else
454         return refCount;
455 }
456
457 /** IPersist methods **/
458
459 static HRESULT WINAPI AVIDec_GetClassID(IBaseFilter * iface, CLSID * pClsid)
460 {
461     AVIDecImpl *This = (AVIDecImpl *)iface;
462
463     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
464
465     *pClsid = CLSID_AVIDec;
466
467     return S_OK;
468 }
469
470 /** IMediaFilter methods **/
471
472 static HRESULT WINAPI AVIDec_Stop(IBaseFilter * iface)
473 {
474     AVIDecImpl *This = (AVIDecImpl *)iface;
475
476     TRACE("(%p/%p)\n", This, iface);
477
478     EnterCriticalSection(&This->csFilter);
479     {
480         This->state = State_Stopped;
481     }
482     LeaveCriticalSection(&This->csFilter);
483     
484     return S_OK;
485 }
486
487 static HRESULT WINAPI AVIDec_Pause(IBaseFilter * iface)
488 {
489     AVIDecImpl *This = (AVIDecImpl *)iface;
490     
491     TRACE("(%p/%p)->()\n", This, iface);
492
493     EnterCriticalSection(&This->csFilter);
494     {
495         This->state = State_Paused;
496     }
497     LeaveCriticalSection(&This->csFilter);
498
499     return S_OK;
500 }
501
502 static HRESULT WINAPI AVIDec_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
503 {
504     HRESULT hr = S_OK;
505     AVIDecImpl *This = (AVIDecImpl *)iface;
506
507     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
508
509     EnterCriticalSection(&This->csFilter);
510     {
511         This->rtStreamStart = tStart;
512         This->state = State_Running;
513         OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
514     }
515     LeaveCriticalSection(&This->csFilter);
516
517     return hr;
518 }
519
520 static HRESULT WINAPI AVIDec_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
521 {
522     AVIDecImpl *This = (AVIDecImpl *)iface;
523
524     TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState);
525
526     EnterCriticalSection(&This->csFilter);
527     {
528         *pState = This->state;
529     }
530     LeaveCriticalSection(&This->csFilter);
531
532     return S_OK;
533 }
534
535 static HRESULT WINAPI AVIDec_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
536 {
537     AVIDecImpl *This = (AVIDecImpl *)iface;
538
539     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
540
541     EnterCriticalSection(&This->csFilter);
542     {
543         if (This->pClock)
544             IReferenceClock_Release(This->pClock);
545         This->pClock = pClock;
546         if (This->pClock)
547             IReferenceClock_AddRef(This->pClock);
548     }
549     LeaveCriticalSection(&This->csFilter);
550
551     return S_OK;
552 }
553
554 static HRESULT WINAPI AVIDec_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
555 {
556     AVIDecImpl *This = (AVIDecImpl *)iface;
557
558     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
559
560     EnterCriticalSection(&This->csFilter);
561     {
562         *ppClock = This->pClock;
563         IReferenceClock_AddRef(This->pClock);
564     }
565     LeaveCriticalSection(&This->csFilter);
566     
567     return S_OK;
568 }
569
570 /** IBaseFilter implementation **/
571
572 static HRESULT WINAPI AVIDec_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
573 {
574     ENUMPINDETAILS epd;
575     AVIDecImpl *This = (AVIDecImpl *)iface;
576
577     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
578
579     epd.cPins = 2; /* input and output pins */
580     epd.ppPins = This->ppPins;
581     return IEnumPinsImpl_Construct(&epd, ppEnum);
582 }
583
584 static HRESULT WINAPI AVIDec_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
585 {
586     AVIDecImpl *This = (AVIDecImpl *)iface;
587
588     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
589
590     FIXME("AVISplitter::FindPin(...)\n");
591
592     /* FIXME: critical section */
593
594     return E_NOTIMPL;
595 }
596
597 static HRESULT WINAPI AVIDec_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
598 {
599     AVIDecImpl *This = (AVIDecImpl *)iface;
600
601     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
602
603     strcpyW(pInfo->achName, This->filterInfo.achName);
604     pInfo->pGraph = This->filterInfo.pGraph;
605
606     if (pInfo->pGraph)
607         IFilterGraph_AddRef(pInfo->pGraph);
608     
609     return S_OK;
610 }
611
612 static HRESULT WINAPI AVIDec_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
613 {
614     HRESULT hr = S_OK;
615     AVIDecImpl *This = (AVIDecImpl *)iface;
616
617     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
618
619     EnterCriticalSection(&This->csFilter);
620     {
621         if (pName)
622             strcpyW(This->filterInfo.achName, pName);
623         else
624             *This->filterInfo.achName = '\0';
625         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
626     }
627     LeaveCriticalSection(&This->csFilter);
628
629     return hr;
630 }
631
632 static HRESULT WINAPI AVIDec_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
633 {
634     AVIDecImpl *This = (AVIDecImpl *)iface;
635     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
636     return E_NOTIMPL;
637 }
638
639 static const IBaseFilterVtbl AVIDec_Vtbl =
640 {
641     AVIDec_QueryInterface,
642     AVIDec_AddRef,
643     AVIDec_Release,
644     AVIDec_GetClassID,
645     AVIDec_Stop,
646     AVIDec_Pause,
647     AVIDec_Run,
648     AVIDec_GetState,
649     AVIDec_SetSyncSource,
650     AVIDec_GetSyncSource,
651     AVIDec_EnumPins,
652     AVIDec_FindPin,
653     AVIDec_QueryFilterInfo,
654     AVIDec_JoinFilterGraph,
655     AVIDec_QueryVendorInfo
656 };
657
658 static const IPinVtbl AVIDec_InputPin_Vtbl = 
659 {
660     InputPin_QueryInterface,
661     IPinImpl_AddRef,
662     InputPin_Release,
663     InputPin_Connect,
664     InputPin_ReceiveConnection,
665     IPinImpl_Disconnect,
666     IPinImpl_ConnectedTo,
667     IPinImpl_ConnectionMediaType,
668     IPinImpl_QueryPinInfo,
669     IPinImpl_QueryDirection,
670     IPinImpl_QueryId,
671     IPinImpl_QueryAccept,
672     IPinImpl_EnumMediaTypes,
673     IPinImpl_QueryInternalConnections,
674     InputPin_EndOfStream,
675     InputPin_BeginFlush,
676     InputPin_EndFlush,
677     InputPin_NewSegment
678 };
679
680 HRESULT WINAPI AVIDec_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
681 {
682     IPinImpl *This = (IPinImpl *)iface;
683     ENUMMEDIADETAILS emd;
684
685     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
686
687     emd.cMediaTypes = 1;
688     emd.pMediaTypes = &This->mtCurrent;
689
690     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
691 }
692
693 HRESULT WINAPI AVIDec_Output_Disconnect(IPin * iface)
694 {
695     OutputPin* This = (OutputPin*)iface;
696     HRESULT hr;
697     AVIDecImpl* pAVIDec = (AVIDecImpl*)This->pin.pinInfo.pFilter;
698
699     TRACE("(%p/%p)->()\n", This, iface);
700     
701     hr = OutputPin_Disconnect(iface);
702
703     if (hr == S_OK)
704     {
705         ICClose(pAVIDec->hvid);
706         pAVIDec->hvid = 0;
707     }
708     
709     return hr;
710 }
711
712 static const IPinVtbl AVIDec_OutputPin_Vtbl = 
713 {
714     OutputPin_QueryInterface,
715     IPinImpl_AddRef,
716     OutputPin_Release,
717     OutputPin_Connect,
718     OutputPin_ReceiveConnection,
719     AVIDec_Output_Disconnect,
720     IPinImpl_ConnectedTo,
721     IPinImpl_ConnectionMediaType,
722     IPinImpl_QueryPinInfo,
723     IPinImpl_QueryDirection,
724     IPinImpl_QueryId,
725     IPinImpl_QueryAccept,
726     AVIDec_Output_EnumMediaTypes,
727     IPinImpl_QueryInternalConnections,
728     OutputPin_EndOfStream,
729     OutputPin_BeginFlush,
730     OutputPin_EndFlush,
731     OutputPin_NewSegment
732 };
733
734 static const IMemInputPinVtbl MemInputPin_Vtbl = 
735 {
736     MemInputPin_QueryInterface,
737     MemInputPin_AddRef,
738     MemInputPin_Release,
739     MemInputPin_GetAllocator,
740     MemInputPin_NotifyAllocator,
741     MemInputPin_GetAllocatorRequirements,
742     MemInputPin_Receive,
743     MemInputPin_ReceiveMultiple,
744     MemInputPin_ReceiveCanBlock
745 };