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