Add missing cast.
[wine] / dlls / quartz / mtype.c
1 /*
2  * Implements IEnumMediaTypes and helper functions. (internal)
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "mmsystem.h"
15 #include "strmif.h"
16 #include "vfwmsgs.h"
17 #include "uuids.h"
18
19 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(quartz);
21
22 #include "quartz_private.h"
23 #include "mtype.h"
24 #include "iunk.h"
25
26
27 /****************************************************************************/
28
29
30
31 HRESULT QUARTZ_MediaType_Copy(
32         AM_MEDIA_TYPE* pmtDst,
33         const AM_MEDIA_TYPE* pmtSrc )
34 {
35         memcpy( &pmtDst->majortype, &pmtSrc->majortype, sizeof(GUID) );
36         memcpy( &pmtDst->subtype, &pmtSrc->subtype, sizeof(GUID) );
37         pmtDst->bFixedSizeSamples = pmtSrc->bFixedSizeSamples;
38         pmtDst->bTemporalCompression = pmtSrc->bTemporalCompression;
39         pmtDst->lSampleSize = pmtSrc->lSampleSize;
40         memcpy( &pmtDst->formattype, &pmtSrc->formattype, sizeof(GUID) );
41         pmtDst->pUnk = NULL;
42         pmtDst->cbFormat = pmtSrc->cbFormat;
43         pmtDst->pbFormat = NULL;
44
45         if ( pmtSrc->pbFormat != NULL && pmtSrc->cbFormat != 0 )
46         {
47                 pmtDst->pbFormat = (BYTE*)CoTaskMemAlloc( pmtSrc->cbFormat );
48                 if ( pmtDst->pbFormat == NULL )
49                 {
50                         CoTaskMemFree( pmtDst );
51                         return E_OUTOFMEMORY;
52                 }
53                 memcpy( pmtDst->pbFormat, pmtSrc->pbFormat, pmtSrc->cbFormat );
54         }
55
56         if ( pmtSrc->pUnk != NULL )
57         {
58                 pmtDst->pUnk = pmtSrc->pUnk;
59                 IUnknown_AddRef( pmtSrc->pUnk );
60         }
61
62         return S_OK;
63 }
64
65 void QUARTZ_MediaType_Free(
66         AM_MEDIA_TYPE* pmt )
67 {
68         if ( pmt->pUnk != NULL )
69         {
70                 IUnknown_Release( pmt->pUnk );
71                 pmt->pUnk = NULL;
72         }
73         if ( pmt->pbFormat != NULL )
74         {
75                 CoTaskMemFree( pmt->pbFormat );
76                 pmt->cbFormat = 0;
77                 pmt->pbFormat = NULL;
78         }
79 }
80
81 AM_MEDIA_TYPE* QUARTZ_MediaType_Duplicate(
82         const AM_MEDIA_TYPE* pmtSrc )
83 {
84         AM_MEDIA_TYPE*  pmtDup;
85
86         pmtDup = (AM_MEDIA_TYPE*)CoTaskMemAlloc( sizeof(AM_MEDIA_TYPE) );
87         if ( pmtDup == NULL )
88                 return NULL;
89         if ( QUARTZ_MediaType_Copy( pmtDup, pmtSrc ) != S_OK )
90         {
91                 CoTaskMemFree( pmtDup );
92                 return NULL;
93         }
94
95         return pmtDup;
96 }
97
98 void QUARTZ_MediaType_Destroy(
99         AM_MEDIA_TYPE* pmt )
100 {
101         QUARTZ_MediaType_Free( pmt );
102         CoTaskMemFree( pmt );
103 }
104
105 void QUARTZ_MediaSubType_FromFourCC(
106         GUID* psubtype, DWORD dwFourCC )
107 {
108         TRACE( "FourCC %c%c%c%c\n",
109                         (int)(dwFourCC>> 0)&0xff,
110                         (int)(dwFourCC>> 8)&0xff,
111                         (int)(dwFourCC>>16)&0xff,
112                         (int)(dwFourCC>>24)&0xff );
113         memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) );
114         psubtype->Data1 = dwFourCC;
115 }
116
117 BOOL QUARTZ_MediaSubType_IsFourCC(
118         const GUID* psubtype )
119 {
120         GUID guidTemp;
121
122         QUARTZ_MediaSubType_FromFourCC(
123                 &guidTemp, psubtype->Data1 );
124         return IsEqualGUID( psubtype, &guidTemp );
125 }
126
127 HRESULT QUARTZ_MediaSubType_FromBitmap(
128         GUID* psubtype, const BITMAPINFOHEADER* pbi )
129 {
130         HRESULT hr;
131         DWORD*  pdwBitf;
132
133         if ( (pbi->biCompression & 0xffff0000) != 0 )
134                 return S_FALSE;
135
136         if ( pbi->biWidth <= 0 || pbi->biHeight == 0 )
137                 return E_FAIL;
138
139         hr = E_FAIL;
140         switch ( pbi->biCompression )
141         {
142         case 0:
143                 if ( pbi->biPlanes != 1 )
144                         break;
145                 switch ( pbi->biBitCount )
146                 {
147                 case  1:
148                         memcpy( psubtype, &MEDIASUBTYPE_RGB1, sizeof(GUID) );
149                         hr = S_OK;
150                         break;
151                 case  4:
152                         memcpy( psubtype, &MEDIASUBTYPE_RGB4, sizeof(GUID) );
153                         hr = S_OK;
154                         break;
155                 case  8:
156                         memcpy( psubtype, &MEDIASUBTYPE_RGB8, sizeof(GUID) );
157                         hr = S_OK;
158                         break;
159                 case 16:
160                         memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
161                         hr = S_OK;
162                         break;
163                 case 24:
164                         memcpy( psubtype, &MEDIASUBTYPE_RGB24, sizeof(GUID) );
165                         hr = S_OK;
166                         break;
167                 case 32:
168                         memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
169                         hr = S_OK;
170                         break;
171                 }
172                 break;
173         case 1:
174                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
175                          pbi->biBitCount == 8 )
176                 {
177                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
178                         hr = S_OK;
179                 }
180                 break;
181         case 2:
182                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
183                          pbi->biBitCount == 4 )
184                 {
185                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
186                         hr = S_OK;
187                 }
188                 break;
189         case 3:
190                 if ( pbi->biPlanes != 1 )
191                         break;
192                 pdwBitf = (DWORD*)( (BYTE*)pbi + sizeof(BITMAPINFOHEADER) );
193                 switch ( pbi->biBitCount )
194                 {
195                 case 16:
196                         if ( pdwBitf[0] == 0x7c00 &&
197                                  pdwBitf[1] == 0x03e0 &&
198                                  pdwBitf[2] == 0x001f )
199                         {
200                                 memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
201                                 hr = S_OK;
202                         }
203                         if ( pdwBitf[0] == 0xf800 &&
204                                  pdwBitf[1] == 0x07e0 &&
205                                  pdwBitf[2] == 0x001f )
206                         {
207                                 memcpy( psubtype, &MEDIASUBTYPE_RGB565, sizeof(GUID) );
208                                 hr = S_OK;
209                         }
210                         break;
211                 case 32:
212                         if ( pdwBitf[0] == 0x00ff0000 &&
213                                  pdwBitf[1] == 0x0000ff00 &&
214                                  pdwBitf[2] == 0x000000ff )
215                         {
216                                 memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
217                                 hr = S_OK;
218                         }
219                         break;
220                 }
221                 break;
222         }
223
224         return hr;
225 }
226
227 void QUARTZ_PatchBitmapInfoHeader( BITMAPINFOHEADER* pbi )
228 {
229         switch ( pbi->biCompression )
230         {
231         case mmioFOURCC('R','G','B',' '):
232                 pbi->biCompression = 0;
233                 break;
234         case mmioFOURCC('R','L','E',' '):
235         case mmioFOURCC('M','R','L','E'):
236         case mmioFOURCC('R','L','E','8'):
237         case mmioFOURCC('R','L','E','4'):
238                 if ( pbi->biBitCount == 4 )
239                         pbi->biCompression = 2;
240                 else
241                         pbi->biCompression = 1;
242                 break;
243         }
244 }
245
246 BOOL QUARTZ_BitmapHasFixedSample( const BITMAPINFOHEADER* pbi )
247 {
248         switch ( pbi->biCompression )
249         {
250         case 0:
251         case 3:
252         case mmioFOURCC('I','4','2','0'):
253         case mmioFOURCC('I','Y','U','V'):
254         case mmioFOURCC('Y','U','Y','V'):
255         case mmioFOURCC('Y','V','U','9'):
256         case mmioFOURCC('Y','4','1','1'):
257         case mmioFOURCC('Y','4','1','P'):
258         case mmioFOURCC('Y','U','Y','2'):
259         case mmioFOURCC('Y','V','Y','U'):
260         case mmioFOURCC('U','Y','V','Y'):
261         case mmioFOURCC('Y','2','1','1'):
262         case mmioFOURCC('Y','V','1','2'):
263                 return TRUE;
264         }
265
266         return FALSE;
267 }
268
269
270 /****************************************************************************/
271
272 typedef struct IEnumMediaTypesImpl
273 {
274         ICOM_VFIELD(IEnumMediaTypes);
275 } IEnumMediaTypesImpl;
276
277 typedef struct
278 {
279         QUARTZ_IUnkImpl unk;
280         IEnumMediaTypesImpl     enummtype;
281         struct QUARTZ_IFEntry   IFEntries[1];
282         CRITICAL_SECTION        cs;
283         AM_MEDIA_TYPE*  pTypes;
284         ULONG   cTypes;
285         ULONG   cCur;
286 } CEnumMediaTypes;
287
288 #define CEnumMediaTypes_THIS(iface,member)              CEnumMediaTypes*        This = ((CEnumMediaTypes*)(((char*)iface)-offsetof(CEnumMediaTypes,member)))
289
290
291
292 static HRESULT WINAPI
293 IEnumMediaTypes_fnQueryInterface(IEnumMediaTypes* iface,REFIID riid,void** ppobj)
294 {
295         CEnumMediaTypes_THIS(iface,enummtype);
296
297         TRACE("(%p)->()\n",This);
298
299         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
300 }
301
302 static ULONG WINAPI
303 IEnumMediaTypes_fnAddRef(IEnumMediaTypes* iface)
304 {
305         CEnumMediaTypes_THIS(iface,enummtype);
306
307         TRACE("(%p)->()\n",This);
308
309         return IUnknown_AddRef(This->unk.punkControl);
310 }
311
312 static ULONG WINAPI
313 IEnumMediaTypes_fnRelease(IEnumMediaTypes* iface)
314 {
315         CEnumMediaTypes_THIS(iface,enummtype);
316
317         TRACE("(%p)->()\n",This);
318
319         return IUnknown_Release(This->unk.punkControl);
320 }
321
322 static HRESULT WINAPI
323 IEnumMediaTypes_fnNext(IEnumMediaTypes* iface,ULONG cReq,AM_MEDIA_TYPE** ppmtype,ULONG* pcFetched)
324 {
325         CEnumMediaTypes_THIS(iface,enummtype);
326         HRESULT hr;
327         ULONG   cFetched;
328
329         TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppmtype,pcFetched);
330
331         if ( pcFetched == NULL && cReq > 1 )
332                 return E_INVALIDARG;
333         if ( ppmtype == NULL )
334                 return E_POINTER;
335
336         EnterCriticalSection( &This->cs );
337
338         hr = NOERROR;
339         cFetched = 0;
340         while ( cReq > 0 )
341         {
342                 if ( This->cCur >= This->cTypes )
343                 {
344                         hr = S_FALSE;
345                         break;
346                 }
347                 ppmtype[ cFetched ] =
348                         QUARTZ_MediaType_Duplicate( &This->pTypes[ This->cCur ] );
349                 if ( ppmtype[ cFetched ] == NULL )
350                 {
351                         hr = E_OUTOFMEMORY;
352                         while ( cFetched > 0 )
353                         {
354                                 cFetched --;
355                                 QUARTZ_MediaType_Destroy( ppmtype[ cFetched ] );
356                         }
357                         break;
358                 }
359
360                 cFetched ++;
361
362                 This->cCur ++;
363                 cReq --;
364         }
365
366         LeaveCriticalSection( &This->cs );
367
368         if ( pcFetched != NULL )
369                 *pcFetched = cFetched;
370
371         return hr;
372 }
373
374 static HRESULT WINAPI
375 IEnumMediaTypes_fnSkip(IEnumMediaTypes* iface,ULONG cSkip)
376 {
377         CEnumMediaTypes_THIS(iface,enummtype);
378         HRESULT hr;
379
380         TRACE("(%p)->()\n",This);
381
382         EnterCriticalSection( &This->cs );
383
384         hr = NOERROR;
385         while ( cSkip > 0 )
386         {
387                 if ( This->cCur >= This->cTypes )
388                 {
389                         hr = S_FALSE;
390                         break;
391                 }
392                 This->cCur ++;
393                 cSkip --;
394         }
395
396         LeaveCriticalSection( &This->cs );
397
398         return hr;
399 }
400
401 static HRESULT WINAPI
402 IEnumMediaTypes_fnReset(IEnumMediaTypes* iface)
403 {
404         CEnumMediaTypes_THIS(iface,enummtype);
405
406         TRACE("(%p)->()\n",This);
407
408         EnterCriticalSection( &This->cs );
409
410         This->cCur = 0;
411
412         LeaveCriticalSection( &This->cs );
413
414         return NOERROR;
415 }
416
417 static HRESULT WINAPI
418 IEnumMediaTypes_fnClone(IEnumMediaTypes* iface,IEnumMediaTypes** ppobj)
419 {
420         CEnumMediaTypes_THIS(iface,enummtype);
421         HRESULT hr;
422
423         TRACE("(%p)->()\n",This);
424
425         if ( ppobj == NULL )
426                 return E_POINTER;
427
428         EnterCriticalSection( &This->cs );
429
430         hr = QUARTZ_CreateEnumMediaTypes(
431                 ppobj,
432                 This->pTypes, This->cTypes );
433         if ( SUCCEEDED(hr) )
434                 IEnumMediaTypes_Skip( *ppobj, This->cCur );
435
436         LeaveCriticalSection( &This->cs );
437
438         return hr;
439 }
440
441
442 static ICOM_VTABLE(IEnumMediaTypes) ienummtype =
443 {
444         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
445         /* IUnknown fields */
446         IEnumMediaTypes_fnQueryInterface,
447         IEnumMediaTypes_fnAddRef,
448         IEnumMediaTypes_fnRelease,
449         /* IEnumMediaTypes fields */
450         IEnumMediaTypes_fnNext,
451         IEnumMediaTypes_fnSkip,
452         IEnumMediaTypes_fnReset,
453         IEnumMediaTypes_fnClone,
454 };
455
456
457 /* can I use offsetof safely? - FIXME? */
458 static QUARTZ_IFEntry IFEntries[] =
459 {
460   { &IID_IEnumMediaTypes, offsetof(CEnumMediaTypes,enummtype)-offsetof(CEnumMediaTypes,unk) },
461 };
462
463
464 void QUARTZ_DestroyEnumMediaTypes(IUnknown* punk)
465 {
466         CEnumMediaTypes_THIS(punk,unk);
467         ULONG   i;
468
469         if ( This->pTypes != NULL )
470         {
471                 for ( i = 0; i < This->cTypes; i++ )
472                         QUARTZ_MediaType_Free( &This->pTypes[i] );
473                 QUARTZ_FreeMem( This->pTypes );
474         }
475
476         DeleteCriticalSection( &This->cs );
477 }
478
479 HRESULT QUARTZ_CreateEnumMediaTypes(
480         IEnumMediaTypes** ppobj,
481         const AM_MEDIA_TYPE* pTypes, ULONG cTypes )
482 {
483         CEnumMediaTypes*        penum;
484         AM_MEDIA_TYPE*  pTypesDup = NULL;
485         ULONG   i;
486         HRESULT hr;
487
488         TRACE("(%p,%p,%lu)\n",ppobj,pTypes,cTypes);
489
490         if ( cTypes > 0 )
491         {
492                 pTypesDup = (AM_MEDIA_TYPE*)QUARTZ_AllocMem(
493                         sizeof( AM_MEDIA_TYPE ) * cTypes );
494                 if ( pTypesDup == NULL )
495                         return E_OUTOFMEMORY;
496
497                 i = 0;
498                 while ( i < cTypes )
499                 {
500                         hr = QUARTZ_MediaType_Copy( &pTypesDup[i], &pTypes[i] );
501                         if ( FAILED(hr) )
502                         {
503                                 while ( i > 0 )
504                                 {
505                                         i --;
506                                         QUARTZ_MediaType_Free( &pTypesDup[i] );
507                                 }
508                                 QUARTZ_FreeMem( pTypesDup );
509                                 return hr;
510                         }
511
512                         i ++;
513                 }
514         }
515
516         penum = (CEnumMediaTypes*)QUARTZ_AllocObj( sizeof(CEnumMediaTypes) );
517         if ( penum == NULL )
518         {
519                 return E_OUTOFMEMORY;
520         }
521         penum->pTypes = pTypesDup;
522         penum->cTypes = cTypes;
523         penum->cCur = 0;
524
525         QUARTZ_IUnkInit( &penum->unk, NULL );
526         ICOM_VTBL(&penum->enummtype) = &ienummtype;
527
528         penum->unk.pEntries = IFEntries;
529         penum->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
530         penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumMediaTypes;
531
532         InitializeCriticalSection( &penum->cs );
533
534         *ppobj = (IEnumMediaTypes*)(&penum->enummtype);
535
536         return S_OK;
537 }
538
539