QueryAccept(업스트림)
[DirectShow 이 페이지와 연결된 기능은 레거시 기능입니다. MediaPlayer, IMFMediaEngine, Media Foundation 오디오/비디오 캡처대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11에 최적화되었습니다. Microsoft는 가능하면 새로운 코드에서 MediaPlayer, IMFMediaEngine 및 Audio/Video Capture를 DirectShow대신 Media Foundation 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
이 메커니즘을 사용하면 입력 핀이 업스트림 피어에 형식 변경을 제안할 수 있습니다. 다운스트림 필터는 IMemAllocator::GetBuffer대한 다음 호출에서 업스트림 필터가 가져올 샘플에 미디어 형식을 연결해야 합니다. 그러나 이렇게 하려면 다운스트림 필터가 연결에 대한 사용자 지정 할당자를 제공해야 합니다. 이 할당자는 다운스트림 필터가 다음 샘플에서 미디어 형식을 설정하는 데 사용할 수 있는 프라이빗 메서드를 구현해야 합니다.
다음 단계가 발생합니다.
- 다운스트림 필터는 핀 연결에서 필터의 사용자 지정 할당자를 사용하는지 여부를 확인합니다. 업스트림 필터가 할당자를 소유하는 경우 다운스트림 필터는 형식을 변경할 수 없습니다.
- 다운스트림 필터는 업스트림 출력 핀에서 IPin::QueryAccept 호출합니다(그림 참조, A단계).
-
QueryAccept
S_OK 반환하는 경우 다운스트림 필터는 미디어 형식을 설정하기 위해 할당자에서 private 메서드를 호출합니다. 이 프라이빗 메서드 내에서 할당자는 사용 가능한 다음 샘플(B)에서 IMediaSample::SetMediaType 호출합니다. - 업스트림 필터는 GetBuffer 호출하여 새 샘플(C) 및 IMediaSample::GetMediaType 호출하여 미디어 형식(D)을 가져옵니다.
- 업스트림 필터가 샘플을 제공하는 경우 해당 샘플에 연결된 미디어 형식을 유지해야 합니다. 이렇게 하면 다운스트림 필터가 미디어 유형이 변경되었음을 확인할 수 있습니다(E).
업스트림 필터가 형식 변경을 수락하는 경우 다음 다이어그램과 같이 원래 미디어 형식으로 다시 전환할 수도 있어야 합니다.
queryaccept(업스트림)
이러한 형식 변경의 주요 예에는 DirectShow 비디오 렌더러가 포함됩니다.
- 원래 Video Renderer 필터는 스트리밍 중에 RGB 및 YUV 형식 간에 전환할 수 있습니다. 필터가 연결되면 현재 표시 설정과 일치하는 RGB 형식이 필요합니다. 이렇게 하면 필요한 경우 GDI에서 대체 될 수 있습니다. 스트리밍이 시작된 후 DirectDraw를 사용할 수 있는 경우 Video Renderer는 YUV 형식에 대한 형식 변경을 요청합니다. 나중에 어떤 이유로든 DirectDraw 표면이 손실되면 RGB로 다시 전환할 수 있습니다.
- 최신 VMR(Video Mixing Renderer) 필터는 YUV 형식을 포함하여 그래픽 하드웨어에서 지원하는 모든 형식으로 연결됩니다. 그러나 그래픽 하드웨어는 성능을 최적화하기 위해 기본 DirectDraw 표면의 보폭을 변경할 수 있습니다. VMR 필터는
QueryAccept
사용하여 BITMAPINFOHEADER 구조체의 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);
}
}