parser.c 20.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Parser (Base for parsers and splitters)
 *
 * Copyright 2003 Robert Shearman
 * Copyright 2004-2005 Christian Costa
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 */

#include "quartz_private.h"
#include "pin.h"

#include "vfwmsgs.h"
#include "amvideo.h"

#include "wine/debug.h"

#include <math.h>
#include <assert.h>

#include "parser.h"

WINE_DEFAULT_DEBUG_CHANNEL(quartz);

37 38 39
static const IMediaSeekingVtbl Parser_Seeking_Vtbl;
static const IPinVtbl Parser_OutputPin_Vtbl;
static const IPinVtbl Parser_InputPin_Vtbl;
40

41 42 43
static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface);
static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface);
static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface);
44
static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest);
45
static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt);
46
static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt);
47
static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *This, IMemInputPin *pPin, IMemAllocator **pAlloc);
48

49
static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
50
{
51
    return CONTAINING_RECORD(iface, ParserImpl, sourceSeeking.IMediaSeeking_iface);
52 53
}

54 55 56 57 58
static inline ParserImpl *impl_from_IBaseFilter( IBaseFilter *iface )
{
    return CONTAINING_RECORD(iface, ParserImpl, filter.IBaseFilter_iface);
}

59
static inline ParserImpl *impl_from_strmbase_filter(struct strmbase_filter *iface)
60 61 62 63
{
    return CONTAINING_RECORD(iface, ParserImpl, filter);
}

64
IPin *parser_get_pin(struct strmbase_filter *iface, unsigned int index)
65
{
66
    ParserImpl *filter = impl_from_strmbase_filter(iface);
67

68 69 70
    if (!index)
        return &filter->pInputPin->pin.IPin_iface;
    else if (index <= filter->cStreams)
71
        return &filter->sources[index - 1]->pin.pin.IPin_iface;
72
    return NULL;
73 74
}

75
HRESULT Parser_Create(ParserImpl *pParser, const IBaseFilterVtbl *vtbl, IUnknown *outer,
76
        const CLSID *clsid, const struct strmbase_filter_ops *func_table, const WCHAR *sink_name,
77
        PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect,
78 79 80
        PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest,
        STOPPROCESSPROC fnDone, SourceSeeking_ChangeStop stop,
        SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate)
81 82 83
{
    HRESULT hr;

84
    strmbase_filter_init(&pParser->filter, vtbl, outer, clsid, func_table);
85

86
    pParser->fnDisconnect = fnDisconnect;
87

88
    pParser->cStreams = 0;
89
    pParser->sources = CoTaskMemAlloc(0 * sizeof(IPin *));
90

91 92
    if (!start)
        start = Parser_ChangeStart;
93 94 95 96 97 98 99

    if (!stop)
        stop = Parser_ChangeStop;

    if (!rate)
        rate = Parser_ChangeRate;

100
    SourceSeeking_Init(&pParser->sourceSeeking, &Parser_Seeking_Vtbl, stop, start, rate,  &pParser->filter.csFilter);
101

102 103 104
    hr = PullPin_Construct(&Parser_InputPin_Vtbl, &pParser->filter, sink_name,
            fnProcessSample, (void *)pParser, fnQueryAccept, fnCleanup, fnRequest,
            fnDone, (IPin **)&pParser->pInputPin);
105 106 107 108 109 110 111

    if (SUCCEEDED(hr))
    {
        pParser->pInputPin->fnPreConnect = fnPreConnect;
    }
    else
    {
112
        CoTaskMemFree(pParser->sources);
113
        strmbase_filter_cleanup(&pParser->filter);
114 115 116 117 118 119
        CoTaskMemFree(pParser);
    }

    return hr;
}

120
HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
121
{
122
    ParserImpl *This = impl_from_IBaseFilter(iface);
123 124 125 126
    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);

    *ppv = NULL;

