QueryAccept(업스트림)

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngineMedia Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

이 메커니즘을 사용하면 입력 핀이 업스트림 피어에 형식 변경을 제안할 수 있습니다. 다운스트림 필터는 IMemAllocator::GetBuffer에 대한 다음 호출에서 업스트림 필터가 가져올 샘플에 미디어 형식을 연결해야 합니다. 그러나 이를 위해 다운스트림 필터는 연결에 대한 사용자 지정 할당자를 제공해야 합니다. 이 할당자는 다운스트림 필터가 다음 샘플에서 미디어 형식을 설정하는 데 사용할 수 있는 프라이빗 메서드를 구현해야 합니다.

수행되는 단계는 다음과 같습니다.

  1. 다운스트림 필터는 핀 연결이 필터의 사용자 지정 할당자를 사용하는지 여부를 확인합니다. 업스트림 필터가 할당자를 소유하는 경우 다운스트림 필터는 형식을 변경할 수 없습니다.
  2. 다운스트림 필터는 업스트림 출력 핀에서 IPin::QueryAccept를 호출합니다(그림 참조, A단계).
  3. S_OK 반환하는 경우 QueryAccept 다운스트림 필터는 미디어 형식을 설정하기 위해 할당자에서 private 메서드를 호출합니다. 이 프라이빗 메서드 내에서 할당자는 사용 가능한 다음 샘플(B)에서 IMediaSample::SetMediaType 을 호출합니다.
  4. 업스트림 필터는 GetBuffer를 호출하여 새 샘플(C) 및 IMediaSample::GetMediaType을 가져와 미디어 형식(D)을 가져옵니다.
  5. 업스트림 필터가 샘플을 제공하는 경우 미디어 형식을 해당 샘플에 연결해야 합니다. 이렇게 하면 다운스트림 필터에서 미디어 유형이 변경되었는지 확인할 수 있습니다(E).

업스트림 필터가 형식 변경을 수락하는 경우 다음 다이어그램과 같이 원래 미디어 형식으로 다시 전환할 수도 있어야 합니다.

queryaccept(업스트림)

이러한 형식 변경의 기본 예제에는 DirectShow 비디오 렌더러가 포함됩니다.

  • 원래 Video Renderer 필터는 스트리밍 중에 RGB 및 YUV 형식 간에 전환할 수 있습니다. 필터가 연결되면 현재 표시 설정과 일치하는 RGB 형식이 필요합니다. 이렇게 하면 필요한 경우 GDI에서 대체 될 수 있습니다. 스트리밍이 시작된 후 DirectDraw를 사용할 수 있는 경우 Video Renderer는 YUV 형식에 대한 형식 변경을 요청합니다. 나중에 어떤 이유로든 DirectDraw 표면이 손실되면 RGB로 다시 전환될 수 있습니다.
  • 최신 VMR(비디오 혼합 렌더러) 필터는 YUV 형식을 포함하여 그래픽 하드웨어에서 지원하는 모든 형식과 연결됩니다. 그러나 그래픽 하드웨어는 성능을 최적화하기 위해 기본 DirectDraw 표면의 보폭을 변경할 수 있습니다. VMR 필터는 를 사용하여 QueryAcceptBITMAPINFOHEADER 구조체의 biWidth 멤버에 지정된 새 보폭을 보고합니다. VIDEOINFOHEADER 또는 VIDEOINFOHEADER2 구조체의 원본 및 대상 사각형은 비디오를 디코딩해야 하는 지역을 식별합니다.

구현 참고 사항

주로 비디오 렌더러의 기능이므로 업스트림 형식 변경을 요청해야 하는 필터를 작성할 가능성은 낮습니다. 그러나 비디오 변환 필터 또는 비디오 디코더를 작성하는 경우 필터가 비디오 렌더러의 요청에 올바르게 응답해야 합니다.

비디오 렌더러와 디코더 사이에 있는 현재 위치 변환 필터는 업스트림 모든 QueryAccept 호출을 전달해야 합니다. 새 형식 정보가 도착하면 저장합니다.

복사 변환 필터(즉, 현재 위치가 아닌 필터)는 다음 동작 중 하나를 구현해야 합니다.

  • 업스트림 형식 변경 내용을 전달하고 도착하면 새 형식 정보를 저장합니다. 필터는 형식을 업스트림 샘플에 연결할 수 있도록 사용자 지정 할당자를 사용해야 합니다.
  • 필터 내에서 형식 변환을 수행합니다. 형식 변경 업스트림 전달하는 것보다 더 쉬울 수 있습니다. 그러나 디코더 필터를 올바른 형식으로 디코딩하는 것보다 효율성이 떨어질 수 있습니다.
  • 최후의 수단으로, 단순히 형식 변경을 거부합니다. 자세한 내용은 DirectShow 기본 클래스 라이브러리의 CTransInPlaceOutputPin::CheckMediaType 메서드에 대한 소스 코드를 참조하세요. 그러나 형식 변경을 거부하면 비디오 렌더러가 가장 효율적인 형식을 사용할 수 없으므로 성능이 저하됩니다.

다음 의사 코드는 YUV 및 RGB 출력 형식 간에 전환할 수 있는 복사 변환 필터( CTransformFilter에서 파생됨)를 구현하는 방법을 보여 줍니다. 이 예제에서는 필터가 형식 변경 업스트림 전달하지 않고 변환 자체를 수행한다고 가정합니다.

HRESULT CMyTransform::CheckInputType(const CMediaType *pmt)
{
    if (pmt is a YUV type that you support) {
        return S_OK;
    }
    else {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
}

HRESULT CMyTransform::CheckTransform(
    const CMediaType *mtIn, const CMediaType *mtOut)
{
    if (mtOut is a YUV or RGB type that you support)
    {
        if ((mtIn has the same video dimensions as mtOut) &&
            (you support the mtIn-to-mtOut transform))
        {
            return S_OK;
        }
    }
    // otherwise
    return VFW_E_TYPE_NOT_ACCEPTED;
}

// GetMediaType: Return a preferred output type.
HRESULT CMyTransform::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    if (iPosition < 0) {
        return E_INVALIDARG;
    }
    switch (iPosition)
    {
    case 0:
        Copy the input type (YUV) to pMediaType
        return S_OK;
    case 1:
        Construct an RGB type that matches the input type.
        return S_OK;
    default:
        return VFW_S_NO_MORE_ITEMS;
    }
}

// SetMediaType: Override from CTransformFilter. 
HRESULT CMyTransform::SetMediaType(
    PIN_DIRECTION direction, const CMediaType *pmt)
{
    // Capture this information...
    if (direction == PINDIR_OUTPUT)
    {
       m_bYuv = (pmt->subtype == MEDIASUBTYPE_UYVY);
    }
    return S_OK;
}

HRESULT CMyTransform::Transform(
    IMediaSample *pSource, IMediaSample *pDest)
{
    // Look for format changes from downstream.
    CMediaType *pMT = NULL;
    HRESULT hr = pDest->GetMediaType((AM_MEDIA_TYPE**)&pMT);
    if (hr == S_OK)
    {
        hr = m_pOutput->CheckMediaType(pMT);
        if(FAILED(hr))
        {
            DeleteMediaType(pMT);
            return E_FAIL;
        }
        // Notify our own output pin about the new type.
        m_pOutput->SetMediaType(pMT);
        DeleteMediaType(pMT);
    }
    // Process the buffers
    if (m_bYuv) {
        return ProcessFrameYUV(pSource, pDest);
    }
    else {
        return ProcessFrameRGB(pSource, pDest);
    }
}