사용자 지정 미디어 원본 작성

이 항목에서는 Microsoft Media Foundation에서 사용자 지정 미디어 원본을 구현하는 방법을 설명합니다. 여기에는 다음 단원이 포함되어 있습니다.

프레젠테이션 설명자 만들기

IMFMediaSource::CreatePresentationDescriptor 메서드는 원본의 프레젠테이션 설명자의 복사본을 반환합니다. 프레젠테이션 설명자를 만들려면 원본 콘텐츠의 스트림 수와 각 스트림의 가능한 형식을 알고 있어야 합니다. 각 스트림에 대해 다음과 같이 스트림 설명자를 만듭니다.

  1. 미디어 형식의 배열을 만듭니다. 배열의 각 미디어 형식은 스트림에 대해 가능한 형식을 나타냅니다. 미디어 형식을 만드는 방법에 대한 자세한 내용은 미디어 형식을 참조하세요.
  2. MFCreateStreamDescriptor를 호출하여 스트림 설명자를 만듭니다. 미디어 형식의 배열을 전달합니다. 함수는 IMFStreamDescriptor 포인터를 반환합니다.
  3. IMFStreamDescriptor::GetMediaTypeHandler를 호출하여 스트림 설명자의 미디어 형식 처리기를 가져옵니다.
  4. IMFMediaTypeHandler::SetCurrentMediaType을 호출하여 기본 스트림 형식을 설정합니다. 1단계에서 만든 미디어 유형 중 하나를 사용합니다. 일반적으로 가장 높은 품질의 형식을 사용해야 합니다.
  5. 필요에 따라 스트림 설명자에 특성을 설정합니다. 스트림 설명자에 적용되는 특성 목록은 스트림 설명자 특성을 참조하세요.

이제 프레젠테이션 설명자를 만듭니다.

  1. MFCreatePresentationDescriptor를 호출하고 스트림 설명자 배열을 전달합니다. 함수는 IMFPresentationDescriptor 포인터를 반환합니다 .
  2. IMFPresentationDescriptor::SelectStream을 호출하여 기본 스트림 선택을 선택하여 하나 이상의 스트림을 선택합니다. 기본 구성에서 하나 이상의 스트림을 선택해야 합니다.
  3. 필요에 따라 프레젠테이션 설명자에 특성을 설정합니다. 스트림 설명자에 적용되는 특성 목록은 프레젠테이션 설명자 특성을 참조하세요.

시작 시 또는 원본이 원본 데이터를 충분히 구문 분석하여 내용을 확인한 후에 프레젠테이션 설명자를 한 번 만들어야 합니다. CreatePresentationDescriptor 메서드는 프레젠테이션 설명자의 복사본을 반환해야 합니다. 복사본을 만들려면 IMFPresentationDescriptor::Clone을 호출합니다. 복사본을 반환하면 클라이언트가 특성 또는 스트림 선택과 같은 원래 프레젠테이션 설명자의 상태를 수정할 수 없습니다. 그러나 복제 는 얕은 복사본을 만들므로 클라이언트는 잠재적으로 기본 스트림 설명자를 수정할 수 있습니다.

미디어 원본 시작

IMFMediaSource::Start 메서드는 미디어 원본을 시작하거나 새 위치를 찾습니다. Start를 호출하면 이전 상태가 일시 중지되거나 실행 중이고 새 시작 시간이 지정될 때 검색이 발생합니다. 그렇지 않으면 Start 메서드가 시작됩니다. 시작 작업이 완료되면 다음 이벤트를 보냅니다.

  1. 각 새 스트림에 대해 MENewStream 이벤트를 보냅니다. 즉, 이전에 선택 취소되어 이제 선택된 각 스트림입니다. 이벤트 데이터는 스트림에 대한 포인터입니다.
  2. 이전에 선택되었지만 여전히 선택된 각 스트림에 대해 MEUpdatedStream 이벤트를 보냅니다. 이벤트 데이터는 스트림에 대한 포인터입니다. (선택 취소된 스트림에 대한 이벤트를 보내지 마세요.)
  3. 원본이 검색하는 경우 MESourceSeeked 이벤트를 보냅니다. 그렇지 않으면 MESourceStarted 이벤트를 보냅니다. 이벤트 데이터는 Start 메서드에 지정된 시작 시간입니다. MESourceStarted 이벤트의 경우 시작 시간이 VT_EMPTY 경우 이벤트에서 MF_EVENT_SOURCE_ACTUAL_START 특성을 설정합니다. 특성 값은 실제 시작 시간입니다.
  4. 각 스트림에 대해 원본이 검색하는 경우 MEStreamSeeked 이벤트를 보냅니다. 그렇지 않으면 MEStreamStarted 이벤트를 보냅니다. 이벤트 데이터는 시작 시간입니다. (미디어 원본은 스트림의 IMFMediaEventGenerator::QueueEvent 메서드를 호출하여 스트림에서 이벤트를 큐에 대기할 수 있습니다.)

