DirectShow DirectShow 의 사용법 DirectShow 필터의 개발 캡춰 포맷과 압축 포맷의 공개 특정의 출력 타입을 보증하기 위해서 입력을 재접속한다   [목차열람] [주소복사] [슬롯비우기]
특정의 출력 타입을 보증하기 위해서 입력을 재접속한다
 
Microsoft DirectX 9.0

특정의 출력 타입을 보증하기 위해서 입력을 재접속한다

필터는, 핀이 접속되기 전에 오디오 또는 비디오의 포맷을 설정하기 위해서,IAMStreamConfig::SetFormat 메서드를 처리 한다. 출력 핀이 이미 접속되어 새로운 타입을 제공할 수 있는 경우, 핀을 재접속하지만, 다른 필터가 새로운 타입을 받아들여지는 경우에 한정하는 것. 다만, 다른 필터가 미디어 타입을 허가할 수 없는 경우,SetFormat 에의 호출은 실패해, 지금까지의 접속이 그대로 남겨진다.

변환 필터는, 그 입력 핀이 접속되지 않은 한, 우선 출력 타입을 가지지 않는 것이 있다. 그 경우,SetFormat 메서드와 IAMStreamConfig::GetStreamCaps 메서드는, 입력 핀이 접속될 때까지 VFW_E_NOT_CONNECTED 를 돌려준다. 그 이외의 경우, 이러한 메서드는 보통 대로 동작할 수 있다.

경우에 따라서는, 확립 끝난 접속에 대해서 포맷을 제시할 경우에 핀을 재접속하는 것이 편리한 일도 있다. 예를 들어, 필터는 24 비트의 RGB 비디오를 포맷 X 에 압축할 수 있어 8 비트의 RGB 비디오를 포맷 Y 에 압축할 수 있으면 상정한다. 출력 핀은 다음의 어느 처리도 실행할 수 있다.

어느 쪽의 경우도, 다음과 같은 재접속 코드가 필요하게 된다.

HRESULT MyOutputPin::CheckMediaType(const CMediaType *pmtOut)
{
    // 입력 핀이 접속되지 않은 경우, 실패한다.
    if (! m_pFilter->m_pInput->IsConnected()) {
        return VFW_E_NOT_CONNECTED;
    }

    // (생략 : 필터로 사용할 수 없는 것을 미리 알고 있는 미디어 타입을
    // 거부한다. 메이저 타입과 서브 타입의 GUID 를 확인한다. )

    // (생략  : SetFormat 가 이전에 불려 갔을 경우, pmtOut 가
    // SetFormat 로 지정된 포맷에 정확하게 일치할지 어떨지 확인한다.
    // 일치하는 경우는 S_OK 를, 일치하지 않는 경우는 VFW_E_INVALIDMEDIATYPE 를 돌려준다. )
   
    // 이 미디어 타입에 대한 보통의 확인을 실시한다.
    HRESULT hr;
    hr = m_pFilter->CheckTransform(
        &m_pFilter->m_pInput->CurrentMediaType(),  // 입력 타입.
        pmtOut  // 제시된 출력 타입.
    );
    if (hr == S_OK)
    {
        // 이 포맷은 현재의 입력 타입과 호환성이 있다.
        return S_OK;
    }
 
    // 이 포맷은 현재의 입력 타입과 호환성이 없다.
    // 새로운 입력 타입을 사용해 입력 핀을 접속할 수 있을 가능성이 있다.
    
    // 업 스트림 필터의 우선 출력 타입을 열거해,
    // 그 중 1 개가 동작할지 어떨지를 확인한다.
    CMediaType *pmtEnum;
    BOOL fFound = FALSE;
    IEnumMediaTypes *pEnum;
    hr = m_pFilter->m_pInput->GetConnected() ->EnumMediaTypes(&pEnum);
    if (hr != S_OK)
    {
        return E_FAIL;
    }
    while (hr = pEnum->Next(1, (AM_MEDIA_TYPE **) &pmtEnum, NULL), hr == S_OK)
    {
        // 제시된 출력 타입에 대해서 이 입력 타입을 조사한다.
        hr = m_pFilter->CheckTransform(pmtEnum, pmtOut);
        if (hr != S_OK) 
        {
            DeleteMediaType(pmtEnum);
            continue; // 다음의 타입을 테스트한다.
        }

        // 이 입력 타입은 후보의 1 개이다. 그러나, 업 스트림 필터가
        // 이 타입에 바뀔 수 있는 것을 확인할 필요가 있다.
        hr = m_pFilter->m_pInput->GetConnected() ->QueryAccept(pmtEnum);
        if (hr != S_OK) 
        {
            // 업 스트림 필터는 이 타입에 바뀌지 않는다.
            DeleteMediaType(pmtEnum);
            continue; // 다음의 타입을 테스트한다.
        }
        fFound = TRUE;
        DeleteMediaType(pmtEnum);
        break;
    }
    pEnum->Release();

    if (fFound)
    {
        // 이 출력 타입은 적정이지만, 이 타입의 사용이 요구되었을 경우, 입력 핀을
        // 재접속할 필요가 있다 ( 후의 SetFormat 에 대한 설명을 참조할것).
        return S_OK;
    }
    else
    {
        return VFW_E_INVALIDMEDIATYPE;
    }
}

