미디어 파운데이션의 오디오/비디오 캡처

Microsoft Media Foundation은 오디오 및 비디오 캡처를 지원합니다. 비디오 캡처 디바이스는 UVC 클래스 드라이버를 통해 지원되며 UVC 1.1과 호환되어야 합니다. 오디오 캡처 디바이스는 WASAPI(Windows Audio Session API)를 통해 지원됩니다.

캡처 디바이스는 Media Foundation에서 미디어 소스 객체에 의해 표시되는데, 이는 IMFMediaSource 인터페이스를 노출합니다. 대부분의 경우, 애플리케이션은 이 인터페이스를 직접 사용하지 않지만 소스 판독기 같은 상위 수준 API를 사용하여 캡처 디바이스를 제어합니다.

캡처 디바이스 열거하기

시스템에서 캡처 디바이스를 열거하려면, 다음 단계를 수행합니다.

  1. 속성 저장소를 만들려면 MFCreateAttributes 함수를 호출합니다.

  2. 다음 값 중 하나로 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 특성을 설정합니다.

    설명
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID 오디오 캡처 디바이스를 열거합니다.
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID 비디오 캡처 디바이스를 열거합니다.

     

  3. 호출할 함수는 MFEnumDeviceSources 입니다. 이 함수는 IMFActivate 포인터의 배열을 할당합니다. 각 포인터는 시스템의 한 디바이스에 대한 활성화 객체를 나타냅니다.

  4. 활성화 객체 중 하나로부터 미디어 소스 인스턴스를 만들려면 IMFActivate::ActivateObject 메서드를 호출합니다.

다음 예제에서는 열거형 목록에서 첫 번째 비디오 캡처 디바이스에 대한 미디어 소스를 만듭니다.

HRESULT CreateVideoCaptureDevice(IMFMediaSource **ppSource)
{
    *ppSource = NULL;

    UINT32 count = 0;

    IMFAttributes *pConfig = NULL;
    IMFActivate **ppDevices = NULL;

    // Create an attribute store to hold the search criteria.
    HRESULT hr = MFCreateAttributes(&pConfig, 1);

    // Request video capture devices.
    if (SUCCEEDED(hr))
    {
        hr = pConfig->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }

    // Enumerate the devices,
    if (SUCCEEDED(hr))
    {
        hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
    }

    // Create a media source for the first device in the list.
    if (SUCCEEDED(hr))
    {
        if (count > 0)
        {
            hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
        }
        else
        {
            hr = MF_E_NOT_FOUND;
        }
    }

    for (DWORD i = 0; i < count; i++)
    {
        ppDevices[i]->Release();
    }
    CoTaskMemFree(ppDevices);
    return hr;
}

다음을 포함하여 다양한 속성에 대한 활성화 객체를 쿼리할 수 있습니다.

  • MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME 속성에는 디바이스의 표시 이름이 포함됩니다. 표시 이름은 사용자에게 표시하기에 적합하지만 고유하지 않을 수 있습니다.
  • 비디오 디바이스의 경우, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK 속성에 디바이스에 대한 기호 링크가 포함됩니다. 기호 링크는 시스템의 디바이스를 고유하게 식별하지만, 읽을 수 있는 문자열은 아닙니다.
  • 오디오 디바이스의 경우, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID 속성에 디바이스의 오디오 엔드포인트 ID가 포함됩니다. 오디오 엔드포인트 ID는 기호 링크와 유사합니다. 시스템에서 디바이스를 고유하게 식별하지만 읽을 수 있는 문자열은 아닙니다.

다음 예제에서는 IMFActivate 포인터의 배열을 가져와서 각 디바이스의 표시 이름을 디버그 창에 출력합니다.

void DebugShowDeviceNames(IMFActivate **ppDevices, UINT count)
{
    for (DWORD i = 0; i < count; i++)
    {
        HRESULT hr = S_OK;
        WCHAR *szFriendlyName = NULL;
    
        // Try to get the display name.
        UINT32 cchName;
        hr = ppDevices[i]->GetAllocatedString(
            MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
            &szFriendlyName, &cchName);

        if (SUCCEEDED(hr))
        {
            OutputDebugString(szFriendlyName);
            OutputDebugString(L"\n");
        }
        CoTaskMemFree(szFriendlyName);
    }
}