스트림이 선택 취소되면 스트림을 종료합니다. 스트림은 해당 시점에서 더 이상 이벤트를 큐에 대기하지 않아야 합니다.

Start 메서드의 시간 형식은 pguidTimeFormat 매개 변수에 지정됩니다. GUID_NULL 표시된 표준 시간 형식은 100나노초 단위입니다. 미디어 원본은 이 시간 형식을 지원해야 합니다.

추구

검색할 때 요청된 시작 위치가 정확한 샘플 경계에 속하지 않을 수 있습니다. 또한 압축된 콘텐츠의 경우 시작 위치가 키 프레임 간에 떨어질 수 있습니다. 스트림은 요청된 시작 위치에서 압축되지 않은 샘플을 생성하는 데 필요한 초기 지점에서 샘플을 제공해야 합니다. 비디오의 경우 이전 키 프레임에서 시작하는 것을 의미합니다. 파이프라인은 디코더에서 추가 프레임을 삭제하여 요청된 시간에 재생이 시작되도록 합니다.

원본 이벤트에 지정된 시작 시간(MESourceStarted, MESourceSeeked, MEStreamStartedMEStreamSeeked)은 실제 시작 위치에 관계없이 요청된 시작 시간( Start 메서드에 지정된 값)입니다.

예를 들어 비디오 스트림의 처음 몇 프레임에 다음과 같은 특성이 있다고 가정합니다.

샘플 1 2 3 4
Time 33msec 66msec 100msec 133msec
키 프레임? Yes 아니요 아니요

 

Start 메서드를 100밀리초 값으로 호출하는 경우 원본은 이 시간 이전의 첫 번째 키 프레임인 프레임 1부터 비디오를 출력해야 합니다. start 이벤트는 여전히 이벤트 데이터에서 100밀리초를 나타냅니다.

미디어 원본 일시 중지

IMFMediaSource::P ause 메서드는 미디어 원본을 일시 중지합니다.

원본이 일시 중지되는 동안 스트림은 새 샘플을 만들고 큐에 저장할 수 있지만 스트림은 샘플을 제공하지 않습니다. 이 규칙에 대한 몇 가지 예외는 다음과 같습니다.

  • 라이브 원본은 일시 중지된 동안 데이터를 삭제해야 합니다.
  • 원본이 네트워크에서 데이터를 가져오는 경우 서버를 일시 중지할 수 있습니다.

원본이 일시 중지되는 동안 클라이언트가 IMFMediaStream::RequestSample 을 호출하는 경우 원본이 다시 시작될 때까지 요청도 큐에 대기됩니다. 요청을 삭제하면 안 됩니다.

일시 중지는 시작된 상태에서만 허용됩니다. 그렇지 않으면 PauseMF_E_INVALID_STATE_TRANSITION 반환해야 합니다.

원본 데이터 생성

Media Foundation은 끌어오기 모델을 사용합니다. 즉, 스트림은 파이프라인의 요청에 대한 응답으로 샘플을 생성하고 제공합니다. 스트림은 미디어 원본이 실행 중이고 스트림이 선택될 때 샘플을 제공할 수 있습니다. 스트림은 클라이언트가 새 샘플을 요청할 때만 데이터를 제공합니다.

