pospass.c 28.2 KB
Newer Older
1 2 3 4
/*
 * Filter Seeking and Control Interfaces
 *
 * Copyright 2003 Robert Shearman
5
 * Copyright 2012 Aric Stewart, CodeWeavers
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
 */
/* FIXME: critical sections */

23
#include "strmbase_private.h"
24

25 26
WINE_DEFAULT_DEBUG_CHANNEL(strmbase);

27
static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl;
28
static const IMediaPositionVtbl IMediaPositionPassThru_Vtbl;
29

30
typedef struct PassThruImpl {
31 32 33
    IUnknown  IUnknown_inner;
    ISeekingPassThru ISeekingPassThru_iface;
    IMediaSeeking IMediaSeeking_iface;
34
    IMediaPosition IMediaPosition_iface;
35 36

    LONG ref;
37
    IUnknown * outer_unk;
38
    IPin * pin;
39 40
    BOOL bUnkOuterValid;
    BOOL bAggregatable;
41
    BOOL renderer;
42 43 44
    CRITICAL_SECTION time_cs;
    BOOL timevalid;
    REFERENCE_TIME time_earliest;
45 46
} PassThruImpl;

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
static inline PassThruImpl *impl_from_IUnknown_inner(IUnknown *iface)
{
    return CONTAINING_RECORD(iface, PassThruImpl, IUnknown_inner);
}

static inline PassThruImpl *impl_from_ISeekingPassThru(ISeekingPassThru *iface)
{
    return CONTAINING_RECORD(iface, PassThruImpl, ISeekingPassThru_iface);
}

static inline PassThruImpl *impl_from_IMediaSeeking(IMediaSeeking *iface)
{
    return CONTAINING_RECORD(iface, PassThruImpl, IMediaSeeking_iface);
}

62 63 64 65 66
static inline PassThruImpl *impl_from_IMediaPosition(IMediaPosition *iface)
{
    return CONTAINING_RECORD(iface, PassThruImpl, IMediaPosition_iface);
}

67 68 69
static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface,
					  REFIID riid,
					  LPVOID *ppvObj) {
70
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
71
    TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
72 73 74 75 76 77

    if (This->bAggregatable)
        This->bUnkOuterValid = TRUE;

    if (IsEqualGUID(&IID_IUnknown, riid))
    {
78
        *ppvObj = &(This->IUnknown_inner);
79 80
        TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
    } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) {
81
        *ppvObj = &(This->ISeekingPassThru_iface);
82 83
        TRACE("   returning ISeekingPassThru interface (%p)\n", *ppvObj);
    } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
84
        *ppvObj = &(This->IMediaSeeking_iface);
85
        TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
86 87 88
    } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
        *ppvObj = &(This->IMediaPosition_iface);
        TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
89 90 91 92 93 94 95 96 97 98 99
    } else {
        *ppvObj = NULL;
        FIXME("unknown interface %s\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown *)(*ppvObj));
    return S_OK;
}

static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) {
100
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
101 102 103 104 105 106 107 108
    ULONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p)->(): new ref = %d\n", This, ref);

    return ref;
}

static ULONG WINAPI SeekInner_Release(IUnknown * iface) {
109
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
110 111 112 113 114 115
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p)->(): new ref = %d\n", This, ref);

    if (ref == 0)
    {
116 117
        This->time_cs.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->time_cs);
118 119 120 121 122 123 124 125 126 127 128 129
        CoTaskMemFree(This);
    }
    return ref;
}

static const IUnknownVtbl IInner_VTable =
{
    SeekInner_QueryInterface,
    SeekInner_AddRef,
    SeekInner_Release
};

Austin English's avatar
Austin English committed
130
/* Generic functions for aggregation */
131
static HRESULT SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv)
132 133 134 135
{
    if (This->bAggregatable)
        This->bUnkOuterValid = TRUE;

136
    if (This->outer_unk)
137 138
    {
        if (This->bAggregatable)
139
            return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
140 141 142 143 144

        if (IsEqualIID(riid, &IID_IUnknown))
        {
            HRESULT hr;

145 146 147
            IUnknown_AddRef(&This->IUnknown_inner);
            hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
            IUnknown_Release(&This->IUnknown_inner);
148 149 150 151 152 153 154 155
            This->bAggregatable = TRUE;
            return hr;
        }

        *ppv = NULL;
        return E_NOINTERFACE;
    }

156
    return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
157 158
}

