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