Added a framework for testing CreateProcess and a few tests.
[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_bIsRunning )
572         {
573                 TRACE("(%p) - already running\n",This);
574                 return NOERROR;
575         }
576
577         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
578         if ( This->m_hEventInit == (HANDLE)NULL )
579                 return E_OUTOFMEMORY;
580
581         /* create the processing thread. */
582         This->m_hThread = CreateThread(
583                 NULL, 0,
584                 CParserImplThread_Entry,
585                 (LPVOID)This,
586                 0, &This->m_dwThreadId );
587         if ( This->m_hThread == (HANDLE)NULL )
588         {
589                 CloseHandle( This->m_hEventInit );
590                 This->m_hEventInit = (HANDLE)NULL;
591                 return E_FAIL;
592         }
593
594         hEvents[0] = This->m_hEventInit;
595         hEvents[1] = This->m_hThread;
596
597         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
598
599         ResetEvent( This->m_hEventInit );
600         CloseHandle( This->m_hThread );
601         This->m_hThread = (HANDLE)NULL;
602
603         if ( dwRes != WAIT_OBJECT_0 )
604                 return E_FAIL;
605
606         This->m_bIsRunning = TRUE;
607
608         return NOERROR;
609 }
610
611 static
612 BOOL CParserImpl_EndThread( CParserImpl* This, BOOL bAsync )
613 {
614         DWORD   dwThreadId;
615
616         TRACE("(%p)\n",This);
617         dwThreadId = This->m_dwThreadId;
618         if ( This->m_hEventInit != (HANDLE)NULL )
619         {
620                 if ( dwThreadId != 0 )
621                         PostThreadMessageA(
622                                 dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 );
623                 if ( bAsync &&
624                          WaitForSingleObject( This->m_hEventInit, 0 ) == WAIT_TIMEOUT )
625                         return FALSE;
626
627                 WaitForSingleObject( This->m_hEventInit, INFINITE );
628                 CloseHandle( This->m_hEventInit );
629                 This->m_bIsRunning = FALSE;
630                 This->m_hEventInit = (HANDLE)NULL;
631         }
632
633         return TRUE;
634 }
635
636 static
637 HRESULT CParserImpl_MemCommit( CParserImpl* This )
638 {
639         HRESULT hr;
640         ULONG   nIndex;
641         IMemAllocator*  pAlloc;
642
643         TRACE("(%p)\n",This);
644
645         if ( This->m_pAllocator == NULL )
646                 return E_UNEXPECTED;
647
648         hr = IMemAllocator_Commit( This->m_pAllocator );
649         if ( FAILED(hr) )
650                 return hr;
651
652         if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
653         {
654                 for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
655                 {
656                         pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
657                         if ( pAlloc != NULL && pAlloc != This->m_pAllocator )
658                         {
659                                 hr = IMemAllocator_Commit( pAlloc );
660                                 if ( FAILED(hr) )
661                                         return hr;
662                         }
663                 }
664         }
665
666         return NOERROR;
667 }
668
669 static
670 HRESULT CParserImpl_GetPreferredTimeFormat( CParserImpl* This, GUID* pguidFormat )
671 {
672         static const GUID* tryformats[] =
673         {
674                 &TIME_FORMAT_MEDIA_TIME,
675                 &TIME_FORMAT_FRAME,
676                 &TIME_FORMAT_SAMPLE,
677                 &TIME_FORMAT_FIELD,
678                 &TIME_FORMAT_BYTE,
679                 NULL,
680         };
681         DWORD   n;
682
683         if ( This->m_pHandler->pIsTimeFormatSupported == NULL )
684                 return E_NOTIMPL;
685
686         n = 0;
687         while ( tryformats[n] != NULL )
688         {
689                 if ( This->m_pHandler->pIsTimeFormatSupported( This, tryformats[n] ) == S_OK )
690                 {
691                         memcpy( pguidFormat, tryformats[n], sizeof(GUID) );
692                         return S_OK;
693                 }
694                 n ++;
695         }
696
697         return E_FAIL;
698
699 }
700
701
702 /***************************************************************************
703  *
704  *      CParserImpl methods
705  *
706  */
707
708 static HRESULT CParserImpl_OnActive( CBaseFilterImpl* pImpl )
709 {
710         CParserImpl_THIS(pImpl,basefilter);
711
712         TRACE( "(%p)\n", This );
713
714         if ( !CParserImpl_OutPinsAreConnected(This) )
715                 return NOERROR;
716
717         return NOERROR;
718 }
719
720 static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl )
721 {
722         CParserImpl_THIS(pImpl,basefilter);
723         HRESULT hr;
724
725         TRACE( "(%p)\n", This );
726
727         if ( !CParserImpl_OutPinsAreConnected(This) )
728                 return NOERROR;
729
730         hr = CParserImpl_MemCommit(This);
731         if ( FAILED(hr) )
732                 return hr;
733
734         if ( This->basefilter.fstate == State_Stopped )
735                 CParserImpl_EndThread(This,FALSE);
736
737         hr = CParserImpl_BeginThread(This);
738         if ( FAILED(hr) )
739         {
740                 FIXME("CParserImpl_BeginThread returns %08lx\n",hr);
741                 CParserImpl_EndThread(This,FALSE);
742                 return hr;
743         }
744
745         return NOERROR;
746 }
747
748 static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl )
749 {
750         CParserImpl_THIS(pImpl,basefilter);
751
752         TRACE( "(%p)\n", This );
753
754         This->basefilter.bIntermediateState = TRUE;
755         if ( !CParserImpl_EndThread(This,TRUE) )
756                 return VFW_S_STATE_INTERMEDIATE;
757
758         This->basefilter.bIntermediateState = FALSE;
759         return NOERROR;
760 }
761
762
763 static const CBaseFilterHandlers filterhandlers =
764 {
765         CParserImpl_OnActive, /* pOnActive */
766         CParserImpl_OnInactive, /* pOnInactive */
767         CParserImpl_OnStop, /* pOnStop */
768 };
769
770
771 /***************************************************************************
772  *
773  *      CParserInPinImpl methods
774  *
775  */
776
777 static HRESULT CParserInPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
778 {
779         CParserInPinImpl_THIS(pImpl,pin);
780         HRESULT hr;
781         ULONG   nIndex;
782         IUnknown*       punk;
783         IAsyncReader* pReader = NULL;
784         LPCWSTR pwszOutPinName;
785         IMemAllocator*  pAllocActual;
786         AM_MEDIA_TYPE*  pmt;
787
788         TRACE("(%p,%p)\n",This,pPin);
789
790         if ( This->pParser->m_pHandler->pInitParser == NULL ||
791                  This->pParser->m_pHandler->pUninitParser == NULL ||
792                  This->pParser->m_pHandler->pGetOutPinName == NULL ||
793                  This->pParser->m_pHandler->pGetStreamType == NULL ||
794                  This->pParser->m_pHandler->pCheckStreamType == NULL ||
795                  This->pParser->m_pHandler->pGetAllocProp == NULL ||
796                  This->pParser->m_pHandler->pGetNextRequest == NULL )
797         {
798                 FIXME("this parser is not implemented.\n");
799                 return E_NOTIMPL;
800         }
801
802         /* at first, release all output pins. */
803         if ( CParserImpl_OutPinsAreConnected(This->pParser) )
804                 return E_FAIL;
805         CParserImpl_ReleaseListOfOutPins(This->pParser);
806         CParserImpl_ReleaseOutPins(This->pParser);
807
808         CParserImpl_SetAsyncReader( This->pParser, NULL );
809         hr = IPin_QueryInterface( pPin, &IID_IAsyncReader, (void**)&pReader );
810         if ( FAILED(hr) )
811                 return hr;
812         CParserImpl_SetAsyncReader( This->pParser, pReader );
813         IAsyncReader_Release(pReader);
814
815         /* initialize parser. */
816         hr = This->pParser->m_pHandler->pInitParser(This->pParser,&This->pParser->m_cOutStreams);
817         if ( FAILED(hr) )
818                 return hr;
819         This->pParser->m_ppOutPins = (CParserOutPinImpl**)QUARTZ_AllocMem(
820                 sizeof(CParserOutPinImpl*) * This->pParser->m_cOutStreams );
821         if ( This->pParser->m_ppOutPins == NULL )
822                 return E_OUTOFMEMORY;
823         for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
824                 This->pParser->m_ppOutPins[nIndex] = NULL;
825
826         /* create and initialize an allocator. */
827         hr = This->pParser->m_pHandler->pGetAllocProp(This->pParser,&This->pParser->m_propAlloc);
828         if ( FAILED(hr) )
829                 return hr;
830         if ( This->pParser->m_propAlloc.cbAlign == 0 )
831                 This->pParser->m_propAlloc.cbAlign = 1;
832
833         if ( This->pParser->m_pAllocator == NULL )
834         {
835                 hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
836                 if ( FAILED(hr) )
837                         return hr;
838                 hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&This->pParser->m_pAllocator );
839                 IUnknown_Release(punk);
840                 if ( FAILED(hr) )
841                         return hr;
842         }
843         pAllocActual = NULL;
844         hr = IAsyncReader_RequestAllocator(pReader,This->pParser->m_pAllocator,&This->pParser->m_propAlloc,&pAllocActual);
845         if ( FAILED(hr) )
846                 return hr;
847         IMemAllocator_Release(This->pParser->m_pAllocator);
848         This->pParser->m_pAllocator = pAllocActual;
849
850         /* create output pins. */
851         for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
852         {
853                 pwszOutPinName = This->pParser->m_pHandler->pGetOutPinName(This->pParser,nIndex);
854                 if ( pwszOutPinName == NULL )
855                         return E_FAIL;
856                 hr = QUARTZ_CreateParserOutPin(
857                         This->pParser,
858                         &This->pParser->m_csParser,
859                         &This->pParser->m_ppOutPins[nIndex],
860                         nIndex, pwszOutPinName );
861                 if ( SUCCEEDED(hr) )
862                         hr = QUARTZ_CompList_AddTailComp(
863                                 This->pParser->basefilter.pOutPins,
864                                 (IUnknown*)&(This->pParser->m_ppOutPins[nIndex]->pin),
865                                 NULL, 0 );
866                 if ( FAILED(hr) )
867                         return hr;
868                 pmt = &This->pParser->m_ppOutPins[nIndex]->m_mtOut;
869                 QUARTZ_MediaType_Free( pmt );
870                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
871                 hr = This->pParser->m_pHandler->pGetStreamType(This->pParser,nIndex,pmt);
872                 if ( FAILED(hr) )
873                 {
874                         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
875                         return hr;
876                 }
877                 This->pParser->m_ppOutPins[nIndex]->pin.cAcceptTypes = 1;
878                 This->pParser->m_ppOutPins[nIndex]->pin.pmtAcceptTypes = pmt;
879         }
880
881         return NOERROR;
882 }
883
884 static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
885 {
886         CParserInPinImpl_THIS(pImpl,pin);
887
888         /* assume the graph is already stopped */
889         /*CParserImpl_OnInactive(&This->pParser->basefilter);*/
890         /*CParserImpl_OnStop(&This->pParser->basefilter);*/
891         if ( This->pParser->m_pHandler->pUninitParser != NULL )
892                 This->pParser->m_pHandler->pUninitParser(This->pParser);
893         CParserImpl_SetAsyncReader( This->pParser, NULL );
894         if ( This->pParser->m_pAllocator != NULL )
895         {
896                 IMemAllocator_Decommit(This->pParser->m_pAllocator);
897                 IMemAllocator_Release(This->pParser->m_pAllocator);
898                 This->pParser->m_pAllocator = NULL;
899         }
900
901         return NOERROR;
902 }
903
904 static HRESULT CParserInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
905 {
906         CParserInPinImpl_THIS(pImpl,pin);
907
908         TRACE("(%p,%p)\n",This,pmt);
909
910         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
911                 return E_FAIL;
912
913         return NOERROR;
914 }
915
916 static const CBasePinHandlers inputpinhandlers =
917 {
918         CParserInPinImpl_OnPreConnect, /* pOnPreConnect */
919         NULL, /* pOnPostConnect */
920         CParserInPinImpl_OnDisconnect, /* pOnDisconnect */
921         CParserInPinImpl_CheckMediaType, /* pCheckMediaType */
922         NULL, /* pQualityNotify */
923         NULL, /* pReceive */
924         NULL, /* pReceiveCanBlock */
925         NULL, /* pEndOfStream */
926         NULL, /* pBeginFlush */
927         NULL, /* pEndFlush */
928         NULL, /* pNewSegment */
929 };
930
931 /***************************************************************************
932  *
933  *      CParserOutPinImpl methods
934  *
935  */
936
937 static HRESULT CParserOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
938 {
939         CParserOutPinImpl_THIS(pImpl,pin);
940         ALLOCATOR_PROPERTIES    propReq;
941         ALLOCATOR_PROPERTIES    propActual;
942         IMemAllocator*  pAllocator;
943         HRESULT hr;
944         BOOL    bNewAllocator = FALSE;
945
946         TRACE("(%p,%p)\n",This,pPin);
947
948         if ( This->pin.pMemInputPinConnectedTo == NULL )
949                 return E_UNEXPECTED;
950
951         if ( This->m_pOutPinAllocator != NULL )
952         {
953                 IMemAllocator_Release(This->m_pOutPinAllocator);
954                 This->m_pOutPinAllocator = NULL;
955         }
956
957         /* try to use This->pParser->m_pAllocator. */
958         ZeroMemory( &propReq, sizeof(ALLOCATOR_PROPERTIES) );
959         hr = IMemInputPin_GetAllocatorRequirements(
960                 This->pin.pMemInputPinConnectedTo, &propReq );
961         if ( propReq.cbAlign != 0 )
962         {
963                 if ( This->pParser->m_propAlloc.cbAlign != ( This->pParser->m_propAlloc.cbAlign / propReq.cbAlign * propReq.cbAlign ) )
964                         bNewAllocator = TRUE;
965         }
966         if ( propReq.cbPrefix != 0 )
967                 bNewAllocator = TRUE;
968         if ( !bNewAllocator )
969         {
970                 hr = IMemInputPin_NotifyAllocator(
971                         This->pin.pMemInputPinConnectedTo,
972                         This->pParser->m_pAllocator, FALSE );
973                 if ( hr == NOERROR )
974                 {
975                         This->m_pOutPinAllocator = This->pParser->m_pAllocator;
976                         IMemAllocator_AddRef(This->m_pOutPinAllocator);
977                         return NOERROR;
978                 }
979         }
980
981         hr = IMemInputPin_GetAllocator(
982                         This->pin.pMemInputPinConnectedTo, &pAllocator );
983         if ( FAILED(hr) )
984                 return hr;
985         hr = IMemAllocator_SetProperties( pAllocator, &This->pParser->m_propAlloc, &propActual );
986         if ( SUCCEEDED(hr) )
987                 hr = IMemInputPin_NotifyAllocator(
988                         This->pin.pMemInputPinConnectedTo, pAllocator, FALSE );
989         if ( FAILED(hr) )
990         {
991                 IMemAllocator_Release(pAllocator);
992                 return hr;
993         }
994
995         This->m_pOutPinAllocator = pAllocator;
996         return NOERROR;
997 }
998
999 static HRESULT CParserOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
1000 {
1001         CParserOutPinImpl_THIS(pImpl,pin);
1002
1003         if ( This->m_pOutPinAllocator != NULL )
1004         {
1005                 IMemAllocator_Release(This->m_pOutPinAllocator);
1006                 This->m_pOutPinAllocator = NULL;
1007         }
1008
1009         return NOERROR;
1010 }
1011
1012 static HRESULT CParserOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
1013 {
1014         CParserOutPinImpl_THIS(pImpl,pin);
1015         HRESULT hr;
1016
1017         TRACE("(%p,%p)\n",This,pmt);
1018         if ( pmt == NULL )
1019                 return E_POINTER;
1020
1021         if ( This->pParser->m_pHandler->pCheckStreamType == NULL )
1022                 return E_NOTIMPL;
1023
1024         hr = This->pParser->m_pHandler->pCheckStreamType( This->pParser, This->nStreamIndex, pmt );
1025         if ( FAILED(hr) )
1026                 return hr;
1027
1028         return NOERROR;
1029 }
1030
1031
1032 static const CBasePinHandlers outputpinhandlers =
1033 {
1034         NULL, /* pOnPreConnect */
1035         CParserOutPinImpl_OnPostConnect, /* pOnPostConnect */
1036         CParserOutPinImpl_OnDisconnect, /* pOnDisconnect */
1037         CParserOutPinImpl_CheckMediaType, /* pCheckMediaType */
1038         NULL, /* pQualityNotify */
1039         OutputPinSync_Receive, /* pReceive */
1040         OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
1041         OutputPinSync_EndOfStream, /* pEndOfStream */
1042         OutputPinSync_BeginFlush, /* pBeginFlush */
1043         OutputPinSync_EndFlush, /* pEndFlush */
1044         OutputPinSync_NewSegment, /* pNewSegment */
1045 };
1046
1047 /***************************************************************************
1048  *
1049  *      new/delete CParserImpl
1050  *
1051  */
1052
1053 /* can I use offsetof safely? - FIXME? */
1054 static QUARTZ_IFEntry FilterIFEntries[] =
1055 {
1056   { &IID_IPersist, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
1057   { &IID_IMediaFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
1058   { &IID_IBaseFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
1059 };
1060
1061 static void QUARTZ_DestroyParser(IUnknown* punk)
1062 {
1063         CParserImpl_THIS(punk,unk);
1064
1065         TRACE( "(%p)\n", This );
1066
1067         if ( This->m_pInPin != NULL )
1068                 CParserInPinImpl_OnDisconnect(&This->m_pInPin->pin);
1069
1070         CParserImpl_SetAsyncReader( This, NULL );
1071         if ( This->m_pAllocator != NULL )
1072         {
1073                 IMemAllocator_Release(This->m_pAllocator);
1074                 This->m_pAllocator = NULL;
1075         }
1076         if ( This->m_pInPin != NULL )
1077         {
1078                 IUnknown_Release(This->m_pInPin->unk.punkControl);
1079                 This->m_pInPin = NULL;
1080         }
1081         CParserImpl_ReleaseOutPins( This );
1082
1083         DeleteCriticalSection( &This->m_csParser );
1084
1085         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
1086 }
1087
1088 HRESULT QUARTZ_CreateParser(
1089         IUnknown* punkOuter,void** ppobj,
1090         const CLSID* pclsidParser,
1091         LPCWSTR pwszParserName,
1092         LPCWSTR pwszInPinName,
1093         const ParserHandlers* pHandler )
1094 {
1095         CParserImpl*    This = NULL;
1096         HRESULT hr;
1097
1098         TRACE("(%p,%p)\n",punkOuter,ppobj);
1099
1100         This = (CParserImpl*)
1101                 QUARTZ_AllocObj( sizeof(CParserImpl) );
1102         if ( This == NULL )
1103                 return E_OUTOFMEMORY;
1104         ZeroMemory( This, sizeof(CParserImpl) );
1105
1106         This->m_pInPin = NULL;
1107         This->m_cOutStreams = 0;
1108         This->m_ppOutPins = NULL;
1109         memcpy( &This->m_guidTimeFormat, &TIME_FORMAT_NONE, sizeof(GUID) );
1110         This->m_pReader = NULL;
1111         This->m_pAllocator = NULL;
1112         ZeroMemory( &This->m_propAlloc, sizeof(ALLOCATOR_PROPERTIES) );
1113         This->m_hEventInit = (HANDLE)NULL;
1114         This->m_bIsRunning = FALSE;
1115         This->m_hThread = (HANDLE)NULL;
1116         This->m_dwThreadId = 0;
1117         This->m_bSendEOS = FALSE;
1118         This->m_pHandler = pHandler;
1119         This->m_pUserData = NULL;
1120
1121         QUARTZ_IUnkInit( &This->unk, punkOuter );
1122
1123         hr = CBaseFilterImpl_InitIBaseFilter(
1124                 &This->basefilter,
1125                 This->unk.punkControl,
1126                 pclsidParser,
1127                 pwszParserName,
1128                 &filterhandlers );
1129         if ( SUCCEEDED(hr) )
1130         {
1131                 /* construct this class. */
1132                 hr = S_OK;
1133
1134                 if ( FAILED(hr) )
1135                 {
1136                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
1137                 }
1138         }
1139
1140         if ( FAILED(hr) )
1141         {
1142                 QUARTZ_FreeObj(This);
1143                 return hr;
1144         }
1145
1146         This->unk.pEntries = FilterIFEntries;
1147         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
1148         This->unk.pOnFinalRelease = QUARTZ_DestroyParser;
1149         InitializeCriticalSection( &This->m_csParser );
1150
1151         /* create the input pin. */
1152         hr = QUARTZ_CreateParserInPin(
1153                 This,
1154                 &This->m_csParser,
1155                 &This->m_pInPin,
1156                 pwszInPinName );
1157         if ( SUCCEEDED(hr) )
1158                 hr = QUARTZ_CompList_AddComp(
1159                         This->basefilter.pInPins,
1160                         (IUnknown*)&(This->m_pInPin->pin),
1161                         NULL, 0 );
1162
1163         if ( FAILED(hr) )
1164         {
1165                 IUnknown_Release( This->unk.punkControl );
1166                 return hr;
1167         }
1168
1169         *ppobj = (void*)&(This->unk);
1170
1171         (void)CParserImpl_GetPreferredTimeFormat( This, &This->m_guidTimeFormat );
1172
1173         return S_OK;
1174 }
1175
1176 /***************************************************************************
1177  *
1178  *      new/delete CParserInPinImpl
1179  *
1180  */
1181
1182 /* can I use offsetof safely? - FIXME? */
1183 static QUARTZ_IFEntry InPinIFEntries[] =
1184 {
1185   { &IID_IPin, offsetof(CParserInPinImpl,pin)-offsetof(CParserInPinImpl,unk) },
1186   { &IID_IMemInputPin, offsetof(CParserInPinImpl,meminput)-offsetof(CParserInPinImpl,unk) },
1187 };
1188
1189 static void QUARTZ_DestroyParserInPin(IUnknown* punk)
1190 {
1191         CParserInPinImpl_THIS(punk,unk);
1192
1193         TRACE( "(%p)\n", This );
1194
1195         CPinBaseImpl_UninitIPin( &This->pin );
1196         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
1197 }
1198
1199 HRESULT QUARTZ_CreateParserInPin(
1200         CParserImpl* pFilter,
1201         CRITICAL_SECTION* pcsPin,
1202         CParserInPinImpl** ppPin,
1203         LPCWSTR pwszPinName )
1204 {
1205         CParserInPinImpl*       This = NULL;
1206         HRESULT hr;
1207
1208         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1209
1210         This = (CParserInPinImpl*)
1211                 QUARTZ_AllocObj( sizeof(CParserInPinImpl) );
1212         if ( This == NULL )
1213                 return E_OUTOFMEMORY;
1214
1215         QUARTZ_IUnkInit( &This->unk, NULL );
1216         This->pParser = pFilter;
1217
1218         hr = CPinBaseImpl_InitIPin(
1219                 &This->pin,
1220                 This->unk.punkControl,
1221                 pcsPin, NULL,
1222                 &pFilter->basefilter,
1223                 pwszPinName,
1224                 FALSE,
1225                 &inputpinhandlers );
1226
1227         if ( SUCCEEDED(hr) )
1228         {
1229                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
1230                         &This->meminput,
1231                         This->unk.punkControl,
1232                         &This->pin );
1233                 if ( FAILED(hr) )
1234                 {
1235                         CPinBaseImpl_UninitIPin( &This->pin );
1236                 }
1237         }
1238
1239         if ( FAILED(hr) )
1240         {
1241                 QUARTZ_FreeObj(This);
1242                 return hr;
1243         }
1244
1245         This->unk.pEntries = InPinIFEntries;
1246         This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
1247         This->unk.pOnFinalRelease = QUARTZ_DestroyParserInPin;
1248
1249         *ppPin = This;
1250
1251         TRACE("returned successfully.\n");
1252
1253         return S_OK;
1254 }
1255
1256
1257 /***************************************************************************
1258  *
1259  *      new/delete CParserOutPinImpl
1260  *
1261  */
1262
1263 /* can I use offsetof safely? - FIXME? */
1264 static QUARTZ_IFEntry OutPinIFEntries[] =
1265 {
1266   { &IID_IPin, offsetof(CParserOutPinImpl,pin)-offsetof(CParserOutPinImpl,unk) },
1267   { &IID_IQualityControl, offsetof(CParserOutPinImpl,qcontrol)-offsetof(CParserOutPinImpl,unk) },
1268   { &IID_IMediaSeeking, offsetof(CParserOutPinImpl,mediaseeking)-offsetof(CParserOutPinImpl,unk) },
1269   { &IID_IMediaPosition, offsetof(CParserOutPinImpl,mediaposition)-offsetof(CParserOutPinImpl,unk) },
1270 };
1271
1272 static void QUARTZ_DestroyParserOutPin(IUnknown* punk)
1273 {
1274         CParserOutPinImpl_THIS(punk,unk);
1275
1276         TRACE( "(%p)\n", This );
1277
1278         QUARTZ_MediaType_Free( &This->m_mtOut );
1279         if ( This->m_pOutPinAllocator != NULL )
1280                 IMemAllocator_Release(This->m_pOutPinAllocator);
1281
1282         CParserOutPinImpl_UninitIMediaPosition(This);
1283         CParserOutPinImpl_UninitIMediaSeeking(This);
1284         CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
1285         CPinBaseImpl_UninitIPin( &This->pin );
1286
1287 }
1288
1289 HRESULT QUARTZ_CreateParserOutPin(
1290         CParserImpl* pFilter,
1291         CRITICAL_SECTION* pcsPin,
1292         CParserOutPinImpl** ppPin,
1293         ULONG nStreamIndex,
1294         LPCWSTR pwszPinName )
1295 {
1296         CParserOutPinImpl*      This = NULL;
1297         HRESULT hr;
1298
1299         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1300
1301         This = (CParserOutPinImpl*)
1302                 QUARTZ_AllocObj( sizeof(CParserOutPinImpl) );
1303         if ( This == NULL )
1304                 return E_OUTOFMEMORY;
1305
1306         QUARTZ_IUnkInit( &This->unk, NULL );
1307         This->pParser = pFilter;
1308         This->nStreamIndex = nStreamIndex;
1309         ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
1310         This->m_pOutPinAllocator = NULL;
1311         This->m_pUserData = NULL;
1312         This->m_bReqUsed = FALSE;
1313         This->m_pReqSample = NULL;
1314         This->m_llReqStart = 0;
1315         This->m_lReqLength = 0;
1316         This->m_rtReqStart = 0;
1317         This->m_rtReqStop = 0;
1318         This->m_dwSampleFlags = 0;
1319
1320
1321         hr = CPinBaseImpl_InitIPin(
1322                 &This->pin,
1323                 This->unk.punkControl,
1324                 pcsPin, NULL,
1325                 &pFilter->basefilter,
1326                 pwszPinName,
1327                 TRUE,
1328                 &outputpinhandlers );
1329
1330         if ( SUCCEEDED(hr) )
1331         {
1332                 hr = CQualityControlPassThruImpl_InitIQualityControl(
1333                         &This->qcontrol,
1334                         This->unk.punkControl,
1335                         &This->pin );
1336                 if ( SUCCEEDED(hr) )
1337                 {
1338                         hr = CParserOutPinImpl_InitIMediaSeeking(This);
1339                         if ( SUCCEEDED(hr) )
1340                         {
1341                                 hr = CParserOutPinImpl_InitIMediaPosition(This);
1342                                 if ( FAILED(hr) )
1343                                 {
1344                                         CParserOutPinImpl_UninitIMediaSeeking(This);
1345                                 }
1346                         }
1347                         if ( FAILED(hr) )
1348                         {
1349                                 CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
1350                         }
1351                 }
1352                 if ( FAILED(hr) )
1353                 {
1354                         CPinBaseImpl_UninitIPin( &This->pin );
1355                 }
1356         }
1357
1358         if ( FAILED(hr) )
1359         {
1360                 QUARTZ_FreeObj(This);
1361                 return hr;
1362         }
1363
1364         This->unk.pEntries = OutPinIFEntries;
1365         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1366         This->unk.pOnFinalRelease = QUARTZ_DestroyParserOutPin;
1367
1368         *ppPin = This;
1369
1370         TRACE("returned successfully.\n");
1371
1372         return S_OK;
1373 }
1374
1375
1376 /***************************************************************************
1377  *
1378  *      IMediaSeeking for CParserOutPinImpl
1379  *
1380  */
1381
1382 static HRESULT WINAPI
1383 IMediaSeeking_fnQueryInterface(IMediaSeeking* iface,REFIID riid,void** ppobj)
1384 {
1385         CParserOutPinImpl_THIS(iface,mediaseeking);
1386
1387         TRACE("(%p)->()\n",This);
1388
1389         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1390 }
1391
1392 static ULONG WINAPI
1393 IMediaSeeking_fnAddRef(IMediaSeeking* iface)
1394 {
1395         CParserOutPinImpl_THIS(iface,mediaseeking);
1396
1397         TRACE("(%p)->()\n",This);
1398
1399         return IUnknown_AddRef(This->unk.punkControl);
1400 }
1401
1402 static ULONG WINAPI
1403 IMediaSeeking_fnRelease(IMediaSeeking* iface)
1404 {
1405         CParserOutPinImpl_THIS(iface,mediaseeking);
1406
1407         TRACE("(%p)->()\n",This);
1408
1409         return IUnknown_Release(This->unk.punkControl);
1410 }
1411
1412
1413 static HRESULT WINAPI
1414 IMediaSeeking_fnGetCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
1415 {
1416         CParserOutPinImpl_THIS(iface,mediaseeking);
1417         HRESULT hr = E_NOTIMPL;
1418
1419         TRACE("(%p)->(%p)\n",This,pdwCaps);
1420
1421         if ( pdwCaps == NULL )
1422                 return E_POINTER;
1423
1424         EnterCriticalSection( &This->pParser->m_csParser );
1425         if ( This->pParser->m_pHandler->pGetSeekingCaps == NULL )
1426         {
1427                 FIXME("(%p)->(%p) not implemented\n",This,pdwCaps);
1428         }
1429         else
1430         {
1431                 hr = This->pParser->m_pHandler->pGetSeekingCaps( This->pParser, pdwCaps );
1432         }
1433         LeaveCriticalSection( &This->pParser->m_csParser );
1434
1435         return hr;
1436 }
1437
1438 static HRESULT WINAPI
1439 IMediaSeeking_fnCheckCapabilities(IMediaSeeking* iface,DWORD* pdwCaps)
1440 {
1441         CParserOutPinImpl_THIS(iface,mediaseeking);
1442         HRESULT hr = E_NOTIMPL;
1443         DWORD   dwCaps;
1444
1445         TRACE("(%p)->(%p)\n",This,pdwCaps);
1446
1447         if ( pdwCaps == NULL )
1448                 return E_POINTER;
1449
1450         EnterCriticalSection( &This->pParser->m_csParser );
1451         if ( This->pParser->m_pHandler->pGetSeekingCaps == NULL )
1452         {
1453                 FIXME("(%p)->(%p) not implemented\n",This,pdwCaps);
1454         }
1455         else
1456         {
1457                 hr = This->pParser->m_pHandler->pGetSeekingCaps( This->pParser, &dwCaps );
1458                 if ( SUCCEEDED(hr) )
1459                 {
1460                         dwCaps &= *pdwCaps;
1461                         if ( dwCaps == *pdwCaps )
1462                                 hr = S_OK;
1463                         else
1464                         if ( dwCaps != 0 )
1465                                 hr = S_FALSE;
1466                         else
1467                                 hr = E_FAIL;
1468                         *pdwCaps = dwCaps;
1469                 }
1470         }
1471         LeaveCriticalSection( &This->pParser->m_csParser );
1472
1473         return hr;
1474
1475         return E_NOTIMPL;
1476 }
1477
1478 static HRESULT WINAPI
1479 IMediaSeeking_fnIsFormatSupported(IMediaSeeking* iface,const GUID* pidFormat)
1480 {
1481         CParserOutPinImpl_THIS(iface,mediaseeking);
1482         HRESULT hr = E_NOTIMPL;
1483
1484         TRACE("(%p)->(%s)\n",This,debugstr_guid(pidFormat));
1485
1486         if ( pidFormat == NULL )
1487                 return E_POINTER;
1488
1489         EnterCriticalSection( &This->pParser->m_csParser );
1490         if ( This->pParser->m_pHandler->pIsTimeFormatSupported == NULL )
1491         {
1492                 FIXME("(%p)->(%s) not implemented\n",This,debugstr_guid(pidFormat));
1493         }
1494         else
1495         {
1496                 hr = This->pParser->m_pHandler->pIsTimeFormatSupported( This->pParser, pidFormat );
1497         }
1498         LeaveCriticalSection( &This->pParser->m_csParser );
1499
1500         return hr;
1501 }
1502
1503 static HRESULT WINAPI
1504 IMediaSeeking_fnQueryPreferredFormat(IMediaSeeking* iface,GUID* pidFormat)
1505 {
1506         CParserOutPinImpl_THIS(iface,mediaseeking);
1507         HRESULT hr;
1508
1509         TRACE("(%p)->(%p)\n",This,pidFormat);
1510
1511         EnterCriticalSection( &This->pParser->m_csParser );
1512         hr = CParserImpl_GetPreferredTimeFormat( This->pParser, pidFormat );
1513         LeaveCriticalSection( &This->pParser->m_csParser );
1514
1515         return hr;
1516 }
1517
1518 static HRESULT WINAPI
1519 IMediaSeeking_fnGetTimeFormat(IMediaSeeking* iface,GUID* pidFormat)
1520 {
1521         CParserOutPinImpl_THIS(iface,mediaseeking);
1522         HRESULT hr = E_NOTIMPL;
1523
1524         TRACE("(%p)->(%p)\n",This,pidFormat);
1525
1526         if ( pidFormat == NULL )
1527                 return E_POINTER;
1528
1529         EnterCriticalSection( &This->pParser->m_csParser );
1530         if ( This->pParser->m_pHandler->pIsTimeFormatSupported == NULL )
1531         {
1532                 FIXME("(%p)->(%p) not implemented\n",This,pidFormat);
1533         }
1534         else
1535         {
1536                 memcpy( pidFormat, &This->pParser->m_guidTimeFormat, sizeof(GUID) );
1537         }
1538         LeaveCriticalSection( &This->pParser->m_csParser );
1539
1540         return hr;
1541 }
1542
1543 static HRESULT WINAPI
1544 IMediaSeeking_fnIsUsingTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
1545 {
1546         CParserOutPinImpl_THIS(iface,mediaseeking);
1547         HRESULT hr = E_NOTIMPL;
1548
1549         TRACE("(%p)->(%p)\n",This,pidFormat);
1550
1551         if ( pidFormat == NULL )
1552                 return E_POINTER;
1553
1554         EnterCriticalSection( &This->pParser->m_csParser );
1555         if ( This->pParser->m_pHandler->pIsTimeFormatSupported == NULL )
1556         {
1557                 FIXME("(%p)->(%p) not implemented\n",This,pidFormat);
1558         }
1559         else
1560         {
1561                 hr = IsEqualGUID( pidFormat, &This->pParser->m_guidTimeFormat ) ? S_OK : S_FALSE;
1562         }
1563         LeaveCriticalSection( &This->pParser->m_csParser );
1564
1565         return hr;
1566 }
1567
1568 static HRESULT WINAPI
1569 IMediaSeeking_fnSetTimeFormat(IMediaSeeking* iface,const GUID* pidFormat)
1570 {
1571         CParserOutPinImpl_THIS(iface,mediaseeking);
1572         HRESULT hr = E_NOTIMPL;
1573
1574         TRACE("(%p)->(%p)\n",This,pidFormat);
1575
1576         if ( pidFormat == NULL )
1577                 return E_POINTER;
1578
1579         EnterCriticalSection( &This->pParser->m_csParser );
1580         if ( This->pParser->m_pHandler->pIsTimeFormatSupported == NULL )
1581         {
1582                 FIXME("(%p)->(%p) not implemented\n",This,pidFormat);
1583         }
1584         else
1585         {
1586                 if ( This->pParser->m_pHandler->pIsTimeFormatSupported( This->pParser, pidFormat ) == S_OK )
1587                 {
1588                         memcpy( &This->pParser->m_guidTimeFormat, pidFormat, sizeof(GUID) );
1589                 }
1590         }
1591         LeaveCriticalSection( &This->pParser->m_csParser );
1592
1593         return hr;
1594 }
1595
1596 static HRESULT WINAPI
1597 IMediaSeeking_fnGetDuration(IMediaSeeking* iface,LONGLONG* pllDuration)
1598 {
1599         CParserOutPinImpl_THIS(iface,mediaseeking);
1600         HRESULT hr = E_NOTIMPL;
1601
1602         TRACE("(%p)->(%p)\n",This,pllDuration);
1603
1604         if ( pllDuration == NULL )
1605                 return E_POINTER;
1606
1607         EnterCriticalSection( &This->pParser->m_csParser );
1608         if ( This->pParser->m_pHandler->pGetDuration == NULL )
1609         {
1610                 FIXME("(%p)->(%p) not implemented\n",This,pllDuration);
1611         }
1612         else
1613         {
1614                 hr = This->pParser->m_pHandler->pGetDuration( This->pParser, &This->pParser->m_guidTimeFormat, This->nStreamIndex, pllDuration );
1615         }
1616         LeaveCriticalSection( &This->pParser->m_csParser );
1617
1618         return hr;
1619 }
1620
1621 static HRESULT WINAPI
1622 IMediaSeeking_fnGetStopPosition(IMediaSeeking* iface,LONGLONG* pllPos)
1623 {
1624         CParserOutPinImpl_THIS(iface,mediaseeking);
1625         HRESULT hr = E_NOTIMPL;
1626
1627         TRACE("(%p)->(%p)\n",This,pllPos);
1628
1629         if ( pllPos == NULL )
1630                 return E_POINTER;
1631
1632         EnterCriticalSection( &This->pParser->m_csParser );
1633         if ( This->pParser->m_pHandler->pGetStopPos == NULL )
1634         {
1635                 FIXME("(%p)->(%p) not implemented\n",This,pllPos);
1636         }
1637         else
1638         {
1639                 hr = This->pParser->m_pHandler->pGetStopPos( This->pParser, &This->pParser->m_guidTimeFormat, This->nStreamIndex, pllPos );
1640         }
1641         LeaveCriticalSection( &This->pParser->m_csParser );
1642
1643         return hr;
1644 }
1645
1646 static HRESULT WINAPI
1647 IMediaSeeking_fnGetCurrentPosition(IMediaSeeking* iface,LONGLONG* pllPos)
1648 {
1649         CParserOutPinImpl_THIS(iface,mediaseeking);
1650         HRESULT hr = E_NOTIMPL;
1651
1652         TRACE("(%p)->(%p)\n",This,pllPos);
1653
1654         if ( pllPos == NULL )
1655                 return E_POINTER;
1656
1657         EnterCriticalSection( &This->pParser->m_csParser );
1658         if ( This->pParser->m_pHandler->pGetCurPos == NULL )
1659         {
1660                 FIXME("(%p)->(%p) not implemented\n",This,pllPos);
1661         }
1662         else
1663         {
1664                 hr = This->pParser->m_pHandler->pGetCurPos( This->pParser, &This->pParser->m_guidTimeFormat, This->nStreamIndex, pllPos );
1665         }
1666         LeaveCriticalSection( &This->pParser->m_csParser );
1667
1668         return hr;
1669 }
1670
1671 static HRESULT WINAPI
1672 IMediaSeeking_fnConvertTimeFormat(IMediaSeeking* iface,LONGLONG* pllOut,const GUID* pidFmtOut,LONGLONG llIn,const GUID* pidFmtIn)
1673 {
1674         CParserOutPinImpl_THIS(iface,mediaseeking);
1675
1676         FIXME("(%p)->() stub!\n",This);
1677
1678         return E_NOTIMPL;
1679 }
1680
1681 static HRESULT WINAPI
1682 IMediaSeeking_fnSetPositions(IMediaSeeking* iface,LONGLONG* pllCur,DWORD dwCurFlags,LONGLONG* pllStop,DWORD dwStopFlags)
1683 {
1684         CParserOutPinImpl_THIS(iface,mediaseeking);
1685
1686         FIXME("(%p)->() stub!\n",This);
1687
1688         return E_NOTIMPL;
1689 }
1690
1691 static HRESULT WINAPI
1692 IMediaSeeking_fnGetPositions(IMediaSeeking* iface,LONGLONG* pllCur,LONGLONG* pllStop)
1693 {
1694         CParserOutPinImpl_THIS(iface,mediaseeking);
1695         HRESULT hr = E_NOTIMPL;
1696
1697         TRACE("(%p)->(%p,%p)\n",This,pllCur,pllStop);
1698
1699         if ( pllCur == NULL || pllStop == NULL )
1700                 return E_POINTER;
1701
1702         EnterCriticalSection( &This->pParser->m_csParser );
1703         if ( This->pParser->m_pHandler->pGetCurPos == NULL ||
1704                  This->pParser->m_pHandler->pGetStopPos == NULL )
1705         {
1706                 FIXME("(%p)->(%p,%p) not implemented\n",This,pllCur,pllStop);
1707         }
1708         else
1709         {
1710                 hr = This->pParser->m_pHandler->pGetCurPos( This->pParser, &This->pParser->m_guidTimeFormat, This->nStreamIndex, pllCur );
1711                 if ( SUCCEEDED(hr) )
1712                         hr = This->pParser->m_pHandler->pGetStopPos( This->pParser, &This->pParser->m_guidTimeFormat, This->nStreamIndex, pllStop );
1713         }
1714         LeaveCriticalSection( &This->pParser->m_csParser );
1715
1716         return hr;
1717 }
1718
1719 static HRESULT WINAPI
1720 IMediaSeeking_fnGetAvailable(IMediaSeeking* iface,LONGLONG* pllFirst,LONGLONG* pllLast)
1721 {
1722         CParserOutPinImpl_THIS(iface,mediaseeking);
1723
1724         FIXME("(%p)->() stub!\n",This);
1725
1726         return E_NOTIMPL;
1727 }
1728
1729 static HRESULT WINAPI
1730 IMediaSeeking_fnSetRate(IMediaSeeking* iface,double dblRate)
1731 {
1732         CParserOutPinImpl_THIS(iface,mediaseeking);
1733
1734         FIXME("(%p)->() stub!\n",This);
1735
1736         return E_NOTIMPL;
1737 }
1738
1739 static HRESULT WINAPI
1740 IMediaSeeking_fnGetRate(IMediaSeeking* iface,double* pdblRate)
1741 {
1742         CParserOutPinImpl_THIS(iface,mediaseeking);
1743
1744         FIXME("(%p)->() stub!\n",This);
1745
1746         return E_NOTIMPL;
1747 }
1748
1749 static HRESULT WINAPI
1750 IMediaSeeking_fnGetPreroll(IMediaSeeking* iface,LONGLONG* pllPreroll)
1751 {
1752         CParserOutPinImpl_THIS(iface,mediaseeking);
1753
1754         FIXME("(%p)->() stub!\n",This);
1755
1756         return E_NOTIMPL;
1757 }
1758
1759
1760
1761
1762 static ICOM_VTABLE(IMediaSeeking) imediaseeking =
1763 {
1764         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1765         /* IUnknown fields */
1766         IMediaSeeking_fnQueryInterface,
1767         IMediaSeeking_fnAddRef,
1768         IMediaSeeking_fnRelease,
1769         /* IMediaSeeking fields */
1770         IMediaSeeking_fnGetCapabilities,
1771         IMediaSeeking_fnCheckCapabilities,
1772         IMediaSeeking_fnIsFormatSupported,
1773         IMediaSeeking_fnQueryPreferredFormat,
1774         IMediaSeeking_fnGetTimeFormat,
1775         IMediaSeeking_fnIsUsingTimeFormat,
1776         IMediaSeeking_fnSetTimeFormat,
1777         IMediaSeeking_fnGetDuration,
1778         IMediaSeeking_fnGetStopPosition,
1779         IMediaSeeking_fnGetCurrentPosition,
1780         IMediaSeeking_fnConvertTimeFormat,
1781         IMediaSeeking_fnSetPositions,
1782         IMediaSeeking_fnGetPositions,
1783         IMediaSeeking_fnGetAvailable,
1784         IMediaSeeking_fnSetRate,
1785         IMediaSeeking_fnGetRate,
1786         IMediaSeeking_fnGetPreroll,
1787 };
1788
1789 HRESULT CParserOutPinImpl_InitIMediaSeeking( CParserOutPinImpl* This )
1790 {
1791         TRACE("(%p)\n",This);
1792         ICOM_VTBL(&This->mediaseeking) = &imediaseeking;
1793
1794         return NOERROR;
1795 }
1796
1797 void CParserOutPinImpl_UninitIMediaSeeking( CParserOutPinImpl* This )
1798 {
1799         TRACE("(%p)\n",This);
1800 }
1801
1802 /***************************************************************************
1803  *
1804  *      IMediaPosition for CParserOutPinImpl
1805  *
1806  */
1807
1808 static HRESULT WINAPI
1809 IMediaPosition_fnQueryInterface(IMediaPosition* iface,REFIID riid,void** ppobj)
1810 {
1811         CParserOutPinImpl_THIS(iface,mediaposition);
1812
1813         TRACE("(%p)->()\n",This);
1814
1815         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1816 }
1817
1818 static ULONG WINAPI
1819 IMediaPosition_fnAddRef(IMediaPosition* iface)
1820 {
1821         CParserOutPinImpl_THIS(iface,mediaposition);
1822
1823         TRACE("(%p)->()\n",This);
1824
1825         return IUnknown_AddRef(This->unk.punkControl);
1826 }
1827
1828 static ULONG WINAPI
1829 IMediaPosition_fnRelease(IMediaPosition* iface)
1830 {
1831         CParserOutPinImpl_THIS(iface,mediaposition);
1832
1833         TRACE("(%p)->()\n",This);
1834
1835         return IUnknown_Release(This->unk.punkControl);
1836 }
1837
1838 static HRESULT WINAPI
1839 IMediaPosition_fnGetTypeInfoCount(IMediaPosition* iface,UINT* pcTypeInfo)
1840 {
1841         CParserOutPinImpl_THIS(iface,mediaposition);
1842
1843         FIXME("(%p)->() stub!\n",This);
1844
1845         return E_NOTIMPL;
1846 }
1847
1848 static HRESULT WINAPI
1849 IMediaPosition_fnGetTypeInfo(IMediaPosition* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
1850 {
1851         CParserOutPinImpl_THIS(iface,mediaposition);
1852
1853         FIXME("(%p)->() stub!\n",This);
1854
1855         return E_NOTIMPL;
1856 }
1857
1858 static HRESULT WINAPI
1859 IMediaPosition_fnGetIDsOfNames(IMediaPosition* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
1860 {
1861         CParserOutPinImpl_THIS(iface,mediaposition);
1862
1863         FIXME("(%p)->() stub!\n",This);
1864
1865         return E_NOTIMPL;
1866 }
1867
1868 static HRESULT WINAPI
1869 IMediaPosition_fnInvoke(IMediaPosition* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
1870 {
1871         CParserOutPinImpl_THIS(iface,mediaposition);
1872
1873         FIXME("(%p)->() stub!\n",This);
1874
1875         return E_NOTIMPL;
1876 }
1877
1878
1879 static HRESULT WINAPI
1880 IMediaPosition_fnget_Duration(IMediaPosition* iface,REFTIME* prefTime)
1881 {
1882         CParserOutPinImpl_THIS(iface,mediaposition);
1883         HRESULT hr = E_NOTIMPL;
1884         LONGLONG        llPos;
1885
1886         TRACE("(%p)->(%p)\n",This,prefTime);
1887
1888         if ( prefTime == NULL )
1889                 return E_POINTER;
1890
1891         EnterCriticalSection( &This->pParser->m_csParser );
1892         if ( This->pParser->m_pHandler->pGetDuration == NULL )
1893         {
1894                 FIXME("(%p)->(%p) not implemented\n",This,prefTime);
1895         }
1896         else
1897         {
1898                 hr = This->pParser->m_pHandler->pGetDuration( This->pParser, &TIME_FORMAT_MEDIA_TIME, This->nStreamIndex, &llPos );
1899                 if ( SUCCEEDED(hr) )
1900                         *prefTime = (REFTIME)llPos;
1901         }
1902         LeaveCriticalSection( &This->pParser->m_csParser );
1903
1904         return hr;
1905 }
1906
1907 static HRESULT WINAPI
1908 IMediaPosition_fnput_CurrentPosition(IMediaPosition* iface,REFTIME refTime)
1909 {
1910         CParserOutPinImpl_THIS(iface,mediaposition);
1911         HRESULT hr = E_NOTIMPL;
1912         /*LONGLONG      llPos;*/
1913
1914         FIXME("(%p)->() stub!\n",This);
1915
1916 #if 0   /* not yet */
1917         EnterCriticalSection( &This->pParser->m_csParser );
1918         if ( This->pParser->m_pHandler->pSetCurPos == NULL )
1919         {
1920                 FIXME("(%p)->() not implemented\n",This);
1921         }
1922         else
1923         {
1924                 llPos = (LONGLONG)refTime;
1925                 hr = This->pParser->m_pHandler->pSetCurPos( This->pParser, &TIME_FORMAT_MEDIA_TIME, This->nStreamIndex, llPos );
1926                 /* FIXME - flush all streams. */
1927         }
1928         LeaveCriticalSection( &This->pParser->m_csParser );
1929 #endif
1930
1931         return hr;
1932 }
1933
1934 static HRESULT WINAPI
1935 IMediaPosition_fnget_CurrentPosition(IMediaPosition* iface,REFTIME* prefTime)
1936 {
1937         CParserOutPinImpl_THIS(iface,mediaposition);
1938         HRESULT hr = E_NOTIMPL;
1939         LONGLONG        llPos;
1940
1941         TRACE("(%p)->(%p)\n",This,prefTime);
1942
1943         if ( prefTime == NULL )
1944                 return E_POINTER;
1945
1946         EnterCriticalSection( &This->pParser->m_csParser );
1947         if ( This->pParser->m_pHandler->pGetCurPos == NULL )
1948         {
1949                 FIXME("(%p)->(%p) not implemented\n",This,prefTime);
1950         }
1951         else
1952         {
1953                 hr = This->pParser->m_pHandler->pGetCurPos( This->pParser, &TIME_FORMAT_MEDIA_TIME, This->nStreamIndex, &llPos );
1954                 if ( SUCCEEDED(hr) )
1955                         *prefTime = (REFTIME)llPos;
1956         }
1957         LeaveCriticalSection( &This->pParser->m_csParser );
1958
1959         return hr;
1960 }
1961
1962 static HRESULT WINAPI
1963 IMediaPosition_fnget_StopTime(IMediaPosition* iface,REFTIME* prefTime)
1964 {
1965         CParserOutPinImpl_THIS(iface,mediaposition);
1966         HRESULT hr = E_NOTIMPL;
1967         LONGLONG        llPos;
1968
1969         TRACE("(%p)->(%p)\n",This,prefTime);
1970
1971         if ( prefTime == NULL )
1972                 return E_POINTER;
1973
1974         EnterCriticalSection( &This->pParser->m_csParser );
1975         if ( This->pParser->m_pHandler->pGetStopPos == NULL )
1976         {
1977                 FIXME("(%p)->(%p) not implemented\n",This,prefTime);
1978         }
1979         else
1980         {
1981                 hr = This->pParser->m_pHandler->pGetStopPos( This->pParser, &TIME_FORMAT_MEDIA_TIME, This->nStreamIndex, &llPos );
1982                 if ( SUCCEEDED(hr) )
1983                         *prefTime = (REFTIME)llPos;
1984         }
1985         LeaveCriticalSection( &This->pParser->m_csParser );
1986
1987         return hr;
1988 }
1989
1990 static HRESULT WINAPI
1991 IMediaPosition_fnput_StopTime(IMediaPosition* iface,REFTIME refTime)
1992 {
1993         CParserOutPinImpl_THIS(iface,mediaposition);
1994         HRESULT hr = E_NOTIMPL;
1995         LONGLONG        llPos;
1996
1997         TRACE("(%p)->()\n",This);
1998
1999         EnterCriticalSection( &This->pParser->m_csParser );
2000         if ( This->pParser->m_pHandler->pSetStopPos == NULL )
2001         {
2002                 FIXME("(%p)->() not implemented\n",This);
2003         }
2004         else
2005         {
2006                 llPos = (LONGLONG)refTime;
2007                 hr = This->pParser->m_pHandler->pSetStopPos( This->pParser, &TIME_FORMAT_MEDIA_TIME, This->nStreamIndex, llPos );
2008         }
2009         LeaveCriticalSection( &This->pParser->m_csParser );
2010
2011         return hr;
2012 }
2013
2014 static HRESULT WINAPI
2015 IMediaPosition_fnget_PrerollTime(IMediaPosition* iface,REFTIME* prefTime)
2016 {
2017         CParserOutPinImpl_THIS(iface,mediaposition);
2018
2019         FIXME("(%p)->() stub!\n",This);
2020
2021         return E_NOTIMPL;
2022 }
2023
2024 static HRESULT WINAPI
2025 IMediaPosition_fnput_PrerollTime(IMediaPosition* iface,REFTIME refTime)
2026 {
2027         CParserOutPinImpl_THIS(iface,mediaposition);
2028
2029         FIXME("(%p)->() stub!\n",This);
2030
2031         return E_NOTIMPL;
2032 }
2033
2034 static HRESULT WINAPI
2035 IMediaPosition_fnput_Rate(IMediaPosition* iface,double dblRate)
2036 {
2037         CParserOutPinImpl_THIS(iface,mediaposition);
2038
2039         return IMediaSeeking_SetRate(CParserOutPinImpl_IMediaSeeking(This),dblRate);
2040 }
2041
2042 static HRESULT WINAPI
2043 IMediaPosition_fnget_Rate(IMediaPosition* iface,double* pdblRate)
2044 {
2045         CParserOutPinImpl_THIS(iface,mediaposition);
2046
2047         return IMediaSeeking_GetRate(CParserOutPinImpl_IMediaSeeking(This),pdblRate);
2048 }
2049
2050 static HRESULT WINAPI
2051 IMediaPosition_fnCanSeekForward(IMediaPosition* iface,LONG* pCanSeek)
2052 {
2053         CParserOutPinImpl_THIS(iface,mediaposition);
2054         HRESULT hr = E_NOTIMPL;
2055         DWORD   dwCaps;
2056
2057         TRACE("(%p)->(%p)\n",This,pCanSeek);
2058
2059         if ( pCanSeek == NULL )
2060                 return E_POINTER;
2061
2062         EnterCriticalSection( &This->pParser->m_csParser );
2063         if ( This->pParser->m_pHandler->pGetSeekingCaps == NULL )
2064         {
2065                 FIXME("(%p)->(%p) not implemented\n",This,pCanSeek);
2066         }
2067         else
2068         {
2069                 hr = This->pParser->m_pHandler->pGetSeekingCaps( This->pParser, &dwCaps );
2070                 if ( SUCCEEDED(hr) )
2071                 {
2072                         *pCanSeek = (dwCaps & AM_SEEKING_CanSeekForwards) ? OATRUE : OAFALSE;
2073                         hr = S_OK;
2074                 }
2075         }
2076         LeaveCriticalSection( &This->pParser->m_csParser );
2077
2078         return hr;
2079 }
2080
2081 static HRESULT WINAPI
2082 IMediaPosition_fnCanSeekBackward(IMediaPosition* iface,LONG* pCanSeek)
2083 {
2084         CParserOutPinImpl_THIS(iface,mediaposition);
2085         HRESULT hr = E_NOTIMPL;
2086         DWORD   dwCaps;
2087
2088         TRACE("(%p)->(%p)\n",This,pCanSeek);
2089
2090         if ( pCanSeek == NULL )
2091                 return E_POINTER;
2092
2093         EnterCriticalSection( &This->pParser->m_csParser );
2094         if ( This->pParser->m_pHandler->pGetSeekingCaps == NULL )
2095         {
2096                 FIXME("(%p)->(%p) not implemented\n",This,pCanSeek);
2097         }
2098         else
2099         {
2100                 hr = This->pParser->m_pHandler->pGetSeekingCaps( This->pParser, &dwCaps );
2101                 if ( SUCCEEDED(hr) )
2102                 {
2103                         *pCanSeek = (dwCaps & AM_SEEKING_CanSeekBackwards) ? OATRUE : OAFALSE;
2104                         hr = S_OK;
2105                 }
2106         }
2107         LeaveCriticalSection( &This->pParser->m_csParser );
2108
2109         return hr;
2110 }
2111
2112
2113 static ICOM_VTABLE(IMediaPosition) imediaposition =
2114 {
2115         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2116         /* IUnknown fields */
2117         IMediaPosition_fnQueryInterface,
2118         IMediaPosition_fnAddRef,
2119         IMediaPosition_fnRelease,
2120         /* IDispatch fields */
2121         IMediaPosition_fnGetTypeInfoCount,
2122         IMediaPosition_fnGetTypeInfo,
2123         IMediaPosition_fnGetIDsOfNames,
2124         IMediaPosition_fnInvoke,
2125         /* IMediaPosition fields */
2126         IMediaPosition_fnget_Duration,
2127         IMediaPosition_fnput_CurrentPosition,
2128         IMediaPosition_fnget_CurrentPosition,
2129         IMediaPosition_fnget_StopTime,
2130         IMediaPosition_fnput_StopTime,
2131         IMediaPosition_fnget_PrerollTime,
2132         IMediaPosition_fnput_PrerollTime,
2133         IMediaPosition_fnput_Rate,
2134         IMediaPosition_fnget_Rate,
2135         IMediaPosition_fnCanSeekForward,
2136         IMediaPosition_fnCanSeekBackward,
2137 };
2138
2139
2140 HRESULT CParserOutPinImpl_InitIMediaPosition( CParserOutPinImpl* This )
2141 {
2142         TRACE("(%p)\n",This);
2143         ICOM_VTBL(&This->mediaposition) = &imediaposition;
2144
2145         return NOERROR;
2146 }
2147
2148 void CParserOutPinImpl_UninitIMediaPosition( CParserOutPinImpl* This )
2149 {
2150         TRACE("(%p)\n",This);
2151 }
2152