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