비디오 디바이스에 대한 기호 링크를 이미 알고 있는 경우, 디바이스에 대한 미디어 소스를 만드는 또 다른 방법이 있습니다.

  1. 속성 저장소를 만들려면 MFCreateAttributes 를 호출합니다.
  2. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 속성을 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID로 설정합니다.
  3. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK 속성을 기호 링크로 설정합니다.
  4. MFCreateDeviceSourceMFCreateDeviceSourceActivate 함수 중 하나를 호출합니다. 전자는 IMFMediaSource 포인터를 반환합니다. 후자는 활성화 객체에 IMFActivate 포인터를 반환합니다. 활성화 객체를 사용하여 소스를 만들 수 있습니다. (활성화 객체를 다른 프로세스로 마샬링할 수 있으므로 다른 프로세스에서 소스를 만들려는 경우에 유용합니다. 자세한 내용은 활성화 객체를 참조하세요.)

다음 예제에서는 비디오 디바이스의 기호 링크를 가져와 미디어 소스를 만듭니다.

HRESULT CreateVideoCaptureDevice(PCWSTR *pszSymbolicLink, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to video.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }


    // Set the symbolic link.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
            (LPCWSTR)pszSymbolicLink
            );            
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

오디오 엔드포인트 ID에서 오디오 디바이스를 동일하게 만드는 방법이 있습니다.

  1. 속성 저장소를 만들려면 MFCreateAttributes 를 호출합니다.
  2. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE 속성을 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID로 설정합니다.
  3. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID 속성을 엔드포인트 ID로 설정합니다.
  4. MFCreateDeviceSourceMFCreateDeviceSourceActivate 함수 중 하나를 호출합니다.

다음 예제에서는 오디오 엔드포인트 ID를 사용하고 미디어 소스를 만듭니다.

HRESULT CreateAudioCaptureDevice(PCWSTR *pszEndPointID, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to audio.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID
            );
    }

    // Set the endpoint ID.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID,
            (LPCWSTR)pszEndPointID
            ); 
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

캡처 디바이스 사용하기

캡처 디바이스에 대한 미디어 소스를 만든 후 소스 판독기 를 사용하여 디바이스에서 데이터를 가져옵니다. 소스 판독기는 캡처 오디오 데이터 또는 비디오 프레임을 포함하는 미디어 샘플을 제공합니다. 다음 단계는 응용 프로그램 시나리오에 따라 달라집니다.

  • 비디오 미리 보기: Microsoft Direct3D 또는 Direct2D를 사용하여 비디오를 표시합니다.
  • 파일 캡처: 싱크 작성기 를 사용하여 파일을 인코딩합니다.
  • 오디오 미리 보기: WASAPI를 사용합니다.

오디오 캡처를 비디오 캡처와 결합하려면 집계 미디어 소스를 사용합니다. 집계 미디어 소스는 미디어 원본 컬렉션을 포함하고 모든 스트림을 단일 미디어 객체 개체로 결합합니다. 집계 미디어 소스의 인스턴스를 만들려면, MFCreateAggregateSource 함수를 호출합니다.

캡처 디바이스 종료하기

캡처 디바이스가 더 이상 필요하지 않은 경우, 디바이스를 종료하려면 종료 가 있는 IMFMediaSource 객체를 MFCreateDeviceSource 또는 IMFActivate::ActivateObject를 호출하여 획득해야 한 뒤 종료를 호출해야 합니다. 만약 종료 호출을 실패하면 메모리 누수가 발생할 수 있습니다. 왜냐하면 시스템에서 IMFMediaSource 리소스에 대해 종료 호출이 될 때까지 참조를 유지할 수 있기 때문입니다.

if (g_pSource)
{
    g_pSource->Shutdown();
    g_pSource->Release();
    g_pSource = NULL;
}

캡처 디바이스에 대한 기호 링크가 포함된 문자열을 할당한 경우 이 객체 또한 해제해야 합니다.

    CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;

    g_cchSymbolicLink = 0;

오디오/비디오 캡처