Fixed some deadlocks.
[wine] / dlls / quartz / parser.c
1 /*
2  * Implements IBaseFilter for parsers. (internal)
3  *
4  * hidenori@a2.ctktv.ne.jp
5  *
6  * FIXME - handle errors/flushing correctly.
7  * FIXME - handle seeking.
8  */
9
10 #include "config.h"
11
12 #include "windef.h"
13 #include "winbase.h"
14 #include "wingdi.h"
15 #include "winuser.h"
16 #include "mmsystem.h"
17 #include "winerror.h"
18 #include "strmif.h"
19 #include "control.h"
20 #include "vfwmsgs.h"
21 #include "evcode.h"
22 #include "uuids.h"
23
24 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(quartz);
26
27 #include "quartz_private.h"
28 #include "parser.h"
29 #include "mtype.h"
30 #include "memalloc.h"
31
32 #define QUARTZ_MSG_EXITTHREAD   (WM_APP+2)
33 #define QUARTZ_MSG_SEEK                 (WM_APP+3)
34
35 HRESULT CParserOutPinImpl_InitIMediaSeeking( CParserOutPinImpl* This );
36 void CParserOutPinImpl_UninitIMediaSeeking( CParserOutPinImpl* This );
37 HRESULT CParserOutPinImpl_InitIMediaPosition( CParserOutPinImpl* This );
38 void CParserOutPinImpl_UninitIMediaPosition( CParserOutPinImpl* This );
39
40 /***************************************************************************
41  *
42  *      CParserImpl internal thread
43  *
44  */
45
46 static
47 void CParserImplThread_ClearAllRequests( CParserImpl* This )
48 {
49         ULONG   nIndex;
50
51         TRACE("(%p)\n",This);
52
53         for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
54         {
55                 This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE;
56                 This->m_ppOutPins[nIndex]->m_pReqSample = NULL;
57         }
58 }
59
60 static
61 void CParserImplThread_ReleaseAllRequests( CParserImpl* This )
62 {
63         ULONG   nIndex;
64
65         TRACE("(%p)\n",This);
66
67         for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
68         {
69                 if ( This->m_ppOutPins[nIndex]->m_bReqUsed )
70                 {
71                         if ( This->m_ppOutPins[nIndex]->m_pReqSample != NULL )
72                         {
73                                 IMediaSample_Release(This->m_ppOutPins[nIndex]->m_pReqSample);
74                                 This->m_ppOutPins[nIndex]->m_pReqSample = NULL;
75                         }
76                         This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE;
77                 }
78         }
79 }
80
81 static
82 BOOL CParserImplThread_HasPendingSamples( CParserImpl* This )
83 {
84         ULONG   nIndex;
85
86         for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
87         {
88                 if ( This->m_ppOutPins[nIndex]->m_bReqUsed &&
89                          This->m_ppOutPins[nIndex]->m_pReqSample != NULL )
90                         return TRUE;
91         }
92
93         return FALSE;
94 }
95
96 static
97 HRESULT CParserImplThread_FlushAllPendingSamples( CParserImpl* This )
98 {
99         HRESULT hr;
100         IMediaSample*   pSample;
101         DWORD_PTR       dwContext;
102
103         TRACE("(%p)\n",This);
104
105         /* remove all samples from queue. */
106         hr = IAsyncReader_BeginFlush(This->m_pReader);
107         if ( FAILED(hr) )
108                 return hr;
109         IAsyncReader_EndFlush(This->m_pReader);
110
111         /* remove all processed samples from queue. */
112         while ( 1 )
113         {
114                 hr = IAsyncReader_WaitForNext(This->m_pReader,0,&pSample,&dwContext);
115                 if ( hr != S_OK )
116                         break;
117         }
118
119         CParserImplThread_ReleaseAllRequests(This);
120
121         return NOERROR;
122 }
123
124 static HRESULT CParserImplThread_SendEndOfStream( CParserImpl* This )
125 {
126         ULONG   nIndex;
127         HRESULT hr;
128         HRESULT hrRet;
129         CParserOutPinImpl*      pOutPin;
130
131         TRACE("(%p)\n",This);
132         if ( This->m_bSendEOS )
133                 return NOERROR;
134         This->m_bSendEOS = TRUE;
135
136         hrRet = S_OK;
137         for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
138         {
139                 pOutPin = This->m_ppOutPins[nIndex];
140                 hr = CPinBaseImpl_SendEndOfStream(&pOutPin->pin);
141                 if ( FAILED(hr) )
142                 {
143                         if ( SUCCEEDED(hrRet) )
144                                 hrRet = hr;
145                 }
146                 else
147                 {
148                         if ( hr != S_OK && hrRet == S_OK )
149                                 hrRet = hr;
150                 }
151         }
152
153         return hrRet;
154 }
155
156 static HRESULT CParserImplThread_SendFlush( CParserImpl* This )
157 {
158         ULONG   nIndex;
159         HRESULT hr;
160         HRESULT hrRet;
161         CParserOutPinImpl*      pOutPin;
162
163         TRACE("(%p)\n",This);
164         hrRet = S_OK;
165         for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
166         {
167                 pOutPin = This->m_ppOutPins[nIndex];
168                 hr = CPinBaseImpl_SendBeginFlush(&pOutPin->pin);
169                 if ( FAILED(hr) )
170                 {
171                         if ( SUCCEEDED(hrRet) )
172                                 hrRet = hr;
173                 }
174                 else
175                 {
176                         if ( hr != S_OK && hrRet == S_OK )
177                                 hrRet = hr;
178                         hr = CPinBaseImpl_SendEndFlush(&pOutPin->pin);
179                         if ( FAILED(hr) )
180                                 hrRet = hr;
181                 }
182         }
183
184         return hrRet;
185 }
186
187 static void CParserImplThread_ErrorAbort( CParserImpl* This, HRESULT hr )
188 {
189         CBaseFilterImpl_MediaEventNotify(
190                 &This->basefilter,EC_ERRORABORT,(LONG_PTR)hr,(LONG_PTR)0);
191         CParserImplThread_SendEndOfStream(This);
192 }
193
194 static
195 HRESULT CParserImplThread_ProcessNextSample( CParserImpl* This )
196 {
197         IMediaSample*   pSample;
198         DWORD_PTR       dwContext;
199         ULONG   nIndex;
200         HRESULT hr;
201         CParserOutPinImpl*      pOutPin;
202         MSG     msg;
203
204         while ( 1 )
205         {
206                 if ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) )
207                 {
208                         hr = NOERROR;
209                         switch ( msg.message )
210                         {
211                         case QUARTZ_MSG_EXITTHREAD:
212                                 TRACE("(%p) EndThread\n",This);
213                                 CParserImplThread_FlushAllPendingSamples(This);
214                                 CParserImplThread_ClearAllRequests(This);
215                                 CParserImplThread_SendFlush(This);
216                                 CParserImplThread_SendEndOfStream(This);
217                                 TRACE("(%p) exit thread\n",This);
218                                 return S_FALSE;
219                         case QUARTZ_MSG_SEEK:
220                                 FIXME("(%p) Seek\n",This);
221                                 CParserImplThread_FlushAllPendingSamples(This);
222                                 hr = CParserImplThread_SendFlush(This);
223                                 CParserImplThread_SendEndOfStream(This);
224                                 /* FIXME - process seeking. */
225                                 /* FIXME - Send NewSegment. */
226                                 break;
227                         default:
228                                 FIXME( "invalid message %04u\n", (unsigned)msg.message );
229                                 hr = E_FAIL;
230                                 CParserImplThread_ErrorAbort(This,hr);
231                         }
232
233                         return hr;
234                 }
235
236                 hr = IAsyncReader_WaitForNext(This->m_pReader,PARSER_POLL_INTERVAL,&pSample,&dwContext);
237                 nIndex = (ULONG)dwContext;
238                 if ( hr != VFW_E_TIMEOUT )
239                         break;
240         }
241         if ( FAILED(hr) )
242         {
243                 CParserImplThread_ErrorAbort(This,hr);
244                 return hr;
245         }
246
247         pOutPin = This->m_ppOutPins[nIndex];
248         if ( pOutPin != NULL && pOutPin->m_bReqUsed )
249         {
250                 if ( This->m_pHandler->pProcessSample != NULL )
251                         hr = This->m_pHandler->pProcessSample(This,nIndex,pOutPin->m_llReqStart,pOutPin->m_lReqLength,pOutPin->m_pReqSample);
252
253                 if ( SUCCEEDED(hr) )
254                 {
255                         if ( pOutPin->m_pOutPinAllocator != NULL &&
256                                  pOutPin->m_pOutPinAllocator != This->m_pAllocator )
257                         {
258                                 /* if pin has its own allocator, sample must be copied */
259                                 hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 );
260                                 if ( SUCCEEDED(hr) )
261                                 {
262                                         hr = QUARTZ_IMediaSample_Copy(
263                                                 pSample, pOutPin->m_pReqSample, TRUE );
264                                         if ( SUCCEEDED(hr) )
265                                                 hr = CPinBaseImpl_SendSample(&pOutPin->pin,pSample);
266                                         IMediaSample_Release(pSample);
267                                 }
268                         }
269                         else
270                         {
271                                 hr = CPinBaseImpl_SendSample(&pOutPin->pin,pOutPin->m_pReqSample);
272                         }
273                 }
274
275                 if ( FAILED(hr) )
276                         CParserImplThread_ErrorAbort(This,hr);
277
278                 IMediaSample_Release(pOutPin->m_pReqSample);
279                 pOutPin->m_pReqSample = NULL;
280                 pOutPin->m_bReqUsed = FALSE;
281         }
282
283         if ( SUCCEEDED(hr) )
284                 hr = NOERROR;
285
286         TRACE("return %08lx\n",hr);
287
288         return hr;
289 }
290
291 static
292 DWORD WINAPI CParserImplThread_Entry( LPVOID pv )
293 {
294         CParserImpl*    This = (CParserImpl*)pv;
295         BOOL    bReqNext;
296         ULONG   nIndex = 0;
297         HRESULT hr;
298         REFERENCE_TIME  rtSampleTimeStart, rtSampleTimeEnd;
299         LONGLONG        llReqStart;
300         LONG    lReqLength;
301         REFERENCE_TIME  rtReqStart, rtReqStop;
302         IMediaSample*   pSample;
303         MSG     msg;
304
305         /* initialize the message queue. */
306         PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE );
307
308         CParserImplThread_ClearAllRequests(This);
309
310         /* resume the owner thread. */
311         SetEvent( This->m_hEventInit );
312
313         TRACE( "Enter message loop.\n" );
314
315         bReqNext = TRUE;
316         while ( 1 )
317         {
318                 if ( bReqNext )
319                 {
320                         /* Get the next request.  */
321                         hr = This->m_pHandler->pGetNextRequest( This, &nIndex, &llReqStart, &lReqLength, &rtReqStart, &rtReqStop );
322                         if ( FAILED(hr) )
323                         {
324                                 CParserImplThread_ErrorAbort(This,hr);
325                                 break;
326                         }
327                         if ( hr != S_OK )
328                         {
329                                 /* Flush pending samples. */
330                                 hr = S_OK;
331                                 while ( CParserImplThread_HasPendingSamples(This) )
332                                 {
333                                         hr = CParserImplThread_ProcessNextSample(This);
334                                         if ( hr != S_OK )
335                                                 break;
336                                 }
337                                 if ( hr != S_OK )
338                                 {
339                                         /* notification is already sent */
340                                         break;
341                                 }
342
343                                 /* Send End Of Stream. */
344                                 hr = CParserImplThread_SendEndOfStream(This);
345                                 if ( hr != S_OK )
346                                 {
347                                         /* notification is already sent */
348                                         break;
349                                 }
350
351                                 /* Blocking... */
352                                 hr = CParserImplThread_ProcessNextSample(This);
353                                 if ( hr != S_OK )
354                                 {
355                                         /* notification is already sent */
356                                         break;
357                                 }
358                                 continue;
359                         }
360                         if ( This->m_ppOutPins[nIndex]->pin.pPinConnectedTo == NULL )
361                                 continue;
362
363                         rtSampleTimeStart = This->basefilter.rtStart + llReqStart * QUARTZ_TIMEUNITS;
364                         rtSampleTimeEnd = (llReqStart + lReqLength) * QUARTZ_TIMEUNITS;
365                         bReqNext = FALSE;
366                 }
367
368                 if ( !This->m_ppOutPins[nIndex]->m_bReqUsed )
369                 {
370                         hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 );
371                         if ( FAILED(hr) )
372                         {
373                                 CParserImplThread_ErrorAbort(This,hr);
374                                 break;
375                         }
376                         hr = IMediaSample_SetTime(pSample,&rtSampleTimeStart,&rtSampleTimeEnd);
377                         if ( SUCCEEDED(hr) )
378                                 hr = IAsyncReader_Request(This->m_pReader,pSample,nIndex);
379                         if ( FAILED(hr) )
380                         {
381                                 CParserImplThread_ErrorAbort(This,hr);
382                                 break;
383                         }
384
385                         This->m_ppOutPins[nIndex]->m_bReqUsed = TRUE;
386                         This->m_ppOutPins[nIndex]->m_pReqSample = pSample;
387                         This->m_ppOutPins[nIndex]->m_llReqStart = llReqStart;
388                         This->m_ppOutPins[nIndex]->m_lReqLength = lReqLength;
389                         This->m_ppOutPins[nIndex]->m_rtReqStart = rtSampleTimeStart;
390                         This->m_ppOutPins[nIndex]->m_rtReqStop = rtSampleTimeEnd;
391                         bReqNext = TRUE;
392                         continue;
393                 }
394
395                 hr = CParserImplThread_ProcessNextSample(This);
396                 if ( hr != S_OK )
397                 {
398                         /* notification is already sent */
399                         break;
400                 }
401         }
402
403         return 0;
404 }
405
406 /***************************************************************************
407  *
408  *      CParserImpl internal methods
409  *
410  */
411
412 static
413 void CParserImpl_SetAsyncReader( CParserImpl* This, IAsyncReader* pReader )
414 {
415         if ( This->m_pReader != NULL )
416         {
417                 IAsyncReader_Release( This->m_pReader );
418                 This->m_pReader = NULL;
419         }
420         if ( pReader != NULL )
421         {
422                 This->m_pReader = pReader;
423                 IAsyncReader_AddRef(This->m_pReader);
424         }
425 }
426
427 static
428 void CParserImpl_ReleaseOutPins( CParserImpl* This )
429 {
430         ULONG nIndex;
431
432         if ( This->m_ppOutPins != NULL )
433         {
434                 for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
435                 {
436                         if ( This->m_ppOutPins[nIndex] != NULL )
437                         {
438                                 IUnknown_Release(This->m_ppOutPins[nIndex]->unk.punkControl);
439                                 This->m_ppOutPins[nIndex] = NULL;
440                         }
441                 }
442                 QUARTZ_FreeMem(This->m_ppOutPins);
443                 This->m_ppOutPins = NULL;
444         }
445         This->m_cOutStreams = 0;
446 }
447
448 static
449 BOOL CParserImpl_OutPinsAreConnected( CParserImpl* This )
450 {
451         QUARTZ_CompListItem*    pItem;
452         IPin*   pPin;
453         IPin*   pPinPeer;
454         HRESULT hr;
455
456         QUARTZ_CompList_Lock( This->basefilter.pOutPins );
457         pItem = QUARTZ_CompList_GetFirst( This->basefilter.pOutPins );
458         while ( pItem != NULL )
459         {
460                 if ( pItem == NULL )
461                         break;
462                 pPin = (IPin*)QUARTZ_CompList_GetItemPtr(pItem);
463                 pPinPeer = NULL;
464                 hr = IPin_ConnectedTo(pPin,&pPinPeer);
465                 if ( hr == S_OK && pPinPeer != NULL )
466                 {
467                         IPin_Release(pPinPeer);
468                         return TRUE;
469                 }
470                 pItem = QUARTZ_CompList_GetNext( This->basefilter.pOutPins, pItem );
471         }
472         QUARTZ_CompList_Unlock( This->basefilter.pOutPins );
473
474         return FALSE;
475 }
476
477 static
478 void CParserImpl_ReleaseListOfOutPins( CParserImpl* This )
479 {
480         QUARTZ_CompListItem*    pItem;
481
482         QUARTZ_CompList_Lock( This->basefilter.pOutPins );
483         while ( 1 )
484         {
485                 pItem = QUARTZ_CompList_GetFirst( This->basefilter.pOutPins );
486                 if ( pItem == NULL )
487                         break;
488                 QUARTZ_CompList_RemoveComp(
489                         This->basefilter.pOutPins,
490                         QUARTZ_CompList_GetItemPtr(pItem) );
491         }
492         QUARTZ_CompList_Unlock( This->basefilter.pOutPins );
493 }
494
495
496 static
497 HRESULT CParserImpl_BeginThread( CParserImpl* This )
498 {
499         DWORD dwRes;
500         HANDLE hEvents[2];
501
502         if ( This->m_hEventInit != (HANDLE)NULL &&
503                  This->m_hThread != (HANDLE)NULL )
504                 return NOERROR;
505
506         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
507         if ( This->m_hEventInit == (HANDLE)NULL )
508                 return E_OUTOFMEMORY;
509
510         /* create the processing thread. */
511         This->m_hThread = CreateThread(
512                 NULL, 0,
513                 CParserImplThread_Entry,
514                 (LPVOID)This,
515                 0, &This->m_dwThreadId );
516         if ( This->m_hThread == (HANDLE)NULL )
517                 return E_FAIL;
518
519         hEvents[0] = This->m_hEventInit;
520         hEvents[1] = This->m_hThread;
521
522         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
523         if ( dwRes != WAIT_OBJECT_0 )
524                 return E_FAIL;
525
526         return NOERROR;
527 }
528
529 static
530 void CParserImpl_EndThread( CParserImpl* This )
531 {
532         TRACE("(%p)\n",This);
533         if ( This->m_hThread != (HANDLE)NULL )
534         {
535                 if ( PostThreadMessageA(
536                         This->m_dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ) )
537                 {
538                         WaitForSingleObject( This->m_hThread, INFINITE );
539                 }
540                 CloseHandle( This->m_hThread );
541                 This->m_hThread = (HANDLE)NULL;
542                 This->m_dwThreadId = 0;
543         }
544         if ( This->m_hEventInit != (HANDLE)NULL )
545         {
546                 CloseHandle( This->m_hEventInit );
547                 This->m_hEventInit = (HANDLE)NULL;
548         }
549 }
550
551 static
552 HRESULT CParserImpl_MemCommit( CParserImpl* This )
553 {
554         HRESULT hr;
555         ULONG   nIndex;
556         IMemAllocator*  pAlloc;
557
558         TRACE("(%p)\n",This);
559
560         if ( This->m_pAllocator == NULL )
561                 return E_UNEXPECTED;
562
563         hr = IMemAllocator_Commit( This->m_pAllocator );
564         if ( FAILED(hr) )
565                 return hr;
566
567         if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
568         {
569                 for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
570                 {
571                         pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
572                         if ( pAlloc != NULL && pAlloc != This->m_pAllocator )
573                         {
574                                 hr = IMemAllocator_Commit( pAlloc );
575                                 if ( FAILED(hr) )
576                                         return hr;
577                         }
578                 }
579         }
580
581         return NOERROR;
582 }
583
584 static
585 void CParserImpl_MemDecommit( CParserImpl* This )
586 {
587         ULONG   nIndex;
588         IMemAllocator*  pAlloc;
589
590         TRACE("(%p)\n",This);
591
592         if ( This->m_pAllocator != NULL )
593                 IMemAllocator_Decommit( This->m_pAllocator );
594
595         if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
596         {
597                 for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
598                 {
599                         pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
600                         if ( pAlloc != NULL )
601                                 IMemAllocator_Decommit( pAlloc );
602                 }
603         }
604 }
605
606
607
608 /***************************************************************************
609  *
610  *      CParserImpl methods
611  *
612  */
613
614 static HRESULT CParserImpl_OnActive( CBaseFilterImpl* pImpl )
615 {
616         CParserImpl_THIS(pImpl,basefilter);
617
618         TRACE( "(%p)\n", This );
619
620         if ( !CParserImpl_OutPinsAreConnected(This) )
621                 return NOERROR;
622
623         return NOERROR;
624 }
625
626 static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl )
627 {
628         CParserImpl_THIS(pImpl,basefilter);
629         HRESULT hr;
630
631         TRACE( "(%p)\n", This );
632
633         if ( !CParserImpl_OutPinsAreConnected(This) )
634                 return NOERROR;
635
636         hr = CParserImpl_MemCommit(This);
637         if ( FAILED(hr) )
638                 return hr;
639         hr = CParserImpl_BeginThread(This);
640         if ( FAILED(hr) )
641         {
642                 CParserImpl_EndThread(This);
643                 return hr;
644         }
645
646         return NOERROR;
647 }
648
649 static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl )
650 {
651         CParserImpl_THIS(pImpl,basefilter);
652
653         FIXME( "(%p)\n", This );
654
655         CParserImpl_EndThread(This);
656         CParserImpl_MemDecommit(This);
657         This->m_bSendEOS = FALSE;
658
659         /* FIXME - reset streams. */
660
661         return NOERROR;
662 }
663
664
665 static const CBaseFilterHandlers filterhandlers =
666 {
667         CParserImpl_OnActive, /* pOnActive */
668         CParserImpl_OnInactive, /* pOnInactive */
669         CParserImpl_OnStop, /* pOnStop */
670 };
671
672
673 /***************************************************************************
674  *
675  *      CParserInPinImpl methods
676  *
677  */
678
679 static HRESULT CParserInPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
680 {
681         CParserInPinImpl_THIS(pImpl,pin);
682         HRESULT hr;
683         ULONG   nIndex;
684         IUnknown*       punk;
685         IAsyncReader* pReader = NULL;
686         LPCWSTR pwszOutPinName;
687         IMemAllocator*  pAllocActual;
688         AM_MEDIA_TYPE*  pmt;
689
690         TRACE("(%p,%p)\n",This,pPin);
691
692         if ( This->pParser->m_pHandler->pInitParser == NULL ||
693                  This->pParser->m_pHandler->pUninitParser == NULL ||
694                  This->pParser->m_pHandler->pGetOutPinName == NULL ||
695                  This->pParser->m_pHandler->pGetStreamType == NULL ||
696                  This->pParser->m_pHandler->pCheckStreamType == NULL ||
697                  This->pParser->m_pHandler->pGetAllocProp == NULL ||
698                  This->pParser->m_pHandler->pGetNextRequest == NULL )
699         {
700                 FIXME("this parser is not implemented.\n");
701                 return E_NOTIMPL;
702         }
703
704         /* at first, release all output pins. */
705         if ( CParserImpl_OutPinsAreConnected(This->pParser) )
706                 return E_FAIL;
707         CParserImpl_ReleaseListOfOutPins(This->pParser);
708         CParserImpl_ReleaseOutPins(This->pParser);
709
710         CParserImpl_SetAsyncReader( This->pParser, NULL );
711         hr = IPin_QueryInterface( pPin, &IID_IAsyncReader, (void**)&pReader );
712         if ( FAILED(hr) )
713                 return hr;
714         CParserImpl_SetAsyncReader( This->pParser, pReader );
715         IAsyncReader_Release(pReader);
716
717         /* initialize parser. */
718         hr = This->pParser->m_pHandler->pInitParser(This->pParser,&This->pParser->m_cOutStreams);
719         if ( FAILED(hr) )
720                 return hr;
721         This->pParser->m_ppOutPins = (CParserOutPinImpl**)QUARTZ_AllocMem(
722                 sizeof(CParserOutPinImpl*) * This->pParser->m_cOutStreams );
723         if ( This->pParser->m_ppOutPins == NULL )
724                 return E_OUTOFMEMORY;
725         for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
726                 This->pParser->m_ppOutPins[nIndex] = NULL;
727
728         /* create and initialize an allocator. */
729         hr = This->pParser->m_pHandler->pGetAllocProp(This->pParser,&This->pParser->m_propAlloc);
730         if ( FAILED(hr) )
731                 return hr;
732         if ( This->pParser->m_propAlloc.cbAlign == 0 )
733                 This->pParser->m_propAlloc.cbAlign = 1;
734
735         if ( This->pParser->m_pAllocator == NULL )
736         {
737                 hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
738                 if ( FAILED(hr) )
739                         return hr;
740                 hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&This->pParser->m_pAllocator );
741                 IUnknown_Release(punk);
742                 if ( FAILED(hr) )
743                         return hr;
744         }
745         pAllocActual = NULL;
746         hr = IAsyncReader_RequestAllocator(pReader,This->pParser->m_pAllocator,&This->pParser->m_propAlloc,&pAllocActual);
747         if ( FAILED(hr) )
748                 return hr;
749         IMemAllocator_Release(This->pParser->m_pAllocator);
750         This->pParser->m_pAllocator = pAllocActual;
751
752         /* create output pins. */
753         for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
754         {
755                 pwszOutPinName = This->pParser->m_pHandler->pGetOutPinName(This->pParser,nIndex);
756                 if ( pwszOutPinName == NULL )
757                         return E_FAIL;
758                 hr = QUARTZ_CreateParserOutPin(
759                         This->pParser,
760                         &This->pParser->m_csParser,
761                         &This->pParser->m_ppOutPins[nIndex],
762                         nIndex, pwszOutPinName );
763                 if ( SUCCEEDED(hr) )
764                         hr = QUARTZ_CompList_AddTailComp(
765                                 This->pParser->basefilter.pOutPins,
766                                 (IUnknown*)&(This->pParser->m_ppOutPins[nIndex]->pin),
767                                 NULL, 0 );
768                 if ( FAILED(hr) )
769                         return hr;
770                 pmt = &This->pParser->m_ppOutPins[nIndex]->m_mtOut;
771                 QUARTZ_MediaType_Free( pmt );
772                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
773                 hr = This->pParser->m_pHandler->pGetStreamType(This->pParser,nIndex,pmt);
774                 if ( FAILED(hr) )
775                 {
776                         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
777                         return hr;
778                 }
779                 This->pParser->m_ppOutPins[nIndex]->pin.cAcceptTypes = 1;
780                 This->pParser->m_ppOutPins[nIndex]->pin.pmtAcceptTypes = pmt;
781         }
782
783         return NOERROR;
784 }
785
786 static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
787 {
788         CParserInPinImpl_THIS(pImpl,pin);
789
790         CParserImpl_OnInactive(&This->pParser->basefilter);
791         CParserImpl_OnStop(&This->pParser->basefilter);
792         if ( This->pParser->m_pHandler->pUninitParser != NULL )
793                 This->pParser->m_pHandler->pUninitParser(This->pParser);
794         CParserImpl_SetAsyncReader( This->pParser, NULL );
795         if ( This->pParser->m_pAllocator != NULL )
796         {
797                 IMemAllocator_Decommit(This->pParser->m_pAllocator);
798                 IMemAllocator_Release(This->pParser->m_pAllocator);
799                 This->pParser->m_pAllocator = NULL;
800         }
801
802         return NOERROR;
803 }
804
805 static HRESULT CParserInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
806 {
807         CParserInPinImpl_THIS(pImpl,pin);
808
809         TRACE("(%p,%p)\n",This,pmt);
810
811         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
812                 return E_FAIL;
813
814         return NOERROR;
815 }
816
817 static const CBasePinHandlers inputpinhandlers =
818 {
819         CParserInPinImpl_OnPreConnect, /* pOnPreConnect */
820         NULL, /* pOnPostConnect */
821         CParserInPinImpl_OnDisconnect, /* pOnDisconnect */
822         CParserInPinImpl_CheckMediaType, /* pCheckMediaType */
823         NULL, /* pQualityNotify */
824         NULL, /* pReceive */
825         NULL, /* pReceiveCanBlock */
826         NULL, /* pEndOfStream */
827         NULL, /* pBeginFlush */
828         NULL, /* pEndFlush */
829         NULL, /* pNewSegment */
830 };
831
832 /***************************************************************************
833  *
834  *      CParserOutPinImpl methods
835  *
836  */
837
838 static HRESULT CParserOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
839 {
840         CParserOutPinImpl_THIS(pImpl,pin);
841         ALLOCATOR_PROPERTIES    propReq;
842         ALLOCATOR_PROPERTIES    propActual;
843         IMemAllocator*  pAllocator;
844         HRESULT hr;
845         BOOL    bNewAllocator = FALSE;
846
847         TRACE("(%p,%p)\n",This,pPin);
848
849         if ( This->pin.pMemInputPinConnectedTo == NULL )
850                 return E_UNEXPECTED;
851
852         if ( This->m_pOutPinAllocator != NULL )
853         {
854                 IMemAllocator_Release(This->m_pOutPinAllocator);
855                 This->m_pOutPinAllocator = NULL;
856         }
857
858         /* try to use This->pParser->m_pAllocator. */
859         ZeroMemory( &propReq, sizeof(ALLOCATOR_PROPERTIES) );
860         hr = IMemInputPin_GetAllocatorRequirements(
861                 This->pin.pMemInputPinConnectedTo, &propReq );
862         if ( propReq.cbAlign != 0 )
863         {
864                 if ( This->pParser->m_propAlloc.cbAlign != ( This->pParser->m_propAlloc.cbAlign / propReq.cbAlign * propReq.cbAlign ) )
865                         bNewAllocator = TRUE;
866         }
867         if ( propReq.cbPrefix != 0 )
868                 bNewAllocator = TRUE;
869         if ( !bNewAllocator )
870         {
871                 hr = IMemInputPin_NotifyAllocator(
872                         This->pin.pMemInputPinConnectedTo,
873                         This->pParser->m_pAllocator, FALSE );
874                 if ( hr == NOERROR )
875                 {
876                         This->m_pOutPinAllocator = This->pParser->m_pAllocator;
877                         IMemAllocator_AddRef(This->m_pOutPinAllocator);
878                         return NOERROR;
879                 }
880         }
881
882         hr = IMemInputPin_GetAllocator(
883                         This->pin.pMemInputPinConnectedTo, &pAllocator );
884         if ( FAILED(hr) )
885                 return hr;
886         hr = IMemAllocator_SetProperties( pAllocator, &This->pParser->m_propAlloc, &propActual );
887         if ( SUCCEEDED(hr) )
888                 hr = IMemInputPin_NotifyAllocator(
889                         This->pin.pMemInputPinConnectedTo, pAllocator, FALSE );
890         if ( FAILED(hr) )
891         {
892                 IMemAllocator_Release(pAllocator);
893                 return hr;
894         }
895
896         This->m_pOutPinAllocator = pAllocator;
897         return NOERROR;
898 }
899
900 static HRESULT CParserOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
901 {
902         CParserOutPinImpl_THIS(pImpl,pin);
903
904         if ( This->m_pOutPinAllocator != NULL )
905         {
906                 IMemAllocator_Release(This->m_pOutPinAllocator);
907                 This->m_pOutPinAllocator = NULL;
908         }
909
910         return NOERROR;
911 }
912
913 static HRESULT CParserOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
914 {
915         CParserOutPinImpl_THIS(pImpl,pin);
916         HRESULT hr;
917
918         TRACE("(%p,%p)\n",This,pmt);
919         if ( pmt == NULL )
920                 return E_POINTER;
921
922         if ( This->pParser->m_pHandler->pCheckStreamType == NULL )
923                 return E_NOTIMPL;
924
925         hr = This->pParser->m_pHandler->pCheckStreamType( This->pParser, This->nStreamIndex, pmt );
926         if ( FAILED(hr) )
927                 return hr;
928
929         return NOERROR;
930 }
931
932
933 static const CBasePinHandlers outputpinhandlers =
934 {
935         NULL, /* pOnPreConnect */
936         CParserOutPinImpl_OnPostConnect, /* pOnPostConnect */
937         CParserOutPinImpl_OnDisconnect, /* pOnDisconnect */
938         CParserOutPinImpl_CheckMediaType, /* pCheckMediaType */
939         NULL, /* pQualityNotify */
940         OutputPinSync_Receive, /* pReceive */
941         OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
942         OutputPinSync_EndOfStream, /* pEndOfStream */
943         OutputPinSync_BeginFlush, /* pBeginFlush */
944         OutputPinSync_EndFlush, /* pEndFlush */
945         OutputPinSync_NewSegment, /* pNewSegment */
946 };
947
948 /***************************************************************************
949  *
950  *      new/delete CParserImpl
951  *
952  */
953
954 /* can I use offsetof safely? - FIXME? */
955 static QUARTZ_IFEntry FilterIFEntries[] =
956 {
957   { &IID_IPersist, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
958   { &IID_IMediaFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
959   { &IID_IBaseFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
960 };
961
962 static void QUARTZ_DestroyParser(IUnknown* punk)
963 {
964         CParserImpl_THIS(punk,unk);
965
966         TRACE( "(%p)\n", This );
967
968         if ( This->m_pInPin != NULL )
969                 CParserInPinImpl_OnDisconnect(&This->m_pInPin->pin);
970
971         CParserImpl_SetAsyncReader( This, NULL );
972         if ( This->m_pAllocator != NULL )
973         {
974                 IMemAllocator_Release(This->m_pAllocator);
975                 This->m_pAllocator = NULL;
976         }
977         if ( This->m_pInPin != NULL )
978         {
979                 IUnknown_Release(This->m_pInPin->unk.punkControl);
980                 This->m_pInPin = NULL;
981         }
982         CParserImpl_ReleaseOutPins( This );
983
984         DeleteCriticalSection( &This->m_csParser );
985
986         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
987 }
988
989 HRESULT QUARTZ_CreateParser(
990         IUnknown* punkOuter,void** ppobj,
991         const CLSID* pclsidParser,
992         LPCWSTR pwszParserName,
993         LPCWSTR pwszInPinName,
994         const ParserHandlers* pHandler )
995 {
996         CParserImpl*    This = NULL;
997         HRESULT hr;
998
999         TRACE("(%p,%p)\n",punkOuter,ppobj);
1000
1001         This = (CParserImpl*)
1002                 QUARTZ_AllocObj( sizeof(CParserImpl) );
1003         if ( This == NULL )
1004                 return E_OUTOFMEMORY;
1005         ZeroMemory( This, sizeof(CParserImpl) );
1006
1007         This->m_pInPin = NULL;
1008         This->m_cOutStreams = 0;
1009         This->m_ppOutPins = NULL;
1010         This->m_pReader = NULL;
1011         This->m_pAllocator = NULL;
1012         ZeroMemory( &This->m_propAlloc, sizeof(ALLOCATOR_PROPERTIES) );
1013         This->m_hEventInit = (HANDLE)NULL;
1014         This->m_hThread = (HANDLE)NULL;
1015         This->m_dwThreadId = 0;
1016         This->m_bSendEOS = FALSE;
1017         This->m_pHandler = pHandler;
1018         This->m_pUserData = NULL;
1019
1020         QUARTZ_IUnkInit( &This->unk, punkOuter );
1021
1022         hr = CBaseFilterImpl_InitIBaseFilter(
1023                 &This->basefilter,
1024                 This->unk.punkControl,
1025                 pclsidParser,
1026                 pwszParserName,
1027                 &filterhandlers );
1028         if ( SUCCEEDED(hr) )
1029         {
1030                 /* construct this class. */
1031                 hr = S_OK;
1032
1033                 if ( FAILED(hr) )
1034                 {
1035                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
1036                 }
1037         }
1038
1039         if ( FAILED(hr) )
1040         {
1041                 QUARTZ_FreeObj(This);
1042                 return hr;
1043         }
1044
1045         This->unk.pEntries = FilterIFEntries;
1046         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
1047         This->unk.pOnFinalRelease = QUARTZ_DestroyParser;
1048         InitializeCriticalSection( &This->m_csParser );
1049
1050         /* create the input pin. */
1051         hr = QUARTZ_CreateParserInPin(
1052                 This,
1053                 &This->m_csParser,
1054                 &This->m_pInPin,
1055                 pwszInPinName );
1056         if ( SUCCEEDED(hr) )
1057                 hr = QUARTZ_CompList_AddComp(
1058                         This->basefilter.pInPins,
1059                         (IUnknown*)&(This->m_pInPin->pin),
1060                         NULL, 0 );
1061
1062         if ( FAILED(hr) )
1063         {
1064                 IUnknown_Release( This->unk.punkControl );
1065                 return hr;
1066         }
1067
1068         *ppobj = (void*)&(This->unk);
1069
1070         return S_OK;
1071 }
1072
1073 /***************************************************************************
1074  *
1075  *      new/delete CParserInPinImpl
1076  *
1077  */
1078
1079 /* can I use offsetof safely? - FIXME? */
1080 static QUARTZ_IFEntry InPinIFEntries[] =
1081 {
1082   { &IID_IPin, offsetof(CParserInPinImpl,pin)-offsetof(CParserInPinImpl,unk) },
1083   { &IID_IMemInputPin, offsetof(CParserInPinImpl,meminput)-offsetof(CParserInPinImpl,unk) },
1084 };
1085
1086 static void QUARTZ_DestroyParserInPin(IUnknown* punk)
1087 {
1088         CParserInPinImpl_THIS(punk,unk);
1089
1090         TRACE( "(%p)\n", This );
1091
1092         CPinBaseImpl_UninitIPin( &This->pin );
1093         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
1094 }
1095
1096 HRESULT QUARTZ_CreateParserInPin(
1097         CParserImpl* pFilter,
1098         CRITICAL_SECTION* pcsPin,
1099         CParserInPinImpl** ppPin,
1100         LPCWSTR pwszPinName )
1101 {
1102         CParserInPinImpl*       This = NULL;
1103         HRESULT hr;
1104
1105         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1106
1107         This = (CParserInPinImpl*)
1108                 QUARTZ_AllocObj( sizeof(CParserInPinImpl) );
1109         if ( This == NULL )
1110                 return E_OUTOFMEMORY;
1111
1112         QUARTZ_IUnkInit( &This->unk, NULL );
1113         This->pParser = pFilter;
1114
1115         hr = CPinBaseImpl_InitIPin(
1116                 &This->pin,
1117                 This->unk.punkControl,
1118                 pcsPin, NULL,
1119                 &pFilter->basefilter,
1120                 pwszPinName,
1121                 FALSE,
1122                 &inputpinhandlers );
1123
1124         if ( SUCCEEDED(hr) )
1125         {
1126                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
1127                         &This->meminput,
1128                         This->unk.punkControl,
1129                         &This->pin );
1130                 if ( FAILED(hr) )
1131                 {
1132                         CPinBaseImpl_UninitIPin( &This->pin );
1133                 }
1134         }
1135
1136         if ( FAILED(hr) )
1137         {
1138                 QUARTZ_FreeObj(This);
1139                 return hr;
1140         }
1141
1142         This->unk.pEntries = InPinIFEntries;
1143         This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
1144         This->unk.pOnFinalRelease = QUARTZ_DestroyParserInPin;
1145
1146         *ppPin = This;
1147
1148         TRACE("returned successfully.\n");
1149
1150         return S_OK;
1151 }
1152
1153
1154 /***************************************************************************
1155  *
1156  *      new/delete CParserOutPinImpl
1157  *
1158  */
1159
1160 /* can I use offsetof safely? - FIXME? */
1161 static QUARTZ_IFEntry OutPinIFEntries[] =
1162 {
1163   { &IID_IPin, offsetof(CParserOutPinImpl,pin)-offsetof(CParserOutPinImpl,unk) },
1164   { &IID_IQualityControl, offsetof(CParserOutPinImpl,qcontrol)-offsetof(CParserOutPinImpl,unk) },
1165   { &IID_IMediaSeeking, offsetof(CParserOutPinImpl,mediaseeking)-offsetof(CParserOutPinImpl,unk) },
1166   { &IID_IMediaPosition, offsetof(CParserOutPinImpl,mediaposition)-offsetof(CParserOutPinImpl,unk) },
1167 };
1168
1169 static void QUARTZ_DestroyParserOutPin(IUnknown* punk)
1170 {
1171         CParserOutPinImpl_THIS(punk,unk);
1172
1173         TRACE( "(%p)\n", This );
1174
1175         QUARTZ_MediaType_Free( &This->m_mtOut );
1176         if ( This->m_pOutPinAllocator != NULL )
1177                 IMemAllocator_Release(This->m_pOutPinAllocator);
1178
1179         CParserOutPinImpl_UninitIMediaPosition(This);
1180         CParserOutPinImpl_UninitIMediaSeeking(This);
1181         CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
1182         CPinBaseImpl_UninitIPin( &This->pin );
1183
1184 }
1185
1186 HRESULT QUARTZ_CreateParserOutPin(
1187         CParserImpl* pFilter,
1188         CRITICAL_SECTION* pcsPin,
1189         CParserOutPinImpl** ppPin,
1190         ULONG nStreamIndex,
1191         LPCWSTR pwszPinName )
1192 {
1193         CParserOutPinImpl*      This = NULL;
1194         HRESULT hr;
1195
1196         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1197
1198         This = (CParserOutPinImpl*)
1199                 QUARTZ_AllocObj( sizeof(CParserOutPinImpl) );
1200         if ( This == NULL )
1201                 return E_OUTOFMEMORY;
1202
1203         QUARTZ_IUnkInit( &This->unk, NULL );
1204         This->pParser = pFilter;
1205         This->nStreamIndex = nStreamIndex;
1206         ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
1207         This->m_pOutPinAllocator = NULL;
1208         This->m_pUserData = NULL;
1209         This->m_bReqUsed = FALSE;
1210         This->m_pReqSample = NULL;
1211         This->m_llReqStart = 0;
1212         This->m_lReqLength = 0;
1213         This->m_rtReqStart = 0;
1214         This->m_rtReqStop = 0;
1215
1216
1217         hr = CPinBaseImpl_InitIPin(
1218                 &This->pin,
1219                 This->unk.punkControl,
1220                 pcsPin, NULL,
1221                 &pFilter->basefilter,
1222                 pwszPinName,
1223                 TRUE,
1224                 &outputpinhandlers );
1225
1226         if ( SUCCEEDED(hr) )
1227         {
1228                 hr = CQualityControlPassThruImpl_InitIQualityControl(
1229                         &This->qcontrol,
1230                         This->unk.punkControl,
1231                         &This->pin );
1232                 if ( SUCCEEDED(hr) )
1233                 {
1234                         hr = CParserOutPinImpl_InitIMediaSeeking(This);
1235                         if ( SUCCEEDED(hr) )
1236                         {
1237                                 hr = CParserOutPinImpl_InitIMediaPosition(This);
1238                                 if ( FAILED(hr) )
1239                                 {
1240                                         CParserOutPinImpl_UninitIMediaSeeking(This);
1241                                 }
1242                         }
1243                         if ( FAILED(hr) )
1244                         {
1245                                 CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
1246                         }
1247                 }
1248                 if ( FAILED(hr) )
1249                 {
1250                         CPinBaseImpl_UninitIPin( &This->pin );
1251                 }
1252         }
1253
1254         if ( FAILED(hr) )
1255         {
1256                 QUARTZ_FreeObj(This);
1257                 return hr;
1258         }
1259
1260         This->unk.pEntries = OutPinIFEntries;
1261         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1262         This->unk.pOnFinalRelease = QUARTZ_DestroyParserOutPin;
1263
1264         *ppPin = This;
1265
1266         TRACE("returned successfully.\n");
1267
1268         return S_OK;
1269 }
1270
1271
1272 /***************************************************************************
1273  *
1274  *      IMediaSeeking for CParserOutPinImpl
1275  *
1276  */
1277
1278 static HRESULT WINAPI
1279 IMediaSeeking_fnQueryInterface(IMediaSeeking* iface,REFIID riid,void** ppobj)
1280 {
1281         CParserOutPinImpl_THIS(iface,mediaseeking);
1282
1283         TRACE("(%p)->()\n",This);
1284
1285         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1286 }
1287
1288 static ULONG WINAPI
1289 IMediaSeeking_fnAddRef(IMediaSeeking* iface)
1290 {
1291         CParserOutPinImpl_THIS(iface,mediaseeking);
1292
1293         TRACE("(%p)->()\n",This);
1294
1295         return IUnknown_AddRef(This->unk.punkControl);
1296 }
1297
1298 static ULONG WINAPI
1299 IMediaSeeking_fnRelease(IMediaSeeking* iface)
1300 {
1301         CParserOutPinImpl_THIS(iface,mediaseeking);
1302
1303         TRACE("(%p)->()\n",This);
1304
1305         return IUnknown_Release(This->unk.punkControl);
1306 }
1307
1308
1309 static HRESULT WINAPI
1310 IMediaSeeking_fnGetCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
1311 {
1312         CParserOutPinImpl_THIS(iface,mediaseeking);
1313
1314         FIXME("(%p)->() stub!\n",This);
1315
1316         return E_NOTIMPL;
1317 }
1318
1319 static HRESULT WINAPI
1320 IMediaSeeking_fnCheckCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
1321 {
1322         CParserOutPinImpl_THIS(iface,mediaseeking);
1323
1324         FIXME("(%p)->() stub!\n",This);
1325
1326         return E_NOTIMPL;
1327 }
1328
1329 static HRESULT WINAPI
1330 IMediaSeeking_fnIsFormatSupported(IMediaSeeking* iface,const GUID* pidFormat)
1331 {
1332         CParserOutPinImpl_THIS(iface,mediaseeking);
1333
1334         FIXME("(%p)->() stub!\n",This);
1335
1336         return E_NOTIMPL;
1337 }
1338
1339 static HRESULT WINAPI
1340 IMediaSeeking_fnQueryPreferredFormat(IMediaSeeking* iface,GUID* pidFormat)
1341 {
1342         CParserOutPinImpl_THIS(iface,mediaseeking);
1343
1344         FIXME("(%p)->() stub!\n",This);
1345
1346         return E_NOTIMPL;
1347 }
1348
1349 static HRESULT WINAPI
1350 IMediaSeeking_fnGetTimeFormat(IMediaSeeking* iface,GUID* pidFormat)
1351 {
1352         CParserOutPinImpl_THIS(iface,mediaseeking);
1353
1354         FIXME("(%p)->() stub!\n",This);
1355
1356         return E_NOTIMPL;
1357 }
1358
1359 static HRESULT WINAPI
1360 IMediaSeeking_fnIsUsingTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
1361 {
1362         CParserOutPinImpl_THIS(iface,mediaseeking);
1363
1364         FIXME("(%p)->() stub!\n",This);
1365
1366         return E_NOTIMPL;
1367 }
1368
1369 static HRESULT WINAPI
1370 IMediaSeeking_fnSetTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
1371 {
1372         CParserOutPinImpl_THIS(iface,mediaseeking);
1373
1374         FIXME("(%p)->() stub!\n",This);
1375
1376         return E_NOTIMPL;
1377 }
1378
1379 static HRESULT WINAPI
1380 IMediaSeeking_fnGetDuration(IMediaSeeking* iface,LONGLONG* pllDuration)
1381 {
1382         CParserOutPinImpl_THIS(iface,mediaseeking);
1383
1384         /* the following line may produce too many FIXMEs... */
1385         FIXME("(%p)->() stub!\n",This);
1386
1387         return E_NOTIMPL;
1388 }
1389
1390 static HRESULT WINAPI
1391 IMediaSeeking_fnGetStopPosition(IMediaSeeking* iface,LONGLONG* pllPos)
1392 {
1393         CParserOutPinImpl_THIS(iface,mediaseeking);
1394
1395         FIXME("(%p)->() stub!\n",This);
1396
1397         return E_NOTIMPL;
1398 }
1399
1400 static HRESULT WINAPI
1401 IMediaSeeking_fnGetCurrentPosition(IMediaSeeking* iface,LONGLONG* pllPos)
1402 {
1403         CParserOutPinImpl_THIS(iface,mediaseeking);
1404
1405         FIXME("(%p)->() stub!\n",This);
1406
1407         return E_NOTIMPL;
1408 }
1409
1410 static HRESULT WINAPI
1411 IMediaSeeking_fnConvertTimeFormat(IMediaSeeking* iface,LONGLONG* pllOut,const GUID* pidFmtOut,LONGLONG llIn,const GUID* pidFmtIn)
1412 {
1413         CParserOutPinImpl_THIS(iface,mediaseeking);
1414
1415         FIXME("(%p)->() stub!\n",This);
1416
1417         return E_NOTIMPL;
1418 }
1419
1420 static HRESULT WINAPI
1421 IMediaSeeking_fnSetPositions(IMediaSeeking* iface,LONGLONG* pllCur,DWORD dwCurFlags,LONGLONG* pllStop,DWORD dwStopFlags)
1422 {
1423         CParserOutPinImpl_THIS(iface,mediaseeking);
1424
1425         FIXME("(%p)->() stub!\n",This);
1426
1427         return E_NOTIMPL;
1428 }
1429
1430 static HRESULT WINAPI
1431 IMediaSeeking_fnGetPositions(IMediaSeeking* iface,LONGLONG* pllCur,LONGLONG* pllStop)
1432 {
1433         CParserOutPinImpl_THIS(iface,mediaseeking);
1434
1435         FIXME("(%p)->() stub!\n",This);
1436
1437         return E_NOTIMPL;
1438 }
1439
1440 static HRESULT WINAPI
1441 IMediaSeeking_fnGetAvailable(IMediaSeeking* iface,LONGLONG* pllFirst,LONGLONG* pllLast)
1442 {
1443         CParserOutPinImpl_THIS(iface,mediaseeking);
1444
1445         FIXME("(%p)->() stub!\n",This);
1446
1447         return E_NOTIMPL;
1448 }
1449
1450 static HRESULT WINAPI
1451 IMediaSeeking_fnSetRate(IMediaSeeking* iface,double dblRate)
1452 {
1453         CParserOutPinImpl_THIS(iface,mediaseeking);
1454
1455         FIXME("(%p)->() stub!\n",This);
1456
1457         return E_NOTIMPL;
1458 }
1459
1460 static HRESULT WINAPI
1461 IMediaSeeking_fnGetRate(IMediaSeeking* iface,double* pdblRate)
1462 {
1463         CParserOutPinImpl_THIS(iface,mediaseeking);
1464
1465         FIXME("(%p)->() stub!\n",This);
1466
1467         return E_NOTIMPL;
1468 }
1469
1470 static HRESULT WINAPI
1471 IMediaSeeking_fnGetPreroll(IMediaSeeking* iface,LONGLONG* pllPreroll)
1472 {
1473         CParserOutPinImpl_THIS(iface,mediaseeking);
1474
1475         FIXME("(%p)->() stub!\n",This);
1476
1477         return E_NOTIMPL;
1478 }
1479
1480
1481
1482
1483 static ICOM_VTABLE(IMediaSeeking) imediaseeking =
1484 {
1485         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1486         /* IUnknown fields */
1487         IMediaSeeking_fnQueryInterface,
1488         IMediaSeeking_fnAddRef,
1489         IMediaSeeking_fnRelease,
1490         /* IMediaSeeking fields */
1491         IMediaSeeking_fnGetCapabilities,
1492         IMediaSeeking_fnCheckCapabilities,
1493         IMediaSeeking_fnIsFormatSupported,
1494         IMediaSeeking_fnQueryPreferredFormat,
1495         IMediaSeeking_fnGetTimeFormat,
1496         IMediaSeeking_fnIsUsingTimeFormat,
1497         IMediaSeeking_fnSetTimeFormat,
1498         IMediaSeeking_fnGetDuration,
1499         IMediaSeeking_fnGetStopPosition,
1500         IMediaSeeking_fnGetCurrentPosition,
1501         IMediaSeeking_fnConvertTimeFormat,
1502         IMediaSeeking_fnSetPositions,
1503         IMediaSeeking_fnGetPositions,
1504         IMediaSeeking_fnGetAvailable,
1505         IMediaSeeking_fnSetRate,
1506         IMediaSeeking_fnGetRate,
1507         IMediaSeeking_fnGetPreroll,
1508 };
1509
1510 HRESULT CParserOutPinImpl_InitIMediaSeeking( CParserOutPinImpl* This )
1511 {
1512         TRACE("(%p)\n",This);
1513         ICOM_VTBL(&This->mediaseeking) = &imediaseeking;
1514
1515         return NOERROR;
1516 }
1517
1518 void CParserOutPinImpl_UninitIMediaSeeking( CParserOutPinImpl* This )
1519 {
1520         TRACE("(%p)\n",This);
1521 }
1522
1523 /***************************************************************************
1524  *
1525  *      IMediaPosition for CParserOutPinImpl
1526  *
1527  */
1528
1529 static HRESULT WINAPI
1530 IMediaPosition_fnQueryInterface(IMediaPosition* iface,REFIID riid,void** ppobj)
1531 {
1532         CParserOutPinImpl_THIS(iface,mediaposition);
1533
1534         TRACE("(%p)->()\n",This);
1535
1536         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1537 }
1538
1539 static ULONG WINAPI
1540 IMediaPosition_fnAddRef(IMediaPosition* iface)
1541 {
1542         CParserOutPinImpl_THIS(iface,mediaposition);
1543
1544         TRACE("(%p)->()\n",This);
1545
1546         return IUnknown_AddRef(This->unk.punkControl);
1547 }
1548
1549 static ULONG WINAPI
1550 IMediaPosition_fnRelease(IMediaPosition* iface)
1551 {
1552         CParserOutPinImpl_THIS(iface,mediaposition);
1553
1554         TRACE("(%p)->()\n",This);
1555
1556         return IUnknown_Release(This->unk.punkControl);
1557 }
1558
1559 static HRESULT WINAPI
1560 IMediaPosition_fnGetTypeInfoCount(IMediaPosition* iface,UINT* pcTypeInfo)
1561 {
1562         CParserOutPinImpl_THIS(iface,mediaposition);
1563
1564         FIXME("(%p)->() stub!\n",This);
1565
1566         return E_NOTIMPL;
1567 }
1568
1569 static HRESULT WINAPI
1570 IMediaPosition_fnGetTypeInfo(IMediaPosition* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
1571 {
1572         CParserOutPinImpl_THIS(iface,mediaposition);
1573
1574         FIXME("(%p)->() stub!\n",This);
1575
1576         return E_NOTIMPL;
1577 }
1578
1579 static HRESULT WINAPI
1580 IMediaPosition_fnGetIDsOfNames(IMediaPosition* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
1581 {
1582         CParserOutPinImpl_THIS(iface,mediaposition);
1583
1584         FIXME("(%p)->() stub!\n",This);
1585
1586         return E_NOTIMPL;
1587 }
1588
1589 static HRESULT WINAPI
1590 IMediaPosition_fnInvoke(IMediaPosition* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
1591 {
1592         CParserOutPinImpl_THIS(iface,mediaposition);
1593
1594         FIXME("(%p)->() stub!\n",This);
1595
1596         return E_NOTIMPL;
1597 }
1598
1599
1600 static HRESULT WINAPI
1601 IMediaPosition_fnget_Duration(IMediaPosition* iface,REFTIME* prefTime)
1602 {
1603         CParserOutPinImpl_THIS(iface,mediaposition);
1604
1605         FIXME("(%p)->() stub!\n",This);
1606
1607         return E_NOTIMPL;
1608 }
1609
1610 static HRESULT WINAPI
1611 IMediaPosition_fnput_CurrentPosition(IMediaPosition* iface,REFTIME refTime)
1612 {
1613         CParserOutPinImpl_THIS(iface,mediaposition);
1614
1615         FIXME("(%p)->() stub!\n",This);
1616
1617         return E_NOTIMPL;
1618 }
1619
1620 static HRESULT WINAPI
1621 IMediaPosition_fnget_CurrentPosition(IMediaPosition* iface,REFTIME* prefTime)
1622 {
1623         CParserOutPinImpl_THIS(iface,mediaposition);
1624
1625         FIXME("(%p)->() stub!\n",This);
1626
1627         return E_NOTIMPL;
1628 }
1629
1630 static HRESULT WINAPI
1631 IMediaPosition_fnget_StopTime(IMediaPosition* iface,REFTIME* prefTime)
1632 {
1633         CParserOutPinImpl_THIS(iface,mediaposition);
1634
1635         FIXME("(%p)->() stub!\n",This);
1636
1637         return E_NOTIMPL;
1638 }
1639
1640 static HRESULT WINAPI
1641 IMediaPosition_fnput_StopTime(IMediaPosition* iface,REFTIME refTime)
1642 {
1643         CParserOutPinImpl_THIS(iface,mediaposition);
1644
1645         FIXME("(%p)->() stub!\n",This);
1646
1647         return E_NOTIMPL;
1648 }
1649
1650 static HRESULT WINAPI
1651 IMediaPosition_fnget_PrerollTime(IMediaPosition* iface,REFTIME* prefTime)
1652 {
1653         CParserOutPinImpl_THIS(iface,mediaposition);
1654
1655         FIXME("(%p)->() stub!\n",This);
1656
1657         return E_NOTIMPL;
1658 }
1659
1660 static HRESULT WINAPI
1661 IMediaPosition_fnput_PrerollTime(IMediaPosition* iface,REFTIME refTime)
1662 {
1663         CParserOutPinImpl_THIS(iface,mediaposition);
1664
1665         FIXME("(%p)->() stub!\n",This);
1666
1667         return E_NOTIMPL;
1668 }
1669
1670 static HRESULT WINAPI
1671 IMediaPosition_fnput_Rate(IMediaPosition* iface,double dblRate)
1672 {
1673         CParserOutPinImpl_THIS(iface,mediaposition);
1674
1675         return IMediaSeeking_SetRate(CParserOutPinImpl_IMediaSeeking(This),dblRate);
1676 }
1677
1678 static HRESULT WINAPI
1679 IMediaPosition_fnget_Rate(IMediaPosition* iface,double* pdblRate)
1680 {
1681         CParserOutPinImpl_THIS(iface,mediaposition);
1682
1683         return IMediaSeeking_GetRate(CParserOutPinImpl_IMediaSeeking(This),pdblRate);
1684 }
1685
1686 static HRESULT WINAPI
1687 IMediaPosition_fnCanSeekForward(IMediaPosition* iface,LONG* pCanSeek)
1688 {
1689         CParserOutPinImpl_THIS(iface,mediaposition);
1690
1691         FIXME("(%p)->() stub!\n",This);
1692
1693         return E_NOTIMPL;
1694 }
1695
1696 static HRESULT WINAPI
1697 IMediaPosition_fnCanSeekBackward(IMediaPosition* iface,LONG* pCanSeek)
1698 {
1699         CParserOutPinImpl_THIS(iface,mediaposition);
1700
1701         FIXME("(%p)->() stub!\n",This);
1702
1703         return E_NOTIMPL;
1704 }
1705
1706
1707 static ICOM_VTABLE(IMediaPosition) imediaposition =
1708 {
1709         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1710         /* IUnknown fields */
1711         IMediaPosition_fnQueryInterface,
1712         IMediaPosition_fnAddRef,
1713         IMediaPosition_fnRelease,
1714         /* IDispatch fields */
1715         IMediaPosition_fnGetTypeInfoCount,
1716         IMediaPosition_fnGetTypeInfo,
1717         IMediaPosition_fnGetIDsOfNames,
1718         IMediaPosition_fnInvoke,
1719         /* IMediaPosition fields */
1720         IMediaPosition_fnget_Duration,
1721         IMediaPosition_fnput_CurrentPosition,
1722         IMediaPosition_fnget_CurrentPosition,
1723         IMediaPosition_fnget_StopTime,
1724         IMediaPosition_fnput_StopTime,
1725         IMediaPosition_fnget_PrerollTime,
1726         IMediaPosition_fnput_PrerollTime,
1727         IMediaPosition_fnput_Rate,
1728         IMediaPosition_fnget_Rate,
1729         IMediaPosition_fnCanSeekForward,
1730         IMediaPosition_fnCanSeekBackward,
1731 };
1732
1733
1734 HRESULT CParserOutPinImpl_InitIMediaPosition( CParserOutPinImpl* This )
1735 {
1736         TRACE("(%p)\n",This);
1737         ICOM_VTBL(&This->mediaposition) = &imediaposition;
1738
1739         return NOERROR;
1740 }
1741
1742 void CParserOutPinImpl_UninitIMediaPosition( CParserOutPinImpl* This )
1743 {
1744         TRACE("(%p)\n",This);
1745 }
1746