159
static ULONG SeekOuter_AddRef(PassThruImpl *This)
160
{
161 162
    if (This->outer_unk && This->bUnkOuterValid)
        return IUnknown_AddRef(This->outer_unk);
163
    return IUnknown_AddRef(&This->IUnknown_inner);
164 165
}

166
static ULONG SeekOuter_Release(PassThruImpl *This)
167
{
168 169
    if (This->outer_unk && This->bUnkOuterValid)
        return IUnknown_Release(This->outer_unk);
170
    return IUnknown_Release(&This->IUnknown_inner);
171 172 173 174
}

static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj)
{
175
    PassThruImpl *This = impl_from_ISeekingPassThru(iface);
176

177
    TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
178 179 180 181 182 183

    return SeekOuter_QueryInterface(This, riid, ppvObj);
}

static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface)
{
184
    PassThruImpl *This = impl_from_ISeekingPassThru(iface);
185 186 187 188 189 190 191 192

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

    return SeekOuter_AddRef(This);
}

static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface)
{
193
    PassThruImpl *This = impl_from_ISeekingPassThru(iface);
194 195 196 197 198 199 200 201

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

    return SeekOuter_Release(This);
}

static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin)
{
202
    PassThruImpl *This = impl_from_ISeekingPassThru(iface);
203

204 205 206 207 208 209 210
    TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin);

    if (This->pin)
        FIXME("Re-initializing?\n");

    This->renderer = renderer;
    This->pin = pin;
211 212 213 214 215 216 217 218 219 220 221 222

    return S_OK;
}

static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl =
{
    SeekingPassThru_QueryInterface,
    SeekingPassThru_AddRef,
    SeekingPassThru_Release,
    SeekingPassThru_Init
};

223 224 225 226 227 228
HRESULT WINAPI CreatePosPassThru(IUnknown* pUnkOuter, BOOL bRenderer, IPin *pPin, IUnknown **ppPassThru)
{
    HRESULT hr;
    ISeekingPassThru *passthru;

    hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)ppPassThru);
229 230
    if (FAILED(hr))
        return hr;
231 232 233 234 235 236 237 238 239

    IUnknown_QueryInterface(*ppPassThru, &IID_ISeekingPassThru, (void**)&passthru);
    hr = ISeekingPassThru_Init(passthru, bRenderer, pPin);
    ISeekingPassThru_Release(passthru);

    return hr;
}

HRESULT WINAPI PosPassThru_Construct(IUnknown *pUnkOuter, LPVOID *ppPassThru)
240 241 242
{
    PassThruImpl *fimpl;

243
    TRACE("(%p,%p)\n", pUnkOuter, ppPassThru);
244

245
    *ppPassThru = fimpl = CoTaskMemAlloc(sizeof(*fimpl));
246 247 248
    if (!fimpl)
        return E_OUTOFMEMORY;

249
    fimpl->outer_unk = pUnkOuter;
250 251
    fimpl->bUnkOuterValid = FALSE;
    fimpl->bAggregatable = FALSE;
252 253 254
    fimpl->IUnknown_inner.lpVtbl = &IInner_VTable;
    fimpl->ISeekingPassThru_iface.lpVtbl = &ISeekingPassThru_Vtbl;
    fimpl->IMediaSeeking_iface.lpVtbl = &IMediaSeekingPassThru_Vtbl;
255
    fimpl->IMediaPosition_iface.lpVtbl = &IMediaPositionPassThru_Vtbl;
256
    fimpl->ref = 1;
257
    fimpl->pin = NULL;
258
    fimpl->timevalid = FALSE;
259 260
    InitializeCriticalSection(&fimpl->time_cs);
    fimpl->time_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PassThruImpl.time_cs");
261 262
    return S_OK;
}
263