샘플 요청

클라이언트는 IMFMediaStream::RequestSample을 호출하여 새 샘플을 요청합니다. 다음은 작업 시퀀스입니다.

  1. 클라이언트는 IMFMediaStream::RequestSample을 호출합니다. 인수는 클라이언트가 요청을 추적하는 데 사용하는 선택적 토큰 개체에 대한 포인터입니다. 클라이언트는 토큰을 구현합니다. 토큰은 IUnknown 인터페이스를 노출해야 합니다. 클라이언트는 토큰 대신 NULL 포인터를 전달할 수도 있습니다.

  2. 클라이언트가 토큰을 제공한 경우 미디어 스트림은 토큰에서 AddRef 를 호출하고 토큰을 첫 번째 선점 큐에 배치합니다. 메서드가 를 반환하고 나머지 단계는 비동기적으로 발생합니다.

  3. 더 많은 데이터를 사용할 수 있는 경우 미디어 스트림은 새 샘플을 만듭니다. (이 단계는 다음 섹션에서 자세히 설명합니다.)

  4. 미디어 스트림은 큐에서 첫 번째 토큰을 가져옵니다.

  5. 토큰이 NULL이 아닌 경우 미디어 스트림은 미디어 샘플에서 MFSampleExtension_Token 특성을 설정합니다. 특성 값은 토큰에 대한 포인터입니다.

  6. 미디어 스트림은 MEMediaSample 이벤트를 보냅니다. 이벤트 데이터는 샘플의 IMFSample 인터페이스에 대한 포인터입니다.

  7. 클라이언트가 토큰을 제공한 경우 미디어 스트림은 토큰 개체에서 Release 를 호출합니다.

미디어 스트림이 클라이언트의 RequestSample 요청을 처리할 수 없는 경우 큐에서 토큰을 끌어와 토큰에서 Release 를 호출하지만 MEMediaSample 이벤트를 보내지는 않습니다.

클라이언트는 토큰을 사용하여 요청의 상태 추적할 수 있습니다. 클라이언트가 MEMediaSample 이벤트를 수신하면 샘플에서 토큰을 가져와서 원래 요청과 일치시킬 수 있습니다. 클라이언트는 토큰을 사용하여 미디어 원본이 요청을 삭제했는지 검색할 수도 있습니다. 토큰의 참조 수가 0으로 떨어지고 미디어 스트림이 MEMediaSample 이벤트를 보내지 않는 경우 요청이 삭제되었음을 의미합니다.

여기에 나열된 단계에서는 RequestSample 메서드가 비동기 작업으로 구현된다고 가정합니다. 메서드가 동기식인 경우 큐에 요청 토큰을 배치할 필요가 없습니다. 그러나 데이터를 생성하는 데 상당한 시간이 걸리는 경우 비동기 접근 방식을 사용하는 것이 좋습니다(예: 원본이 바이트 스트림에서 데이터를 읽는 경우).

스트림은 RequestSample 호출 사이에 누적되는 모든 데이터를 버퍼링합니다.

미디어 스트림이 스트림의 끝에 도달하면 마지막 샘플 이후에 MEEndOfStream 이벤트를 보냅니다. 모든 스트림이 종료되면 미디어 원본은 MEEndOfPresentation 이벤트를 보냅니다. 미디어 스트림이 MEEndOfStream 이벤트를 보낸 후 RequestSample 메서드는 원본이 다시 시작될 때까지 MF_E_END_OF_STREAM 반환합니다.

샘플 할당

스트림이 보류 중인 샘플 요청을 채울 준비가 되면 새 샘플을 만들고 하나 이상의 미디어 버퍼를 샘플에 추가합니다. 미디어 버퍼를 만드는 방법에 대한 자세한 내용은 미디어 버퍼를 참조하세요.

알려진 경우 스트림은 타임스탬프를 설정하고 기간을 설정해야 합니다. 타임스탬프는 원본을 기준으로 합니다. 대부분의 경우 콘텐츠의 시작은 타임스탬프를 0으로 지정합니다. 예를 들어 원본이 미디어 파일에서 읽는 경우 파일의 시작 부분에 타임스탬프는 0입니다.

