When including 'wine/port.h', include it first.
[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         memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) );
109         psubtype->Data1 = dwFourCC;
110 }
111
112 BOOL QUARTZ_MediaSubType_IsFourCC(
113         const GUID* psubtype )
114 {
115         GUID guidTemp;
116
117         QUARTZ_MediaSubType_FromFourCC(
118                 &guidTemp, psubtype->Data1 );
119         return IsEqualGUID( psubtype, &guidTemp );
120 }
121
122 HRESULT QUARTZ_MediaSubType_FromBitmap(
123         GUID* psubtype, const BITMAPINFOHEADER* pbi )
124 {
125         HRESULT hr;
126         DWORD*  pdwBitf;
127
128         if ( (pbi->biCompression & 0xffff) != 0 )
129                 return S_FALSE;
130
131         if ( pbi->biWidth <= 0 || pbi->biHeight == 0 )
132                 return E_FAIL;
133
134         hr = E_FAIL;
135         switch ( pbi->biCompression )
136         {
137         case 0:
138                 if ( pbi->biPlanes != 1 )
139                         break;
140                 switch ( pbi->biBitCount )
141                 {
142                 case  1:
143                         memcpy( psubtype, &MEDIASUBTYPE_RGB1, sizeof(GUID) );
144                         hr = S_OK;
145                         break;
146                 case  4:
147                         memcpy( psubtype, &MEDIASUBTYPE_RGB4, sizeof(GUID) );
148                         hr = S_OK;
149                         break;
150                 case  8:
151                         memcpy( psubtype, &MEDIASUBTYPE_RGB8, sizeof(GUID) );
152                         hr = S_OK;
153                         break;
154                 case 16:
155                         memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
156                         hr = S_OK;
157                         break;
158                 case 24:
159                         memcpy( psubtype, &MEDIASUBTYPE_RGB24, sizeof(GUID) );
160                         hr = S_OK;
161                         break;
162                 case 32:
163                         memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
164                         hr = S_OK;
165                         break;
166                 }
167                 break;
168         case 1:
169                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
170                          pbi->biBitCount == 8 )
171                 {
172                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
173                         hr = S_OK;
174                 }
175                 break;
176         case 2:
177                 if ( pbi->biPlanes == 1 && pbi->biHeight > 0 &&
178                          pbi->biBitCount == 4 )
179                 {
180                         QUARTZ_MediaSubType_FromFourCC( psubtype, mmioFOURCC('M','R','L','E') );
181                         hr = S_OK;
182                 }
183                 break;
184         case 3:
185                 if ( pbi->biPlanes != 1 )
186                         break;
187                 pdwBitf = (DWORD*)( (BYTE*)pbi + sizeof(BITMAPINFOHEADER) );
188                 switch ( pbi->biBitCount )
189                 {
190                 case 16:
191                         if ( pdwBitf[0] == 0x7c00 &&
192                                  pdwBitf[1] == 0x03e0 &&
193                                  pdwBitf[2] == 0x001f )
194                         {
195                                 memcpy( psubtype, &MEDIASUBTYPE_RGB555, sizeof(GUID) );
196                                 hr = S_OK;
197                         }
198                         if ( pdwBitf[0] == 0xf800 &&
199                                  pdwBitf[1] == 0x07e0 &&
200                                  pdwBitf[2] == 0x001f )
201                         {
202                                 memcpy( psubtype, &MEDIASUBTYPE_RGB565, sizeof(GUID) );
203                                 hr = S_OK;
204                         }
205                         break;
206                 case 32:
207                         if ( pdwBitf[0] == 0x00ff0000 &&
208                                  pdwBitf[1] == 0x0000ff00 &&
209                                  pdwBitf[2] == 0x000000ff )
210                         {
211                                 memcpy( psubtype, &MEDIASUBTYPE_RGB32, sizeof(GUID) );
212                                 hr = S_OK;
213                         }
214                         break;
215                 }
216                 break;
217         }
218
219         return hr;
220 }
221
222
223
224 /****************************************************************************/
225
226 typedef struct IEnumMediaTypesImpl
227 {
228         ICOM_VFIELD(IEnumMediaTypes);
229 } IEnumMediaTypesImpl;
230
231 typedef struct
232 {
233         QUARTZ_IUnkImpl unk;
234         IEnumMediaTypesImpl     enummtype;
235         struct QUARTZ_IFEntry   IFEntries[1];
236         CRITICAL_SECTION        cs;
237         AM_MEDIA_TYPE*  pTypes;
238         ULONG   cTypes;
239         ULONG   cCur;
240 } CEnumMediaTypes;
241
242 #define CEnumMediaTypes_THIS(iface,member)              CEnumMediaTypes*        This = ((CEnumMediaTypes*)(((char*)iface)-offsetof(CEnumMediaTypes,member)))
243
244
245
246 static HRESULT WINAPI
247 IEnumMediaTypes_fnQueryInterface(IEnumMediaTypes* iface,REFIID riid,void** ppobj)
248 {
249         CEnumMediaTypes_THIS(iface,enummtype);
250
251         TRACE("(%p)->()\n",This);
252
253         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
254 }
255
256 static ULONG WINAPI
257 IEnumMediaTypes_fnAddRef(IEnumMediaTypes* iface)
258 {
259         CEnumMediaTypes_THIS(iface,enummtype);
260
261         TRACE("(%p)->()\n",This);
262
263         return IUnknown_AddRef(This->unk.punkControl);
264 }
265
266 static ULONG WINAPI
267 IEnumMediaTypes_fnRelease(IEnumMediaTypes* iface)
268 {
269         CEnumMediaTypes_THIS(iface,enummtype);
270
271         TRACE("(%p)->()\n",This);
272
273         return IUnknown_Release(This->unk.punkControl);
274 }
275
276 static HRESULT WINAPI
277 IEnumMediaTypes_fnNext(IEnumMediaTypes* iface,ULONG cReq,AM_MEDIA_TYPE** ppmtype,ULONG* pcFetched)
278 {
279         CEnumMediaTypes_THIS(iface,enummtype);
280         HRESULT hr;
281         ULONG   cFetched;
282
283         TRACE("(%p)->(%lu,%p,%p)\n",This,cReq,ppmtype,pcFetched);
284
285         if ( pcFetched == NULL && cReq > 1 )
286                 return E_INVALIDARG;
287         if ( ppmtype == NULL )
288                 return E_POINTER;
289
290         EnterCriticalSection( &This->cs );
291
292         hr = NOERROR;
293         cFetched = 0;
294         while ( cReq > 0 )
295         {
296                 if ( This->cCur >= This->cTypes )
297                 {
298                         hr = S_FALSE;
299                         break;
300                 }
301                 ppmtype[ cFetched ] =
302                         QUARTZ_MediaType_Duplicate( &This->pTypes[ This->cCur ] );
303                 if ( ppmtype[ cFetched ] == NULL )
304                 {
305                         hr = E_OUTOFMEMORY;
306                         while ( cFetched > 0 )
307                         {
308                                 cFetched --;
309                                 QUARTZ_MediaType_Destroy( ppmtype[ cFetched ] );
310                         }
311                         break;
312                 }
313
314                 cFetched ++;
315
316                 This->cCur ++;
317                 cReq --;
318         }
319
320         LeaveCriticalSection( &This->cs );
321
322         if ( pcFetched != NULL )
323                 *pcFetched = cFetched;
324
325         return hr;
326 }
327
328 static HRESULT WINAPI
329 IEnumMediaTypes_fnSkip(IEnumMediaTypes* iface,ULONG cSkip)
330 {
331         CEnumMediaTypes_THIS(iface,enummtype);
332         HRESULT hr;
333
334         TRACE("(%p)->()\n",This);
335
336         EnterCriticalSection( &This->cs );
337
338         hr = NOERROR;
339         while ( cSkip > 0 )
340         {
341                 if ( This->cCur >= This->cTypes )
342                 {
343                         hr = S_FALSE;
344                         break;
345                 }
346                 This->cCur ++;
347                 cSkip --;
348         }
349
350         LeaveCriticalSection( &This->cs );
351
352         return hr;
353 }
354
355 static HRESULT WINAPI
356 IEnumMediaTypes_fnReset(IEnumMediaTypes* iface)
357 {
358         CEnumMediaTypes_THIS(iface,enummtype);
359
360         TRACE("(%p)->()\n",This);
361
362         EnterCriticalSection( &This->cs );
363
364         This->cCur = 0;
365
366         LeaveCriticalSection( &This->cs );
367
368         return NOERROR;
369 }
370
371 static HRESULT WINAPI
372 IEnumMediaTypes_fnClone(IEnumMediaTypes* iface,IEnumMediaTypes** ppobj)
373 {
374         CEnumMediaTypes_THIS(iface,enummtype);
375         HRESULT hr;
376
377         TRACE("(%p)->()\n",This);
378
379         if ( ppobj == NULL )
380                 return E_POINTER;
381
382         EnterCriticalSection( &This->cs );
383
384         hr = QUARTZ_CreateEnumMediaTypes(
385                 ppobj,
386                 This->pTypes, This->cTypes );
387         if ( SUCCEEDED(hr) )
388                 IEnumMediaTypes_Skip( *ppobj, This->cCur );
389
390         LeaveCriticalSection( &This->cs );
391
392         return hr;
393 }
394
395
396 static ICOM_VTABLE(IEnumMediaTypes) ienummtype =
397 {
398         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
399         /* IUnknown fields */
400         IEnumMediaTypes_fnQueryInterface,
401         IEnumMediaTypes_fnAddRef,
402         IEnumMediaTypes_fnRelease,
403         /* IEnumMediaTypes fields */
404         IEnumMediaTypes_fnNext,
405         IEnumMediaTypes_fnSkip,
406         IEnumMediaTypes_fnReset,
407         IEnumMediaTypes_fnClone,
408 };
409
410
411 /* can I use offsetof safely? - FIXME? */
412 static QUARTZ_IFEntry IFEntries[] =
413 {
414   { &IID_IEnumMediaTypes, offsetof(CEnumMediaTypes,enummtype)-offsetof(CEnumMediaTypes,unk) },
415 };
416
417
418 void QUARTZ_DestroyEnumMediaTypes(IUnknown* punk)
419 {
420         CEnumMediaTypes_THIS(punk,unk);
421         ULONG   i;
422
423         if ( This->pTypes != NULL )
424         {
425                 for ( i = 0; i < This->cTypes; i++ )
426                         QUARTZ_MediaType_Free( &This->pTypes[i] );
427                 QUARTZ_FreeMem( This->pTypes );
428         }
429
430         DeleteCriticalSection( &This->cs );
431 }
432
433 HRESULT QUARTZ_CreateEnumMediaTypes(
434         IEnumMediaTypes** ppobj,
435         const AM_MEDIA_TYPE* pTypes, ULONG cTypes )
436 {
437         CEnumMediaTypes*        penum;
438         AM_MEDIA_TYPE*  pTypesDup = NULL;
439         ULONG   i;
440         HRESULT hr;
441
442         TRACE("(%p,%p,%lu)\n",ppobj,pTypes,cTypes);
443
444         if ( cTypes > 0 )
445         {
446                 pTypesDup = (AM_MEDIA_TYPE*)QUARTZ_AllocMem(
447                         sizeof( AM_MEDIA_TYPE ) * cTypes );
448                 if ( pTypesDup == NULL )
449                         return E_OUTOFMEMORY;
450
451                 i = 0;
452                 while ( i < cTypes )
453                 {
454                         hr = QUARTZ_MediaType_Copy( &pTypesDup[i], &pTypes[i] );
455                         if ( FAILED(hr) )
456                         {
457                                 while ( i > 0 )
458                                 {
459                                         i --;
460                                         QUARTZ_MediaType_Free( &pTypesDup[i] );
461                                 }
462                                 QUARTZ_FreeMem( pTypesDup );
463                                 return hr;
464                         }
465
466                         i ++;
467                 }
468         }
469
470         penum = (CEnumMediaTypes*)QUARTZ_AllocObj( sizeof(CEnumMediaTypes) );
471         if ( penum == NULL )
472         {
473                 return E_OUTOFMEMORY;
474         }
475         penum->pTypes = pTypesDup;
476         penum->cTypes = cTypes;
477         penum->cCur = 0;
478
479         QUARTZ_IUnkInit( &penum->unk, NULL );
480         ICOM_VTBL(&penum->enummtype) = &ienummtype;
481
482         penum->unk.pEntries = IFEntries;
483         penum->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
484         penum->unk.pOnFinalRelease = QUARTZ_DestroyEnumMediaTypes;
485
486         InitializeCriticalSection( &penum->cs );
487
488         *ppobj = (IEnumMediaTypes*)(&penum->enummtype);
489
490         return S_OK;
491 }
492
493