264 265
static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj)
{
266
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
267

268
    TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
269 270 271 272 273 274

    return SeekOuter_QueryInterface(This, riid, ppvObj);
}

static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface)
{
275
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
276 277 278 279 280 281 282 283

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

    return SeekOuter_AddRef(This);
}

static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface)
{
284
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
285 286 287 288 289 290

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

    return SeekOuter_Release(This);
}

291
static HRESULT get_connected(PassThruImpl *This, REFIID riid, LPVOID *ppvObj) {
292 293
    HRESULT hr;
    IPin *pin;
294
    *ppvObj = NULL;
295 296
    hr = IPin_ConnectedTo(This->pin, &pin);
    if (FAILED(hr))
297
        return VFW_E_NOT_CONNECTED;
298
    hr = IPin_QueryInterface(pin, riid, ppvObj);
299 300 301 302 303 304
    IPin_Release(pin);
    if (FAILED(hr))
        hr = E_NOTIMPL;
    return hr;
}

305 306
static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
{
307
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
308 309
    IMediaSeeking *seek;
    HRESULT hr;
310
    TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
311
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
312 313 314 315
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetCapabilities(seek, pCapabilities);
        IMediaSeeking_Release(seek);
    }
316 317
    else
        return E_NOTIMPL;
318
    return hr;
319 320 321 322
}

static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities)
{
323
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
324 325
    IMediaSeeking *seek;
    HRESULT hr;
326
    TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities);
327
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
328 329 330 331
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_CheckCapabilities(seek, pCapabilities);
        IMediaSeeking_Release(seek);
    }
332 333
    else
        return E_NOTIMPL;
334
    return hr;
335 336 337 338
}

static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat)
{
339
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
340 341
    IMediaSeeking *seek;
    HRESULT hr;
342
    TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
343
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
344 345 346 347
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_IsFormatSupported(seek, pFormat);
        IMediaSeeking_Release(seek);
    }
348 349
    else
        return E_NOTIMPL;
350
    return hr;
351 352 353 354
}

static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat)
{
355
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
356 357
    IMediaSeeking *seek;
    HRESULT hr;
358
    TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
359
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
360 361 362 363
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_QueryPreferredFormat(seek, pFormat);
        IMediaSeeking_Release(seek);
    }
364 365
    else
        return E_NOTIMPL;
366
    return hr;
367 368 369 370
}

static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat)
{
371
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
372 373
    IMediaSeeking *seek;
    HRESULT hr;
374
    TRACE("(%p/%p)->(%p)\n", iface, This, pFormat);
375
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
376 377 378 379
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetTimeFormat(seek, pFormat);
        IMediaSeeking_Release(seek);
    }
380 381
    else
        return E_NOTIMPL;
382
    return hr;
383 384 385 386
}

static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
{
387
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
388 389
    IMediaSeeking *seek;
    HRESULT hr;
390
    TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
391
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
392 393 394 395
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_IsUsingTimeFormat(seek, pFormat);
        IMediaSeeking_Release(seek);
    }
396 397
    else
        return E_NOTIMPL;
398
    return hr;
399 400 401 402
}

static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat)
{
403
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
404 405
    IMediaSeeking *seek;
    HRESULT hr;
406
    TRACE("(%p/%p)->(%s)\n", iface, This, debugstr_guid(pFormat));
407
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
408 409 410 411
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_SetTimeFormat(seek, pFormat);
        IMediaSeeking_Release(seek);
    }
412 413
    else
        return E_NOTIMPL;
414
    return hr;
415 416 417 418
}

static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration)
{
419
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
420
    IMediaSeeking *seek;
421
    HRESULT hr;
422
    TRACE("(%p/%p)->(%p)\n", iface, This, pDuration);
423
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
424 425 426 427
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetDuration(seek, pDuration);
        IMediaSeeking_Release(seek);
    }
428 429
    else
        return E_NOTIMPL;
430
    return hr;
431 432 433 434
}

