입력을 다시 연결하여 특정 출력 형식 확인
[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine 및 오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
필터는 IAMStreamConfig::SetFormat 메서드를 구현하여 필터의 핀이 연결되기 전에 오디오 또는 비디오 형식을 설정합니다. 출력 핀이 이미 연결되어 있고 새 형식을 제공할 수 있는 경우 다른 필터가 새 형식을 수락할 수 있는 경우에만 핀을 다시 연결합니다. 다른 필터가 미디어 형식을 수락할 수 없는 경우 SetFormat 호출에 실패하고 연결을 그대로 둡니다.
입력 핀이 연결되지 않는 한 변환 필터에는 기본 출력 형식이 없을 수 있습니다. 이 경우 SetFormat 및 IAMStreamConfig::GetStreamCaps 메서드는 입력 핀이 연결될 때까지 VFW_E_NOT_CONNECTED 반환해야 합니다. 그렇지 않으면 이러한 메서드가 평소와 같이 작동할 수 있습니다.
어떤 경우에는 설정된 연결에서 형식을 제공할 때 핀을 다시 연결하는 것이 유용합니다. 예를 들어 필터가 24비트 RGB 비디오를 X 형식으로 압축하고 8비트 RGB 비디오를 Y 형식으로 압축할 수 있다고 가정합니다. 출력 핀은 다음 중 하나를 수행할 수 있습니다.
- GetStreamCaps에서 항상 X와 Y를 모두 제공하고 항상 SetFormat에서 X와 Y를 모두 수락합니다.
- 입력 형식이 24비트 RGB인 경우 X 형식만 제공하고 적용합니다. 입력 형식이 8비트 RGB인 경우 Y 형식만 제공하고 그대로 적용합니다. 입력 핀이 연결되지 않은 경우 두 메서드 모두 실패합니다.
두 경우 모두 다음과 같은 몇 가지 다시 연결 코드가 필요합니다.
HRESULT MyOutputPin::CheckMediaType(const CMediaType *pmtOut)
{
// Fail if the input pin is not connected.
if (!m_pFilter->m_pInput->IsConnected()) {
return VFW_E_NOT_CONNECTED;
}
// (Not shown: Reject any media types that you know in advance your
// filter cannot use. Check the major type and subtype GUIDs.)
// (Not shown: If SetFormat was previously called, check whether
// pmtOut exactly matches the format that was specified in SetFormat.
// Return S_OK if they match, or VFW_E_INVALIDMEDIATYPE otherwise.)
// Now do the normal check for this media type.
HRESULT hr;
hr = m_pFilter->CheckTransform(
&m_pFilter->m_pInput->CurrentMediaType(), // The input type.
pmtOut // The proposed output type.
);
if (hr == S_OK)
{
// This format is compatible with the current input type.
return S_OK;
}
// This format is not compatible with the current input type.
// Maybe we can reconnect the input pin with a new input type.
// Enumerate the upstream filter's preferred output types, and
// see if one of them will work.
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)
{
// Check this input type against the proposed output type.
hr = m_pFilter->CheckTransform(pmtEnum, pmtOut);
if (hr != S_OK)
{
DeleteMediaType(pmtEnum);
continue; // Try the next one.
}
// This input type is a possible candidate. But, we have to make
// sure that the upstream filter can switch to this type.
hr = m_pFilter->m_pInput->GetConnected()->QueryAccept(pmtEnum);
if (hr != S_OK)
{
// The upstream filter will not switch to this type.
DeleteMediaType(pmtEnum);
continue; // Try the next one.
}
fFound = TRUE;
DeleteMediaType(pmtEnum);
break;
}
pEnum->Release();
if (fFound)
{
// This output type is OK, but if we are asked to use it, we will
// need to reconnect our input pin. (See SetFormat, below.)
return S_OK;
}
else
{
return VFW_E_INVALIDMEDIATYPE;
}
}
HRESULT MyOutputPin::SetFormat(AM_MEDIA_TYPE *pmt)
{
CheckPointer(pmt, E_POINTER);
HRESULT hr;
// Hold the filter state lock, to make sure that streaming isn't
// in the middle of starting or stopping:
CAutoLock cObjectLock(&m_pFilter->m_csFilter);
// Cannot set the format unless the filter is stopped.
if (m_pFilter->m_State != State_Stopped)
{
return VFW_E_NOT_STOPPED;
}
// The set of possible output formats depends on the input format,
// so if the input pin is not connected, return a failure code.
if (!m_pFilter->m_pInput->IsConnected())
{
return VFW_E_NOT_CONNECTED;
}
// If the pin is already using this format, there's nothing to do.
if (IsConnected() && CurrentMediaType() == *pmt)
{
return S_OK;
}
// See if this media type is acceptable.
if ((hr = CheckMediaType((CMediaType *)pmt)) != S_OK)
{
return hr;
}
// If we're connected to a downstream filter, we have to make
// sure that the downstream filter accepts this media type.
if (IsConnected())
{
hr = GetConnected()->QueryAccept(pmt);
if (hr != S_OK)
{
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;
}
// Override CTransformFilter::SetMediaType to reconnect the input pin.
// This method is called immediately after the media type is set on a pin.
HRESULT MyFilter::SetMediaType(
PIN_DIRECTION direction,
const CMediaType *pmt
)
{
HRESULT hr;
if (direction == PINDIR_OUTPUT)
{
// Before we set the output type, we might need to reconnect
// the input pin with a new type.
if (m_pInput && m_pInput->IsConnected())
{
// Check if the current input type is compatible.
hr = CheckTransform(
&m_pInput->CurrentMediaType(),
&m_pOutput->CurrentMediaType());
if (SUCCEEDED(hr))
{
return S_OK;
}
// Otherwise, we need to reconnect the input pin.
// Note: The CheckMediaType method has already called
// QueryAccept on the upstream filter.
hr = m_pGraph->Reconnect(m_pInput);
return hr;
}
}
return S_OK;
}