2 * AVI Decompressor (VFW decompressors wrapper)
4 * Copyright 2004 Christian Costa
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.
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.
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
23 #include "quartz_private.h"
24 #include "control_private.h"
39 /* #include "fourcc.h" */
40 /* #include "avcodec.h" */
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
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};
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
;
57 typedef struct AVIDecImpl
59 const IBaseFilterVtbl
* lpVtbl
;
62 CRITICAL_SECTION csFilter
;
64 REFERENCE_TIME rtStreamStart
;
65 IReferenceClock
* pClock
;
66 FILTER_INFO filterInfo
;
74 static DWORD
AVIDec_SendSampleData(AVIDecImpl
* This
, LPBYTE data
, DWORD size
)
76 VIDEOINFOHEADER
* format
;
81 IMediaSample
* pSample
= NULL
;
85 hr
= IPin_ConnectionMediaType(This
->ppPins
[0], &amt
);
87 ERR("Unable to retrieve media type\n");
90 format
= (VIDEOINFOHEADER
*)amt
.pbFormat
;
92 /* Fill a bitmap header for output */
93 bi
.biSize
= sizeof(bi
);
94 bi
.biWidth
= format
->bmiHeader
.biWidth
;
95 bi
.biHeight
= format
->bmiHeader
.biHeight
;
97 bi
.biBitCount
= format
->bmiHeader
.biBitCount
;
99 bi
.biSizeImage
= bi
.biWidth
* bi
.biHeight
* bi
.biBitCount
/ 8;
101 hr
= OutputPin_GetDeliveryBuffer((OutputPin
*)This
->ppPins
[1], &pSample
, NULL
, NULL
, 0);
103 ERR("Unable to get delivery buffer (%lx)\n", hr
);
107 hr
= IMediaSample_SetActualDataLength(pSample
, 0);
110 hr
= IMediaSample_GetPointer(pSample
, &pbDstStream
);
112 ERR("Unable to get pointer to buffer (%lx)\n", hr
);
115 cbDstStream
= IMediaSample_GetSize(pSample
);
116 if (cbDstStream
< bi
.biSizeImage
) {
117 ERR("Sample size is too small %ld < %ld\n", cbDstStream
, bi
.biSizeImage
);
122 res
= ICDecompress(This
->hvid
, 0, &format
->bmiHeader
, data
, &bi
, pbDstStream
);
124 ERR("Error occurred during the decompression (%lx)\n", res
);
126 hr
= OutputPin_SendSample((OutputPin
*)This
->ppPins
[1], pSample
);
127 if (hr
!= S_OK
&& hr
!= VFW_E_NOT_CONNECTED
) {
128 ERR("Error sending sample (%lx)\n", hr
);
135 /* If we have a sample that has not been delivered, release it */
137 IMediaSample_Release(pSample
);
142 static HRESULT
AVIDec_Sample(LPVOID iface
, IMediaSample
* pSample
)
144 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
145 LPBYTE pbSrcStream
= NULL
;
146 long cbSrcStream
= 0;
147 REFERENCE_TIME tStart
, tStop
;
150 TRACE("%p %p\n", iface
, pSample
);
152 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
155 ERR("Cannot get pointer to sample data (%lx)\n", hr
);
159 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
161 ERR("Cannot get sample time (%lx)\n", hr
);
163 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
165 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream
, cbSrcStream
);
167 #if 0 /* For debugging purpose */
170 for(i
= 0; i
< cbSrcStream
; i
++)
172 if ((i
!=0) && !(i
%16))
174 DPRINTF("%02x ", pbSrcStream
[i
]);
180 AVIDec_SendSampleData(This
, pbSrcStream
, cbSrcStream
);
182 /* We have finished with the incoming sample, we must release it now */
183 IMediaSample_Release(pSample
);
188 static HRESULT
AVIDec_Input_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
190 AVIDecImpl
* pAVIDec
= (AVIDecImpl
*)iface
;
191 TRACE("%p\n", iface
);
192 dump_AM_MEDIA_TYPE(pmt
);
194 if ((IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
)) &&
195 (!memcmp(((char*)&pmt
->subtype
)+4, ((char*)&MEDIATYPE_Video
)+4, sizeof(GUID
)-4)) && /* Check root (GUID w/o FOURCC) */
196 (IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
)))
199 VIDEOINFOHEADER
* format
= (VIDEOINFOHEADER
*)pmt
->pbFormat
;
200 drv
= ICLocate(pmt
->majortype
.Data1
, pmt
->subtype
.Data1
, &format
->bmiHeader
, NULL
, ICMODE_DECOMPRESS
);
203 AM_MEDIA_TYPE
* outpmt
= &((OutputPin
*)pAVIDec
->ppPins
[1])->pin
.mtCurrent
;
204 const CLSID
* outsubtype
;
205 switch(format
->bmiHeader
.biBitCount
)
207 case 32: outsubtype
= &MEDIATYPE_Video
; break;
208 case 24: outsubtype
= &MEDIASUBTYPE_RGB24
; break;
209 case 16: outsubtype
= &MEDIASUBTYPE_RGB565
; break;
210 case 8: outsubtype
= &MEDIASUBTYPE_RGB8
; break;
212 FIXME("Depth %d not supported\n", format
->bmiHeader
.biBitCount
);
216 CopyMediaType( outpmt
, pmt
);
217 outpmt
->subtype
= *outsubtype
;
220 TRACE("Connection accepted\n");
223 TRACE("Unable to find a suitable VFW decompressor\n");
226 TRACE("Connection refused\n");
231 static HRESULT
AVIDec_Output_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
233 AVIDecImpl
* pAVIDec
= (AVIDecImpl
*)iface
;
234 AM_MEDIA_TYPE
* outpmt
= &((OutputPin
*)pAVIDec
->ppPins
[1])->pin
.mtCurrent
;
235 TRACE("%p\n", iface
);
237 if (IsEqualIID(&pmt
->majortype
, &outpmt
->majortype
) && IsEqualIID(&pmt
->subtype
, &outpmt
->subtype
))
242 static HRESULT
AVIDec_InputPin_Construct(const PIN_INFO
* pPinInfo
, SAMPLEPROC pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
248 if (pPinInfo
->dir
!= PINDIR_INPUT
)
250 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo
->dir
);
254 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
257 return E_OUTOFMEMORY
;
258 TRACE("QA : %p %p\n", pQueryAccept
, AVIDec_Input_QueryAccept
);
259 if (SUCCEEDED(InputPin_Init(pPinInfo
, pSampleProc
, pUserData
, pQueryAccept
, pCritSec
, pPinImpl
)))
261 pPinImpl
->pin
.lpVtbl
= &AVIDec_InputPin_Vtbl
;
262 pPinImpl
->lpVtblMemInput
= &MemInputPin_Vtbl
;
264 *ppPin
= (IPin
*)(&pPinImpl
->pin
.lpVtbl
);
270 HRESULT
AVIDec_OutputPin_Construct(const PIN_INFO
* pPinInfo
, ALLOCATOR_PROPERTIES
*props
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
272 OutputPin
* pPinImpl
;
276 if (pPinInfo
->dir
!= PINDIR_OUTPUT
)
278 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo
->dir
);
282 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
285 return E_OUTOFMEMORY
;
287 if (SUCCEEDED(OutputPin_Init(pPinInfo
, props
, pUserData
, pQueryAccept
, pCritSec
, pPinImpl
)))
289 pPinImpl
->pin
.lpVtbl
= &AVIDec_OutputPin_Vtbl
;
291 *ppPin
= (IPin
*)(&pPinImpl
->pin
.lpVtbl
);
297 HRESULT
AVIDec_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
302 AVIDecImpl
* pAVIDec
;
304 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
309 return CLASS_E_NOAGGREGATION
;
311 pAVIDec
= CoTaskMemAlloc(sizeof(AVIDecImpl
));
313 pAVIDec
->lpVtbl
= &AVIDec_Vtbl
;
315 pAVIDec
->refCount
= 1;
316 InitializeCriticalSection(&pAVIDec
->csFilter
);
317 pAVIDec
->state
= State_Stopped
;
318 pAVIDec
->pClock
= NULL
;
320 ZeroMemory(&pAVIDec
->filterInfo
, sizeof(FILTER_INFO
));
322 pAVIDec
->ppPins
= CoTaskMemAlloc(2 * sizeof(IPin
*));
324 /* construct input pin */
325 piInput
.dir
= PINDIR_INPUT
;
326 piInput
.pFilter
= (IBaseFilter
*)pAVIDec
;
327 strncpyW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
328 piOutput
.dir
= PINDIR_OUTPUT
;
329 piOutput
.pFilter
= (IBaseFilter
*)pAVIDec
;
330 strncpyW(piOutput
.achName
, wcsOutputPinName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
332 hr
= AVIDec_InputPin_Construct(&piInput
, AVIDec_Sample
, (LPVOID
)pAVIDec
, AVIDec_Input_QueryAccept
, &pAVIDec
->csFilter
, &pAVIDec
->ppPins
[0]);
336 hr
= AVIDec_OutputPin_Construct(&piOutput
, NULL
, NULL
, AVIDec_Output_QueryAccept
, &pAVIDec
->csFilter
, &pAVIDec
->ppPins
[1]);
339 ERR("Cannot create output pin (%lx)\n", hr
);
341 *ppv
= (LPVOID
)pAVIDec
;
345 CoTaskMemFree(pAVIDec
->ppPins
);
346 DeleteCriticalSection(&pAVIDec
->csFilter
);
347 CoTaskMemFree(pAVIDec
);
353 static HRESULT WINAPI
AVIDec_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
355 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
356 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
360 if (IsEqualIID(riid
, &IID_IUnknown
))
362 else if (IsEqualIID(riid
, &IID_IPersist
))
364 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
366 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
371 IUnknown_AddRef((IUnknown
*)(*ppv
));
375 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
377 return E_NOINTERFACE
;
380 static ULONG WINAPI
AVIDec_AddRef(IBaseFilter
* iface
)
382 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
383 TRACE("(%p/%p)->()\n", This
, iface
);
384 return InterlockedIncrement(&This
->refCount
);
387 static ULONG WINAPI
AVIDec_Release(IBaseFilter
* iface
)
389 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
390 TRACE("(%p/%p)->()\n", This
, iface
);
391 if (!InterlockedDecrement(&This
->refCount
))
395 DeleteCriticalSection(&This
->csFilter
);
396 IReferenceClock_Release(This
->pClock
);
398 for (i
= 0; i
< 2; i
++)
399 IPin_Release(This
->ppPins
[i
]);
401 HeapFree(GetProcessHeap(), 0, This
->ppPins
);
407 TRACE("Destroying AVI Decompressor\n");
413 return This
->refCount
;
416 /** IPersist methods **/
418 static HRESULT WINAPI
AVIDec_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
420 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
422 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
424 *pClsid
= CLSID_AVIDec
;
429 /** IMediaFilter methods **/
431 static HRESULT WINAPI
AVIDec_Stop(IBaseFilter
* iface
)
433 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
435 TRACE("(%p/%p)\n", This
, iface
);
437 EnterCriticalSection(&This
->csFilter
);
439 This
->state
= State_Stopped
;
441 LeaveCriticalSection(&This
->csFilter
);
446 static HRESULT WINAPI
AVIDec_Pause(IBaseFilter
* iface
)
448 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
450 TRACE("(%p/%p)->()\n", This
, iface
);
452 EnterCriticalSection(&This
->csFilter
);
454 This
->state
= State_Paused
;
456 LeaveCriticalSection(&This
->csFilter
);
461 static HRESULT WINAPI
AVIDec_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
464 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
466 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
468 EnterCriticalSection(&This
->csFilter
);
470 This
->rtStreamStart
= tStart
;
472 This
->state
= State_Running
;
474 LeaveCriticalSection(&This
->csFilter
);
479 static HRESULT WINAPI
AVIDec_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
481 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
483 TRACE("(%p/%p)->(%ld, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
485 EnterCriticalSection(&This
->csFilter
);
487 *pState
= This
->state
;
489 LeaveCriticalSection(&This
->csFilter
);
494 static HRESULT WINAPI
AVIDec_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
496 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
498 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
500 EnterCriticalSection(&This
->csFilter
);
503 IReferenceClock_Release(This
->pClock
);
504 This
->pClock
= pClock
;
506 IReferenceClock_AddRef(This
->pClock
);
508 LeaveCriticalSection(&This
->csFilter
);
513 static HRESULT WINAPI
AVIDec_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
515 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
517 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
519 EnterCriticalSection(&This
->csFilter
);
521 *ppClock
= This
->pClock
;
522 IReferenceClock_AddRef(This
->pClock
);
524 LeaveCriticalSection(&This
->csFilter
);
529 /** IBaseFilter implementation **/
531 static HRESULT WINAPI
AVIDec_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
534 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
536 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
538 epd
.cPins
= 2; /* input and output pins */
539 epd
.ppPins
= This
->ppPins
;
540 return IEnumPinsImpl_Construct(&epd
, ppEnum
);
543 static HRESULT WINAPI
AVIDec_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
545 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
547 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
549 FIXME("AVISplitter::FindPin(...)\n");
551 /* FIXME: critical section */
556 static HRESULT WINAPI
AVIDec_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
558 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
560 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
562 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
563 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
566 IFilterGraph_AddRef(pInfo
->pGraph
);
571 static HRESULT WINAPI
AVIDec_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
574 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
576 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
578 EnterCriticalSection(&This
->csFilter
);
581 strcpyW(This
->filterInfo
.achName
, pName
);
583 *This
->filterInfo
.achName
= '\0';
584 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
586 LeaveCriticalSection(&This
->csFilter
);
591 static HRESULT WINAPI
AVIDec_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
593 AVIDecImpl
*This
= (AVIDecImpl
*)iface
;
594 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
598 static const IBaseFilterVtbl AVIDec_Vtbl
=
600 AVIDec_QueryInterface
,
608 AVIDec_SetSyncSource
,
609 AVIDec_GetSyncSource
,
612 AVIDec_QueryFilterInfo
,
613 AVIDec_JoinFilterGraph
,
614 AVIDec_QueryVendorInfo
617 static const IPinVtbl AVIDec_InputPin_Vtbl
=
619 InputPin_QueryInterface
,
623 InputPin_ReceiveConnection
,
625 IPinImpl_ConnectedTo
,
626 IPinImpl_ConnectionMediaType
,
627 IPinImpl_QueryPinInfo
,
628 IPinImpl_QueryDirection
,
630 IPinImpl_QueryAccept
,
631 IPinImpl_EnumMediaTypes
,
632 IPinImpl_QueryInternalConnections
,
633 InputPin_EndOfStream
,
639 HRESULT WINAPI
AVIDec_Output_EnumMediaTypes(IPin
* iface
, IEnumMediaTypes
** ppEnum
)
641 IPinImpl
*This
= (IPinImpl
*)iface
;
642 ENUMMEDIADETAILS emd
;
644 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
647 emd
.pMediaTypes
= &This
->mtCurrent
;
649 return IEnumMediaTypesImpl_Construct(&emd
, ppEnum
);
652 HRESULT WINAPI
AVIDec_Output_Disconnect(IPin
* iface
)
654 OutputPin
* This
= (OutputPin
*)iface
;
656 AVIDecImpl
* pAVIDec
= (AVIDecImpl
*)This
->pin
.pinInfo
.pFilter
;
658 TRACE("(%p/%p)->()\n", This
, iface
);
660 hr
= OutputPin_Disconnect(iface
);
664 ICClose(pAVIDec
->hvid
);
671 static const IPinVtbl AVIDec_OutputPin_Vtbl
=
673 OutputPin_QueryInterface
,
677 OutputPin_ReceiveConnection
,
678 AVIDec_Output_Disconnect
,
679 IPinImpl_ConnectedTo
,
680 IPinImpl_ConnectionMediaType
,
681 IPinImpl_QueryPinInfo
,
682 IPinImpl_QueryDirection
,
684 IPinImpl_QueryAccept
,
685 AVIDec_Output_EnumMediaTypes
,
686 IPinImpl_QueryInternalConnections
,
687 OutputPin_EndOfStream
,
688 OutputPin_BeginFlush
,
693 static const IMemInputPinVtbl MemInputPin_Vtbl
=
695 MemInputPin_QueryInterface
,
698 MemInputPin_GetAllocator
,
699 MemInputPin_NotifyAllocator
,
700 MemInputPin_GetAllocatorRequirements
,
702 MemInputPin_ReceiveMultiple
,
703 MemInputPin_ReceiveCanBlock