Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / quartz / mpadec.c
1 /*
2  * Implements MPEG Audio Decoder(CLSID_CMpegAudioCodec)
3  *
4  *      FIXME - what library can we use? SMPEG??
5  *
6  *      FIXME - stub
7  *
8  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "mmsystem.h"
33 #include "mmreg.h"
34 #include "strmif.h"
35 #include "control.h"
36 #include "amvideo.h"
37 #include "vfwmsgs.h"
38 #include "uuids.h"
39
40 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
42
43 #include "quartz_private.h"
44 #include "xform.h"
45 #include "mtype.h"
46
47 static const WCHAR CMPEGAudioDecoderImpl_FilterName[] =
48 {'M','P','E','G',' ','A','u','d','i','o',' ','D','e','c','o','d','e','r',0};
49
50
51 typedef struct CMPEGAudioDecoderImpl
52 {
53         AM_MEDIA_TYPE*  pmt;
54         DWORD           cmt;
55         WAVEFORMATEX    wfxOut;
56
57         /* codec stuffs */
58
59 } CMPEGAudioDecoderImpl;
60
61
62 /*****************************************************************************
63  *
64  *      codec-dependent stuffs  - no codec
65  *
66  */
67
68 #define NO_CODEC_IMPL
69
70 static void Codec_OnConstruct(CMPEGAudioDecoderImpl* This)
71 {
72 }
73
74 static void Codec_OnCleanup(CMPEGAudioDecoderImpl* This)
75 {
76 }
77
78 static HRESULT Codec_BeginTransform(CTransformBaseImpl* pImpl,CMPEGAudioDecoderImpl* This)
79 {
80         FIXME("no codec\n");
81         return E_NOTIMPL;
82 }
83
84 static HRESULT Codec_ProcessReceive(CTransformBaseImpl* pImpl,CMPEGAudioDecoderImpl* This,IMediaSample* pSampIn)
85 {
86         FIXME("no codec\n");
87         return E_NOTIMPL;
88 }
89
90 static HRESULT Codec_EndTransform(CTransformBaseImpl* pImpl,CMPEGAudioDecoderImpl* This)
91 {
92         FIXME("no codec\n");
93         return E_NOTIMPL;
94 }
95
96
97
98 /***************************************************************************
99  *
100  *      CMPEGAudioDecoderImpl methods
101  *
102  */
103
104 static void CMPEGAudioDecoderImpl_CleanupOutTypes(CMPEGAudioDecoderImpl* This)
105 {
106         DWORD   i;
107
108         if ( This->pmt != NULL )
109         {
110                 for ( i = 0; i < This->cmt; i++ )
111                 {
112                         QUARTZ_MediaType_Free(&This->pmt[i]);
113                 }
114                 QUARTZ_FreeMem(This->pmt);
115                 This->pmt = NULL;
116         }
117         This->cmt = 0;
118 }
119
120 static HRESULT CMPEGAudioDecoderImpl_Init( CTransformBaseImpl* pImpl )
121 {
122         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
123
124         TRACE("(%p)\n",This);
125
126         if ( This != NULL )
127                 return NOERROR;
128
129         This = (CMPEGAudioDecoderImpl*)QUARTZ_AllocMem( sizeof(CMPEGAudioDecoderImpl) );
130         if ( This == NULL )
131                 return E_OUTOFMEMORY;
132         ZeroMemory( This, sizeof(CMPEGAudioDecoderImpl) );
133         pImpl->m_pUserData = This;
134
135         /* construct */
136         This->pmt = NULL;
137         This->cmt = 0;
138         Codec_OnConstruct(This);
139
140         return S_OK;
141 }
142
143 static HRESULT CMPEGAudioDecoderImpl_Cleanup( CTransformBaseImpl* pImpl )
144 {
145         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
146
147         TRACE("(%p)\n",This);
148
149         if ( This == NULL )
150                 return S_OK;
151
152         /* destruct */
153         Codec_OnCleanup(This);
154         CMPEGAudioDecoderImpl_CleanupOutTypes(This);
155
156         QUARTZ_FreeMem( This );
157         pImpl->m_pUserData = NULL;
158
159         return S_OK;
160 }
161
162 static HRESULT CMPEGAudioDecoderImpl_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut )
163 {
164         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
165         const WAVEFORMATEX* pwfxIn;
166         const WAVEFORMATEX* pwfxOut;
167
168         TRACE("(%p)\n",This);
169         if ( This == NULL )
170                 return E_UNEXPECTED;
171
172         if ( !IsEqualGUID( &pmtIn->majortype, &MEDIATYPE_Audio ) )
173                 return E_FAIL;
174         if ( !IsEqualGUID( &pmtIn->formattype, &FORMAT_WaveFormatEx ) )
175                 return E_FAIL;
176
177         if ( pmtIn->pbFormat == NULL ||
178              pmtIn->cbFormat < sizeof(WAVEFORMATEX) )
179                 return E_FAIL;
180         pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat;
181         if ( pwfxIn->wFormatTag != WAVE_FORMAT_MPEG &&
182              pwfxIn->wFormatTag != WAVE_FORMAT_MPEGLAYER3 )
183                 return E_FAIL;
184         if ( pwfxIn->nChannels != 1 && pwfxIn->nChannels != 2 )
185                 return E_FAIL;
186         if ( pwfxIn->nBlockAlign < 1 )
187                 return E_FAIL;
188
189         if ( pmtOut != NULL )
190         {
191                 if ( !IsEqualGUID( &pmtOut->majortype, &MEDIATYPE_Audio ) )
192                         return E_FAIL;
193                 if ( !IsEqualGUID( &pmtOut->formattype, &FORMAT_WaveFormatEx ) )
194                         return E_FAIL;
195
196                 if ( pmtOut->pbFormat == NULL ||
197                      pmtOut->cbFormat < sizeof(WAVEFORMATEX) )
198                         return E_FAIL;
199                 pwfxOut = (const WAVEFORMATEX*)pmtOut->pbFormat;
200
201                 if ( pwfxOut->wFormatTag != WAVE_FORMAT_PCM )
202                         return E_FAIL;
203                 if ( pwfxOut->nChannels != pwfxIn->nChannels ||
204                      pwfxOut->nSamplesPerSec != pwfxIn->nSamplesPerSec )
205                         return E_FAIL;
206                 if ( pwfxOut->wBitsPerSample != 16 )
207                         return E_FAIL;
208                 if ( pwfxOut->nBlockAlign != (pwfxOut->nChannels * pwfxOut->wBitsPerSample >> 3 ) )
209                         return E_FAIL;
210         }
211
212 #ifdef  NO_CODEC_IMPL
213         WARN("no codec implementation\n");
214         return E_NOTIMPL;
215 #else
216         return S_OK;
217 #endif
218 }
219
220 static HRESULT CMPEGAudioDecoderImpl_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes )
221 {
222         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
223         HRESULT hr;
224         const WAVEFORMATEX*     pwfxIn;
225         AM_MEDIA_TYPE*  pmtOut;
226         WAVEFORMATEX*   pwfxOut;
227
228         TRACE("(%p)\n",This);
229         if ( This == NULL )
230                 return E_UNEXPECTED;
231
232         hr = CMPEGAudioDecoderImpl_CheckMediaType( pImpl, pmtIn, NULL );
233         if ( FAILED(hr) )
234                 return hr;
235         pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat;
236
237         CMPEGAudioDecoderImpl_CleanupOutTypes(This);
238
239         This->cmt = 1;
240         This->pmt = (AM_MEDIA_TYPE*)QUARTZ_AllocMem(
241                 sizeof(AM_MEDIA_TYPE) * This->cmt );
242         if ( This->pmt == NULL )
243                 return E_OUTOFMEMORY;
244         ZeroMemory( This->pmt, sizeof(AM_MEDIA_TYPE) * This->cmt );
245
246         pmtOut = &This->pmt[0];
247
248         memcpy( &pmtOut->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
249         memcpy( &pmtOut->subtype, &MEDIASUBTYPE_PCM, sizeof(GUID) );
250         memcpy( &pmtOut->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
251         pmtOut->bFixedSizeSamples = 1;
252         pmtOut->bTemporalCompression = 0;
253         pmtOut->lSampleSize = pwfxIn->nChannels * 16 >> 3;
254         pmtOut->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(WAVEFORMATEX) );
255         if ( pmtOut->pbFormat == NULL )
256                 return E_OUTOFMEMORY;
257         pwfxOut = (WAVEFORMATEX*)pmtOut->pbFormat;
258         pmtOut->cbFormat = sizeof(WAVEFORMATEX);
259         pwfxOut->wFormatTag = WAVE_FORMAT_PCM;
260         pwfxOut->nChannels = pwfxIn->nChannels;
261         pwfxOut->nSamplesPerSec = pwfxIn->nSamplesPerSec;
262         pwfxOut->nAvgBytesPerSec = pwfxOut->nSamplesPerSec * pmtOut->lSampleSize;
263         pwfxOut->nBlockAlign = pmtOut->lSampleSize;
264         pwfxOut->wBitsPerSample = 16;
265         pwfxOut->cbSize = 0;
266
267         *ppmtAcceptTypes = This->pmt;
268         *pcAcceptTypes = This->cmt;
269
270         return S_OK;
271 }
272
273 static HRESULT CMPEGAudioDecoderImpl_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample )
274 {
275         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
276         const WAVEFORMATEX*     pwfxIn;
277         const WAVEFORMATEX*     pwfxOut;
278         HRESULT hr;
279
280         TRACE("(%p)\n",This);
281         if ( This == NULL )
282                 return E_UNEXPECTED;
283
284         hr = CMPEGAudioDecoderImpl_CheckMediaType( pImpl, pmtIn, pmtOut );
285         if ( FAILED(hr) )
286                 return hr;
287         pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat;
288         pwfxOut = (const WAVEFORMATEX*)pmtOut->pbFormat;
289
290         pProp->cBuffers = 1;
291         pProp->cbBuffer = pwfxOut->nAvgBytesPerSec;
292
293         TRACE("cbBuffer %ld\n",pProp->cbBuffer);
294
295         *pbTransInPlace = FALSE;
296         *pbTryToReuseSample = FALSE;
297
298         return S_OK;
299 }
300
301 static HRESULT CMPEGAudioDecoderImpl_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample )
302 {
303         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
304         HRESULT hr;
305
306         TRACE("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample);
307         if ( This == NULL )
308                 return E_UNEXPECTED;
309
310         hr = CMPEGAudioDecoderImpl_CheckMediaType( pImpl, pmtIn, pmtOut );
311         if ( FAILED(hr) )
312                 return hr;
313         memcpy( &This->wfxOut, (const WAVEFORMATEX*)pmtOut->pbFormat, sizeof(WAVEFORMATEX) );
314
315         return Codec_BeginTransform(pImpl,This);
316 }
317
318 static HRESULT CMPEGAudioDecoderImpl_ProcessReceive( CTransformBaseImpl* pImpl, IMediaSample* pSampIn )
319 {
320         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
321
322         TRACE("(%p,%p)\n",This,pSampIn);
323         if ( This == NULL )
324                 return E_UNEXPECTED;
325
326         return Codec_ProcessReceive(pImpl,This,pSampIn);
327 }
328
329 static HRESULT CMPEGAudioDecoderImpl_EndTransform( CTransformBaseImpl* pImpl )
330 {
331         CMPEGAudioDecoderImpl*  This = (CMPEGAudioDecoderImpl*)pImpl->m_pUserData;
332         HRESULT hr;
333
334         TRACE("(%p)\n",This);
335         if ( This == NULL )
336                 return E_UNEXPECTED;
337
338         hr = Codec_EndTransform(pImpl,This);
339         if ( FAILED(hr) )
340                 return hr;
341         ZeroMemory( &This->wfxOut, sizeof(WAVEFORMATEX) );
342
343         return S_OK;
344 }
345
346
347 static const TransformBaseHandlers transhandlers =
348 {
349         CMPEGAudioDecoderImpl_Init,
350         CMPEGAudioDecoderImpl_Cleanup,
351         CMPEGAudioDecoderImpl_CheckMediaType,
352         CMPEGAudioDecoderImpl_GetOutputTypes,
353         CMPEGAudioDecoderImpl_GetAllocProp,
354         CMPEGAudioDecoderImpl_BeginTransform,
355         CMPEGAudioDecoderImpl_ProcessReceive,
356         NULL,
357         CMPEGAudioDecoderImpl_EndTransform,
358 };
359
360 HRESULT QUARTZ_CreateCMpegAudioCodec(IUnknown* punkOuter,void** ppobj)
361 {
362         return QUARTZ_CreateTransformBase(
363                 punkOuter,ppobj,
364                 &CLSID_CMpegAudioCodec,
365                 CMPEGAudioDecoderImpl_FilterName,
366                 NULL, NULL,
367                 &transhandlers );
368 }
369