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