다음을 통해 공유


캡처 디바이스 선택

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

오디오 또는 비디오 캡처 디바이스를 선택하려면 시스템 디바이스 열거자 사용 항목에 설명된 시스템 디바이스 열거자를 사용합니다. 시스템 디바이스 열거자는 디바이스 범주에서 선택한 디바이스 모니커 컬렉션을 반환합니다. 모니커는 다른 개체에 대한 정보를 포함하는 COM 개체입니다. 모니커를 사용하면 실제로 개체를 만들지 않고도 애플리케이션에서 개체에 대한 정보를 가져올 수 있습니다. 나중에 애플리케이션에서 모니커를 사용하여 개체를 만들 수 있습니다. 모니커에 대한 자세한 내용은 IMoniker에 대한 설명서를 참조하세요.

시스템 디바이스 열거자를 사용하려면 다음 단계를 수행합니다.

  1. CoCreateInstance를 호출하여 시스템 디바이스 열거자의 instance 만듭니다.

  2. ICreateDevEnum::CreateClassEnumerator를 호출하고 디바이스 범주를 GUID로 지정합니다. 캡처 디바이스의 경우 다음 범주는 관련이 있습니다.

    범주 GUID Description
    CLSID_AudioInputDeviceCategory 오디오 캡처 디바이스
    CLSID_VideoInputDeviceCategory 비디오 캡처 디바이스

     

    비디오 카메라에 통합 마이크가 있는 경우 두 범주 모두에 표시됩니다. 그러나 카메라와 마이크는 열거형, 디바이스 만들기 및 데이터 스트리밍을 위해 시스템에서 별도의 디바이스로 처리됩니다.

  3. CreateClassEnumerator 메서드는 IEnumMoniker 인터페이스에 대한 포인터를 반환합니다. 모니커를 열거하려면 IEnumMoniker::Next를 호출합니다.

다음 코드는 지정된 디바이스 범주에 대한 열거자를 만듭니다.

#include <windows.h>
#include <dshow.h>

#pragma comment(lib, "strmiids")

HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
    // Create the System Device Enumerator.
    ICreateDevEnum *pDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,  
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the category.
        hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
        if (hr == S_FALSE)
        {
            hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
        }
        pDevEnum->Release();
    }
    return hr;
}

IEnumMoniker 인터페이스는 각각 디바이스 모니커를 나타내는 IMoniker 인터페이스 목록을 열거합니다. 애플리케이션은 모니커에서 속성을 읽거나 모니커를 사용하여 디바이스에 대한 DirectShow 캡처 필터를 만들 수 있습니다. 모니커 속성은 VARIANT 값으로 반환됩니다. 다음 속성은 디바이스 모니커에서 지원됩니다.

속성 Description VARIANT 형식
"FriendlyName" 서버의 이름입니다. VT_BSTR
"설명" 디바이스에 대한 설명 VT_BSTR
"DevicePath" 디바이스를 식별하는 고유 문자열입니다. (비디오 캡처 디바이스만 해당) VT_BSTR
"WaveInID" 오디오 캡처 디바이스의 식별자입니다. (오디오 캡처 디바이스만 해당) VT_I4

 

"FriendlyName" 및 "Description" 속성은 UI에 표시하기에 적합합니다.

  • "FriendlyName" 속성은 모든 디바이스에서 사용할 수 있습니다. 디바이스에 대해 사람이 읽을 수 있는 이름을 포함합니다.
  • "설명" 속성은 DV 및 D-VHS/MPEG 캠코더 디바이스에서만 사용할 수 있습니다. 자세한 내용은 MSDV 드라이버MSTape 드라이버를 참조하세요. 사용 가능한 경우 "FriendlyName" 속성보다 더 구체적인 디바이스에 대한 설명이 포함되어 있습니다. 일반적으로 공급업체 이름이 포함됩니다.
  • "DevicePath" 속성은 사람이 읽을 수 있는 문자열이 아니지만 시스템의 각 비디오 캡처 디바이스에 대해 고유하도록 보장됩니다. 이 속성을 사용하여 동일한 디바이스 모델의 두 개 이상의 인스턴스를 구분할 수 있습니다.
  • "WaveInID" 속성이 있는 경우 DirectShow 캡처 필터가 내부적으로 파형 오디오 API를 사용하여 디바이스와 통신한다는 의미입니다. "WaveInID" 속성의 값은 waveInOpen과 같은 waveIn* 함수에서 사용하는 식별자에 해당합니다.

모니커에서 속성을 읽으려면 다음 단계를 수행합니다.

  1. IMoniker::BindToStorage를 호출하여 IPropertyBag 인터페이스에 대한 포인터를 가져옵니다.
  2. IPropertyBag::Read를 호출하여 속성을 읽습니다.

다음 코드 예제에서는 디바이스 모니커 목록을 열거하고 속성을 가져오는 방법을 보여줍니다.

void DisplayDeviceInformation(IEnumMoniker *pEnum)
{
    IMoniker *pMoniker = NULL;

    while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
    {
        IPropertyBag *pPropBag;
        HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
        if (FAILED(hr))
        {
            pMoniker->Release();
            continue;  
        } 

        VARIANT var;
        VariantInit(&var);

        // Get description or friendly name.
        hr = pPropBag->Read(L"Description", &var, 0);
        if (FAILED(hr))
        {
            hr = pPropBag->Read(L"FriendlyName", &var, 0);
        }
        if (SUCCEEDED(hr))
        {
            printf("%S\n", var.bstrVal);
            VariantClear(&var); 
        }

        hr = pPropBag->Write(L"FriendlyName", &var);

        // WaveInID applies only to audio capture devices.
        hr = pPropBag->Read(L"WaveInID", &var, 0);
        if (SUCCEEDED(hr))
        {
            printf("WaveIn ID: %d\n", var.lVal);
            VariantClear(&var); 
        }

        hr = pPropBag->Read(L"DevicePath", &var, 0);
        if (SUCCEEDED(hr))
        {
            // The device path is not intended for display.
            printf("Device path: %S\n", var.bstrVal);
            VariantClear(&var); 
        }

        pPropBag->Release();
        pMoniker->Release();
    }
}

void main()
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (SUCCEEDED(hr))
    {
        IEnumMoniker *pEnum;

        hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
        if (SUCCEEDED(hr))
        {
            DisplayDeviceInformation(pEnum);
            pEnum->Release();
        }
        hr = EnumerateDevices(CLSID_AudioInputDeviceCategory, &pEnum);
        if (SUCCEEDED(hr))
        {
            DisplayDeviceInformation(pEnum);
            pEnum->Release();
        }
        CoUninitialize();
    }
}

디바이스에 대한 DirectShow 캡처 필터를 만들려면 IMoniker::BindToObject 메서드를 호출하여 IBaseFilter 포인터를 가져옵니다. 그런 다음 , IFilterGraph::AddFilter 를 호출하여 필터 그래프에 필터를 추가합니다.

IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
    hr = m_pGraph->AddFilter(pCap, L"Capture Filter");
}

오디오 캡처

비디오 캡처