Exemple #1
0
void Parser_Destroy(ParserImpl *This)
{
    IPin *connected = NULL;
    ULONG pinref;

    assert(!This->filter.refCount);
    PullPin_WaitForStateChange(This->pInputPin, INFINITE);

    /* Don't need to clean up output pins, freeing input pin will do that */
    IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &connected);
    if (connected)
    {
        assert(IPin_Disconnect(connected) == S_OK);
        IPin_Release(connected);
        assert(IPin_Disconnect(&This->pInputPin->pin.IPin_iface) == S_OK);
    }
    pinref = IPin_Release(&This->pInputPin->pin.IPin_iface);
    if (pinref)
    {
        /* Valgrind could find this, if I kill it here */
        ERR("pinref should be null, is %u, destroying anyway\n", pinref);
        assert((LONG)pinref > 0);

        while (pinref)
            pinref = IPin_Release(&This->pInputPin->pin.IPin_iface);
    }

    CoTaskMemFree(This->ppPins);

    TRACE("Destroying parser\n");
    CoTaskMemFree(This);
}
Exemple #2
0
ULONG WINAPI BaseRendererImpl_Release(IBaseFilter* iface)
{
    BaseRenderer *This = impl_from_IBaseFilter(iface);
    ULONG refCount = BaseFilterImpl_Release(iface);

    if (!refCount)
    {
        IPin *pConnectedTo;

        if (SUCCEEDED(IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &pConnectedTo)))
        {
            IPin_Disconnect(pConnectedTo);
            IPin_Release(pConnectedTo);
        }
        IPin_Disconnect(&This->pInputPin->pin.IPin_iface);
        IPin_Release(&This->pInputPin->pin.IPin_iface);

        if (This->pPosition)
            IUnknown_Release(This->pPosition);

        This->csRenderLock.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->csRenderLock);

        BaseRendererImpl_ClearPendingSample(This);
        CloseHandle(This->evComplete);
        CloseHandle(This->ThreadSignal);
        CloseHandle(This->RenderEvent);
        QualityControlImpl_Destroy(This->qcimpl);
    }
    return refCount;
}
Exemple #3
0
static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
{
    VfwCapture *This = impl_from_IUnknown(iface);
    ULONG ref = InterlockedDecrement(&This->filter.refCount);

    TRACE("(%p) ref=%d\n", This, ref);

    if (!ref)
    {
        IPin *conn = NULL;

        TRACE("destroying everything\n");
        if (This->init)
        {
            if (This->filter.state != State_Stopped)
                qcap_driver_stop(This->driver_info, &This->filter.state);
            qcap_driver_destroy(This->driver_info);
        }
        IPin_ConnectedTo(This->pOutputPin, &conn);
        if (conn)
        {
            IPin_Disconnect(conn);
            IPin_Disconnect(This->pOutputPin);
            IPin_Release(conn);
        }
        IPin_Release(This->pOutputPin);
        BaseFilter_Destroy(&This->filter);
        CoTaskMemFree(This);
        ObjectRefCount(FALSE);
    }

    return ref;
}
Exemple #4
0
static ULONG WINAPI NullRendererInner_Release(IUnknown * iface)
{
    ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
    ULONG refCount = InterlockedDecrement(&This->refCount);

    TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);

    if (!refCount)
    {
        IPin *pConnectedTo;

        if (This->pClock)
            IReferenceClock_Release(This->pClock);

        if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
        {
            IPin_Disconnect(pConnectedTo);
            IPin_Release(pConnectedTo);
        }
        IPin_Disconnect((IPin *)This->pInputPin);
        IPin_Release((IPin *)This->pInputPin);

        This->lpVtbl = NULL;

        This->csFilter.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->csFilter);

        TRACE("Destroying Null Renderer\n");
        CoTaskMemFree(This);
        return 0;
    }
    else
        return refCount;
}
Exemple #5
0
static HRESULT WINAPI QTInPin_Disconnect(IPin *iface)
{
    HRESULT hr;
    QTInPin *This = impl_from_IPin(iface);
    FILTER_STATE state;
    TRACE("()\n");

    hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
    EnterCriticalSection(This->pin.pCritSec);
    if (This->pin.pConnectedTo)
    {
        QTSplitter *Parser = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);

        if (SUCCEEDED(hr) && state == State_Stopped)
        {
            IMemAllocator_Decommit(This->pAlloc);
            IPin_Disconnect(This->pin.pConnectedTo);
            This->pin.pConnectedTo = NULL;
            hr = QT_RemoveOutputPins(Parser);
        }
        else
            hr = VFW_E_NOT_STOPPED;
    }
    else
        hr = S_FALSE;
    LeaveCriticalSection(This->pin.pCritSec);
    return hr;
}
Exemple #6
0
static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
{
    DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
    ULONG refCount = InterlockedDecrement(&This->refCount);

    TRACE("(%p)->() Release from %d\n", This, refCount + 1);

    if (!refCount)
    {
        IPin *pConnectedTo;

        if (This->pClock)
            IReferenceClock_Release(This->pClock);

        if (This->dsbuffer)
            IDirectSoundBuffer_Release(This->dsbuffer);
        This->dsbuffer = NULL;
        if (This->dsound)
            IDirectSound_Release(This->dsound);
        This->dsound = NULL;
       
        if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
        {
            IPin_Disconnect(pConnectedTo);
            IPin_Release(pConnectedTo);
        }
        IPin_Disconnect((IPin *)This->pInputPin);

        IPin_Release((IPin *)This->pInputPin);

        This->lpVtbl = NULL;
        This->IBasicAudio_vtbl = NULL;
        
        This->csFilter.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->csFilter);

        CloseHandle(This->state_change);
        CloseHandle(This->blocked);

        TRACE("Destroying Audio Renderer\n");
        CoTaskMemFree(This);
        
        return 0;
    }
    else
        return refCount;
}
Exemple #7
0
static void QT_Destroy(QTSplitter *This)
{
    IPin *connected = NULL;
    ULONG pinref;

    TRACE("Destroying\n");

    EnterCriticalSection(&This->csReceive);
    /* Don't need to clean up output pins, disconnecting input pin will do that */
    IPin_ConnectedTo(&This->pInputPin.pin.IPin_iface, &connected);
    if (connected)
    {
        IPin_Disconnect(connected);
        IPin_Release(connected);
    }
    pinref = IPin_Release(&This->pInputPin.pin.IPin_iface);
    if (pinref)
    {
        ERR("pinref should be null, is %u, destroying anyway\n", pinref);
        assert((LONG)pinref > 0);

        while (pinref)
            pinref = IPin_Release(&This->pInputPin.pin.IPin_iface);
    }

    if (This->pQTMovie)
    {
        DisposeMovie(This->pQTMovie);
        This->pQTMovie = NULL;
    }
    if (This->vContext)
        QTVisualContextRelease(This->vContext);
    if (This->aSession)
        MovieAudioExtractionEnd(This->aSession);

    ExitMoviesOnThread();
    LeaveCriticalSection(&This->csReceive);

    if (This->loaderThread)
    {
        WaitForSingleObject(This->loaderThread, INFINITE);
        CloseHandle(This->loaderThread);
    }
    if (This->splitterThread)
    {
        SetEvent(This->runEvent);
        WaitForSingleObject(This->splitterThread, INFINITE);
        CloseHandle(This->splitterThread);
    }

    CloseHandle(This->runEvent);

    This->csReceive.DebugInfo->Spare[0] = 0;
    DeleteCriticalSection(&This->csReceive);
    BaseFilter_Destroy(&This->filter);

    CoTaskMemFree(This);
}
Exemple #8
0
static HRESULT WINAPI QTOutPin_BreakConnect(BaseOutputPin *This)
{
    HRESULT hr;

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

    EnterCriticalSection(This->pin.pCritSec);
    if (!This->pin.pConnectedTo || !This->pMemInputPin)
        hr = VFW_E_NOT_CONNECTED;
    else
    {
        hr = IPin_Disconnect(This->pin.pConnectedTo);
        IPin_Disconnect(&This->pin.IPin_iface);
    }
    LeaveCriticalSection(This->pin.pCritSec);

    return hr;
}
Exemple #9
0
static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
{
    TransformFilterImpl *This = (TransformFilterImpl *)iface;
    ULONG refCount = InterlockedDecrement(&This->refCount);

    TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);

    if (!refCount)
    {
        ULONG i;

        if (This->pClock)
            IReferenceClock_Release(This->pClock);

        for (i = 0; i < This->npins; i++)
        {
            IPin *pConnectedTo;

            if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
            {
                IPin_Disconnect(pConnectedTo);
                IPin_Release(pConnectedTo);
            }
            IPin_Disconnect(This->ppPins[i]);

            IPin_Release(This->ppPins[i]);
        }

        CoTaskMemFree(This->ppPins);
        This->lpVtbl = NULL;

        This->csFilter.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->csFilter);

        TRACE("Destroying transform filter\n");
        FreeMediaType(&This->pmt);
        CoTaskMemFree(This);

        return 0;
    }
    else
        return refCount;
}
Exemple #10
0
static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
{
    DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
    ULONG refCount = BaseFilterImpl_Release(iface);

    TRACE("(%p)->() Release from %d\n", This, refCount + 1);

    if (!refCount)
    {
        IPin *pConnectedTo;

        if (This->dsbuffer)
            IDirectSoundBuffer_Release(This->dsbuffer);
        This->dsbuffer = NULL;
        if (This->dsound)
            IDirectSound_Release(This->dsound);
        This->dsound = NULL;
       
        if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
        {
            IPin_Disconnect(pConnectedTo);
            IPin_Release(pConnectedTo);
        }
        IPin_Disconnect((IPin *)This->pInputPin);

        IPin_Release((IPin *)This->pInputPin);

        This->IBasicAudio_vtbl = NULL;
        if (This->seekthru_unk)
            IUnknown_Release(This->seekthru_unk);

        CloseHandle(This->state_change);
        CloseHandle(This->blocked);

        TRACE("Destroying Audio Renderer\n");
        CoTaskMemFree(This);
        
        return 0;
    }
    else
        return refCount;
}
Exemple #11
0
ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
{
    TransformFilter *This = impl_from_IBaseFilter(iface);
    ULONG refCount = InterlockedDecrement(&This->filter.refCount);

    TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);

    if (!refCount)
    {
        ULONG i;

        for (i = 0; i < This->npins; i++)
        {
            IPin *pConnectedTo;

            if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
            {
                IPin_Disconnect(pConnectedTo);
                IPin_Release(pConnectedTo);
            }
            IPin_Disconnect(This->ppPins[i]);

            IPin_Release(This->ppPins[i]);
        }

        CoTaskMemFree(This->ppPins);

        TRACE("Destroying transform filter\n");
        This->csReceive.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->csReceive);
        FreeMediaType(&This->pmt);
        QualityControlImpl_Destroy(This->qcimpl);
        IUnknown_Release(This->seekthru_unk);
        BaseFilter_Destroy(&This->filter);
        CoTaskMemFree(This);

        return 0;
    }
    else
        return refCount;
}
Exemple #12
0
ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
{
    TransformFilter *This = (TransformFilter *)iface;
    ULONG refCount = BaseFilterImpl_Release(iface);

    TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);

    if (!refCount)
    {
        ULONG i;

        for (i = 0; i < This->npins; i++)
        {
            IPin *pConnectedTo;

            if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
            {
                IPin_Disconnect(pConnectedTo);
                IPin_Release(pConnectedTo);
            }
            IPin_Disconnect(This->ppPins[i]);

            IPin_Release(This->ppPins[i]);
        }

        CoTaskMemFree(This->ppPins);

        TRACE("Destroying transform filter\n");
        FreeMediaType(&This->pmt);
        CoTaskMemFree(This);

        return 0;
    }
    else
        return refCount;
}
Exemple #13
0
/* This test doesn't use the quartz filtergraph because it makes it impossible
 * to be certain that a thread is really one owned by the avi splitter.
 * A lot of the decoder filters will also have their own thread, and Windows'
 * filtergraph has a separate thread for start/stop/seeking requests.
 * By avoiding the filtergraph altogether and connecting streams directly to
 * the null renderer I am sure that this is not the case here.
 */
