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