Added LGPL standard comment, and copyright notices where necessary.
[wine] / dlls / quartz / csconv.c
1 /*
2  * Implements Color Space Converter(CLSID_Colour).
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
22 #include "config.h"
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "vfw.h"
30 #include "strmif.h"
31 #include "control.h"
32 #include "amvideo.h"
33 #include "vfwmsgs.h"
34 #include "uuids.h"
35
36 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38
39 #include "quartz_private.h"
40 #include "xform.h"
41 #include "videoblt.h"
42
43 static const WCHAR ColorConv_FilterName[] =
44 {'C','o','l','o','r',' ','S','p','a','c','e',' ','C','o','n','v','e','r','t','e','r',0};
45
46 struct BltHandler
47 {
48         const GUID*     psubtypeIn;
49         const GUID*     psubtypeOut;
50         pVIDEOBLT_Blt   pBlt;
51 };
52
53 static const struct BltHandler conv_handlers[] =
54 {
55         { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB32, VIDEOBLT_Blt_888_to_8888 },
56         { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB565, VIDEOBLT_Blt_888_to_565 },
57         { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB555, VIDEOBLT_Blt_888_to_555 },
58         { &MEDIASUBTYPE_RGB24, &MEDIASUBTYPE_RGB8, VIDEOBLT_Blt_888_to_332 },
59         { NULL, NULL, NULL },
60 };
61
62 typedef struct CColorConvImpl
63 {
64         pVIDEOBLT_Blt   m_pBlt;
65         AM_MEDIA_TYPE*  m_pmtConv;
66         DWORD   m_cConv;
67         LONG    pitchIn;
68         LONG    pitchOut;
69 } CColorConvImpl;
70
71 /***************************************************************************
72  *
73  *      CColorConvImpl methods
74  *
75  */
76
77 static void ColorConv_FreeOutTypes(CColorConvImpl* This)
78 {
79         DWORD   i;
80
81         if ( This->m_pmtConv == NULL )
82                 return;
83
84         TRACE("cConv = %lu\n",This->m_cConv);
85         for ( i = 0; i < This->m_cConv; i++ )
86         {
87                 QUARTZ_MediaType_Free(&This->m_pmtConv[i]);
88         }
89         QUARTZ_FreeMem(This->m_pmtConv);
90         This->m_pmtConv = NULL;
91         This->m_cConv = 0;
92 }
93
94 static HRESULT ColorConv_FillBitmapInfo( BITMAPINFO* pbiOut, LONG biWidth, LONG biHeight, const GUID* psubtype )
95 {
96         int i;
97         DWORD* pdwBitf;
98         HRESULT hr = E_FAIL;
99
100         pbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
101         pbiOut->bmiHeader.biWidth = biWidth;
102         pbiOut->bmiHeader.biHeight = biHeight;
103         pbiOut->bmiHeader.biPlanes = 1;
104
105         if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB8 ) )
106         {
107                 pbiOut->bmiHeader.biBitCount = 8;
108                 for ( i = 0; i < 256; i++ )
109                 {
110                         pbiOut->bmiColors[i].rgbRed = ((i>>5)&7)*255/7;
111                         pbiOut->bmiColors[i].rgbGreen = ((i>>2)&7)*255/7;
112                         pbiOut->bmiColors[i].rgbBlue = (i&3)*255/3;
113                 }
114                 hr = S_OK;
115         }
116         if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB555 ) )
117         {
118                 pbiOut->bmiHeader.biBitCount = 16;
119                 hr = S_OK;
120         }
121         if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB565 ) )
122         {
123                 pbiOut->bmiHeader.biBitCount = 16;
124                 pbiOut->bmiHeader.biCompression = 3;
125                 pdwBitf = (DWORD*)(&pbiOut->bmiColors[0]);
126                 pdwBitf[0] = 0xf800;
127                 pdwBitf[1] = 0x07e0;
128                 pdwBitf[2] = 0x001f;
129                 hr = S_OK;
130         }
131         if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB24 ) )
132         {
133                 pbiOut->bmiHeader.biBitCount = 24;
134                 hr = S_OK;
135         }
136         if ( IsEqualGUID( psubtype, &MEDIASUBTYPE_RGB32 ) )
137         {
138                 pbiOut->bmiHeader.biBitCount = 32;
139                 hr = S_OK;
140         }
141
142         pbiOut->bmiHeader.biSizeImage = DIBSIZE(pbiOut->bmiHeader);
143
144         return hr;
145 }
146
147
148 static HRESULT ColorConv_Init( CTransformBaseImpl* pImpl )
149 {
150         CColorConvImpl* This = pImpl->m_pUserData;
151
152         if ( This != NULL )
153                 return NOERROR;
154
155         This = (CColorConvImpl*)QUARTZ_AllocMem( sizeof(CColorConvImpl) );
156         if ( This == NULL )
157                 return E_OUTOFMEMORY;
158         ZeroMemory( This, sizeof(CColorConvImpl) );
159         pImpl->m_pUserData = This;
160         /* construct */
161         This->m_pBlt = NULL;
162         This->m_pmtConv = NULL;
163         This->m_cConv = 0;
164
165         return NOERROR;
166 }
167
168 static HRESULT ColorConv_Cleanup( CTransformBaseImpl* pImpl )
169 {
170         CColorConvImpl* This = pImpl->m_pUserData;
171
172         if ( This == NULL )
173                 return NOERROR;
174         /* destruct */
175         ColorConv_FreeOutTypes(This);
176
177         QUARTZ_FreeMem( This );
178         pImpl->m_pUserData = NULL;
179
180         return NOERROR;
181 }
182
183 static HRESULT ColorConv_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
184 {
185         CColorConvImpl* This = pImpl->m_pUserData;
186         BITMAPINFOHEADER*       pbiIn = NULL;
187         BITMAPINFOHEADER*       pbiOut = NULL;
188         HRESULT hr;
189         GUID stIn, stOut;
190         const struct BltHandler*        phandler;
191
192         TRACE("(%p)\n",This);
193
194         if ( This == NULL )
195                 return E_UNEXPECTED;
196
197         if ( !IsEqualGUID( &pmtIn->majortype, &MEDIATYPE_Video ) )
198                 return E_FAIL;
199         if ( !IsEqualGUID( &pmtIn->formattype, &FORMAT_VideoInfo ) )
200                 return E_FAIL;
201         pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
202         if ( pbiIn->biCompression != 0 &&
203                  pbiIn->biCompression != 3 )
204                 return E_FAIL;
205
206         hr = QUARTZ_MediaSubType_FromBitmap( &stIn, pbiIn );
207         if ( hr != S_OK || !IsEqualGUID( &pmtIn->subtype, &stIn ) )
208                 return E_FAIL;
209
210         if ( pmtOut != NULL )
211         {
212                 if ( !IsEqualGUID( &pmtOut->majortype, &MEDIATYPE_Video ) )
213                         return E_FAIL;
214                 if ( !IsEqualGUID( &pmtOut->formattype, &FORMAT_VideoInfo ) )
215                         return E_FAIL;
216                 pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
217                 if ( pbiOut->biCompression != 0 &&
218                          pbiOut->biCompression != 3 )
219                         return E_FAIL;
220                 hr = QUARTZ_MediaSubType_FromBitmap( &stOut, pbiOut );
221                 if ( hr != S_OK || !IsEqualGUID( &pmtOut->subtype, &stOut ) )
222                         return E_FAIL;
223                 if ( pbiIn->biWidth != pbiOut->biWidth ||
224                          pbiIn->biHeight != pbiOut->biHeight ||
225                          pbiIn->biPlanes != 1 || pbiOut->biPlanes != 1 )
226                         return E_FAIL;
227         }
228
229         phandler = conv_handlers;
230         while ( phandler->psubtypeIn != NULL )
231         {
232                 if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) )
233                 {
234                         if ( pmtOut == NULL )
235                                 return S_OK;
236                         if ( IsEqualGUID( &pmtOut->subtype, phandler->psubtypeOut ) )
237                                 return S_OK;
238                 }
239                 phandler ++;
240         }
241
242         return E_FAIL;
243 }
244
245 static HRESULT ColorConv_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
246 {
247         CColorConvImpl* This = pImpl->m_pUserData;
248         HRESULT hr;
249         const struct BltHandler*        phandler;
250         DWORD   cConv;
251         BITMAPINFOHEADER*       pbiIn = NULL;
252         BITMAPINFOHEADER*       pbiOut = NULL;
253
254         TRACE("(%p)\n",This);
255
256         if ( This == NULL )
257                 return E_UNEXPECTED;
258
259         hr = ColorConv_CheckMediaType( pImpl, pmtIn, NULL );
260         if ( FAILED(hr) )
261                 return hr;
262         pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
263
264         ColorConv_FreeOutTypes(This);
265
266         cConv = 0;
267         phandler = conv_handlers;
268         while ( phandler->psubtypeIn != NULL )
269         {
270                 if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) )
271                         cConv ++;
272                 phandler ++;
273         }
274
275         This->m_cConv = cConv;
276         This->m_pmtConv = (AM_MEDIA_TYPE*)QUARTZ_AllocMem(
277                 sizeof(AM_MEDIA_TYPE) * cConv );
278         if ( This->m_pmtConv == NULL )
279                 return E_OUTOFMEMORY;
280         ZeroMemory( This->m_pmtConv, sizeof(AM_MEDIA_TYPE) * cConv );
281
282         cConv = 0;
283         phandler = conv_handlers;
284         while ( phandler->psubtypeIn != NULL )
285         {
286                 if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) )
287                 {
288                         memcpy( &This->m_pmtConv[cConv].majortype, &MEDIATYPE_Video, sizeof(GUID) );
289                         memcpy( &This->m_pmtConv[cConv].subtype, phandler->psubtypeOut, sizeof(GUID) );
290                         This->m_pmtConv[cConv].bFixedSizeSamples = 1;
291                         This->m_pmtConv[cConv].bTemporalCompression = 0;
292                         This->m_pmtConv[cConv].lSampleSize = DIBSIZE(*pbiIn);
293                         memcpy( &This->m_pmtConv[cConv].formattype, &FORMAT_VideoInfo, sizeof(GUID) );
294                         This->m_pmtConv[cConv].cbFormat = sizeof(VIDEOINFO);
295                         This->m_pmtConv[cConv].pbFormat = (BYTE*)CoTaskMemAlloc( This->m_pmtConv[cConv].cbFormat );
296                         if ( This->m_pmtConv[cConv].pbFormat == NULL )
297                                 return E_OUTOFMEMORY;
298                         ZeroMemory( This->m_pmtConv[cConv].pbFormat, This->m_pmtConv[cConv].cbFormat );
299                         pbiOut = &(((VIDEOINFOHEADER*)(This->m_pmtConv[cConv].pbFormat))->bmiHeader);
300                         hr = ColorConv_FillBitmapInfo( (BITMAPINFO*)pbiOut, pbiIn->biWidth, pbiIn->biHeight, phandler->psubtypeOut );
301                         if ( FAILED(hr) )
302                                 return hr;
303
304                         cConv ++;
305                 }
306                 phandler ++;
307         }
308
309         *ppmtAcceptTypes = This->m_pmtConv;
310         *pcAcceptTypes = This->m_cConv;
311
312         return NOERROR;
313 }
314
315 static HRESULT ColorConv_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
316 {
317         CColorConvImpl* This = pImpl->m_pUserData;
318         HRESULT hr;
319         BITMAPINFOHEADER*       pbiOut = NULL;
320
321         TRACE("(%p)\n",This);
322
323         if ( This == NULL )
324                 return E_UNEXPECTED;
325
326         hr = ColorConv_CheckMediaType( pImpl, pmtIn, pmtOut );
327         if ( FAILED(hr) )
328                 return hr;
329
330         pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
331
332         pProp->cBuffers = 1;
333         pProp->cbBuffer = DIBSIZE(*pbiOut);
334         TRACE("%ldx%ldx%u cbBuffer = %ld\n",pbiOut->biWidth,pbiOut->biHeight,(unsigned)pbiOut->biBitCount,pProp->cbBuffer);
335
336         return NOERROR;
337 }
338
339 static HRESULT ColorConv_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
340 {
341         CColorConvImpl* This = pImpl->m_pUserData;
342         HRESULT hr;
343         BITMAPINFOHEADER*       pbiIn = NULL;
344         BITMAPINFOHEADER*       pbiOut = NULL;
345         const struct BltHandler*        phandler;
346
347         TRACE("(%p)\n",This);
348
349         if ( This == NULL )
350                 return E_UNEXPECTED;
351
352         hr = ColorConv_CheckMediaType( pImpl, pmtIn, pmtOut );
353         if ( FAILED(hr) )
354                 return hr;
355
356         pbiIn = (&((VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
357         pbiOut = (&((VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
358
359         This->pitchIn = DIBWIDTHBYTES(*pbiIn);
360         This->pitchOut = DIBWIDTHBYTES(*pbiOut);
361
362         This->m_pBlt = NULL;
363         phandler = conv_handlers;
364         while ( phandler->psubtypeIn != NULL )
365         {
366                 if ( IsEqualGUID( &pmtIn->subtype, phandler->psubtypeIn ) )
367                 {
368                         if ( IsEqualGUID( &pmtOut->subtype, phandler->psubtypeOut ) )
369                         {
370                                 This->m_pBlt = phandler->pBlt;
371                                 return S_OK;
372                         }
373                 }
374                 phandler ++;
375         }
376
377         return E_FAIL;
378 }
379
380 static HRESULT ColorConv_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut )
381 {
382         CColorConvImpl* This = pImpl->m_pUserData;
383         BYTE*   pDataIn = NULL;
384         BYTE*   pDataOut = NULL;
385         BITMAPINFO*     pbiIn;
386         BITMAPINFO*     pbiOut;
387         HRESULT hr;
388
389         if ( This == NULL )
390                 return E_UNEXPECTED;
391
392         hr = IMediaSample_GetPointer( pSampIn, &pDataIn );
393         if ( FAILED(hr) )
394                 return hr;
395         hr = IMediaSample_GetPointer( pSampOut, &pDataOut );
396         if ( FAILED(hr) )
397                 return hr;
398
399         if ( This->m_pBlt != NULL )
400         {
401                 pbiIn = (BITMAPINFO*)&(((VIDEOINFOHEADER*)pImpl->pInPin->pin.pmtConn->pbFormat)->bmiHeader);
402                 pbiOut = (BITMAPINFO*)&(((VIDEOINFOHEADER*)pImpl->pOutPin->pin.pmtConn->pbFormat)->bmiHeader);
403                 This->m_pBlt(
404                         pDataOut, This->pitchOut,
405                         pDataIn, This->pitchIn,
406                         pbiIn->bmiHeader.biWidth,
407                         abs(pbiIn->bmiHeader.biHeight),
408                         &pbiIn->bmiColors[0], pbiIn->bmiHeader.biClrUsed );
409                 hr = IMediaSample_SetActualDataLength(pSampOut,DIBSIZE(pbiOut->bmiHeader));
410                 if ( FAILED(hr) )
411                         return hr;
412         }
413
414         return NOERROR;
415 }
416
417 static HRESULT ColorConv_EndTransform( CTransformBaseImpl* pImpl )
418 {
419         CColorConvImpl* This = pImpl->m_pUserData;
420
421         if ( This == NULL )
422                 return E_UNEXPECTED;
423
424         This->m_pBlt = NULL;
425
426         return NOERROR;
427 }
428
429
430 static const TransformBaseHandlers transhandlers =
431 {
432         ColorConv_Init,
433         ColorConv_Cleanup,
434         ColorConv_CheckMediaType,
435         ColorConv_GetOutputTypes,
436         ColorConv_GetAllocProp,
437         ColorConv_BeginTransform,
438         ColorConv_Transform,
439         ColorConv_EndTransform,
440 };
441
442 HRESULT QUARTZ_CreateColour(IUnknown* punkOuter,void** ppobj)
443 {
444         return QUARTZ_CreateTransformBase(
445                 punkOuter,ppobj,
446                 &CLSID_Colour,
447                 ColorConv_FilterName,
448                 NULL, NULL,
449                 &transhandlers );
450 }
451