static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop)
{
435
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
436 437
    IMediaSeeking *seek;
    HRESULT hr;
438
    TRACE("(%p/%p)->(%p)\n", iface, This, pStop);
439
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
440 441 442 443
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetStopPosition(seek, pStop);
        IMediaSeeking_Release(seek);
    }
444 445
    else
        return E_NOTIMPL;
446
    return hr;
447 448 449 450
}

static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent)
{
451
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
452
    IMediaSeeking *seek;
453
    HRESULT hr = S_OK;
454
    TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent);
455 456 457 458 459 460 461 462 463 464 465 466
    if (!pCurrent)
        return E_POINTER;
    EnterCriticalSection(&This->time_cs);
    if (This->timevalid)
        *pCurrent = This->time_earliest;
    else
        hr = E_FAIL;
    LeaveCriticalSection(&This->time_cs);
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_ConvertTimeFormat(iface, pCurrent, NULL, *pCurrent, &TIME_FORMAT_MEDIA_TIME);
        return hr;
    }
467
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
468 469 470 471
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetCurrentPosition(seek, pCurrent);
        IMediaSeeking_Release(seek);
    }
472 473
    else
        return E_NOTIMPL;
474
    return hr;
475 476 477 478
}

static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat)
{
479
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
480 481
    IMediaSeeking *seek;
    HRESULT hr;
482
    TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat));
483
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
484 485 486 487
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_ConvertTimeFormat(seek, pTarget, pTargetFormat, Source, pSourceFormat);
        IMediaSeeking_Release(seek);
    }
488 489
    else
        return E_NOTIMPL;
490
    return hr;
491 492 493 494
}

static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags)
{
495
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
496
    IMediaSeeking *seek;
497
    HRESULT hr;
498
    TRACE("(%p/%p)->(%p,%x,%p,%x)\n", iface, This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
499
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
500 501 502
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_SetPositions(seek, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
        IMediaSeeking_Release(seek);
503 504
    } else if (hr == VFW_E_NOT_CONNECTED)
        hr = S_OK;
505
    return hr;
506 507 508 509
}

static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop)
{
510
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
511 512
    IMediaSeeking *seek;
    HRESULT hr;
513
    TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop);
514
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
515 516 517 518
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetPositions(seek, pCurrent, pStop);
        IMediaSeeking_Release(seek);
    }
519 520
    else
        return E_NOTIMPL;
521
    return hr;
522 523 524 525
}

static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest)
{
526
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
527 528
    IMediaSeeking *seek;
    HRESULT hr;
529
    TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest);
530
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
531 532 533 534
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetAvailable(seek, pEarliest, pLatest);
        IMediaSeeking_Release(seek);
    }
535 536
    else
        return E_NOTIMPL;
537
    return hr;
538 539 540 541
}

static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate)
{
542
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
543 544
    IMediaSeeking *seek;
    HRESULT hr;
545
    TRACE("(%p/%p)->(%e)\n", iface, This, dRate);
546
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
547 548 549 550
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_SetRate(seek, dRate);
        IMediaSeeking_Release(seek);
    }
551 552
    else
        return E_NOTIMPL;
553
    return hr;
554 555 556 557
}

static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate)
{
558
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
559 560
    IMediaSeeking *seek;
    HRESULT hr;
561
    TRACE("(%p/%p)->(%p)\n", iface, This, dRate);
562
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
563 564 565 566
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetRate(seek, dRate);
        IMediaSeeking_Release(seek);
    }
567 568
    else
        return E_NOTIMPL;
569
    return hr;
570 571 572 573
}

static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll)
{
574
    PassThruImpl *This = impl_from_IMediaSeeking(iface);
575 576
    IMediaSeeking *seek;
    HRESULT hr;
577
    TRACE("(%p)\n", pPreroll);
578
    hr = get_connected(This, &IID_IMediaSeeking, (LPVOID*)&seek);
579 580 581 582
    if (SUCCEEDED(hr)) {
        hr = IMediaSeeking_GetPreroll(seek, pPreroll);
        IMediaSeeking_Release(seek);
    }
583 584
    else
        return E_NOTIMPL;
585
    return hr;
586 587
}