127 128 129 130
    if ( IsEqualIID(riid, &IID_IUnknown)
      || IsEqualIID(riid, &IID_IPersist)
      || IsEqualIID(riid, &IID_IMediaFilter)
      || IsEqualIID(riid, &IID_IBaseFilter) )
131
        *ppv = &This->filter.IBaseFilter_iface;
132 133 134

    if (*ppv)
    {
135
        IUnknown_AddRef((IUnknown *)*ppv);
136 137 138
        return S_OK;
    }

139
    if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
140
        FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
141 142 143 144

    return E_NOINTERFACE;
}

145
ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
146
{
147
    return BaseFilterImpl_AddRef(iface);
148 149
}

150
void Parser_Destroy(ParserImpl *This)
151
{
152
    IPin *connected = NULL;
153
    HRESULT hr;
154 155

    PullPin_WaitForStateChange(This->pInputPin, INFINITE);
156

157
    /* Don't need to clean up output pins, freeing input pin will do that */
158
    IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &connected);
159
    if (connected)
160
    {
161 162
        hr = IPin_Disconnect(connected);
        assert(hr == S_OK);
163
        IPin_Release(connected);
164 165
        hr = IPin_Disconnect(&This->pInputPin->pin.IPin_iface);
        assert(hr == S_OK);
166
    }
167

168
    PullPin_destroy(This->pInputPin);
169

170
    CoTaskMemFree(This->sources);
171
    strmbase_filter_cleanup(&This->filter);
172

173 174 175
    TRACE("Destroying parser\n");
    CoTaskMemFree(This);
}
176

177 178
/** IMediaFilter methods **/

179
HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
180
{
181
    ParserImpl *This = impl_from_IBaseFilter(iface);
182
    PullPin *pin = This->pInputPin;
183
    ULONG i;
184

185
    TRACE("%p->()\n", This);
186

187
    EnterCriticalSection(&pin->thread_lock);
188 189

    IAsyncReader_BeginFlush(This->pInputPin->pReader);
190
    EnterCriticalSection(&This->filter.csFilter);
191

192
    if (This->filter.state == State_Stopped)
193
    {
194
        LeaveCriticalSection(&This->filter.csFilter);
195
        IAsyncReader_EndFlush(This->pInputPin->pReader);
196 197
        LeaveCriticalSection(&pin->thread_lock);
        return S_OK;
198
    }
199

200
    This->filter.state = State_Stopped;
201

202
    for (i = 0; i < This->cStreams; ++i)
203
    {
204
        BaseOutputPinImpl_Inactive(&This->sources[i]->pin);
205 206
    }

207
    LeaveCriticalSection(&This->filter.csFilter);
208 209 210

    PullPin_PauseProcessing(This->pInputPin);
    PullPin_WaitForStateChange(This->pInputPin, INFINITE);
211
    IAsyncReader_EndFlush(This->pInputPin->pReader);
212

213
    LeaveCriticalSection(&pin->thread_lock);
214
    return S_OK;
215 216
}

217
HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
218 219
{
    HRESULT hr = S_OK;
220
    ParserImpl *This = impl_from_IBaseFilter(iface);
221
    PullPin *pin = This->pInputPin;
222

223
    TRACE("%p->()\n", This);
224

225
    EnterCriticalSection(&pin->thread_lock);
226
    EnterCriticalSection(&This->filter.csFilter);
227

228
    if (This->filter.state == State_Paused)
229
    {
230
        LeaveCriticalSection(&This->filter.csFilter);
231
        LeaveCriticalSection(&pin->thread_lock);
232
        return S_OK;
233 234
    }

235
    if (This->filter.state == State_Stopped)
236
    {
237
        LeaveCriticalSection(&This->filter.csFilter);
238
        hr = IBaseFilter_Run(iface, -1);
239
        EnterCriticalSection(&This->filter.csFilter);
240 241
    }

242
    if (SUCCEEDED(hr))
243
        This->filter.state = State_Paused;
244

245
    LeaveCriticalSection(&This->filter.csFilter);
246
    LeaveCriticalSection(&pin->thread_lock);
247

248 249 250
    return hr;
}

