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