588
HRESULT WINAPI RendererPosPassThru_RegisterMediaTime(IUnknown *iface, REFERENCE_TIME start)
589
{
590
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
591 592
    EnterCriticalSection(&This->time_cs);
    This->time_earliest = start;
593
    This->timevalid = TRUE;
594
    LeaveCriticalSection(&This->time_cs);
595
    return S_OK;
596 597
}

598
HRESULT WINAPI RendererPosPassThru_ResetMediaTime(IUnknown *iface)
599
{
600
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
601
    EnterCriticalSection(&This->time_cs);
602
    This->timevalid = FALSE;
603
    LeaveCriticalSection(&This->time_cs);
604
    return S_OK;
605 606
}

607
HRESULT WINAPI RendererPosPassThru_EOS(IUnknown *iface)
608
{
609
    PassThruImpl *This = impl_from_IUnknown_inner(iface);
610 611
    REFERENCE_TIME time;
    HRESULT hr;
612
    hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &time);
613 614
    EnterCriticalSection(&This->time_cs);
    if (SUCCEEDED(hr)) {
615
        This->timevalid = TRUE;
616 617
        This->time_earliest = time;
    } else
618
        This->timevalid = FALSE;
619
    LeaveCriticalSection(&This->time_cs);
620
    return hr;
621 622
}

623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl =
{
    MediaSeekingPassThru_QueryInterface,
    MediaSeekingPassThru_AddRef,
    MediaSeekingPassThru_Release,
    MediaSeekingPassThru_GetCapabilities,
    MediaSeekingPassThru_CheckCapabilities,
    MediaSeekingPassThru_IsFormatSupported,
    MediaSeekingPassThru_QueryPreferredFormat,
    MediaSeekingPassThru_GetTimeFormat,
    MediaSeekingPassThru_IsUsingTimeFormat,
    MediaSeekingPassThru_SetTimeFormat,
    MediaSeekingPassThru_GetDuration,
    MediaSeekingPassThru_GetStopPosition,
    MediaSeekingPassThru_GetCurrentPosition,
    MediaSeekingPassThru_ConvertTimeFormat,
    MediaSeekingPassThru_SetPositions,
    MediaSeekingPassThru_GetPositions,
    MediaSeekingPassThru_GetAvailable,
    MediaSeekingPassThru_SetRate,
    MediaSeekingPassThru_GetRate,
    MediaSeekingPassThru_GetPreroll
};
646 647 648 649 650

static HRESULT WINAPI MediaPositionPassThru_QueryInterface(IMediaPosition *iface, REFIID riid, LPVOID *ppvObj)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);

651
    TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673

    return SeekOuter_QueryInterface(This, riid, ppvObj);
}

static ULONG WINAPI MediaPositionPassThru_AddRef(IMediaPosition *iface)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);

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

    return SeekOuter_AddRef(This);
}

static ULONG WINAPI MediaPositionPassThru_Release(IMediaPosition *iface)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);

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

    return SeekOuter_Release(This);
}

674
static HRESULT WINAPI MediaPositionPassThru_GetTypeInfoCount(IMediaPosition *iface, UINT *count)
675
{
676 677 678
    TRACE("iface %p, count %p.\n", iface, count);
    *count = 1;
    return S_OK;
679 680
}

681 682
static HRESULT WINAPI MediaPositionPassThru_GetTypeInfo(IMediaPosition *iface, UINT index,
        LCID lcid, ITypeInfo **typeinfo)
683
{
684 685
    TRACE("iface %p, index %u, lcid %#x, typeinfo %p.\n", iface, index, lcid, typeinfo);
    return strmbase_get_typeinfo(IMediaPosition_tid, typeinfo);
686 687
}

688 689
static HRESULT WINAPI MediaPositionPassThru_GetIDsOfNames(IMediaPosition *iface, REFIID iid,
        LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
690
{
691 692 693 694 695
    ITypeInfo *typeinfo;
    HRESULT hr;

    TRACE("iface %p, iid %s, names %p, count %u, lcid %#x, ids %p.\n",
            iface, debugstr_guid(iid), names, count, lcid, ids);
696

697 698 699 700 701 702
    if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaPosition_tid, &typeinfo)))
    {
        hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids);
        ITypeInfo_Release(typeinfo);
    }
    return hr;