251
HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
252 253
{
    HRESULT hr = S_OK;
254
    ParserImpl *This = impl_from_IBaseFilter(iface);
255
    PullPin *pin = This->pInputPin;
256

257
    ULONG i;
258

259
    TRACE("%p->(%s)\n", This, wine_dbgstr_longlong(tStart));
260

261
    EnterCriticalSection(&pin->thread_lock);
262
    EnterCriticalSection(&This->filter.csFilter);
263
    {
264 265
        HRESULT hr_any = VFW_E_NOT_CONNECTED;

266
        This->filter.rtStreamStart = tStart;
267
        if (This->filter.state == State_Running || This->filter.state == State_Paused)
268
        {
269 270
            This->filter.state = State_Running;
            LeaveCriticalSection(&This->filter.csFilter);
271
            LeaveCriticalSection(&pin->thread_lock);
272 273 274
            return S_OK;
        }

275
        for (i = 0; i < This->cStreams; ++i)
276
        {
277
            hr = BaseOutputPinImpl_Active(&This->sources[i]->pin);
278 279
            if (SUCCEEDED(hr))
                hr_any = hr;
280
        }
281

282
        hr = hr_any;
283
        if (SUCCEEDED(hr))
284
        {
285
            LeaveCriticalSection(&This->filter.csFilter);
286
            hr = PullPin_StartProcessing(This->pInputPin);
287
            EnterCriticalSection(&This->filter.csFilter);
288
        }
289 290

        if (SUCCEEDED(hr))
291
            This->filter.state = State_Running;
292
    }
293
    LeaveCriticalSection(&This->filter.csFilter);
294
    LeaveCriticalSection(&pin->thread_lock);
295 296 297 298

    return hr;
}

299
HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
300
{
301
    ParserImpl *This = impl_from_IBaseFilter(iface);
302
    PullPin *pin = This->pInputPin;
303
    HRESULT hr = S_OK;
304

305
    TRACE("%p->(%d, %p)\n", This, dwMilliSecsTimeout, pState);
306

307
    EnterCriticalSection(&pin->thread_lock);
308
    EnterCriticalSection(&This->filter.csFilter);
309
    {
310
        *pState = This->filter.state;
311
    }
312
    LeaveCriticalSection(&This->filter.csFilter);
313 314

    if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
315 316
        hr = VFW_S_STATE_INTERMEDIATE;
    LeaveCriticalSection(&pin->thread_lock);
317

318
    return hr;
319 320
}

321
HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
322
{
323
    ParserImpl *This = impl_from_IBaseFilter(iface);
324
    PullPin *pin = This->pInputPin;
325

326
    TRACE("%p->(%p)\n", This, pClock);
327

328
    EnterCriticalSection(&pin->thread_lock);
329
    BaseFilterImpl_SetSyncSource(iface,pClock);
330
    LeaveCriticalSection(&pin->thread_lock);
331 332 333 334

    return S_OK;
}

335
static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
336
    {
337
        Parser_OutputPin_CheckMediaType,
338 339
        Parser_OutputPin_GetMediaType
    },
340
    BaseOutputPinImpl_AttemptConnection,
341 342
    Parser_OutputPin_DecideBufferSize,
    Parser_OutputPin_DecideAllocator,
343 344
};

345
HRESULT Parser_AddPin(ParserImpl *filter, const WCHAR *name,
346
        ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *mt)
