Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / quartz / mjpgdec.c
1 /*
2  * Implements AVI MJPG Decompressor.
3  *
4  *      FIXME - stub
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23
24 #include "config.h"
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "vfw.h"
32 #include "strmif.h"
33 #include "control.h"
34 #include "amvideo.h"
35 #include "vfwmsgs.h"
36 #include "uuids.h"
37
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
40
41 #include "quartz_private.h"
42 #include "xform.h"
43 #include "ijgdec.h"
44
45 static const WCHAR MJPGDec_FilterName[] =
46 {'M','J','P','G',' ','D','e','c','o','m','p','r','e','s','s','o','r',0};
47
48 typedef struct CMJPGDecImpl
49 {
50         AM_MEDIA_TYPE*  m_pmtConv;
51         DWORD   m_cConv;
52         BITMAPINFOHEADER        m_biOut;
53 } CMJPGDecImpl;
54
55 static const BYTE jpeg_standard_dht_data[0x1f+0xb5+0x1f+0xb5+2*4] =
56 {
57          0xff, 0xc4, 0x00, 0x1f, 0x00,
58          0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
59          0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
61          0x08, 0x09, 0x0a, 0x0b,
62
63          0xff, 0xc4, 0x00, 0xb5, 0x10,
64          0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
65          0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
66          0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
67          0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
68          0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
69          0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
70          0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
71          0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
72          0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
73          0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
74          0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
75          0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
76          0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
77          0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
78          0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
79          0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
80          0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
81          0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
82          0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
83          0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
84          0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
85          0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
86          0xf9, 0xfa,
87
88          0xff, 0xc4, 0x00, 0x1f, 0x01,
89          0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
90          0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
91          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
92          0x08, 0x09, 0x0a, 0x0b,
93
94          0xff, 0xc4, 0x00, 0xb5, 0x11,
95          0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
96          0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
97          0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
98          0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
99          0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
100          0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
101          0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
102          0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
103          0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
104          0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
105          0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
106          0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
107          0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
108          0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
109          0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
110          0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
111          0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
112          0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
113          0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
114          0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
115          0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
116          0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
117          0xf9, 0xfa,
118 };
119
120 /***************************************************************************
121  *
122  *      CMJPGDecImpl methods
123  *
124  */
125
126 static void MJPGDec_FreeOutTypes(CMJPGDecImpl* This)
127 {
128         DWORD   i;
129
130         if ( This->m_pmtConv == NULL )
131                 return;
132
133         TRACE("cConv = %lu\n",This->m_cConv);
134         for ( i = 0; i < This->m_cConv; i++ )
135         {
136                 QUARTZ_MediaType_Free(&This->m_pmtConv[i]);
137         }
138         QUARTZ_FreeMem(This->m_pmtConv);
139         This->m_pmtConv = NULL;
140         This->m_cConv = 0;
141 }
142
143
144 static HRESULT MJPGDec_Init( CTransformBaseImpl* pImpl )
145 {
146         CMJPGDecImpl*   This = pImpl->m_pUserData;
147
148         if ( This != NULL )
149                 return NOERROR;
150
151         This = (CMJPGDecImpl*)QUARTZ_AllocMem( sizeof(CMJPGDecImpl) );
152         if ( This == NULL )
153                 return E_OUTOFMEMORY;
154         ZeroMemory( This, sizeof(CMJPGDecImpl) );
155         pImpl->m_pUserData = This;
156         /* construct */
157         This->m_pmtConv = NULL;
158         This->m_cConv = 0;
159
160         return NOERROR;
161 }
162
163 static HRESULT MJPGDec_Cleanup( CTransformBaseImpl* pImpl )
164 {
165         CMJPGDecImpl*   This = pImpl->m_pUserData;
166
167         if ( This == NULL )
168                 return NOERROR;
169         /* destruct */
170         MJPGDec_FreeOutTypes(This);
171
172         QUARTZ_FreeMem( This );
173         pImpl->m_pUserData = NULL;
174
175         return NOERROR;
176 }
177
178 static HRESULT MJPGDec_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
179 {
180         CMJPGDecImpl*   This = pImpl->m_pUserData;
181         const BITMAPINFOHEADER* pbiIn = NULL;
182         const BITMAPINFOHEADER* pbiOut = NULL;
183
184         TRACE("(%p)\n",This);
185
186         if ( This == NULL )
187                 return E_UNEXPECTED;
188
189         if ( !IsEqualGUID( &pmtIn->majortype, &MEDIATYPE_Video ) )
190                 return E_FAIL;
191         if ( !IsEqualGUID( &pmtIn->formattype, &FORMAT_VideoInfo ) )
192                 return E_FAIL;
193         pbiIn = (&((const VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
194         if ( pbiIn->biCompression != mmioFOURCC('M','J','P','G') &&
195                  pbiIn->biCompression != mmioFOURCC('m','j','p','g') )
196                 return E_FAIL;
197         if ( pbiIn->biBitCount != 24 )
198                 return E_FAIL;
199
200         if ( pmtOut != NULL )
201         {
202                 if ( !IsEqualGUID( &pmtOut->majortype, &MEDIATYPE_Video ) )
203                         return E_FAIL;
204                 if ( !IsEqualGUID( &pmtOut->formattype, &FORMAT_VideoInfo ) )
205                         return E_FAIL;
206                 if ( !IsEqualGUID( &pmtOut->subtype, &MEDIASUBTYPE_RGB24 ) )
207                         return E_FAIL;
208                 pbiOut = (&((const VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
209                 if ( pbiOut->biCompression != 0 )
210                         return E_FAIL;
211                 if ( pbiIn->biWidth != pbiOut->biWidth ||
212                          pbiIn->biHeight != pbiOut->biHeight ||
213                          pbiIn->biPlanes != 1 || pbiOut->biPlanes != 1 ||
214                          pbiOut->biBitCount != pbiIn->biBitCount )
215                         return E_FAIL;
216         }
217
218         return S_OK;
219 }
220
221 static HRESULT MJPGDec_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
222 {
223         CMJPGDecImpl*   This = pImpl->m_pUserData;
224         HRESULT hr;
225         DWORD dwIndex;
226         const BITMAPINFOHEADER* pbiIn = NULL;
227         BITMAPINFOHEADER*       pbiOut = NULL;
228
229         TRACE("(%p)\n",This);
230
231         if ( This == NULL )
232                 return E_UNEXPECTED;
233
234         hr = MJPGDec_CheckMediaType( pImpl, pmtIn, NULL );
235         if ( FAILED(hr) )
236                 return hr;
237         pbiIn = (&((const VIDEOINFOHEADER*)pmtIn->pbFormat)->bmiHeader);
238
239         MJPGDec_FreeOutTypes(This);
240
241         This->m_cConv = 1;
242         This->m_pmtConv = (AM_MEDIA_TYPE*)QUARTZ_AllocMem( sizeof(AM_MEDIA_TYPE) );
243         if ( This->m_pmtConv == NULL )
244                 return E_OUTOFMEMORY;
245         ZeroMemory( This->m_pmtConv, sizeof(AM_MEDIA_TYPE) * 1 );
246
247         dwIndex = 0;
248
249         memcpy( &This->m_pmtConv[dwIndex].majortype, &MEDIATYPE_Video, sizeof(GUID) );
250         memcpy( &This->m_pmtConv[dwIndex].subtype, &MEDIASUBTYPE_RGB24, sizeof(GUID) );
251         This->m_pmtConv[dwIndex].bFixedSizeSamples = 1;
252         This->m_pmtConv[dwIndex].bTemporalCompression = 0;
253         This->m_pmtConv[dwIndex].lSampleSize = DIBSIZE(*pbiIn);
254         memcpy( &This->m_pmtConv[dwIndex].formattype, &FORMAT_VideoInfo, sizeof(GUID) );
255         This->m_pmtConv[dwIndex].cbFormat = sizeof(VIDEOINFO);
256         This->m_pmtConv[dwIndex].pbFormat = (BYTE*)CoTaskMemAlloc( This->m_pmtConv[dwIndex].cbFormat );
257         if ( This->m_pmtConv[dwIndex].pbFormat == NULL )
258                 return E_OUTOFMEMORY;
259         ZeroMemory( This->m_pmtConv[dwIndex].pbFormat, This->m_pmtConv[dwIndex].cbFormat );
260         pbiOut = &(((VIDEOINFOHEADER*)(This->m_pmtConv[dwIndex].pbFormat))->bmiHeader);
261         pbiOut->biSize = sizeof(BITMAPINFOHEADER);
262         pbiOut->biWidth = pbiIn->biWidth;
263         pbiOut->biHeight = pbiIn->biHeight;
264         pbiOut->biPlanes = 1;
265         pbiOut->biBitCount = pbiIn->biBitCount;
266
267         *ppmtAcceptTypes = This->m_pmtConv;
268         *pcAcceptTypes = This->m_cConv;
269
270         return S_OK;
271 }
272
273 static HRESULT MJPGDec_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
274 {
275         CMJPGDecImpl*   This = pImpl->m_pUserData;
276         HRESULT hr;
277         const BITMAPINFOHEADER* pbiOut = NULL;
278
279         TRACE("(%p)\n",This);
280
281         if ( This == NULL )
282                 return E_UNEXPECTED;
283
284         hr = MJPGDec_CheckMediaType( pImpl, pmtIn, NULL );
285         if ( FAILED(hr) )
286                 return hr;
287         pbiOut = (&((const VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
288
289         pProp->cBuffers = 1;
290         pProp->cbBuffer = DIBSIZE(*pbiOut);
291
292         return S_OK;
293 }
294
295 static HRESULT MJPGDec_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
296 {
297         CMJPGDecImpl*   This = pImpl->m_pUserData;
298         HRESULT hr;
299         const BITMAPINFOHEADER* pbiOut = NULL;
300
301         TRACE("(%p)\n",This);
302
303         if ( This == NULL )
304                 return E_UNEXPECTED;
305
306         hr = MJPGDec_CheckMediaType( pImpl, pmtIn, NULL );
307         if ( FAILED(hr) )
308                 return hr;
309
310         ZeroMemory( &This->m_biOut, sizeof(BITMAPINFOHEADER) );
311
312         pbiOut = (&((const VIDEOINFOHEADER*)pmtOut->pbFormat)->bmiHeader);
313         memcpy( &This->m_biOut, pbiOut, sizeof(BITMAPINFOHEADER) );
314
315         return S_OK;
316 }
317
318 static HRESULT MJPGDec_Transform( CTransformBaseImpl* pImpl, IMediaSample* pSampIn, IMediaSample* pSampOut )
319 {
320         CMJPGDecImpl*   This = pImpl->m_pUserData;
321         BYTE*   pDataIn = NULL;
322         BYTE*   pDataOut = NULL;
323         LONG    lDataInLen;
324         LONG    outpitch;
325         HRESULT hr;
326         const char*     psrcs[3];
327         int     lenofsrcs[3];
328
329         TRACE("(%p)\n",This);
330
331         if ( This == NULL )
332                 return E_UNEXPECTED;
333
334         hr = IMediaSample_GetPointer( pSampIn, &pDataIn );
335         if ( FAILED(hr) )
336                 return hr;
337         lDataInLen = IMediaSample_GetActualDataLength( pSampIn );
338         if ( lDataInLen < 4 )
339                 return E_FAIL;
340         hr = IMediaSample_GetPointer( pSampOut, &pDataOut );
341         if ( FAILED(hr) )
342                 return hr;
343         IMediaSample_SetActualDataLength( pSampOut, DIBSIZE(This->m_biOut) );
344
345         if ( pDataIn[0] != 0xff || pDataIn[1] != 0xd8 )
346                 return E_FAIL;
347
348         psrcs[0] = (const char*)&pDataIn[0];
349         psrcs[1] = (const char*)jpeg_standard_dht_data;
350         psrcs[2] = (const char*)&pDataIn[2];
351         lenofsrcs[0] = 2;
352         lenofsrcs[1] = sizeof(jpeg_standard_dht_data);
353         lenofsrcs[2] = lDataInLen - 2;
354
355         outpitch = DIBWIDTHBYTES(This->m_biOut);
356         if ( 0 > IJGDEC_Decode(
357                 pDataOut + (This->m_biOut.biHeight-1) * outpitch, - outpitch,
358                 This->m_biOut.biWidth, This->m_biOut.biHeight,
359                 This->m_biOut.biBitCount,
360                 &psrcs[0], &lenofsrcs[0], 3 ) )
361         {
362                 return E_FAIL;
363         }
364
365         return S_OK;
366 }
367
368 static HRESULT MJPGDec_EndTransform( CTransformBaseImpl* pImpl )
369 {
370         CMJPGDecImpl*   This = pImpl->m_pUserData;
371
372         TRACE("(%p)\n",This);
373
374         if ( This == NULL )
375                 return E_UNEXPECTED;
376
377         ZeroMemory( &This->m_biOut, sizeof(BITMAPINFOHEADER) );
378
379         return S_OK;
380 }
381
382
383 static const TransformBaseHandlers transhandlers =
384 {
385         MJPGDec_Init,
386         MJPGDec_Cleanup,
387         MJPGDec_CheckMediaType,
388         MJPGDec_GetOutputTypes,
389         MJPGDec_GetAllocProp,
390         MJPGDec_BeginTransform,
391         NULL,
392         MJPGDec_Transform,
393         MJPGDec_EndTransform,
394 };
395
396 HRESULT QUARTZ_CreateMJPGDecompressor(IUnknown* punkOuter,void** ppobj)
397 {
398         return QUARTZ_CreateTransformBase(
399                 punkOuter,ppobj,
400                 &CLSID_quartzMJPGDecompressor,
401                 MJPGDec_FilterName,
402                 NULL, NULL,
403                 &transhandlers );
404 }
405
406