다음을 통해 공유


5단계. 이미지 변환

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

변환 필터 작성 자습서의 5단계입니다.

업스트림 필터는 변환 필터의 입력 핀에서 IMemInputPin::Receive 메서드를 호출하여 미디어 샘플을 변환 필터에 제공합니다. 데이터를 처리하기 위해 변환 필터는 순수 가상인 Transform 메서드를 호출합니다. CTransformFilterCTransInPlaceFilter 클래스는 이 메서드의 두 가지 버전을 사용합니다.

  • CTransformFilter::Transform 은 입력 샘플에 대한 포인터와 출력 샘플에 대한 포인터를 사용합니다. 필터가 메서드를 호출하기 전에 입력 샘플의 샘플 속성을 타임스탬프를 포함한 출력 샘플로 복사합니다.
  • CTransInPlaceFilter::Transform 은 입력 샘플에 대한 포인터를 사용합니다. 필터는 현재 위치에 있는 데이터를 수정합니다.

Transform 메서드가 S_OK 반환하는 경우 필터는 샘플 다운스트림을 제공합니다. 프레임을 건너뛰려면 S_FALSE 반환합니다. 스트리밍 오류가 있는 경우 오류 코드를 반환합니다.

다음 예제에서는 RLE 인코더가 이 메서드를 구현하는 방법을 보여줍니다. 사용자 고유의 구현은 필터의 수행에 따라 상당히 다를 수 있습니다.

HRESULT CRleFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Get pointers to the underlying buffers.
    BYTE *pBufferIn, *pBufferOut;
    hr = pSource->GetPointer(&pBufferIn);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    // Process the data.
    DWORD cbDest = EncodeFrame(pBufferIn, pBufferOut);
    KASSERT((long)cbDest <= pDest->GetSize());

    pDest->SetActualDataLength(cbDest);
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

이 예제에서는 EncodeFrame이 RLE 인코딩을 구현하는 프라이빗 메서드라고 가정합니다. 인코딩 알고리즘 자체는 여기에 설명되어 있지 않습니다. 자세한 내용은 플랫폼 SDK 설명서의 "비트맵 압축" 항목을 참조하세요.

먼저 IMediaSample::GetPointer 를 호출하여 기본 버퍼의 주소를 검색합니다. 프라이빗 EncoderFrame 메서드에 전달합니다. 그런 다음 IMediaSample::SetActualDataLength 를 호출하여 인코딩된 데이터의 길이를 지정합니다. 다운스트림 필터에는 버퍼를 제대로 관리할 수 있도록 이 정보가 필요합니다. 마지막으로 메서드는 IMediaSample::SetSyncPoint 를 호출하여 키 프레임 플래그를 TRUE로 설정합니다. 런 길이 인코딩은 델타 프레임을 사용하지 않으므로 모든 프레임은 키 프레임입니다. 델타 프레임의 경우 값을 FALSE로 설정합니다.

고려해야 할 다른 문제는 다음과 같습니다.

  • 타임스탬프를 선택합니다. CTransformFilter 클래스는 Transform 메서드를 호출하기 전에 출력 샘플을 타임스탬프합니다. 타임스탬프를 수정하지 않고 입력 샘플에서 타임스탬프를 복사합니다. 필터에서 타임스탬프를 변경해야 하는 경우 출력 샘플에서 IMediaSample::SetTime 을 호출합니다.

  • 변경 내용의 서식을 지정합니다. 업스트림 필터는 미디어 형식을 샘플에 연결하여 스트림 중간 형식을 변경할 수 있습니다. 이렇게 하기 전에 필터의 입력 핀에서 IPin::QueryAccept 를 호출합니다. CTransformFilter 클래스에서 CheckInputType을 호출한 다음 CheckTransform을 호출합니다. 다운스트림 필터는 동일한 메커니즘을 사용하여 미디어 형식을 변경할 수도 있습니다. 사용자 고유의 필터에는 watch 두 가지가 있습니다.

    • QueryAccept가 잘못된 동의를 반환하지 않는지 확인합니다.
    • 필터가 형식 변경을 수락하는 경우 IMediaSample::GetMediaType을 호출하여 Transform 메서드 내에서 검사. 해당 메서드가 S_OK 반환하는 경우 필터는 형식 변경에 응답해야 합니다.

    자세한 내용은 동적 형식 변경을 참조하세요.

  • 스레드. CTransformFilterCTransInPlaceFilter 모두에서 변환 필터는 Receive 메서드 내에서 동기적으로 출력 샘플을 제공합니다. 필터는 데이터를 처리하는 작업자 스레드를 만들지 않습니다. 일반적으로 변환 필터가 작업자 스레드를 만들 이유가 없습니다.

다음: 6단계. COM에 대한 지원을 추가합니다.

DirectShow 필터 작성