Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / quartz / mpgparse.c
1 /*
2  * Implements MPEG-1 / MPEG-2 Parser(Splitter).
3  *
4  *      FIXME - no splitter implementation.
5  *      FIXME - no packet support (implemented payload only)
6  *      FIXME - no seeking
7  *
8  * Copyright (C) 2002 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 "mmsystem.h"
32 #include "vfw.h"
33 #include "winerror.h"
34 #include "strmif.h"
35 #include "control.h"
36 #include "vfwmsgs.h"
37 #include "amvideo.h"
38 #include "mmreg.h"
39 #include "uuids.h"
40 #include "dvdmedia.h"
41
42 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44
45 #include "quartz_private.h"
46 #include "parser.h"
47 #include "mtype.h"
48
49 static const WCHAR QUARTZ_MPEG1Parser_Name[] =
50 { 'M','P','E','G','-','I',' ','S','p','l','i','t','t','e','r',0 };
51 static const WCHAR QUARTZ_MPEG2Parser_Name[] =
52 { 'M','P','E','G','-','2',' ','S','p','l','i','t','t','e','r',0 };
53 static const WCHAR QUARTZ_MPGParserInPin_Name[] =
54 { 'I','n',0 };
55 static const WCHAR QUARTZ_MPGParserOutPin_VideoPinName[] =
56 { 'V','i','d','e','o',0 };
57 static const WCHAR QUARTZ_MPGParserOutPin_AudioPinName[] =
58 { 'A','u','d','i','o',0 };
59         /* FIXME */
60 static const WCHAR QUARTZ_MPGParserOutPin_UnknownTypePinName[] =
61 { 'O','u','t',0 };
62
63
64
65 static DWORD bitratesl1[16] =
66         {  0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448,  0};
67 static DWORD bitratesl2[16] =
68         {  0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384,  0};
69 static DWORD bitratesl3[16] =
70         {  0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,  0};
71
72
73 /****************************************************************************
74  *
75  *      CMPGParseImpl
76  */
77
78
79 typedef struct CMPGParseImpl CMPGParseImpl;
80 typedef struct CMPGParsePayload CMPGParsePayload;
81
82 enum MPGPayloadType
83 {
84         MPGPayload_Video = 0xe0,
85         MPGPayload_Audio = 0xc0,
86 };
87
88 struct CMPGParseImpl
89 {
90         LONGLONG        llPosNext;
91         BOOL    bRawPayload;
92         DWORD   dwPayloadBlockSizeMax;
93         DWORD   cPayloads;
94         CMPGParsePayload*       pPayloads;
95 };
96
97 struct CMPGParsePayload
98 {
99         enum MPGPayloadType     payloadtype;
100         BOOL    bDataDiscontinuity;
101 };
102
103 static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt );
104
105 static HRESULT CMPGParseImpl_SyncReadPayload(
106         CParserImpl* pImpl, CMPGParseImpl* This,
107         enum MPGPayloadType payloadtype,
108         LONGLONG llPosStart, LONG lLength, BYTE* pbBuf )
109 {
110         if ( This == NULL || This->pPayloads == NULL )
111                 return E_UNEXPECTED;
112
113         if ( This->bRawPayload )
114         {
115                 if ( payloadtype != This->pPayloads[0].payloadtype )
116                         return E_UNEXPECTED;
117                 return IAsyncReader_SyncRead( pImpl->m_pReader, llPosStart, lLength, pbBuf );
118         }
119         else
120         {
121                 FIXME( "not implemented\n" );
122         }
123
124         return E_NOTIMPL;
125 }
126
127
128
129 static HRESULT CMPGParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
130 {
131         CMPGParseImpl*  This = NULL;
132         HRESULT hr;
133         DWORD   n;
134         AM_MEDIA_TYPE   mt;
135         BYTE    hdrbuf[8];
136
137         TRACE("(%p,%p)\n",pImpl,pcStreams);
138
139         This = (CMPGParseImpl*)QUARTZ_AllocMem( sizeof(CMPGParseImpl) );
140         if ( This == NULL )
141                 return E_OUTOFMEMORY;
142         pImpl->m_pUserData = This;
143         ZeroMemory( This, sizeof(CMPGParseImpl) );
144
145         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 8, hdrbuf );
146         if ( FAILED(hr) )
147                 return hr;
148         if ( hr != S_OK )
149                 return E_FAIL;
150
151         if ( hdrbuf[0] == 0x00 && hdrbuf[1] == 0x00 &&
152                  hdrbuf[2] == 0x01 && hdrbuf[3] == 0xba )
153         {
154                 This->bRawPayload = FALSE;
155                 This->dwPayloadBlockSizeMax = 0;
156
157                 FIXME( "no mpeg/system support\n" );
158                 return E_FAIL;
159         }
160         else
161         if ( hdrbuf[0] == 0x00 && hdrbuf[1] == 0x00 &&
162                  hdrbuf[2] == 0x01 && hdrbuf[3] == 0xb3 )
163         {
164                 TRACE( "mpeg/video payload\n" );
165                 This->llPosNext = 0;
166                 This->bRawPayload = TRUE;
167                 This->dwPayloadBlockSizeMax = 0x4000;
168                 This->cPayloads = 1;
169                 This->pPayloads = (CMPGParsePayload*)QUARTZ_AllocMem( sizeof(CMPGParsePayload) );
170                 if ( This->pPayloads == NULL )
171                         return E_OUTOFMEMORY;
172                 *pcStreams = 1;
173                 This->pPayloads[0].payloadtype = MPGPayload_Video;
174                 This->pPayloads[0].bDataDiscontinuity = TRUE;
175         }
176         else
177         if ( hdrbuf[0] == 0xff && (hdrbuf[1]&0xf0) == 0xf0 )
178         {
179                 TRACE( "mpeg/audio payload\n" );
180                 This->llPosNext = 0;
181                 This->bRawPayload = TRUE;
182                 This->dwPayloadBlockSizeMax = 0;
183                 This->cPayloads = 1;
184                 This->pPayloads = (CMPGParsePayload*)QUARTZ_AllocMem( sizeof(CMPGParsePayload) );
185                 if ( This->pPayloads == NULL )
186                         return E_OUTOFMEMORY;
187                 *pcStreams = 1;
188                 This->pPayloads[0].payloadtype = MPGPayload_Audio;
189                 This->pPayloads[0].bDataDiscontinuity = TRUE;
190         }
191         else
192         {
193                 return E_FAIL;
194         }
195
196         /* To determine block size, scan all payloads. */
197         ZeroMemory( &mt, sizeof(mt) );
198         for ( n = 0; n < This->cPayloads; n++ )
199         {
200                 CMPGParseImpl_GetStreamType(pImpl,n,&mt);
201                 QUARTZ_MediaType_Free(&mt);
202         }
203
204         return S_OK;
205 }
206
207 static HRESULT CMPGParseImpl_UninitParser( CParserImpl* pImpl )
208 {
209         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
210         ULONG   nIndex;
211
212         TRACE("(%p)\n",This);
213
214         if ( This == NULL )
215                 return NOERROR;
216
217         /* destruct */
218
219         if ( This->pPayloads != NULL )
220         {
221                 for ( nIndex = 0; nIndex < This->cPayloads; nIndex++ )
222                 {
223                         /* release this stream */
224
225                         
226                 }
227                 QUARTZ_FreeMem( This->pPayloads );
228                 This->pPayloads = NULL;
229         }
230
231         QUARTZ_FreeMem( This );
232         pImpl->m_pUserData = NULL;
233
234         return NOERROR;
235 }
236
237 static LPCWSTR CMPGParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
238 {
239         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
240
241         TRACE("(%p,%lu)\n",This,nStreamIndex);
242
243         if ( This == NULL || nStreamIndex >= This->cPayloads )
244                 return NULL;
245
246         switch ( This->pPayloads[nStreamIndex].payloadtype )
247         {
248         case MPGPayload_Video:
249                 return QUARTZ_MPGParserOutPin_VideoPinName;
250         case MPGPayload_Audio:
251                 return QUARTZ_MPGParserOutPin_AudioPinName;
252         default:
253                 FIXME("mpeg - unknown stream type %02x\n",This->pPayloads[nStreamIndex].payloadtype);
254         }
255
256         /* FIXME */
257         return QUARTZ_MPGParserOutPin_UnknownTypePinName;
258 }
259
260 static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
261 {
262         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
263         HRESULT hr;
264         BYTE    hdrbuf[140+10];
265         UINT    seqhdrlen;
266         MPEG1VIDEOINFO* pmpg1vi;
267         MPEG2VIDEOINFO* pmpg2vi;
268         MPEG1WAVEFORMAT*        pmpg1wav;
269         enum MPGPayloadType     payloadtype;
270         DWORD   dwPayloadBlockSize;
271
272         TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
273
274         if ( This == NULL )
275                 return E_UNEXPECTED;
276         if ( nStreamIndex >= This->cPayloads )
277                 return E_INVALIDARG;
278
279         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
280
281         payloadtype = This->pPayloads[nStreamIndex].payloadtype;
282         switch ( payloadtype )
283         {
284         case MPGPayload_Video:
285                 hr = CMPGParseImpl_SyncReadPayload(
286                         pImpl, This, payloadtype, 0, 140+10, hdrbuf );
287                 if ( FAILED(hr) )
288                         return hr;
289                 if ( hr != S_OK )
290                         return E_FAIL;
291
292                 memcpy( &pmt->majortype, &MEDIATYPE_Video, sizeof(GUID) );
293                 seqhdrlen = 12;
294                 if ( hdrbuf[seqhdrlen-1] & 0x2 )
295                         seqhdrlen += 64;
296                 if ( hdrbuf[seqhdrlen-1] & 0x1 )
297                         seqhdrlen += 64;
298                 if ( hdrbuf[seqhdrlen  ] == 0x00 && hdrbuf[seqhdrlen+1] == 0x00 &&
299                          hdrbuf[seqhdrlen+2] == 0x01 && hdrbuf[seqhdrlen+3] == 0xb5 )
300                 {
301                         /* video MPEG-2 */
302                         FIXME("video MPEG-2\n");
303                         if ( (hdrbuf[seqhdrlen+4]&0xf0) != 0x1 )
304                                 return E_FAIL;
305                         memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG2_VIDEO, sizeof(GUID) );
306                         memcpy( &pmt->formattype, &FORMAT_MPEG2_VIDEO, sizeof(GUID) );
307                         pmt->bFixedSizeSamples = 0;
308                         pmt->bTemporalCompression = 1;
309                         pmt->lSampleSize = 0;
310                         pmt->cbFormat = sizeof(MPEG2VIDEOINFO);
311                         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG2VIDEOINFO) );
312                         if ( pmt->pbFormat == NULL )
313                                 return E_OUTOFMEMORY;
314                         ZeroMemory( pmt->pbFormat, sizeof(MPEG2VIDEOINFO) );
315                         pmpg2vi = (MPEG2VIDEOINFO*)pmt->pbFormat;
316                         pmpg2vi->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
317                         pmpg2vi->hdr.bmiHeader.biWidth = ((UINT)hdrbuf[4] << 4) | ((UINT)hdrbuf[5] >> 4); /* FIXME! */
318                         pmpg2vi->hdr.bmiHeader.biHeight = (((UINT)hdrbuf[5] & 0xf) << 8) | ((UINT)hdrbuf[6]); /* FIXME! */
319                         pmpg2vi->hdr.dwInterlaceFlags = AMINTERLACE_FieldPatBothRegular; /* FIXME? */
320                         pmpg2vi->hdr.dwCopyProtectFlags = AMCOPYPROTECT_RestrictDuplication; /* FIXME? */
321                         pmpg2vi->hdr.dwPictAspectRatioX = 1; /* FIXME? */
322                         pmpg2vi->hdr.dwPictAspectRatioY = 1; /* FIXME? */
323                         pmpg2vi->dwStartTimeCode = 0;
324                         pmpg2vi->cbSequenceHeader = seqhdrlen + 10;
325                         switch ( hdrbuf[seqhdrlen+4] & 0xf )
326                         {
327                         case 5: pmpg2vi->dwProfile = AM_MPEG2Profile_Simple; break;
328                         case 4: pmpg2vi->dwProfile = AM_MPEG2Profile_Main; break;
329                         case 3: pmpg2vi->dwProfile = AM_MPEG2Profile_SNRScalable; break;
330                         case 2: pmpg2vi->dwProfile = AM_MPEG2Profile_SpatiallyScalable; break;
331                         case 1: pmpg2vi->dwProfile = AM_MPEG2Profile_High; break;
332                         default: return E_FAIL;
333                         }
334                         switch ( hdrbuf[seqhdrlen+5] >> 4 )
335                         {
336                         case 10: pmpg2vi->dwLevel = AM_MPEG2Level_Low; break;
337                         case  8: pmpg2vi->dwLevel = AM_MPEG2Level_Main; break;
338                         case  6: pmpg2vi->dwLevel = AM_MPEG2Level_High1440; break;
339                         case  4: pmpg2vi->dwLevel = AM_MPEG2Level_High; break;
340                         default: return E_FAIL;
341                         }
342                         pmpg2vi->dwFlags = 0; /* FIXME? */
343                         memcpy( pmpg2vi->dwSequenceHeader, hdrbuf, seqhdrlen + 10 );
344
345                         return S_OK;
346                 }
347                 else
348                 {
349                         /* MPEG-1 */
350                         memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG1Payload, sizeof(GUID) );
351                         memcpy( &pmt->formattype, &FORMAT_MPEGVideo, sizeof(GUID) );
352                         pmt->bFixedSizeSamples = 0;
353                         pmt->bTemporalCompression = 1;
354                         pmt->lSampleSize = 0;
355                         pmt->cbFormat = sizeof(MPEG1VIDEOINFO);
356                         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG1VIDEOINFO) );
357                         if ( pmt->pbFormat == NULL )
358                                 return E_OUTOFMEMORY;
359                         ZeroMemory( pmt->pbFormat, sizeof(MPEG1VIDEOINFO) );
360                         pmpg1vi = (MPEG1VIDEOINFO*)pmt->pbFormat;
361                         pmpg1vi->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
362                         pmpg1vi->hdr.bmiHeader.biWidth = ((UINT)hdrbuf[4] << 4) | ((UINT)hdrbuf[5] >> 4);
363                         pmpg1vi->hdr.bmiHeader.biHeight = (((UINT)hdrbuf[5] & 0xf) << 8) | ((UINT)hdrbuf[6]);
364                         pmpg1vi->hdr.bmiHeader.biPlanes = 1;
365                         pmpg1vi->dwStartTimeCode = 0;
366                         pmpg1vi->cbSequenceHeader = seqhdrlen;
367                         memcpy( pmpg1vi->bSequenceHeader, hdrbuf, seqhdrlen );
368                 }
369
370                 return S_OK;
371         case MPGPayload_Audio:
372                 hr = CMPGParseImpl_SyncReadPayload(
373                         pImpl, This, payloadtype, 0, 4, hdrbuf );
374                 if ( FAILED(hr) )
375                         return hr;
376                 if ( hr != S_OK )
377                         return E_FAIL;
378
379                 memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
380                 memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
381
382                 if ( !( hdrbuf[1] & 0x8 ) )
383                 {
384                         /* FIXME!!! */
385                         FIXME("audio not MPEG-1\n");
386                         return E_FAIL;
387                 }
388                 else
389                 {
390                         /* MPEG-1 */
391                         memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload, sizeof(GUID) );
392                         pmt->bFixedSizeSamples = 0;
393                         pmt->bTemporalCompression = 1;
394                         pmt->lSampleSize = 0;
395                         pmt->cbFormat = sizeof(MPEG1WAVEFORMAT);
396                         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG1WAVEFORMAT) );
397                         if ( pmt->pbFormat == NULL )
398                                 return E_OUTOFMEMORY;
399                         ZeroMemory( pmt->pbFormat, sizeof(MPEG1WAVEFORMAT) );
400                         pmpg1wav = (MPEG1WAVEFORMAT*)pmt->pbFormat;
401                         switch ( hdrbuf[1] & 0x6 )
402                         {
403                         case 0x6:
404                                 TRACE("layer 1\n");
405                                 pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER1;
406                                 break;
407                         case 0x4:
408                                 TRACE("layer 2\n");
409                                 pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER2;
410                                 break;
411                         case 0x2:
412                                 TRACE("layer 3\n");
413                                 pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER3;
414                                 break;
415                         default: return E_FAIL;
416                         }
417
418                         switch ( pmpg1wav->fwHeadLayer )
419                         {
420                         case ACM_MPEG_LAYER1:
421                                 pmpg1wav->dwHeadBitrate = bitratesl1[hdrbuf[2]>>4]*1000;
422                                 break;
423                         case ACM_MPEG_LAYER2:
424                                 pmpg1wav->dwHeadBitrate = bitratesl2[hdrbuf[2]>>4]*1000;
425                                 break;
426                         case ACM_MPEG_LAYER3:
427                                 pmpg1wav->dwHeadBitrate = bitratesl3[hdrbuf[2]>>4]*1000;
428                                 break;
429                         }
430                         if ( pmpg1wav->dwHeadBitrate == 0 )
431                                 return E_FAIL;
432
433                         switch ( hdrbuf[3] & 0xc0 )
434                         {
435                         case 0x00:
436                                 TRACE("STEREO\n");
437                                 pmpg1wav->fwHeadMode = ACM_MPEG_STEREO;
438                                 break;
439                         case 0x40:
440                                 TRACE("JOINTSTEREO\n");
441                                 pmpg1wav->fwHeadMode = ACM_MPEG_JOINTSTEREO;
442                                 break;
443                         case 0x80:
444                                 TRACE("DUALCHANNEL\n");
445                                 pmpg1wav->fwHeadMode = ACM_MPEG_DUALCHANNEL;
446                                 break;
447                         case 0xc0:
448                                 TRACE("SINGLECHANNEL\n");
449                                 pmpg1wav->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
450                                 break;
451                         }
452
453                         pmpg1wav->fwHeadModeExt = (hdrbuf[3] & 0x30) >> 4; /* FIXME?? */
454                         pmpg1wav->wHeadEmphasis = (hdrbuf[3] & 0x03); /* FIXME?? */
455                         pmpg1wav->fwHeadFlags = ACM_MPEG_ID_MPEG1;
456                         if ( hdrbuf[1] & 0x1 )
457                                 pmpg1wav->fwHeadFlags |= ACM_MPEG_PROTECTIONBIT;
458                         if ( hdrbuf[2] & 0x1 )
459                                 pmpg1wav->fwHeadFlags |= ACM_MPEG_PRIVATEBIT;
460                         if ( hdrbuf[3] & 0x8 )
461                                 pmpg1wav->fwHeadFlags |= ACM_MPEG_COPYRIGHT;
462                         if ( hdrbuf[3] & 0x4 )
463                                 pmpg1wav->fwHeadFlags |= ACM_MPEG_ORIGINALHOME;
464                         pmpg1wav->dwPTSLow = 0;
465                         pmpg1wav->dwPTSHigh = 0;
466
467                         pmpg1wav->wfx.wFormatTag = WAVE_FORMAT_MPEG;
468                         pmpg1wav->wfx.nChannels = (pmpg1wav->fwHeadMode != ACM_MPEG_SINGLECHANNEL) ? 2 : 1;
469                         switch ( hdrbuf[2] & 0x0c )
470                         {
471                         case 0x00:
472                                 TRACE("44100Hz\n");
473                                 pmpg1wav->wfx.nSamplesPerSec = 44100;
474                                 break;
475                         case 0x01:
476                                 TRACE("48000Hz\n");
477                                 pmpg1wav->wfx.nSamplesPerSec = 48000;
478                                 break;
479                         case 0x02:
480                                 TRACE("32000Hz\n");
481                                 pmpg1wav->wfx.nSamplesPerSec = 32000;
482                                 break;
483                         default: return E_FAIL;
484                         }
485                         pmpg1wav->wfx.nAvgBytesPerSec = pmpg1wav->dwHeadBitrate >> 3;
486                         switch ( pmpg1wav->fwHeadLayer )
487                         {
488                         case ACM_MPEG_LAYER1:
489                                 pmpg1wav->wfx.nBlockAlign = (384>>3) * pmpg1wav->dwHeadBitrate / pmpg1wav->wfx.nSamplesPerSec;
490                                 break;
491                         case ACM_MPEG_LAYER2:
492                                 pmpg1wav->wfx.nBlockAlign = (1152>>3) * pmpg1wav->dwHeadBitrate / pmpg1wav->wfx.nSamplesPerSec;
493                                 break;
494                         case ACM_MPEG_LAYER3:
495                                 pmpg1wav->wfx.nBlockAlign = 1;
496                                 break;
497                         }
498                         pmpg1wav->wfx.wBitsPerSample = 0;
499                         pmpg1wav->wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX);
500                         if ( pmpg1wav->fwHeadLayer != ACM_MPEG_LAYER3 )
501                         {
502                                 pmt->bFixedSizeSamples = 1;
503                                 pmt->lSampleSize = pmpg1wav->wfx.nBlockAlign;
504                         }
505                         dwPayloadBlockSize = (pmpg1wav->wfx.nAvgBytesPerSec + pmpg1wav->wfx.nBlockAlign - 1) / pmpg1wav->wfx.nBlockAlign;
506                         if ( dwPayloadBlockSize > This->dwPayloadBlockSizeMax )
507                                 This->dwPayloadBlockSizeMax = dwPayloadBlockSize;
508                         TRACE("payload block size = %lu\n",dwPayloadBlockSize);
509                 }
510
511                 return S_OK;
512         default:
513                 FIXME("mpeg - unknown stream type %02x\n",This->pPayloads[nStreamIndex].payloadtype);
514                 break;
515         }
516
517         FIXME("stub\n");
518         return E_NOTIMPL;
519 }
520
521 static HRESULT CMPGParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
522 {
523         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
524         HRESULT hr;
525         AM_MEDIA_TYPE   mt;
526         MPEG1VIDEOINFO* pmpg1vi;
527         MPEG1VIDEOINFO* pmpg1viCheck;
528         MPEG2VIDEOINFO* pmpg2vi;
529         MPEG2VIDEOINFO* pmpg2viCheck;
530         WAVEFORMATEX*   pwfx;
531         WAVEFORMATEX*   pwfxCheck;
532         enum MPGPayloadType     payloadtype;
533
534         TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt);
535
536         if ( This == NULL )
537                 return E_UNEXPECTED;
538         if ( nStreamIndex >= This->cPayloads )
539                 return E_INVALIDARG;
540
541         hr = CMPGParseImpl_GetStreamType( pImpl, nStreamIndex, &mt );
542         if ( FAILED(hr) )
543                 return hr;
544         if ( !IsEqualGUID( &pmt->majortype, &mt.majortype ) ||
545                  !IsEqualGUID( &pmt->subtype, &mt.subtype ) ||
546                  !IsEqualGUID( &pmt->formattype, &mt.formattype ) )
547         {
548                 hr = E_FAIL;
549                 goto end;
550         }
551
552         TRACE("check format\n");
553         hr = S_OK;
554
555         payloadtype = This->pPayloads[nStreamIndex].payloadtype;
556         switch ( payloadtype )
557         {
558         case MPGPayload_Video:
559                 if ( IsEqualGUID( &mt.formattype, &FORMAT_MPEGVideo ) )
560                 {
561                         /* MPEG-1 Video */
562                         if ( pmt->cbFormat != mt.cbFormat ||
563                                  pmt->pbFormat == NULL )
564                         {
565                                 hr = E_FAIL;
566                                 goto end;
567                         }
568                         pmpg1vi = (MPEG1VIDEOINFO*)mt.pbFormat;
569                         pmpg1viCheck = (MPEG1VIDEOINFO*)pmt->pbFormat;
570                         if ( memcmp( pmpg1vi, pmpg1viCheck, sizeof(MPEG1VIDEOINFO) ) != 0 )
571                         {
572                                 hr = E_FAIL;
573                                 goto end;
574                         }
575                 }
576                 else
577                 if ( IsEqualGUID( &mt.formattype, &FORMAT_MPEG2_VIDEO ) )
578                 {
579                         /* MPEG-2 Video */
580                         if ( pmt->cbFormat != mt.cbFormat ||
581                                  pmt->pbFormat == NULL )
582                         {
583                                 hr = E_FAIL;
584                                 goto end;
585                         }
586                         pmpg2vi = (MPEG2VIDEOINFO*)mt.pbFormat;
587                         pmpg2viCheck = (MPEG2VIDEOINFO*)pmt->pbFormat;
588                         if ( memcmp( pmpg2vi, pmpg2viCheck, sizeof(MPEG2VIDEOINFO) ) != 0 )
589                         {
590                                 hr = E_FAIL;
591                                 goto end;
592                         }
593                 }
594                 else
595                 {
596                         hr = E_FAIL;
597                         goto end;
598                 }
599                 break;
600         case MPGPayload_Audio:
601                 if ( IsEqualGUID( &mt.formattype, &FORMAT_WaveFormatEx ) )
602                 {
603                         if ( mt.cbFormat != pmt->cbFormat ||
604                                  pmt->pbFormat == NULL )
605                         {
606                                 hr = E_FAIL;
607                                 goto end;
608                         }
609                         pwfx = (WAVEFORMATEX*)mt.pbFormat;
610                         pwfxCheck = (WAVEFORMATEX*)pmt->pbFormat;
611
612                         if ( memcmp( pwfx, pwfxCheck, sizeof(WAVEFORMATEX) ) != 0 )
613                         {
614                                 hr = E_FAIL;
615                                 goto end;
616                         }
617                 }
618                 else
619                 {
620                         hr = E_FAIL;
621                         goto end;
622                 }
623
624                 break;
625         default:
626                 FIXME( "unsupported payload type\n" );
627                 hr = E_FAIL;
628                 goto end;
629         }
630
631         hr = S_OK;
632 end:
633         QUARTZ_MediaType_Free( &mt );
634
635         TRACE("%08lx\n",hr);
636
637         return hr;
638 }
639
640 static HRESULT CMPGParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
641 {
642         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
643
644         TRACE("(%p,%p)\n",This,pReqProp);
645
646         if ( This == NULL )
647                 return E_UNEXPECTED;
648
649         ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
650         pReqProp->cBuffers = This->cPayloads;
651         pReqProp->cbBuffer = This->dwPayloadBlockSizeMax;
652
653         TRACE("buf %d size %d\n",
654                 (int)This->cPayloads,
655                 (int)This->dwPayloadBlockSizeMax);
656
657         return S_OK;
658 }
659
660 static HRESULT CMPGParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop, DWORD* pdwSampleFlags )
661 {
662         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
663
664         if ( This == NULL )
665                 return E_UNEXPECTED;
666         *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT;
667
668         TRACE("(%p)\n",This);
669
670         if ( This->bRawPayload )
671         {
672                 if ( This->dwPayloadBlockSizeMax == 0 ||
673                          This->cPayloads != 1 || This->pPayloads == NULL )
674                         return E_UNEXPECTED;
675                 *pnStreamIndex = 0;
676                 *pllStart = This->llPosNext;
677                 *plLength = This->dwPayloadBlockSizeMax;
678                 *prtStart = 0;
679                 *prtStop = 0;
680                 if ( This->pPayloads[0].bDataDiscontinuity )
681                 {
682                         *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
683                         This->pPayloads[0].bDataDiscontinuity = FALSE;
684                 }
685         }
686         else
687         {
688                 FIXME("stub\n");
689                 return E_NOTIMPL;
690         }
691
692         return S_OK;
693 }
694
695 static HRESULT CMPGParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
696 {
697         CMPGParseImpl*  This = (CMPGParseImpl*)pImpl->m_pUserData;
698         HRESULT hr;
699
700         TRACE("(%p,%lu,%ld,%ld,%p)\n",This,nStreamIndex,(long)llStart,lLength,pSample);
701
702         if ( This == NULL )
703                 return E_UNEXPECTED;
704
705         if ( This->bRawPayload )
706         {
707                 hr = IMediaSample_SetTime(pSample,NULL,NULL);
708                 if ( FAILED(hr) )
709                         return hr;
710         }
711
712         return NOERROR;
713 }
714
715
716 static const struct ParserHandlers CMPGParseImpl_Handlers =
717 {
718         CMPGParseImpl_InitParser,
719         CMPGParseImpl_UninitParser,
720         CMPGParseImpl_GetOutPinName,
721         CMPGParseImpl_GetStreamType,
722         CMPGParseImpl_CheckStreamType,
723         CMPGParseImpl_GetAllocProp,
724         CMPGParseImpl_GetNextRequest,
725         CMPGParseImpl_ProcessSample,
726
727         /* for IQualityControl */
728         NULL, /* pQualityNotify */
729
730         /* for seeking */
731         NULL, /* pGetSeekingCaps */
732         NULL, /* pIsTimeFormatSupported */
733         NULL, /* pGetCurPos */
734         NULL, /* pSetCurPos */
735         NULL, /* pGetDuration */
736         NULL, /* pGetStopPos */
737         NULL, /* pSetStopPos */
738         NULL, /* pGetPreroll */
739 };
740
741 HRESULT QUARTZ_CreateMPEG1Splitter(IUnknown* punkOuter,void** ppobj)
742 {
743         return QUARTZ_CreateParser(
744                 punkOuter,ppobj,
745                 &CLSID_MPEG1Splitter,
746                 QUARTZ_MPEG1Parser_Name,
747                 QUARTZ_MPGParserInPin_Name,
748                 &CMPGParseImpl_Handlers );
749 }
750
751