Microsoft DirectX 8.1 (C++)

Reconnecting Your Input to Ensure Specific Output Types

Filters implement the IAMStreamConfig::SetFormat method to set the audio or video stream's format before pins are connected. Additionally, if your output pin is already connected and you can provide a new type, then reconnect your pin. If the other pin your filter is connected to can't accept the media type, fail this call and leave your connection alone.

Transform filters that do not know what output types their pins can provide should refuse any calls to SetFormat and IAMStreamConfig::GetStreamCaps with the error code VFW_E_NOT_CONNECTED until their input pin is connected.

If your pin knows what types it can provide even when your input is not connected, it is okay to offer and accept them as usual. For more information, see Connecting Transform Filters.

In certain cases it is useful to reconnect pins when you are offering a format on an established connection. For example, if you can compress video into format X but only if you get 24-bit RGB input, and you can turn 8-bit RGB input into compressed format Y, you can either:

  1. Offer and accept both X and Y in GetStreamCaps and SetFormat all the time, or,
  2. Only offer format X if your input is connected as 24, and only offer Y if your input is connected as 8. Fail both GetStreamCaps and SetFormat if your input is not connected.

No matter which one you choose, you will need some reconnecting code that looks like this:

// Overridden to do fancy reconnecting footwork.
//
HRESULT MyOutputPin::CheckMediaType(const CMediaType *pmtOut)
{
    HRESULT hr;
    CMediaType *pmtEnum;
    BOOL fFound = FALSE;
    IEnumMediaTypes *pEnum;

    if (!m_pFilter->m_pInput->IsConnected()) {
        return VFW_E_NOT_CONNECTED;
    }

    // Quickly verify that the media type is not bogus here.
    //
   
    // If SetFormat was previously called, fail this call if the media type 
    // isn't an exact match.
   
    // Accept this output type like normal; nothing fancy required.
    hr = m_pFilter->CheckTransform(&m_pFilter->m_pInput->CurrentMediaType(),
        pmtOut);
    if (hr == NOERROR)
        return hr;

    DbgLog((LOG_TRACE,3,TEXT("Can't accept this output media type")));
    DbgLog((LOG_TRACE,3,TEXT(" But how about reconnecting the input...")));
    
    // Attempt to find an acceptable type by reconnecting the input pin.
    // The pin the input pin connects to might be able to provide a type
    // that the pin can convert into the necessary type.
    hr = m_pFilter->m_pInput->GetConnected()->EnumMediaTypes(&pEnum);
    if (hr != NOERROR)
        return E_FAIL;
    while (1) {
        hr = pEnum->Next(1, (AM_MEDIA_TYPE **)&pmtEnum, &j);

    // All out of enumerated types.
    if (hr == S_FALSE || j == 0) {
        break;
    }

    // Can the pin convert between these?
    hr = m_pFilter->CheckTransform(pmtEnum, pmtOut);

    if (hr != NOERROR) {
        DeleteMediaType(pmtEnum);
        continue;
    }

    // OK, it offers an acceptable type, but will it accept it now?
    hr = m_pFilter->m_pInput->GetConnected()->QueryAccept(pmtEnum);
    // Nope.
    if (hr != NOERROR) {
        DeleteMediaType(pmtEnum);
        continue;
    }
    // OK.
    fFound = TRUE;
    DbgLog((LOG_TRACE,2,TEXT("This output type is only acceptable after
                                reconnecting the input.")));

    // All done with this.
    DeleteMediaType(pmtEnum);
    break;
    }
    pEnum->Release();

    if (!fFound)
        DbgLog((LOG_TRACE,3,TEXT("*NO! Reconnecting the input won't help")));
    
    return fFound ? NOERROR : VFW_E_INVALIDMEDIATYPE;
}



HRESULT MyOutputPin::SetFormat(AM_MEDIA_TYPE *pmt)
{
    HRESULT hr;
    LPWAVEFORMATEX lpwfx;
    DWORD dwSize;

    if (pmt == NULL)
    return E_POINTER;


    // To make sure streaming isn't in the middle of starting/stopping:
    CAutoLock cObjectLock(&m_pFilter->m_csFilter);

    if (m_pFilter->m_State != State_Stopped)
    return VFW_E_NOT_STOPPED;

    // Possible output formats depend on the input format.
    if (!m_pFilter->m_pInput->IsConnected())
    return VFW_E_NOT_CONNECTED;

    // Already using this format.
    if (IsConnected() && CurrentMediaType() == *pmt)
    return NOERROR;

    // See if this type is acceptable.
    if ((hr = CheckMediaType((CMediaType *)pmt)) != NOERROR) {
    DbgLog((LOG_TRACE,2,TEXT("IAMStreamConfig::SetFormat rejected")));
    return hr;
    }

    // If connecting to another filter, make sure the filter likes it.
    if (IsConnected()) {
    hr = GetConnected()->QueryAccept(pmt);
    if (hr != NOERROR)
        return VFW_E_INVALIDMEDIATYPE;
    }

    // Now make a note that from now on, this is the only format allowed,
    // and refuse anything but this in the CheckMediaType code above.

    // Changing the format means reconnecting if necessary.
    if (IsConnected())
        m_pFilter->m_pGraph->Reconnect(this);

    return NOERROR;
}


// Overridden to complete the fancy reconnection footwork:
//
HRESULT MyWrapper::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
{
    HRESULT hr;

    // Set the OUTPUT type.
    if (direction == PINDIR_OUTPUT) {

    // Uh oh. As part of the fancy reconnection, the input pin might be asked to
    // provide a media type it cannot provide without reconnection
    // to a different type.
    if (m_pInput && m_pInput->IsConnected()) {

        // If the pin can actually provide this type now, don't worry.
            hr = CheckTransform(&m_pInput->CurrentMediaType(),
                    &m_pOutput->CurrentMediaType());
        if (hr == NOERROR)
        return hr;
    
                DbgLog((LOG_TRACE,2,TEXT("*Set OUTPUT requires RECONNECT of INPUT!")));

        // Reconnect the input pin. 
        return m_pGraph->Reconnect(m_pInput);

    }

    return NOERROR;
    }

    return NOERROR;
}