다음을 통해 공유


원격 카메라에 연결

이 문서에서는 하나 이상의 원격 카메라에 연결하고 각 카메라에서 프레임을 읽을 수 있는 MediaFrameSourceGroup 개체를 가져오는 방법을 보여줍니다. 미디어 원본에서 프레임을 읽는 방법에 대한 자세한 내용은 MediaFrameReader를 통해 미디어 프레임 처리를 참조하세요. 디바이스와 페어링에 대한 자세한 내용은 디바이스 페어링을 참조하세요.

참고 항목

이 문서에 설명된 기능은 Windows 10 버전 1903부터 사용할 수 있습니다.

사용 가능한 원격 카메라를 감시할 DeviceWatcher 클래스 만들기

DeviceWatcher 클래스는 앱에서 사용할 수 있는 디바이스를 모니터링하고 디바이스를 추가하거나 제거할 때 앱에 알립니다. DeviceInformation.CreateWatcher를 호출하여 모니터링할 디바이스 유형을 식별하는 AQS(고급 쿼리 구문) 문자열을 전달하여 DeviceWatcher의 인스턴스를 가져옵니다. 네트워크 카메라 디바이스를 지정하는 AQS 문자열은 다음과 같습니다.

@"System.Devices.InterfaceClassGuid:=""{B8238652-B500-41EB-B4F3-4234F7F5AE99}"" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True"

참고 항목

도우미 메서드 MediaFrameSourceGroup.GetDeviceSelector는 로컬로 연결된 원격 네트워크 카메라를 모니터링하는 AQS 문자열을 반환합니다. 네트워크 카메라만 모니터링하려면 위에 표시된 AQS 문자열을 사용해야 합니다.

Start 메서드를 호출하여 반환된 DeviceWatcher를 시작하면 현재 사용할 수 있는 모든 네트워크 카메라에 대해 Added 이벤트가 발생합니다. Stop을 호출하여 감시자를 중지할 때까지 새 네트워크 카메라 디바이스를 사용할 수 있게 되면 Added 이벤트가 발생하고 카메라 디바이스를 사용할 수 없게 되면 Removed 이벤트가 발생합니다.

AddedRemoved 이벤트 처리기에 전달된 이벤트 인수는 각각 DeviceInformation 또는 DeviceInformationUpdate 개체입니다. 이러한 각 개체에는 이벤트가 발생한 네트워크 카메라의 식별자인 ID 속성이 있습니다. 이 ID를 MediaFrameSourceGroup.FromIdAsync 메서드에 전달하여 카메라에서 프레임을 검색하는 데 사용할 수 있는 MediaFrameSourceGroup 개체를 가져옵니다.

원격 카메라 페어링 도우미 클래스

다음 예제에서는 DeviceWatcher를 사용하여 카메라 목록에 대한 데이터 바인딩을 지원하도록 MediaFrameSourceGroup 개체의 ObservableCollection을 만들고 업데이트하는 도우미 클래스를 보여줍니다. 일반적인 앱은 사용자 지정 모델 클래스에서 MediaFrameSourceGroup을 래핑합니다. 도우미 클래스는 앱의 CoreDispatcher에 대한 참조를 유지 관리하고 RunAsync 호출 내에서 카메라 컬렉션을 업데이트하여 컬렉션에 바인딩된 UI가 UI 스레드에서 업데이트되도록 합니다.

또한 이 예제에서는 AddedRemoved 이벤트 외에 DeviceWatcher.Updated 이벤트를 처리합니다. 업데이트된 처리기에서 연결된 원격 카메라 디바이스가 컬렉션에서 제거된 다음, 컬렉션에 다시 추가됩니다.

