Implement function number 0x5 (Return mouse button press information).
[wine] / dlls / quartz / avidec.c
1 /*
2  * Implements AVI Decompressor(CLSID_AVIDec).
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7
8 #include "config.h"
9
10 #include "windef.h"
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "winerror.h"
15 #include "vfw.h"
16 #include "strmif.h"
17 #include "control.h"
18 #include "amvideo.h"
19 #include "vfwmsgs.h"
20 #include "uuids.h"
21
22 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(quartz);
24
25 #include "quartz_private.h"
26 #include "xform.h"
27
28
29 static const WCHAR AVIDec_FilterName[] =
30 {'A','V','I',' ','D','e','c','o','m','p','r','e','s','s','o','r',0};
31
32 typedef struct CAVIDecImpl
33 {
34         HIC hicCached;
35         HIC hicTrans;
36         AM_MEDIA_TYPE m_mtOut;
37         BITMAPINFO* m_pbiIn;
38         BITMAPINFO* m_pbiOut;
39         BYTE* m_pOutBuf;
40 } CAVIDecImpl;
41
42 /***************************************************************************
43  *
44  *      CAVIDecImpl methods
45  *
46  */
47
48 static void AVIDec_ReleaseDIBBuffers(CAVIDecImpl* This)
49 {
50         TRACE("(%p)\n",This);
51
52         if ( This->m_pbiIn != NULL )
53         {
54                 QUARTZ_FreeMem(This->m_pbiIn); This->m_pbiIn = NULL;
55         }
56         if ( This->m_pbiOut != NULL )
57         {
58                 QUARTZ_FreeMem(This->m_pbiOut); This->m_pbiOut = NULL;
59         }
60         if ( This->m_pOutBuf != NULL )
61         {
62                 QUARTZ_FreeMem(This->m_pOutBuf); This->m_pOutBuf = NULL;
63         }
64 }
65
66 static BITMAPINFO* AVIDec_DuplicateBitmapInfo(const BITMAPINFO* pbi)
67 {
68         DWORD dwSize;
69         BITMAPINFO*     pbiRet;
70
71         dwSize = pbi->bmiHeader.biSize;
72         if ( dwSize < sizeof(BITMAPINFOHEADER) )
73                 return NULL;
74         if ( pbi->bmiHeader.biBitCount <= 8 )
75         {
76                 if ( pbi->bmiHeader.biClrUsed == 0 )
77                         dwSize += sizeof(RGBQUAD)*(1<<pbi->bmiHeader.biBitCount);
78                 else
79                         dwSize += sizeof(RGBQUAD)*pbi->bmiHeader.biClrUsed;
80         }
81         if ( pbi->bmiHeader.biCompression == 3 &&
82                  dwSize == sizeof(BITMAPINFOHEADER) )
83                 dwSize += sizeof(DWORD)*3;
84
85         pbiRet = (BITMAPINFO*)QUARTZ_AllocMem(dwSize);
86         if ( pbiRet != NULL )
87                 memcpy( pbiRet, pbi, dwSize );
88
89         return pbiRet;
90 }
91
92 static HRESULT AVIDec_Init( CTransformBaseImpl* pImpl )
93 {
94         CAVIDecImpl*    This = pImpl->m_pUserData;
95
96         TRACE("(%p)\n",This);
97
98         if ( This != NULL )
99                 return NOERROR;
100
101         This = (CAVIDecImpl*)QUARTZ_AllocMem( sizeof(CAVIDecImpl) );
102         if ( This == NULL )
103                 return E_OUTOFMEMORY;
104         ZeroMemory( This, sizeof(CAVIDecImpl) );
105         pImpl->m_pUserData = This;
106         /* construct */
107         This->hicCached = (HIC)NULL;
108         This->hicTrans = (HIC)NULL;
109         ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
110         This->m_pbiIn = NULL;
111         This->m_pbiOut = NULL;
112         This->m_pOutBuf = NULL;
113
114         return NOERROR;
115 }
116
117 static HRESULT AVIDec_Cleanup( CTransformBaseImpl* pImpl )
118 {
119         CAVIDecImpl*    This = pImpl->m_pUserData;
120
121         TRACE("(%p)\n",This);
122
123         if ( This == NULL )
124                 return NOERROR;
125
126         /* destruct */
127         QUARTZ_MediaType_Free( &This->m_mtOut );
128
129         AVIDec_ReleaseDIBBuffers(This);
130
131         if ( This->hicCached != (HIC)NULL )
132                 ICClose(This->hicCached);
133         if ( This->hicTrans != (HIC)NULL )
134                 ICClose(This->hicTrans);
135
136         QUARTZ_FreeMem( This );
137         pImpl->m_pUserData = NULL;
138
139         return NOERROR;
140 }
141
142 static HRESULT AVIDec_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
143 {
144         CAVIDecImpl*    This = pImpl->m_pUserData;
145         BITMAPINFO*     pbiIn = NULL;
146         BITMAPINFO*     pbiOut = NULL;
147         HIC     hic;
148
149         TRACE("(%p)\n",This);
150         if ( This == NULL )
151                 return E_UNEXPECTED;
152
153         if ( !IsEqualGUID( &pmtIn->majortype, &MEDIATYPE_Video ) )
154                 return E_FAIL;
155         if ( !IsEqualGUID( &pmtIn->formattype, &FORMAT_VideoInfo ) )
156                 return E_FAIL;
157         pbiIn = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
158         if ( pmtOut != NULL )
159         {
160                 if ( !IsEqualGUID( &pmtOut->majortype, &MEDIATYPE_Video ) )
161                         return E_FAIL;
162                 if ( !IsEqualGUID( &pmtOut->formattype, &FORMAT_VideoInfo ) )
163                         return E_FAIL;
164                 pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
165         }
166
167         if ( This->hicCached != (HIC)NULL &&
168                  ICDecompressQuery( This->hicCached, pbiIn, pbiOut ) == ICERR_OK )
169         {
170                 TRACE("supported format\n");
171                 return NOERROR;
172         }
173
174         TRACE("try to find a decoder...\n");
175         hic = ICLocate(
176                 mmioFOURCC('V','I','D','C'), 0,
177                 &pbiIn->bmiHeader, &pbiOut->bmiHeader, ICMODE_DECOMPRESS );
178         if ( hic == (HIC)NULL )
179         {
180                 WARN("no decoder for %c%c%c%c\n",
181                         (int)(( pbiIn->bmiHeader.biCompression >>  0 ) & 0xff),
182                         (int)(( pbiIn->bmiHeader.biCompression >>  8 ) & 0xff),
183                         (int)(( pbiIn->bmiHeader.biCompression >> 16 ) & 0xff),
184                         (int)(( pbiIn->bmiHeader.biCompression >> 24 ) & 0xff) );
185                 return E_FAIL;
186         }
187         TRACE("found\n");
188
189         if ( This->hicCached != (HIC)NULL )
190                 ICClose(This->hicCached);
191         This->hicCached = hic;
192
193         return NOERROR;
194 }
195
196 static HRESULT AVIDec_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
197 {
198         CAVIDecImpl*    This = pImpl->m_pUserData;
199         HRESULT hr;
200         LONG cbFmt;
201         BITMAPINFO*     pbiIn = NULL;
202         BITMAPINFO*     pbiOut = NULL;
203
204         TRACE("(%p)\n",This);
205         hr = AVIDec_CheckMediaType( pImpl, pmtIn, NULL );
206         if ( FAILED(hr) )
207                 return hr;
208
209         TRACE("(%p) - get size of format\n",This);
210         pbiIn = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
211         cbFmt = (LONG)ICDecompressGetFormatSize( This->hicCached, pbiIn );
212         if ( cbFmt < sizeof(BITMAPINFOHEADER) )
213                 return E_FAIL;
214
215         QUARTZ_MediaType_Free( &This->m_mtOut );
216         ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
217
218         memcpy( &This->m_mtOut.majortype, &MEDIATYPE_Video, sizeof(GUID) );
219         memcpy( &This->m_mtOut.formattype, &FORMAT_VideoInfo, sizeof(GUID) );
220         This->m_mtOut.cbFormat = sizeof(VIDEOINFOHEADER) + cbFmt + sizeof(RGBQUAD)*256;
221         This->m_mtOut.pbFormat = (BYTE*)CoTaskMemAlloc(This->m_mtOut.cbFormat);
222         if ( This->m_mtOut.pbFormat == NULL )
223                 return E_OUTOFMEMORY;
224         ZeroMemory( This->m_mtOut.pbFormat, This->m_mtOut.cbFormat );
225
226         pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)This->m_mtOut.pbFormat)->bmiHeader);
227
228         TRACE("(%p) - get format\n",This);
229         if ( ICDecompressGetFormat( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
230                 return E_FAIL;
231
232         hr = QUARTZ_MediaSubType_FromBitmap( &This->m_mtOut.subtype, &pbiOut->bmiHeader );
233         if ( FAILED(hr) )
234                 return hr;
235         if ( hr != S_OK )
236                 QUARTZ_MediaSubType_FromFourCC( &This->m_mtOut.subtype, pbiOut->bmiHeader.biCompression );
237
238         This->m_mtOut.bFixedSizeSamples = (pbiOut->bmiHeader.biCompression == 0) ? 1 : 0;
239         This->m_mtOut.lSampleSize = (pbiOut->bmiHeader.biCompression == 0) ? DIBSIZE(pbiOut->bmiHeader) : pbiOut->bmiHeader.biSizeImage;
240
241         /* get palette */
242         if ( pbiOut->bmiHeader.biBitCount <= 8 )
243         {
244                 TRACE("(%p) - get palette\n",This);
245                 if ( ICDecompressGetPalette( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
246                 {
247                         TRACE("(%p) - use the input palette\n",This);
248                         if ( pbiIn->bmiHeader.biBitCount != pbiOut->bmiHeader.biBitCount )
249                         {
250                                 FIXME( "no palette...fixme?\n" );
251                                 return E_FAIL;
252                         }
253                         if ( pbiOut->bmiHeader.biClrUsed == 0 )
254                                 pbiOut->bmiHeader.biClrUsed = 1<<pbiOut->bmiHeader.biBitCount;
255                         if ( pbiOut->bmiHeader.biClrUsed > (1<<pbiOut->bmiHeader.biBitCount) )
256                         {
257                                 ERR( "biClrUsed=%ld\n", pbiOut->bmiHeader.biClrUsed );
258                                 return E_FAIL;
259                         }
260
261                         memcpy( pbiOut->bmiColors, pbiIn->bmiColors,
262                                 sizeof(RGBQUAD) * pbiOut->bmiHeader.biClrUsed );
263                 }
264         }
265
266         TRACE("(%p) - return format\n",This);
267         *ppmtAcceptTypes = &This->m_mtOut;
268         *pcAcceptTypes = 1;
269
270         return NOERROR;
271 }
272
273 static HRESULT AVIDec_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
274 {
275         CAVIDecImpl*    This = pImpl->m_pUserData;
276         BITMAPINFO*     pbiOut = NULL;
277         HRESULT hr;
278
279         TRACE("(%p)\n",This);
280
281         if ( This == NULL )
282                 return E_UNEXPECTED;
283
284         hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
285         if ( FAILED(hr) )
286                 return hr;
287
288         pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
289
290         pProp->cBuffers = 1;
291         if ( pbiOut->bmiHeader.biCompression == 0 )
292                 pProp->cbBuffer = DIBSIZE(pbiOut->bmiHeader);
293         else
294                 pProp->cbBuffer = pbiOut->bmiHeader.biSizeImage;
295
296         *pbTransInPlace = FALSE;
297         *pbTryToReuseSample = TRUE;
298
299         return NOERROR;
300 }
301
302 static HRESULT AVIDec_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
303 {
304         CAVIDecImpl*    This = pImpl->m_pUserData;
305         BITMAPINFO*     pbiIn = NULL;
306         BITMAPINFO*     pbiOut = NULL;
307         HRESULT hr;
308
309         TRACE("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample);
310
311         if ( This == NULL ||
312                  This->hicTrans != (HIC)NULL )
313                 return E_UNEXPECTED;
314
315         hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
316         if ( FAILED(hr) )
317                 return hr;
318
319         AVIDec_ReleaseDIBBuffers(This);
320
321         pbiIn = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
322         pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
323         This->m_pbiIn = AVIDec_DuplicateBitmapInfo(pbiIn);
324         This->m_pbiOut = AVIDec_DuplicateBitmapInfo(pbiOut);
325         if ( This->m_pbiIn == NULL || This->m_pbiOut == NULL )
326                 return E_OUTOFMEMORY;
327         if ( This->m_pbiOut->bmiHeader.biCompression == 0 || This->m_pbiOut->bmiHeader.biCompression == 3 )
328                 This->m_pbiOut->bmiHeader.biSizeImage = DIBSIZE(This->m_pbiOut->bmiHeader);
329
330         if ( !bReuseSample )
331         {
332                 This->m_pOutBuf = QUARTZ_AllocMem(This->m_pbiOut->bmiHeader.biSizeImage);
333                 if ( This->m_pOutBuf == NULL )
334                         return E_OUTOFMEMORY;
335                 ZeroMemory( This->m_pOutBuf, This->m_pbiOut->bmiHeader.biSizeImage );
336         }
337
338         if ( ICERR_OK != ICDecompressBegin(
339                 This->hicCached, This->m_pbiIn, This->m_pbiOut ) )
340                 return E_FAIL;
341
342         This->hicTrans = This->hicCached;
343         This->hicCached = (HIC)NULL;
344
345         return NOERROR;
346 }
347
348 static HRESULT AVIDec_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut )
349 {
350         CAVIDecImpl*    This = pImpl->m_pUserData;
351         DWORD   dwFlags;
352         BYTE*   pDataIn = NULL;
353         BYTE*   pDataOut = NULL;
354         HRESULT hr;
355
356         TRACE("(%p)\n",This);
357
358         if ( This == NULL || pSampOut == NULL ||
359                  This->hicTrans == (HIC)NULL ||
360                  This->m_pbiIn == NULL ||
361                  This->m_pbiOut == NULL )
362                 return E_UNEXPECTED;
363
364         hr = IMediaSample_GetPointer( pSampIn, &pDataIn );
365         if ( FAILED(hr) )
366                 return hr;
367         hr = IMediaSample_GetPointer( pSampOut, &pDataOut );
368         if ( FAILED(hr) )
369                 return hr;
370
371         dwFlags = 0;
372         /*** FIXME!!!
373          *
374          * if ( IMediaSample_IsSyncPoint(pSampIn) != S_OK )
375          *      dwFlags |= ICDECOMPRESS_NOTKEYFRAME;
376          ****/
377
378         if ( IMediaSample_IsPreroll(pSampIn) == S_OK )
379                 dwFlags |= ICDECOMPRESS_PREROLL;
380
381         if ( ICERR_OK != ICDecompress(
382                 This->hicTrans,
383                 dwFlags,
384                 &This->m_pbiIn->bmiHeader,
385                 pDataIn,
386                 &This->m_pbiOut->bmiHeader,
387                 ( This->m_pOutBuf != NULL ) ? This->m_pOutBuf : pDataOut ) )
388                 return E_FAIL;
389
390         if ( This->m_pOutBuf != NULL )
391                 memcpy( pDataOut, This->m_pOutBuf,
392                                 This->m_pbiOut->bmiHeader.biSizeImage );
393
394         return NOERROR;
395 }
396
397 static HRESULT AVIDec_EndTransform( CTransformBaseImpl* pImpl )
398 {
399         CAVIDecImpl*    This = pImpl->m_pUserData;
400
401         TRACE("(%p)\n",This);
402
403         if ( This == NULL )
404                 return E_UNEXPECTED;
405         if ( This->hicTrans == (HIC)NULL )
406                 return NOERROR;
407
408         ICDecompressEnd(This->hicTrans);
409
410         if ( This->hicCached != (HIC)NULL )
411                 ICClose(This->hicCached);
412         This->hicCached = This->hicTrans;
413         This->hicTrans = (HIC)NULL;
414
415         AVIDec_ReleaseDIBBuffers(This);
416
417         return NOERROR;
418 }
419
420
421 static const TransformBaseHandlers transhandlers =
422 {
423         AVIDec_Init,
424         AVIDec_Cleanup,
425         AVIDec_CheckMediaType,
426         AVIDec_GetOutputTypes,
427         AVIDec_GetAllocProp,
428         AVIDec_BeginTransform,
429         AVIDec_Transform,
430         AVIDec_EndTransform,
431 };
432
433
434 HRESULT QUARTZ_CreateAVIDec(IUnknown* punkOuter,void** ppobj)
435 {
436         return QUARTZ_CreateTransformBase(
437                 punkOuter,ppobj,
438                 &CLSID_AVIDec,
439                 AVIDec_FilterName,
440                 NULL, NULL,
441                 &transhandlers );
442 }
443