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;
}