Fixed some bugs.
[wine/multimedia.git] / dlls / quartz / avidec.c
blob241f7c0ef963eea070aaea3f6c0f0ac8de1f4ea3
1 /*
2 * Implements AVI Decompressor(CLSID_AVIDec).
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
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
22 #include "config.h"
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"
36 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
39 #include "quartz_private.h"
40 #include "xform.h"
43 static const WCHAR AVIDec_FilterName[] =
44 {'A','V','I',' ','D','e','c','o','m','p','r','e','s','s','o','r',0};
46 typedef struct CAVIDecImpl
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;
56 /***************************************************************************
58 * CAVIDecImpl methods
62 static void AVIDec_ReleaseDIBBuffers(CAVIDecImpl* This)
64 TRACE("(%p)\n",This);
66 if ( This->m_pbiIn != NULL )
68 QUARTZ_FreeMem(This->m_pbiIn); This->m_pbiIn = NULL;
70 if ( This->m_pbiOut != NULL )
72 QUARTZ_FreeMem(This->m_pbiOut); This->m_pbiOut = NULL;
74 if ( This->m_pOutBuf != NULL )
76 QUARTZ_FreeMem(This->m_pOutBuf); This->m_pOutBuf = NULL;
80 static BITMAPINFO* AVIDec_DuplicateBitmapInfo(const BITMAPINFO* pbi)
82 DWORD dwSize;
83 BITMAPINFO* pbiRet;
85 dwSize = pbi->bmiHeader.biSize;
86 if ( dwSize < sizeof(BITMAPINFOHEADER) )
87 return NULL;
88 if ( pbi->bmiHeader.biBitCount <= 8 )
90 if ( pbi->bmiHeader.biClrUsed == 0 )
91 dwSize += sizeof(RGBQUAD)*(1<<pbi->bmiHeader.biBitCount);
92 else
93 dwSize += sizeof(RGBQUAD)*pbi->bmiHeader.biClrUsed;
95 if ( pbi->bmiHeader.biCompression == 3 &&
96 dwSize == sizeof(BITMAPINFOHEADER) )
97 dwSize += sizeof(DWORD)*3;
99 pbiRet = (BITMAPINFO*)QUARTZ_AllocMem(dwSize);
100 if ( pbiRet != NULL )
101 memcpy( pbiRet, pbi, dwSize );
103 return pbiRet;
106 static HRESULT AVIDec_Init( CTransformBaseImpl* pImpl )
108 CAVIDecImpl* This = pImpl->m_pUserData;
110 TRACE("(%p)\n",This);
112 if ( This != NULL )
113 return NOERROR;
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;
128 return NOERROR;
131 static HRESULT AVIDec_Cleanup( CTransformBaseImpl* pImpl )
133 CAVIDecImpl* This = pImpl->m_pUserData;
135 TRACE("(%p)\n",This);
137 if ( This == NULL )
138 return NOERROR;
140 /* destruct */
141 QUARTZ_MediaType_Free( &This->m_mtOut );
143 AVIDec_ReleaseDIBBuffers(This);
145 if ( This->hicCached != (HIC)NULL )
146 ICClose(This->hicCached);
147 if ( This->hicTrans != (HIC)NULL )
148 ICClose(This->hicTrans);
150 QUARTZ_FreeMem( This );
151 pImpl->m_pUserData = NULL;
153 return NOERROR;
156 static HRESULT AVIDec_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
158 CAVIDecImpl* This = pImpl->m_pUserData;
159 BITMAPINFO* pbiIn = NULL;
160 BITMAPINFO* pbiOut = NULL;
161 HIC hic;
163 TRACE("(%p)\n",This);
164 if ( This == NULL )
165 return E_UNEXPECTED;
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 )
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);
181 if ( This->hicCached != (HIC)NULL &&
182 ICDecompressQuery( This->hicCached, pbiIn, pbiOut ) == ICERR_OK )
184 TRACE("supported format\n");
185 return NOERROR;
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 )
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;
201 TRACE("found\n");
203 if ( This->hicCached != (HIC)NULL )
204 ICClose(This->hicCached);
205 This->hicCached = hic;
207 return NOERROR;
210 static HRESULT AVIDec_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
212 CAVIDecImpl* This = pImpl->m_pUserData;
213 HRESULT hr;
214 LONG cbFmt;
215 BITMAPINFO* pbiIn = NULL;
216 BITMAPINFO* pbiOut = NULL;
218 TRACE("(%p)\n",This);
219 hr = AVIDec_CheckMediaType( pImpl, pmtIn, NULL );
220 if ( FAILED(hr) )
221 return hr;
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;
229 QUARTZ_MediaType_Free( &This->m_mtOut );
230 ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
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 );
240 pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)This->m_mtOut.pbFormat)->bmiHeader);
242 TRACE("(%p) - get format\n",This);
243 if ( ICDecompressGetFormat( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
244 return E_FAIL;
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 );
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;
255 /* get palette */
256 if ( pbiOut->bmiHeader.biBitCount <= 8 )
258 TRACE("(%p) - get palette\n",This);
259 if ( ICDecompressGetPalette( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
261 TRACE("(%p) - use the input palette\n",This);
262 if ( pbiIn->bmiHeader.biBitCount != pbiOut->bmiHeader.biBitCount )
264 FIXME( "no palette...FIXME?\n" );
265 return E_FAIL;
267 if ( pbiOut->bmiHeader.biClrUsed == 0 )
268 pbiOut->bmiHeader.biClrUsed = 1<<pbiOut->bmiHeader.biBitCount;
269 if ( pbiOut->bmiHeader.biClrUsed > (1<<pbiOut->bmiHeader.biBitCount) )
271 ERR( "biClrUsed=%ld\n", pbiOut->bmiHeader.biClrUsed );
272 return E_FAIL;
275 memcpy( pbiOut->bmiColors, pbiIn->bmiColors,
276 sizeof(RGBQUAD) * pbiOut->bmiHeader.biClrUsed );
280 TRACE("(%p) - return format\n",This);
281 *ppmtAcceptTypes = &This->m_mtOut;
282 *pcAcceptTypes = 1;
284 return NOERROR;
287 static HRESULT AVIDec_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
289 CAVIDecImpl* This = pImpl->m_pUserData;
290 BITMAPINFO* pbiOut = NULL;
291 HRESULT hr;
293 TRACE("(%p)\n",This);
295 if ( This == NULL )
296 return E_UNEXPECTED;
298 hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
299 if ( FAILED(hr) )
300 return hr;
302 pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
304 pProp->cBuffers = 1;
305 if ( pbiOut->bmiHeader.biCompression == 0 )
306 pProp->cbBuffer = DIBSIZE(pbiOut->bmiHeader);
307 else
308 pProp->cbBuffer = pbiOut->bmiHeader.biSizeImage;
310 *pbTransInPlace = FALSE;
311 *pbTryToReuseSample = TRUE;
313 return NOERROR;
316 static HRESULT AVIDec_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
318 CAVIDecImpl* This = pImpl->m_pUserData;
319 BITMAPINFO* pbiIn = NULL;
320 BITMAPINFO* pbiOut = NULL;
321 HRESULT hr;
323 TRACE("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample);
325 if ( This == NULL ||
326 This->hicTrans != (HIC)NULL )
327 return E_UNEXPECTED;
329 hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
330 if ( FAILED(hr) )
331 return hr;
333 AVIDec_ReleaseDIBBuffers(This);
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);
344 if ( !bReuseSample )
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 );
352 if ( ICERR_OK != ICDecompressBegin(
353 This->hicCached, This->m_pbiIn, This->m_pbiOut ) )
354 return E_FAIL;
356 This->hicTrans = This->hicCached;
357 This->hicCached = (HIC)NULL;
359 return NOERROR;
362 static HRESULT AVIDec_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut )
364 CAVIDecImpl* This = pImpl->m_pUserData;
365 DWORD dwFlags;
366 BYTE* pDataIn = NULL;
367 BYTE* pDataOut = NULL;
368 HRESULT hr;
370 TRACE("(%p)\n",This);
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;
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;
385 dwFlags = 0;
386 /*** FIXME!!!
388 * if ( IMediaSample_IsSyncPoint(pSampIn) != S_OK )
389 * dwFlags |= ICDECOMPRESS_NOTKEYFRAME;
390 ****/
392 if ( IMediaSample_IsPreroll(pSampIn) == S_OK )
393 dwFlags |= ICDECOMPRESS_PREROLL;
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;
404 if ( This->m_pOutBuf != NULL )
405 memcpy( pDataOut, This->m_pOutBuf,
406 This->m_pbiOut->bmiHeader.biSizeImage );
408 return NOERROR;
411 static HRESULT AVIDec_EndTransform( CTransformBaseImpl* pImpl )
413 CAVIDecImpl* This = pImpl->m_pUserData;
415 TRACE("(%p)\n",This);
417 if ( This == NULL )
418 return E_UNEXPECTED;
419 if ( This->hicTrans == (HIC)NULL )
420 return NOERROR;
422 ICDecompressEnd(This->hicTrans);
424 if ( This->hicCached != (HIC)NULL )
425 ICClose(This->hicCached);
426 This->hicCached = This->hicTrans;
427 This->hicTrans = (HIC)NULL;
429 AVIDec_ReleaseDIBBuffers(This);
431 return NOERROR;
435 static const TransformBaseHandlers transhandlers =
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,
449 HRESULT QUARTZ_CreateAVIDec(IUnknown* punkOuter,void** ppobj)
451 return QUARTZ_CreateTransformBase(
452 punkOuter,ppobj,
453 &CLSID_AVIDec,
454 AVIDec_FilterName,
455 NULL, NULL,
456 &transhandlers );