Don't return from overlapped ReadFile on EAGAIN and other non-fatal
[wine/gsoc_dplay.git] / dlls / quartz / avidec.c
blobe2bd156218a437934948eeaa8594b14e2c5b492b
1 /*
2 * Implements AVI Decompressor(CLSID_AVIDec).
4 * hidenori@a2.ctktv.ne.jp
5 */
8 #include "config.h"
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"
22 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(quartz);
25 #include "quartz_private.h"
26 #include "xform.h"
29 static const WCHAR AVIDec_FilterName[] =
30 {'A','V','I',' ','D','e','c','o','m','p','r','e','s','s','o','r',0};
32 typedef struct CAVIDecImpl
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;
42 /***************************************************************************
44 * CAVIDecImpl methods
48 static void AVIDec_ReleaseDIBBuffers(CAVIDecImpl* This)
50 TRACE("(%p)\n",This);
52 if ( This->m_pbiIn != NULL )
54 QUARTZ_FreeMem(This->m_pbiIn); This->m_pbiIn = NULL;
56 if ( This->m_pbiOut != NULL )
58 QUARTZ_FreeMem(This->m_pbiOut); This->m_pbiOut = NULL;
60 if ( This->m_pOutBuf != NULL )
62 QUARTZ_FreeMem(This->m_pOutBuf); This->m_pOutBuf = NULL;
66 static BITMAPINFO* AVIDec_DuplicateBitmapInfo(const BITMAPINFO* pbi)
68 DWORD dwSize;
69 BITMAPINFO* pbiRet;
71 dwSize = pbi->bmiHeader.biSize;
72 if ( dwSize < sizeof(BITMAPINFOHEADER) )
73 return NULL;
74 if ( pbi->bmiHeader.biBitCount <= 8 )
76 if ( pbi->bmiHeader.biClrUsed == 0 )
77 dwSize += sizeof(RGBQUAD)*(1<<pbi->bmiHeader.biBitCount);
78 else
79 dwSize += sizeof(RGBQUAD)*pbi->bmiHeader.biClrUsed;
81 if ( pbi->bmiHeader.biCompression == 3 &&
82 dwSize == sizeof(BITMAPINFOHEADER) )
83 dwSize += sizeof(DWORD)*3;
85 pbiRet = (BITMAPINFO*)QUARTZ_AllocMem(dwSize);
86 if ( pbiRet != NULL )
87 memcpy( pbiRet, pbi, dwSize );
89 return pbiRet;
92 static HRESULT AVIDec_Init( CTransformBaseImpl* pImpl )
94 CAVIDecImpl* This = pImpl->m_pUserData;
96 TRACE("(%p)\n",This);
98 if ( This != NULL )
99 return NOERROR;
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;
114 return NOERROR;
117 static HRESULT AVIDec_Cleanup( CTransformBaseImpl* pImpl )
119 CAVIDecImpl* This = pImpl->m_pUserData;
121 TRACE("(%p)\n",This);
123 if ( This == NULL )
124 return NOERROR;
126 /* destruct */
127 QUARTZ_MediaType_Free( &This->m_mtOut );
129 AVIDec_ReleaseDIBBuffers(This);
131 if ( This->hicCached != (HIC)NULL )
132 ICClose(This->hicCached);
133 if ( This->hicTrans != (HIC)NULL )
134 ICClose(This->hicTrans);
136 QUARTZ_FreeMem( This );
137 pImpl->m_pUserData = NULL;
139 return NOERROR;
142 static HRESULT AVIDec_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
144 CAVIDecImpl* This = pImpl->m_pUserData;
145 BITMAPINFO* pbiIn = NULL;
146 BITMAPINFO* pbiOut = NULL;
147 HIC hic;
149 TRACE("(%p)\n",This);
150 if ( This == NULL )
151 return E_UNEXPECTED;
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 )
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);
167 if ( This->hicCached != (HIC)NULL &&
168 ICDecompressQuery( This->hicCached, pbiIn, pbiOut ) == ICERR_OK )
170 TRACE("supported format\n");
171 return NOERROR;
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 )
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;
187 TRACE("found\n");
189 if ( This->hicCached != (HIC)NULL )
190 ICClose(This->hicCached);
191 This->hicCached = hic;
193 return NOERROR;
196 static HRESULT AVIDec_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
198 CAVIDecImpl* This = pImpl->m_pUserData;
199 HRESULT hr;
200 LONG cbFmt;
201 BITMAPINFO* pbiIn = NULL;
202 BITMAPINFO* pbiOut = NULL;
204 TRACE("(%p)\n",This);
205 hr = AVIDec_CheckMediaType( pImpl, pmtIn, NULL );
206 if ( FAILED(hr) )
207 return hr;
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;
215 QUARTZ_MediaType_Free( &This->m_mtOut );
216 ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
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 );
226 pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)This->m_mtOut.pbFormat)->bmiHeader);
228 TRACE("(%p) - get format\n",This);
229 if ( ICDecompressGetFormat( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
230 return E_FAIL;
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 );
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;
241 /* get palette */
242 if ( pbiOut->bmiHeader.biBitCount <= 8 )
244 TRACE("(%p) - get palette\n",This);
245 if ( ICDecompressGetPalette( This->hicCached, pbiIn, pbiOut ) != ICERR_OK )
247 TRACE("(%p) - use the input palette\n",This);
248 if ( pbiIn->bmiHeader.biBitCount != pbiOut->bmiHeader.biBitCount )
250 FIXME( "no palette...fixme?\n" );
251 return E_FAIL;
253 if ( pbiOut->bmiHeader.biClrUsed == 0 )
254 pbiOut->bmiHeader.biClrUsed = 1<<pbiOut->bmiHeader.biBitCount;
255 if ( pbiOut->bmiHeader.biClrUsed > (1<<pbiOut->bmiHeader.biBitCount) )
257 ERR( "biClrUsed=%ld\n", pbiOut->bmiHeader.biClrUsed );
258 return E_FAIL;
261 memcpy( pbiOut->bmiColors, pbiIn->bmiColors,
262 sizeof(RGBQUAD) * pbiOut->bmiHeader.biClrUsed );
266 TRACE("(%p) - return format\n",This);
267 *ppmtAcceptTypes = &This->m_mtOut;
268 *pcAcceptTypes = 1;
270 return NOERROR;
273 static HRESULT AVIDec_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
275 CAVIDecImpl* This = pImpl->m_pUserData;
276 BITMAPINFO* pbiOut = NULL;
277 HRESULT hr;
279 TRACE("(%p)\n",This);
281 if ( This == NULL )
282 return E_UNEXPECTED;
284 hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
285 if ( FAILED(hr) )
286 return hr;
288 pbiOut = (BITMAPINFO*)(&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
290 pProp->cBuffers = 1;
291 if ( pbiOut->bmiHeader.biCompression == 0 )
292 pProp->cbBuffer = DIBSIZE(pbiOut->bmiHeader);
293 else
294 pProp->cbBuffer = pbiOut->bmiHeader.biSizeImage;
296 *pbTransInPlace = FALSE;
297 *pbTryToReuseSample = TRUE;
299 return NOERROR;
302 static HRESULT AVIDec_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
304 CAVIDecImpl* This = pImpl->m_pUserData;
305 BITMAPINFO* pbiIn = NULL;
306 BITMAPINFO* pbiOut = NULL;
307 HRESULT hr;
309 TRACE("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample);
311 if ( This == NULL ||
312 This->hicTrans != (HIC)NULL )
313 return E_UNEXPECTED;
315 hr = AVIDec_CheckMediaType( pImpl, pmtIn, pmtOut );
316 if ( FAILED(hr) )
317 return hr;
319 AVIDec_ReleaseDIBBuffers(This);
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);
330 if ( !bReuseSample )
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 );
338 if ( ICERR_OK != ICDecompressBegin(
339 This->hicCached, This->m_pbiIn, This->m_pbiOut ) )
340 return E_FAIL;
342 This->hicTrans = This->hicCached;
343 This->hicCached = (HIC)NULL;
345 return NOERROR;
348 static HRESULT AVIDec_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut )
350 CAVIDecImpl* This = pImpl->m_pUserData;
351 DWORD dwFlags;
352 BYTE* pDataIn = NULL;
353 BYTE* pDataOut = NULL;
354 HRESULT hr;
356 TRACE("(%p)\n",This);
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;
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;
371 dwFlags = 0;
372 /*** FIXME!!!
374 * if ( IMediaSample_IsSyncPoint(pSampIn) != S_OK )
375 * dwFlags |= ICDECOMPRESS_NOTKEYFRAME;
376 ****/
378 if ( IMediaSample_IsPreroll(pSampIn) == S_OK )
379 dwFlags |= ICDECOMPRESS_PREROLL;
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;
390 if ( This->m_pOutBuf != NULL )
391 memcpy( pDataOut, This->m_pOutBuf,
392 This->m_pbiOut->bmiHeader.biSizeImage );
394 return NOERROR;
397 static HRESULT AVIDec_EndTransform( CTransformBaseImpl* pImpl )
399 CAVIDecImpl* This = pImpl->m_pUserData;
401 TRACE("(%p)\n",This);
403 if ( This == NULL )
404 return E_UNEXPECTED;
405 if ( This->hicTrans == (HIC)NULL )
406 return NOERROR;
408 ICDecompressEnd(This->hicTrans);
410 if ( This->hicCached != (HIC)NULL )
411 ICClose(This->hicCached);
412 This->hicCached = This->hicTrans;
413 This->hicTrans = (HIC)NULL;
415 AVIDec_ReleaseDIBBuffers(This);
417 return NOERROR;
421 static const TransformBaseHandlers transhandlers =
423 AVIDec_Init,
424 AVIDec_Cleanup,
425 AVIDec_CheckMediaType,
426 AVIDec_GetOutputTypes,
427 AVIDec_GetAllocProp,
428 AVIDec_BeginTransform,
429 AVIDec_Transform,
430 AVIDec_EndTransform,
434 HRESULT QUARTZ_CreateAVIDec(IUnknown* punkOuter,void** ppobj)
436 return QUARTZ_CreateTransformBase(
437 punkOuter,ppobj,
438 &CLSID_AVIDec,
439 AVIDec_FilterName,
440 NULL, NULL,
441 &transhandlers );