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