347
{
348 349
    Parser_OutputPin **old_sources;
    Parser_OutputPin *object;
350

351 352
    if (!(object = CoTaskMemAlloc(sizeof(*object))))
        return E_OUTOFMEMORY;
353

354
    old_sources = filter->sources;
355

356 357 358
    filter->sources = CoTaskMemAlloc((filter->cStreams + 1) * sizeof(filter->sources[0]));
    memcpy(filter->sources, old_sources, filter->cStreams * sizeof(filter->sources[0]));
    filter->sources[filter->cStreams] = object;
359

360 361
    strmbase_source_init(&object->pin, &Parser_OutputPin_Vtbl, &filter->filter,
            name, &output_BaseOutputFuncTable);
362

363 364 365 366 367 368 369 370 371
    object->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
    CopyMediaType(object->pmt, mt);
    object->dwSamplesProcessed = 0;
    object->allocProps = *props;
    filter->cStreams++;
    BaseFilterImpl_IncrementPinVersion(&filter->filter);
    CoTaskMemFree(old_sources);

    return S_OK;
372 373
}

374
static void free_source_pin(Parser_OutputPin *pin)
375
{
376
    if (pin->pin.pin.pConnectedTo)
377
    {
378
        IPin_Disconnect(pin->pin.pin.pConnectedTo);
379
        IPin_Disconnect(&pin->pin.pin.IPin_iface);
380 381
    }

382 383
    FreeMediaType(pin->pmt);
    CoTaskMemFree(pin->pmt);
384
    strmbase_source_cleanup(&pin->pin);
385
    CoTaskMemFree(pin);
386 387
}

388 389 390 391
static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
{
    /* NOTE: should be in critical section when calling this function */
    ULONG i;
392
    Parser_OutputPin **old_sources = This->sources;
393

394 395
    TRACE("(%p)\n", This);

396
    This->sources = CoTaskMemAlloc(0);
397 398

    for (i = 0; i < This->cStreams; i++)
399
        free_source_pin(old_sources[i]);
400

401
    BaseFilterImpl_IncrementPinVersion(&This->filter);
402
    This->cStreams = 0;
403
    CoTaskMemFree(old_sources);
404 405 406 407

    return S_OK;
}

408
static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface)
409
{
410
    FIXME("(%p) filter hasn't implemented start position change!\n", iface);
411 412 413
    return S_OK;
}

414
static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface)
415
{
416
    FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
417 418 419
    return S_OK;
}

420
static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface)
421
{
422
    FIXME("(%p) filter hasn't implemented rate change!\n", iface);
423 424 425 426 427 428
    return S_OK;
}


static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
{
429
    ParserImpl *This = impl_from_IMediaSeeking(iface);
430

431
    return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
432 433 434 435
}

static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
{
436
    ParserImpl *This = impl_from_IMediaSeeking(iface);
437

438
    return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
439 440 441 442
}

static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
{
443
    ParserImpl *This = impl_from_IMediaSeeking(iface);
444

445
    return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
446 447 448 449 450 451 452
}

static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
{
    Parser_Seeking_QueryInterface,
    Parser_Seeking_AddRef,
    Parser_Seeking_Release,
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    SourceSeekingImpl_GetCapabilities,
    SourceSeekingImpl_CheckCapabilities,
    SourceSeekingImpl_IsFormatSupported,
    SourceSeekingImpl_QueryPreferredFormat,
    SourceSeekingImpl_GetTimeFormat,
    SourceSeekingImpl_IsUsingTimeFormat,
    SourceSeekingImpl_SetTimeFormat,
    SourceSeekingImpl_GetDuration,
    SourceSeekingImpl_GetStopPosition,
    SourceSeekingImpl_GetCurrentPosition,
    SourceSeekingImpl_ConvertTimeFormat,
    SourceSeekingImpl_SetPositions,
    SourceSeekingImpl_GetPositions,
    SourceSeekingImpl_GetAvailable,
    SourceSeekingImpl_SetRate,
    SourceSeekingImpl_GetRate,
    SourceSeekingImpl_GetPreroll
470 471
};