703 704
}

705 706
static HRESULT WINAPI MediaPositionPassThru_Invoke(IMediaPosition *iface, DISPID id, REFIID iid, LCID lcid,
        WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *error_arg)
707
{
708 709
    ITypeInfo *typeinfo;
    HRESULT hr;
710

711 712 713 714
    TRACE("iface %p, id %d, iid %s, lcid %#x, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n",
            iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg);

    if (SUCCEEDED(hr = strmbase_get_typeinfo(IMediaPosition_tid, &typeinfo)))
715
    {
716 717
        hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg);
        ITypeInfo_Release(typeinfo);
718 719
    }
    return hr;
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
}

static HRESULT WINAPI MediaPositionPassThru_get_Duration(IMediaPosition *iface, REFTIME *plength)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", plength);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_get_Duration(pos, plength);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_put_CurrentPosition(IMediaPosition *iface, REFTIME llTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%s)\n", wine_dbgstr_longlong(llTime));

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_put_CurrentPosition(pos, llTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_get_CurrentPosition(IMediaPosition *iface, REFTIME *pllTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pllTime);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_get_CurrentPosition(pos, pllTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_get_StopTime(IMediaPosition *iface, REFTIME *pllTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pllTime);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_get_StopTime(pos, pllTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_put_StopTime(IMediaPosition *iface, REFTIME llTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%s)\n", wine_dbgstr_longlong(llTime));

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_put_StopTime(pos, llTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_get_PrerollTime(IMediaPosition *iface, REFTIME *pllTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pllTime);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_get_PrerollTime(pos, pllTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_put_PrerollTime(IMediaPosition *iface, REFTIME llTime)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%s)\n", wine_dbgstr_longlong(llTime));

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_put_PrerollTime(pos, llTime);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_put_Rate(IMediaPosition *iface, double dRate)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%f)\n", dRate);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_put_Rate(pos, dRate);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_get_Rate(IMediaPosition *iface, double *pdRate)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pdRate);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_get_Rate(pos, pdRate);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_CanSeekForward(IMediaPosition *iface, LONG *pCanSeekForward)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pCanSeekForward);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_CanSeekForward(pos, pCanSeekForward);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static HRESULT WINAPI MediaPositionPassThru_CanSeekBackward(IMediaPosition *iface, LONG *pCanSeekBackward)
{
    PassThruImpl *This = impl_from_IMediaPosition(iface);
    IMediaPosition *pos;
    HRESULT hr;

    TRACE("(%p)\n", pCanSeekBackward);

    hr = get_connected(This, &IID_IMediaPosition, (LPVOID*)&pos);
    if (SUCCEEDED(hr)) {
        hr = IMediaPosition_CanSeekBackward(pos, pCanSeekBackward);
        IMediaPosition_Release(pos);
    }
    else
        return E_NOTIMPL;
    return hr;
}

static const IMediaPositionVtbl IMediaPositionPassThru_Vtbl =
{
    MediaPositionPassThru_QueryInterface,
    MediaPositionPassThru_AddRef,
    MediaPositionPassThru_Release,
    MediaPositionPassThru_GetTypeInfoCount,
    MediaPositionPassThru_GetTypeInfo,
    MediaPositionPassThru_GetIDsOfNames,
    MediaPositionPassThru_Invoke,
    MediaPositionPassThru_get_Duration,
    MediaPositionPassThru_put_CurrentPosition,
    MediaPositionPassThru_get_CurrentPosition,
    MediaPositionPassThru_get_StopTime,
    MediaPositionPassThru_put_StopTime,
    MediaPositionPassThru_get_PrerollTime,
    MediaPositionPassThru_put_PrerollTime,
    MediaPositionPassThru_put_Rate,
    MediaPositionPassThru_get_Rate,
    MediaPositionPassThru_CanSeekForward,
    MediaPositionPassThru_CanSeekBackward
};