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