472
static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
473
{
474
    Parser_OutputPin *This = (Parser_OutputPin*)iface;
475 476 477 478 479 480 481 482 483 484 485 486 487 488
    ALLOCATOR_PROPERTIES actual;

    if (ppropInputRequest->cbAlign && ppropInputRequest->cbAlign != This->allocProps.cbAlign)
        FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This->allocProps.cbAlign, ppropInputRequest->cbAlign);
    if (ppropInputRequest->cbPrefix)
        FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This->allocProps.cbPrefix, ppropInputRequest->cbPrefix);
    if (ppropInputRequest->cbBuffer)
        FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This->allocProps.cbBuffer, ppropInputRequest->cbBuffer);
    if (ppropInputRequest->cBuffers)
        FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This->allocProps.cBuffers, ppropInputRequest->cBuffers);

    return IMemAllocator_SetProperties(pAlloc, &This->allocProps, &actual);
}

489
static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
490
{
491
    Parser_OutputPin *This = (Parser_OutputPin*)iface;
492 493 494 495 496 497 498 499
    if (iPosition < 0)
        return E_INVALIDARG;
    if (iPosition > 0)
        return VFW_S_NO_MORE_ITEMS;
    CopyMediaType(pmt, This->pmt);
    return S_OK;
}

500 501
static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc)
{
502
    Parser_OutputPin *This = (Parser_OutputPin*)iface;
503 504
    HRESULT hr;

505
    *pAlloc = NULL;
506 507

    if (This->alloc)
508
    {
509
        hr = IMemInputPin_NotifyAllocator(pPin, This->alloc, This->readonly);
510 511 512 513 514 515
        if (SUCCEEDED(hr))
        {
            *pAlloc = This->alloc;
            IMemAllocator_AddRef(*pAlloc);
        }
    }
516 517 518 519 520 521
    else
        hr = VFW_E_NO_ALLOCATOR;

    return hr;
}

522
static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
523
{
524
    Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface);
525 526 527 528 529 530

    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);

    *ppv = NULL;

    if (IsEqualIID(riid, &IID_IUnknown))
531
        *ppv = iface;
532
    else if (IsEqualIID(riid, &IID_IPin))
533
        *ppv = iface;
534
    /* The Parser filter does not support querying IMediaSeeking, return it directly */
535
    else if (IsEqualIID(riid, &IID_IMediaSeeking))
536
        *ppv = &impl_from_IBaseFilter(&This->pin.pin.filter->IBaseFilter_iface)->sourceSeeking;
537 538 539 540 541 542 543 544 545 546 547 548

    if (*ppv)
    {
        IUnknown_AddRef((IUnknown *)(*ppv));
        return S_OK;
    }

    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));

    return E_NOINTERFACE;
}

549 550
static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
{
551
    Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface);
552
    ParserImpl *parser = impl_from_IBaseFilter(&This->pin.pin.filter->IBaseFilter_iface);
553 554

    /* Set the allocator to our input pin's */
555
    EnterCriticalSection(&parser->filter.csFilter);
556
    This->alloc = parser->pInputPin->pAlloc;
557
    LeaveCriticalSection(&parser->filter.csFilter);
558

559
    return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt);
560 561
}

562
static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt)
563
{
564
    Parser_OutputPin *This = (Parser_OutputPin *)pin;
565 566 567 568 569 570 571 572 573

    dump_AM_MEDIA_TYPE(pmt);

    return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
}

static const IPinVtbl Parser_OutputPin_Vtbl = 
{
    Parser_OutputPin_QueryInterface,
574 575
    BasePinImpl_AddRef,
    BasePinImpl_Release,
576
    Parser_OutputPin_Connect,
577 578
    BaseOutputPinImpl_ReceiveConnection,
    BaseOutputPinImpl_Disconnect,
579 580 581 582 583
    BasePinImpl_ConnectedTo,
    BasePinImpl_ConnectionMediaType,
    BasePinImpl_QueryPinInfo,
    BasePinImpl_QueryDirection,
    BasePinImpl_QueryId,
584
    BasePinImpl_QueryAccept,
585
    BasePinImpl_EnumMediaTypes,
586
    BasePinImpl_QueryInternalConnections,
587 588 589
    BaseOutputPinImpl_EndOfStream,
    BaseOutputPinImpl_BeginFlush,
    BaseOutputPinImpl_EndFlush,
590
    BasePinImpl_NewSegment
591 592
};