HRESULT MyOutputPin::SetFormat(AM_MEDIA_TYPE *pmt)
{
    CheckPointer(pmt, E_POINTER);
    HRESULT hr;

    // 스트리밍이 시작 또는 정지의 한중간이 아니게,
    // 필터 상태 잠금을 보관 유지한다.
    CAutoLock cObjectLock(&m_pFilter->m_csFilter);

    // 필터가 정지하지 않는 한, 포맷은 설정할 수 없다.
    if (m_pFilter->m_State != State_Stopped)
    {
        return VFW_E_NOT_STOPPED;
    }

    // 가능한 출력 포맷의 집합은 입력 포맷에 의해 다르다.
    // 따라서, 입력 핀이 접속되지 않은 경우, 실패 코드를 돌려준다.
    if (! m_pFilter->m_pInput->IsConnected())
    {
        return VFW_E_NOT_CONNECTED;
    }

    // 핀이 이미 이 포맷을 사용하고 있는 경우, 처리는 필요없다.
    if (IsConnected() && CurrentMediaType() == *pmt)
    {
        return S_OK;
    }

    // 이 미디어 타입이 받아들이고 가능한가 어떤가를 확인한다.
    if ((hr = CheckMediaType((CMediaType *) pmt)) != S_OK) 
    {
        return hr;
    }

    // 다운 스트림 필터에 접속하고 있는 경우, 다운 스트림 필터가
    // 이 미디어 타입을 받아들일지 어떨지 확인할 필요가 있다.
    if (IsConnected()) 
    {
        hr = GetConnected() ->QueryAccept(pmt);
        if (hr != S_OK)
        {
            return VFW_E_INVALIDMEDIATYPE;
        }
    }

    // 이후는 이것이 유일 사용할 수 있는 포맷이며, 위에의 CheckMediaType 
    // 코드에서는 이 포맷 이외를 거부하는 점에 주의 해야 한다.

    // 포맷의 변경은, 필요에 따라서 재접속하는 것을 의미한다.
    if (IsConnected())
    {
        m_pFilter->m_pGraph->Reconnect(this);
    }

    return NOERROR;
}


// CTransformFilter::SetMediaType 를 오버라이드(override) 해 입력 핀을 재접속한다.
// 미디어 타입이 핀으로 설정된 직후에 이 메서드가 호출된다.
HRESULT MyFilter::SetMediaType(
    PIN_DIRECTION direction, 
    const CMediaType *pmt
)
{
    HRESULT hr;
    if (direction == PINDIR_OUTPUT) 
    {
        // 출력 타입을 설정하기 전에, 새로운 타입을 사용했다
        // 입력 핀의 재접속이 필요하게 되는 일이 있다.
        if (m_pInput && m_pInput->IsConnected()) 
        {
            // 현재의 입력 타입에 호환성이 있을지 어떨지를 조사한다.
            hr = CheckTransform(
                    &m_pInput->CurrentMediaType(),
                    &m_pOutput->CurrentMediaType());
            if (SUCCEEDED(hr))
            {
                return S_OK;
            }
            // 호환성이 없는 경우, 입력 핀을 재접속할 필요가 있다.
            // 주 : CheckMediaType 메서드는 업 스트림 필터에
            // 대해 이미 QueryAccept 를 호출하고 있다.
            hr = m_pGraph->Reconnect(m_pInput);
            return hr;
        }
    }
    return S_OK;
}
↑TOP