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;
71 BITMAPINFOHEADER* pBihIn;
72 BITMAPINFOHEADER* pBihOut;
76 static DWORD AVIDec_SendSampleData(AVIDecImpl* This, LPBYTE data, DWORD size)
78 VIDEOINFOHEADER* format;
82 IMediaSample* pSample = NULL;
86 hr = IPin_ConnectionMediaType(This->ppPins[0], &amt);
88 ERR("Unable to retrieve media type\n");
91 format = (VIDEOINFOHEADER*)amt.pbFormat;
93 /* Update input size to match sample size */
94 This->pBihIn->biSizeImage = size;
96 hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->ppPins[1], &pSample, NULL, NULL, 0);
98 ERR("Unable to get delivery buffer (%lx)\n", hr);
102 hr = IMediaSample_SetActualDataLength(pSample, 0);
105 hr = IMediaSample_GetPointer(pSample, &pbDstStream);
107 ERR("Unable to get pointer to buffer (%lx)\n", hr);
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);
117 res = ICDecompress(This->hvid, 0, This->pBihIn, data, This->pBihOut, pbDstStream);
119 ERR("Error occurred during the decompression (%lx)\n", res);
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);
129 IMediaSample_Release(pSample);
134 static HRESULT AVIDec_Sample(LPVOID iface, IMediaSample * pSample)
136 AVIDecImpl *This = (AVIDecImpl *)iface;
137 LPBYTE pbSrcStream = NULL;
138 long cbSrcStream = 0;
139 REFERENCE_TIME tStart, tStop;
142 TRACE("%p %p\n", iface, pSample);
144 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
147 ERR("Cannot get pointer to sample data (%lx)\n", hr);
151 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
153 ERR("Cannot get sample time (%lx)\n", hr);
155 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
157 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
159 #if 0 /* For debugging purpose */
162 for(i = 0; i < cbSrcStream; i++)
164 if ((i!=0) && !(i%16))
166 DPRINTF("%02x ", pbSrcStream[i]);
172 AVIDec_SendSampleData(This, pbSrcStream, cbSrcStream);
177 static HRESULT AVIDec_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
179 AVIDecImpl* pAVIDec = (AVIDecImpl*)iface;
180 TRACE("%p\n", iface);
181 dump_AM_MEDIA_TYPE(pmt);
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)))
188 VIDEOINFOHEADER* format = (VIDEOINFOHEADER*)pmt->pbFormat;
189 drv = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, &format->bmiHeader, NULL, ICMODE_DECOMPRESS);
192 AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent;
193 const CLSID* outsubtype;
196 switch(format->bmiHeader.biBitCount)
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;
203 FIXME("Depth %d not supported\n", format->bmiHeader.biBitCount);
207 CopyMediaType( outpmt, pmt);
208 outpmt->subtype = *outsubtype;
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);
216 bih_size = format->bmiHeader.biSize + format->bmiHeader.biClrUsed * 4;
217 pAVIDec->pBihIn = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
218 if (!pAVIDec->pBihIn)
221 return E_OUTOFMEMORY;
223 pAVIDec->pBihOut = (BITMAPINFOHEADER*)CoTaskMemAlloc(bih_size);
224 if (!pAVIDec->pBihOut)
226 CoTaskMemFree(pAVIDec->pBihIn);
227 pAVIDec->pBihIn = NULL;
229 return E_OUTOFMEMORY;
231 memcpy(pAVIDec->pBihIn, &format->bmiHeader, bih_size);
232 memcpy(pAVIDec->pBihOut, &format->bmiHeader, bih_size);
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;
238 /* Update buffer size of media samples in output */
239 ((OutputPin*)pAVIDec->ppPins[1])->allocProps.cbBuffer = pAVIDec->pBihOut->biSizeImage;
242 TRACE("Connection accepted\n");
245 TRACE("Unable to find a suitable VFW decompressor\n");
248 TRACE("Connection refused\n");
253 static HRESULT AVIDec_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
255 AVIDecImpl* pAVIDec = (AVIDecImpl*)iface;
256 AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent;
257 TRACE("%p\n", iface);
259 if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype))
264 static HRESULT AVIDec_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
270 if (pPinInfo->dir != PINDIR_INPUT)
272 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
276 pPinImpl = CoTaskMemAlloc(sizeof(*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)))
283 pPinImpl->pin.lpVtbl = &AVIDec_InputPin_Vtbl;
284 pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
286 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
292 HRESULT AVIDec_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
294 OutputPin * pPinImpl;
298 if (pPinInfo->dir != PINDIR_OUTPUT)
300 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
304 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
307 return E_OUTOFMEMORY;
309 if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
311 pPinImpl->pin.lpVtbl = &AVIDec_OutputPin_Vtbl;
313 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
319 HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv)
324 AVIDecImpl * pAVIDec;
326 TRACE("(%p, %p)\n", pUnkOuter, ppv);
331 return CLASS_E_NOAGGREGATION;
333 pAVIDec = CoTaskMemAlloc(sizeof(AVIDecImpl));
335 pAVIDec->lpVtbl = &AVIDec_Vtbl;
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;
344 ZeroMemory(&pAVIDec->filterInfo, sizeof(FILTER_INFO));
346 pAVIDec->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
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]));
356 hr = AVIDec_InputPin_Construct(&piInput, AVIDec_Sample, (LPVOID)pAVIDec, AVIDec_Input_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[0]);
360 ALLOCATOR_PROPERTIES props;
363 props.cbBuffer = 0; /* Will be updated at connection time */
366 hr = AVIDec_OutputPin_Construct(&piOutput, &props, NULL, AVIDec_Output_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[1]);
369 ERR("Cannot create output pin (%lx)\n", hr);
371 *ppv = (LPVOID)pAVIDec;
375 CoTaskMemFree(pAVIDec->ppPins);
376 DeleteCriticalSection(&pAVIDec->csFilter);
377 CoTaskMemFree(pAVIDec);
383 static HRESULT WINAPI AVIDec_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
385 AVIDecImpl *This = (AVIDecImpl *)iface;
386 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
390 if (IsEqualIID(riid, &IID_IUnknown))
392 else if (IsEqualIID(riid, &IID_IPersist))
394 else if (IsEqualIID(riid, &IID_IMediaFilter))
396 else if (IsEqualIID(riid, &IID_IBaseFilter))
401 IUnknown_AddRef((IUnknown *)(*ppv));
405 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
407 return E_NOINTERFACE;
410 static ULONG WINAPI AVIDec_AddRef(IBaseFilter * iface)
412 AVIDecImpl *This = (AVIDecImpl *)iface;
413 ULONG refCount = InterlockedIncrement(&This->refCount);
415 TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
420 static ULONG WINAPI AVIDec_Release(IBaseFilter * iface)
422 AVIDecImpl *This = (AVIDecImpl *)iface;
423 ULONG refCount = InterlockedDecrement(&This->refCount);
425 TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
431 DeleteCriticalSection(&This->csFilter);
432 IReferenceClock_Release(This->pClock);
434 for (i = 0; i < 2; i++)
435 IPin_Release(This->ppPins[i]);
437 HeapFree(GetProcessHeap(), 0, This->ppPins);
444 CoTaskMemFree(This->pBihIn);
445 CoTaskMemFree(This->pBihOut);
448 TRACE("Destroying AVI Decompressor\n");
457 /** IPersist methods **/
459 static HRESULT WINAPI AVIDec_GetClassID(IBaseFilter * iface, CLSID * pClsid)
461 AVIDecImpl *This = (AVIDecImpl *)iface;
463 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
465 *pClsid = CLSID_AVIDec;
470 /** IMediaFilter methods **/
472 static HRESULT WINAPI AVIDec_Stop(IBaseFilter * iface)
474 AVIDecImpl *This = (AVIDecImpl *)iface;
476 TRACE("(%p/%p)\n", This, iface);
478 EnterCriticalSection(&This->csFilter);
480 This->state = State_Stopped;
482 LeaveCriticalSection(&This->csFilter);
487 static HRESULT WINAPI AVIDec_Pause(IBaseFilter * iface)
489 AVIDecImpl *This = (AVIDecImpl *)iface;
491 TRACE("(%p/%p)->()\n", This, iface);
493 EnterCriticalSection(&This->csFilter);
495 This->state = State_Paused;
497 LeaveCriticalSection(&This->csFilter);
502 static HRESULT WINAPI AVIDec_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
505 AVIDecImpl *This = (AVIDecImpl *)iface;
507 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
509 EnterCriticalSection(&This->csFilter);
511 This->rtStreamStart = tStart;
512 This->state = State_Running;
513 OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
515 LeaveCriticalSection(&This->csFilter);
520 static HRESULT WINAPI AVIDec_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
522 AVIDecImpl *This = (AVIDecImpl *)iface;
524 TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState);
526 EnterCriticalSection(&This->csFilter);
528 *pState = This->state;
530 LeaveCriticalSection(&This->csFilter);
535 static HRESULT WINAPI AVIDec_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
537 AVIDecImpl *This = (AVIDecImpl *)iface;
539 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
541 EnterCriticalSection(&This->csFilter);
544 IReferenceClock_Release(This->pClock);
545 This->pClock = pClock;
547 IReferenceClock_AddRef(This->pClock);
549 LeaveCriticalSection(&This->csFilter);
554 static HRESULT WINAPI AVIDec_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
556 AVIDecImpl *This = (AVIDecImpl *)iface;
558 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
560 EnterCriticalSection(&This->csFilter);
562 *ppClock = This->pClock;
563 IReferenceClock_AddRef(This->pClock);
565 LeaveCriticalSection(&This->csFilter);
570 /** IBaseFilter implementation **/
572 static HRESULT WINAPI AVIDec_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
575 AVIDecImpl *This = (AVIDecImpl *)iface;
577 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
579 epd.cPins = 2; /* input and output pins */
580 epd.ppPins = This->ppPins;
581 return IEnumPinsImpl_Construct(&epd, ppEnum);
584 static HRESULT WINAPI AVIDec_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
586 AVIDecImpl *This = (AVIDecImpl *)iface;
588 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
590 FIXME("AVISplitter::FindPin(...)\n");
592 /* FIXME: critical section */
597 static HRESULT WINAPI AVIDec_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
599 AVIDecImpl *This = (AVIDecImpl *)iface;
601 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
603 strcpyW(pInfo->achName, This->filterInfo.achName);
604 pInfo->pGraph = This->filterInfo.pGraph;
607 IFilterGraph_AddRef(pInfo->pGraph);
612 static HRESULT WINAPI AVIDec_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
615 AVIDecImpl *This = (AVIDecImpl *)iface;
617 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
619 EnterCriticalSection(&This->csFilter);
622 strcpyW(This->filterInfo.achName, pName);
624 *This->filterInfo.achName = '\0';
625 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
627 LeaveCriticalSection(&This->csFilter);
632 static HRESULT WINAPI AVIDec_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
634 AVIDecImpl *This = (AVIDecImpl *)iface;
635 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
639 static const IBaseFilterVtbl AVIDec_Vtbl =
641 AVIDec_QueryInterface,
649 AVIDec_SetSyncSource,
650 AVIDec_GetSyncSource,
653 AVIDec_QueryFilterInfo,
654 AVIDec_JoinFilterGraph,
655 AVIDec_QueryVendorInfo
658 static const IPinVtbl AVIDec_InputPin_Vtbl =
660 InputPin_QueryInterface,
664 InputPin_ReceiveConnection,
666 IPinImpl_ConnectedTo,
667 IPinImpl_ConnectionMediaType,
668 IPinImpl_QueryPinInfo,
669 IPinImpl_QueryDirection,
671 IPinImpl_QueryAccept,
672 IPinImpl_EnumMediaTypes,
673 IPinImpl_QueryInternalConnections,
674 InputPin_EndOfStream,
680 HRESULT WINAPI AVIDec_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
682 IPinImpl *This = (IPinImpl *)iface;
683 ENUMMEDIADETAILS emd;
685 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
688 emd.pMediaTypes = &This->mtCurrent;
690 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
693 HRESULT WINAPI AVIDec_Output_Disconnect(IPin * iface)
695 OutputPin* This = (OutputPin*)iface;
697 AVIDecImpl* pAVIDec = (AVIDecImpl*)This->pin.pinInfo.pFilter;
699 TRACE("(%p/%p)->()\n", This, iface);
701 hr = OutputPin_Disconnect(iface);
705 ICClose(pAVIDec->hvid);
712 static const IPinVtbl AVIDec_OutputPin_Vtbl =
714 OutputPin_QueryInterface,
718 OutputPin_ReceiveConnection,
719 AVIDec_Output_Disconnect,
720 IPinImpl_ConnectedTo,
721 IPinImpl_ConnectionMediaType,
722 IPinImpl_QueryPinInfo,
723 IPinImpl_QueryDirection,
725 IPinImpl_QueryAccept,
726 AVIDec_Output_EnumMediaTypes,
727 IPinImpl_QueryInternalConnections,
728 OutputPin_EndOfStream,
729 OutputPin_BeginFlush,
734 static const IMemInputPinVtbl MemInputPin_Vtbl =
736 MemInputPin_QueryInterface,
739 MemInputPin_GetAllocator,
740 MemInputPin_NotifyAllocator,
741 MemInputPin_GetAllocatorRequirements,
743 MemInputPin_ReceiveMultiple,
744 MemInputPin_ReceiveCanBlock