static void test_threads(void)
{
    IFileSourceFilter *pfile = NULL;
    IBaseFilter *preader = NULL, *pavi = NULL;
    IEnumPins *enumpins = NULL;
    IPin *filepin = NULL, *avipin = NULL;
    HRESULT hr;
    int baselevel, curlevel, expected;
    HANDLE file = NULL;
    PIN_DIRECTION dir = PINDIR_OUTPUT;
    char buffer[13];
    DWORD readbytes;
    FILTER_STATE state;

    /* We need another way of counting threads on NT4. Skip these tests (for now) */
    if (!pCreateToolhelp32Snapshot || !pThread32First || !pThread32Next)
    {
        win_skip("Needed thread functions are not available (NT4)\n");
        return;
    }

    /* Before doing anything (the thread count at the start differs per OS) */
    baselevel = count_threads();

    file = CreateFileW(wfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, 0, NULL);
    if (file == INVALID_HANDLE_VALUE)
    {
        skip("Could not read test file \"%s\", skipping test\n", afile);
        return;
    }

    memset(buffer, 0, 13);
    readbytes = 12;
    ReadFile(file, buffer, readbytes, &readbytes, NULL);
    CloseHandle(file);
    if (strncmp(buffer, "RIFF", 4) || strcmp(buffer + 8, "AVI "))
    {
        skip("%s is not an avi riff file, not doing the avi splitter test\n",
            afile);
        return;
    }

    hr = IUnknown_QueryInterface(pAviSplitter, &IID_IFileSourceFilter,
        (void **)&pfile);
    ok(hr == E_NOINTERFACE,
        "Avi splitter returns unexpected error: %08x\n", hr);
    if (pfile)
        IFileSourceFilter_Release(pfile);
    pfile = NULL;

    hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER,
        &IID_IBaseFilter, (LPVOID*)&preader);
    ok(hr == S_OK, "Could not create asynchronous reader: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter,
        (void**)&pfile);
    ok(hr == S_OK, "Could not get IFileSourceFilter: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter,
        (void**)&pavi);
    ok(hr == S_OK, "Could not get base filter: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    hr = IFileSourceFilter_Load(pfile, wfile, NULL);
    if (hr != S_OK)
    {
        trace("Could not load file\n");
        goto fail;
    }

    hr = IBaseFilter_EnumPins(preader, &enumpins);
    ok(hr == S_OK, "No enumpins: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    hr = IEnumPins_Next(enumpins, 1, &filepin, NULL);
    ok(hr == S_OK, "No pin: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    IEnumPins_Release(enumpins);
    enumpins = NULL;

    hr = IBaseFilter_EnumPins(pavi, &enumpins);
    ok(hr == S_OK, "No enumpins: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    hr = IEnumPins_Next(enumpins, 1, &avipin, NULL);
    ok(hr == S_OK, "No pin: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    curlevel = count_threads();
    ok(curlevel == baselevel,
        "The thread count should be %d not %d\n", baselevel, curlevel);

    hr = IPin_Connect(filepin, avipin, NULL);
    ok(hr == S_OK, "Could not connect: %08x\n", hr);
    if (hr != S_OK)
        goto fail;

    expected = 1 + baselevel;
    curlevel = count_threads();
    ok(curlevel == expected,
        "The thread count should be %d not %d\n", expected, curlevel);

    IPin_Release(avipin);
    avipin = NULL;

    IEnumPins_Reset(enumpins);

    /* Windows puts the pins in the order: Outputpins - Inputpin,
     * wine does the reverse, just don't test it for now
     * Hate to admit it, but windows way makes more sense
     */
    while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK)
    {
        IPin_QueryDirection(avipin, &dir);
        if (dir == PINDIR_OUTPUT)
        {
            /* Well, connect it to a null renderer! */
            IBaseFilter *pnull = NULL;
            IEnumPins *nullenum = NULL;
            IPin *nullpin = NULL;

            hr = CoCreateInstance(&CLSID_NullRenderer, NULL,
                CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pnull);
            ok(hr == S_OK, "Could not create null renderer: %08x\n", hr);
            if (hr != S_OK)
                break;

            IBaseFilter_EnumPins(pnull, &nullenum);
            IEnumPins_Next(nullenum, 1, &nullpin, NULL);
            IEnumPins_Release(nullenum);
            IPin_QueryDirection(nullpin, &dir);

            hr = IPin_Connect(avipin, nullpin, NULL);
            ok(hr == S_OK, "Failed to connect output pin: %08x\n", hr);
            IPin_Release(nullpin);
            if (hr != S_OK)
            {
                IBaseFilter_Release(pnull);
                break;
            }
            IBaseFilter_Run(pnull, 0);
            ++expected;
        }

        IPin_Release(avipin);
        avipin = NULL;
    }

    if (avipin)
        IPin_Release(avipin);
    avipin = NULL;

    if (hr != S_OK)
        goto fail2;
    /* At this point there is a minimalistic connected avi splitter that can
     * be used for all sorts of source filter tests. However that still needs
     * to be written at a later time.
     *
     * Interesting tests:
     * - Can you disconnect an output pin while running?
     *   Expecting: Yes
     * - Can you disconnect the pullpin while running?
     *   Expecting: No
     * - Is the reference count incremented during playback or when connected?
     *   Does this happen once for every output pin? Or is there something else
     *   going on.
     *   Expecting: You tell me
     */

    IBaseFilter_Run(preader, 0);
    IBaseFilter_Run(pavi, 0);
    IBaseFilter_GetState(pavi, INFINITE, &state);

    curlevel = count_threads();
    ok(curlevel == expected,
        "The thread count should be %d not %d\n", expected, curlevel);

    IBaseFilter_Pause(pavi);
    IBaseFilter_Pause(preader);
    IBaseFilter_Stop(pavi);
    IBaseFilter_Stop(preader);
    IBaseFilter_GetState(pavi, INFINITE, &state);
    IBaseFilter_GetState(preader, INFINITE, &state);

fail2:
    IEnumPins_Reset(enumpins);
    while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK)
    {
        IPin *to = NULL;

        IPin_QueryDirection(avipin, &dir);
        IPin_ConnectedTo(avipin, &to);
        if (to)
        {
            IPin_Release(to);

            if (dir == PINDIR_OUTPUT)
            {
                PIN_INFO info;
                IPin_QueryPinInfo(to, &info);

                /* Release twice: Once normal, second from the
                 * previous while loop
                 */
                IBaseFilter_Stop(info.pFilter);
                IPin_Disconnect(to);
                IPin_Disconnect(avipin);
                IBaseFilter_Release(info.pFilter);
                IBaseFilter_Release(info.pFilter);
            }
            else
            {
                IPin_Disconnect(to);
                IPin_Disconnect(avipin);
            }
        }
        IPin_Release(avipin);
        avipin = NULL;
    }

fail:
    if (hr != S_OK)
        skip("Prerequisites not matched, skipping remainder of test\n");
    if (enumpins)
        IEnumPins_Release(enumpins);

    if (avipin)
        IPin_Release(avipin);
    if (filepin)
    {
        IPin *to = NULL;

        IPin_ConnectedTo(filepin, &to);
        if (to)
        {
            IPin_Disconnect(filepin);
            IPin_Disconnect(to);
        }
        IPin_Release(filepin);
    }

    if (preader)
        IBaseFilter_Release(preader);
    if (pavi)
        IBaseFilter_Release(pavi);
    if (pfile)
        IFileSourceFilter_Release(pfile);

    curlevel = count_threads();
    todo_wine
    ok(curlevel == baselevel,
        "The thread count should be %d not %d\n", baselevel, curlevel);
}
Exemple #14
0
static void test_AviMux(void)
{
    test_filter source_filter, sink_filter;
    VIDEOINFOHEADER videoinfoheader;
    IPin *avimux_in, *avimux_out, *pin;
    AM_MEDIA_TYPE source_media_type;
    AM_MEDIA_TYPE *media_type;
    PIN_DIRECTION dir;
    IBaseFilter *avimux;
    IEnumPins *ep;
    IEnumMediaTypes *emt;
    HRESULT hr;

    init_test_filter(&source_filter, PINDIR_OUTPUT, SOURCE_FILTER);
    init_test_filter(&sink_filter, PINDIR_INPUT, SINK_FILTER);

    hr = CoCreateInstance(&CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void**)&avimux);
    ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG),
            "couldn't create AVI Mux filter, hr = %08x\n", hr);
    if(hr != S_OK) {
        win_skip("AVI Mux filter is not registered\n");
        return;
    }

    hr = IBaseFilter_EnumPins(avimux, &ep);
    ok(hr == S_OK, "EnumPins returned %x\n", hr);

    hr = IEnumPins_Next(ep, 1, &avimux_out, NULL);
    ok(hr == S_OK, "Next returned %x\n", hr);
    hr = IPin_QueryDirection(avimux_out, &dir);
    ok(hr == S_OK, "QueryDirection returned %x\n", hr);
    ok(dir == PINDIR_OUTPUT, "dir = %d\n", dir);

    hr = IEnumPins_Next(ep, 1, &avimux_in, NULL);
    ok(hr == S_OK, "Next returned %x\n", hr);
    hr = IPin_QueryDirection(avimux_in, &dir);
    ok(hr == S_OK, "QueryDirection returned %x\n", hr);
    ok(dir == PINDIR_INPUT, "dir = %d\n", dir);
    IEnumPins_Release(ep);

    hr = IPin_EnumMediaTypes(avimux_out, &emt);
    ok(hr == S_OK, "EnumMediaTypes returned %x\n", hr);
    hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL);
    ok(hr == S_OK, "Next returned %x\n", hr);
    ok(IsEqualIID(&media_type->majortype, &MEDIATYPE_Stream), "majortype = %s\n",
            debugstr_guid(&media_type->majortype));
    ok(IsEqualIID(&media_type->subtype, &MEDIASUBTYPE_Avi), "subtype = %s\n",
            debugstr_guid(&media_type->subtype));
    ok(media_type->bFixedSizeSamples, "bFixedSizeSamples = %x\n", media_type->bFixedSizeSamples);
    ok(!media_type->bTemporalCompression, "bTemporalCompression = %x\n", media_type->bTemporalCompression);
    ok(media_type->lSampleSize == 1, "lSampleSize = %d\n", media_type->lSampleSize);
    ok(IsEqualIID(&media_type->formattype, &GUID_NULL), "formattype = %s\n",
            debugstr_guid(&media_type->formattype));
    ok(!media_type->pUnk, "pUnk = %p\n", media_type->pUnk);
    ok(!media_type->cbFormat, "cbFormat = %d\n", media_type->cbFormat);
    ok(!media_type->pbFormat, "pbFormat = %p\n", media_type->pbFormat);
    CoTaskMemFree(media_type);
    hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL);
    ok(hr == S_FALSE, "Next returned %x\n", hr);
    IEnumMediaTypes_Release(emt);

    hr = IPin_EnumMediaTypes(avimux_in, &emt);
    ok(hr == S_OK, "EnumMediaTypes returned %x\n", hr);
    hr = IEnumMediaTypes_Reset(emt);
    ok(hr == S_OK, "Reset returned %x\n", hr);
    hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL);
    ok(hr == S_FALSE, "Next returned %x\n", hr);
    IEnumMediaTypes_Release(emt);

    hr = IPin_ReceiveConnection(avimux_in, &source_filter.IPin_iface, NULL);
    ok(hr == E_POINTER, "ReceiveConnection returned %x\n", hr);

    current_calls_list = NULL;
    memset(&source_media_type, 0, sizeof(AM_MEDIA_TYPE));
    memset(&videoinfoheader, 0, sizeof(VIDEOINFOHEADER));
    source_media_type.majortype = MEDIATYPE_Video;
    source_media_type.subtype = MEDIASUBTYPE_RGB32;
    source_media_type.formattype = FORMAT_VideoInfo;
    source_media_type.bFixedSizeSamples = TRUE;
    source_media_type.lSampleSize = 40000;
    source_media_type.cbFormat = sizeof(VIDEOINFOHEADER);
    source_media_type.pbFormat = (BYTE*)&videoinfoheader;
    videoinfoheader.AvgTimePerFrame = 333333;
    videoinfoheader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    videoinfoheader.bmiHeader.biWidth = 100;
    videoinfoheader.bmiHeader.biHeight = 100;
    videoinfoheader.bmiHeader.biPlanes = 1;
    videoinfoheader.bmiHeader.biBitCount = 32;
    videoinfoheader.bmiHeader.biSizeImage = 40000;
    videoinfoheader.bmiHeader.biClrImportant = 256;
    hr = IPin_ReceiveConnection(avimux_in, &source_filter.IPin_iface, &source_media_type);
    ok(hr == S_OK, "ReceiveConnection returned %x\n", hr);

    hr = IPin_ConnectedTo(avimux_in, &pin);
    ok(hr == S_OK, "ConnectedTo returned %x\n", hr);
    ok(pin == &source_filter.IPin_iface, "incorrect pin: %p, expected %p\n",
            pin, &source_filter.IPin_iface);

    hr = IPin_Connect(avimux_out, &source_filter.IPin_iface, NULL);
    todo_wine ok(hr == VFW_E_INVALID_DIRECTION, "Connect returned %x\n", hr);

    hr = IBaseFilter_JoinFilterGraph(avimux, (IFilterGraph*)&GraphBuilder, NULL);
    ok(hr == S_OK, "JoinFilterGraph returned %x\n", hr);

    SET_EXPECT(ReceiveConnection);
    SET_EXPECT(GetAllocatorRequirements);
    SET_EXPECT(NotifyAllocator);
    SET_EXPECT(Reconnect);
    hr = IPin_Connect(avimux_out, &sink_filter.IPin_iface, NULL);
    ok(hr == S_OK, "Connect returned %x\n", hr);
    CHECK_CALLED(ReceiveConnection);
    CHECK_CALLED(GetAllocatorRequirements);
    CHECK_CALLED(NotifyAllocator);
    CHECK_CALLED(Reconnect);

    hr = IPin_Disconnect(avimux_out);
    ok(hr == S_OK, "Disconnect returned %x\n", hr);

    IPin_Release(avimux_in);
    IPin_Release(avimux_out);
    IBaseFilter_Release(avimux);
}