class RemoteCameraPairingHelper : IDisposable
{
    private CoreDispatcher _dispatcher;
    private DeviceWatcher _watcher;
    private ObservableCollection<MediaFrameSourceGroup> _remoteCameraCollection;
    public RemoteCameraPairingHelper(CoreDispatcher uiDispatcher)
    {
        _dispatcher = uiDispatcher;
        _remoteCameraCollection = new ObservableCollection<MediaFrameSourceGroup>();
        var remoteCameraAqs = @"System.Devices.InterfaceClassGuid:=""{B8238652-B500-41EB-B4F3-4234F7F5AE99}"" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True";
        _watcher = DeviceInformation.CreateWatcher(remoteCameraAqs);
        _watcher.Added += Watcher_Added;
        _watcher.Removed += Watcher_Removed;
        _watcher.Updated += Watcher_Updated;
        _watcher.Start();
    }
    public void Dispose()
    {
        _watcher.Stop();
        _watcher.Updated -= Watcher_Updated;
        _watcher.Removed -= Watcher_Removed;
        _watcher.Added -= Watcher_Added;
    }
    public IReadOnlyList<MediaFrameSourceGroup> FrameSourceGroups
    {
        get { return _remoteCameraCollection; }
    }
    private async void Watcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        await RemoveDevice(args.Id);
        await AddDeviceAsync(args.Id);
    }
    private async void Watcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        await RemoveDevice(args.Id);
    }
    private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
    {
        await AddDeviceAsync(args.Id);
    }
    private async Task AddDeviceAsync(string id)
    {
        var group = await MediaFrameSourceGroup.FromIdAsync(id);
        if (group != null)
        {
            await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                _remoteCameraCollection.Add(group);
            });
        }
    }
    private async Task RemoveDevice(string id)
    {
        await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            var existing = _remoteCameraCollection.FirstOrDefault(item => item.Id == id);
            if (existing != null)
            {
                _remoteCameraCollection.Remove(existing);
            }
        });
    }
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Media.Capture.Frames.h>
#include <winrt/Windows.UI.Core.h>
using namespace winrt;
using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Media::Capture::Frames;
using namespace winrt::Windows::UI::Core;

struct RemoteCameraPairingHelper
{
    RemoteCameraPairingHelper(CoreDispatcher uiDispatcher) :
        m_dispatcher(uiDispatcher)
    {
        m_remoteCameraCollection = winrt::single_threaded_observable_vector<MediaFrameSourceGroup>();
        auto remoteCameraAqs =
            LR"(System.Devices.InterfaceClassGuid:=""{B8238652-B500-41EB-B4F3-4234F7F5AE99}"")"
            LR"(AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True)";
        m_watcher = DeviceInformation::CreateWatcher(remoteCameraAqs);
        m_watcherAddedAutoRevoker = m_watcher.Added(winrt::auto_revoke, { this, &RemoteCameraPairingHelper::Watcher_Added });
        m_watcherRemovedAutoRevoker = m_watcher.Removed(winrt::auto_revoke, { this, &RemoteCameraPairingHelper::Watcher_Removed });
        m_watcherUpdatedAutoRevoker = m_watcher.Updated(winrt::auto_revoke, { this, &RemoteCameraPairingHelper::Watcher_Updated });
        m_watcher.Start();
    }
    ~RemoteCameraPairingHelper()
    {
        m_watcher.Stop();
    }
    IObservableVector<MediaFrameSourceGroup> FrameSourceGroups()
    {
        return m_remoteCameraCollection;
    }
    winrt::fire_and_forget Watcher_Added(DeviceWatcher /* sender */, DeviceInformation args)
    {
        co_await AddDeviceAsync(args.Id());
    }
    winrt::fire_and_forget Watcher_Removed(DeviceWatcher /* sender */, DeviceInformationUpdate args)
    {
        co_await RemoveDevice(args.Id());
    }
    winrt::fire_and_forget Watcher_Updated(DeviceWatcher /* sender */, DeviceInformationUpdate args)
    {
        co_await RemoveDevice(args.Id());
        co_await AddDeviceAsync(args.Id());
    }
    Windows::Foundation::IAsyncAction AddDeviceAsync(winrt::hstring id)
    {
        auto group = co_await MediaFrameSourceGroup::FromIdAsync(id);
        if (group)
        {
            co_await m_dispatcher;
            m_remoteCameraCollection.Append(group);
        }
    }
    Windows::Foundation::IAsyncAction RemoveDevice(winrt::hstring id)
    {
        co_await m_dispatcher;

        uint32_t ix{ 0 };
        for (auto const&& item : m_remoteCameraCollection)
        {
            if (item.Id() == id)
            {
                m_remoteCameraCollection.RemoveAt(ix);
                break;
            }
            ++ix;
        }
    }

private:
    CoreDispatcher m_dispatcher{ nullptr };
    DeviceWatcher m_watcher{ nullptr };
    IObservableVector<MediaFrameSourceGroup> m_remoteCameraCollection;
    DeviceWatcher::Added_revoker m_watcherAddedAutoRevoker;
    DeviceWatcher::Removed_revoker m_watcherRemovedAutoRevoker;
    DeviceWatcher::Updated_revoker m_watcherUpdatedAutoRevoker;
};