593 594
static HRESULT WINAPI Parser_PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
{
595
    PullPin *This = impl_PullPin_from_IPin(iface);
596 597 598 599 600 601 602 603 604 605 606

    TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);

    *ppv = NULL;

    /*
     * It is important to capture the request for the IMediaSeeking interface before it is passed
     * on to PullPin_QueryInterface, this is necessary since the Parser filter does not support
     * querying IMediaSeeking
     */
    if (IsEqualIID(riid, &IID_IMediaSeeking))
607
        *ppv = &impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface)->sourceSeeking;
608 609 610 611 612 613 614 615 616 617

    if (*ppv)
    {
        IUnknown_AddRef((IUnknown *)(*ppv));
        return S_OK;
    }

    return PullPin_QueryInterface(iface, riid, ppv);
}

618
static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
619 620
{
    HRESULT hr;
621
    PullPin *This = impl_PullPin_from_IPin(iface);
622 623 624

    TRACE("()\n");

625
    EnterCriticalSection(&This->thread_lock);
626
    EnterCriticalSection(&This->pin.filter->csFilter);
627
    {
628
        if (This->pin.pConnectedTo)
629 630
        {
            FILTER_STATE state;
631
            ParserImpl *Parser = impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface);
632

633
            LeaveCriticalSection(&This->pin.filter->csFilter);
634
            hr = IBaseFilter_GetState(&This->pin.filter->IBaseFilter_iface, INFINITE, &state);
635
            EnterCriticalSection(&This->pin.filter->csFilter);
636

637
            if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
638
            {
639
                LeaveCriticalSection(&This->pin.filter->csFilter);
640
                PullPin_Disconnect(iface);
641
                EnterCriticalSection(&This->pin.filter->csFilter);
642
                hr = Parser_RemoveOutputPins(impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface));
643 644 645 646 647 648 649
            }
            else
                hr = VFW_E_NOT_STOPPED;
        }
        else
            hr = S_FALSE;
    }
650
    LeaveCriticalSection(&This->pin.filter->csFilter);
651 652
    LeaveCriticalSection(&This->thread_lock);

653 654 655
    return hr;
}

656
static HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
657 658 659 660 661 662 663 664
{
    HRESULT hr;

    TRACE("()\n");

    hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
    if (FAILED(hr))
    {
665
        BasePin *This = (BasePin *)iface;
666

667
        EnterCriticalSection(&This->filter->csFilter);
668
        Parser_RemoveOutputPins(impl_from_IBaseFilter(&This->filter->IBaseFilter_iface));
669
        LeaveCriticalSection(&This->filter->csFilter);
670 671 672 673 674
    }

    return hr;
}

675 676 677 678 679 680 681 682 683
static HRESULT WINAPI Parser_PullPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
{
    BasePin *This = (BasePin *)iface;

    TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);

    return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
}

684 685
static const IPinVtbl Parser_InputPin_Vtbl =
{
686
    Parser_PullPin_QueryInterface,
687 688
    BasePinImpl_AddRef,
    BasePinImpl_Release,
689
    BaseInputPinImpl_Connect,
690
    Parser_PullPin_ReceiveConnection,
691
    Parser_PullPin_Disconnect,
692 693 694 695 696 697
    BasePinImpl_ConnectedTo,
    BasePinImpl_ConnectionMediaType,
    BasePinImpl_QueryPinInfo,
    BasePinImpl_QueryDirection,
    BasePinImpl_QueryId,
    PullPin_QueryAccept,
698
    Parser_PullPin_EnumMediaTypes,
699
    BasePinImpl_QueryInternalConnections,
700 701 702 703 704
    PullPin_EndOfStream,
    PullPin_BeginFlush,
    PullPin_EndFlush,
    PullPin_NewSegment
};