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