샘플의 타임스탬프는 프레젠테이션 시간과 반드시 같지는 않습니다. 미디어 세션은 원본 시간에서 프레젠테이션 시간으로 변환됩니다. 압축된 데이터의 경우 스트림은 시작 시간 전에 가장 가까운 키 프레임에서 시작하는 데이터를 생성해야 합니다. 이렇게 하면 디코더가 요청된 시작 시간에 표시되는 프레임을 전달할 수 있습니다. 그렇지 않으면 디코더는 다음 키 프레임까지 기다려야 합니다.

재생 속도가 1.0보다 빠르거나 느린 경우 파이프라인은 프레젠테이션 클록의 속도를 조정합니다. 원본은 샘플에 대한 타임스탬프를 조정하지 않습니다.

원본은 특성을 설정하여 샘플에 대한 추가 정보를 설정할 수 있습니다. 샘플 특성 목록은 샘플 특성을 참조하세요.

스트림의 간격

스트림에 상당한 길이의 간격이 포함된 경우 스트림이 MEStreamTick 이벤트를 보내는 것이 좋습니다. 이 이벤트는 샘플이 없음을 클라이언트에 알 수 있습니다. 이벤트 데이터는 누락된 샘플의 타임스탬프를 100나노초 단위(VT_I8)로 표시합니다. 이 이벤트는 다운스트림 구성 요소가 도착하지 않는 샘플을 기다리지 않도록 저장할 수 있습니다. 스트림은 스트림의 간격을 넓히는 데 필요한 만큼 MEStreamTick 이벤트를 보낼 수 있습니다.

미디어 원본 종료

클라이언트가 미디어 원본을 사용하여 완료되면 IMFMediaSource::Shutdown을 호출합니다. 이 메서드 내에서 미디어 소스는 순환 참조 수를 중단해야 합니다. 일반적으로 미디어 원본과 미디어 스트림 간에 순환 참조가 있습니다.

이벤트 큐를 사용하여 IMFMediaEventGenerator를 구현하는 경우 이벤트 큐에서 IMFMediaEventQueue::Shutdown 을 호출합니다. 이 메서드는 이벤트 큐를 종료하고 현재 이벤트를 대기 중인 호출자에게 신호를 보냅니다.

종료 후 원본의 모든 메서드는 IUnknown 메서드를 제외하고 MF_E_SHUTDOWN 반환합니다.

라이브 소스

Windows 7부터 Media Foundation은 오디오 및 비디오 캡처 디바이스를 자동으로 지원합니다. 비디오의 경우 디바이스는 비디오 캡처 범주에 KS(커널 스트리밍) 미니드라이버를 제공해야 합니다. Media Foundation은 PnP 경로를 사용하여 디바이스를 열거합니다. 오디오의 경우 Media Foundation은 MMDevice(Windows 멀티미디어 디바이스) API를 사용하여 오디오 엔드포인트 디바이스를 열거합니다. 디바이스가 이러한 조건을 충족하는 경우 사용자 지정 미디어 원본을 구현할 필요가 없습니다.

그러나 다른 유형의 디바이스 또는 다른 라이브 데이터 원본에 대한 사용자 지정 미디어 원본을 구현할 수 있습니다. 라이브 원본과 다른 미디어 원본 간에는 몇 가지 차이점이 있습니다.

  • IMFMediaSource::GetCharacteristics 메서드에서 MFMEDIASOURCE_IS_LIVE 플래그를 반환합니다.
  • 첫 번째 샘플에는 타임스탬프는 0이어야 합니다.
  • 이벤트 및 스트리밍 상태는 일시 중지된 상태를 제외하고 미디어 원본과 동일하게 처리됩니다.
  • 일시 중지된 동안에는 샘플을 큐에 대기하지 마세요. 일시 중지하는 동안 생성된 모든 데이터를 삭제합니다.
  • 라이브 소스는 일반적으로 검색, 역방향 플레이 또는 속도 제어를 지원하지 않습니다.

미디어 원본

자습서: 사용자 지정 미디어 원본 작성