원격 카메라에 연결Connect to remote cameras

이 문서에서는 하나 이상의 원격 카메라에 연결 하 고 각 카메라의 프레임을 읽을 수 있는 Mediaframesourcegroup 개체를 가져오는 방법을 보여 줍니다.This article shows you how to connect to one or more remote cameras and get a MediaFrameSourceGroup object that allows you to read frames from each camera. 미디어 원본에서 프레임을 읽는 방법에 대 한 자세한 내용은 MediaFrameReader를 사용 하 여 미디어 프레임 처리를 참조 하세요.For more information on reading frames from a media source, see Process media frames with MediaFrameReader. 장치와의 페어링에 대 한 자세한 내용은 페어링 장치를 참조 하세요.For more information on pairing with devices, see Pair devices.

참고

이 문서에서 설명 하는 기능은 Windows 10, 버전 1903부터 사용할 수 있습니다.The features discussed in this article are available starting with Windows 10, version 1903.

사용 가능한 원격 카메라를 감시 하는 DeviceWatcher 클래스 만들기Create a DeviceWatcher class to watch for available remote cameras

Devicewatcher 클래스는 앱에서 사용할 수 있는 장치를 모니터링 하 고 장치를 추가 하거나 제거할 때 앱에 알립니다.The DeviceWatcher class monitors the devices available to your app and notifies your app when devices are added or removed. Devicewatcher을 호출 하 여 devicewatcher 의 인스턴스를 가져옵니다 . createwatcher는 모니터링 하려는 장치 유형을 식별 하는 AQS (고급 쿼리 구문) 문자열을 전달 합니다.Get an instance of DeviceWatcher by calling DeviceInformation.CreateWatcher, passing in an Advanced Query Syntax (AQS) string that identifies the type of devices you want to monitor. 네트워크 카메라 장치를 지정 하는 AQS 문자열은 다음과 같습니다.The AQS string specifying network camera devices is the following:

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

참고

도우미 메서드 MediafAQS Esourcegroup. GetDeviceSelector 는 로컬로 연결 되 고 원격 네트워크 카메라를 모니터링 하는 문자열을 반환 합니다.The helper method MediaFrameSourceGroup.GetDeviceSelector returns an AQS string that will monitor locally-connected and remote network cameras. 네트워크 카메라만 모니터링 하려면 위에 표시 된 AQS 문자열을 사용 해야 합니다.To monitor only network cameras, you should use the AQS string shown above.

Start 메서드를 호출 하 여 반환 된 devicewatcher 를 시작 하면 현재 사용할 수 있는 모든 네트워크 카메라에 대해 추가 된 이벤트가 발생 합니다.When you start the returned DeviceWatcher by calling the Start method, it will raise the Added event for every network camera that is currently available. 중지를 호출 하 여 감시자를 중지 하기 전에는 새 네트워크 카메라 장치를 사용할 수 있게 되 면 추가 된 이벤트가 발생 하 고 카메라 장치를 사용할 수 없게 되 면 제거 된 이벤트가 발생 합니다.Until you stop the watcher by calling Stop, the Added event will be raised when new network camera devices become available and the Removed event will be raised when a camera device becomes unavailable.

추가제거 된 이벤트 처리기에 전달 되는 이벤트 인수는 각각 Deviceinformation 또는 deviceinformationupdate 개체입니다.The event args passed into the Added and Removed event handlers are a DeviceInformation or a DeviceInformationUpdate object, respectively. 이러한 각 개체에는 이벤트가 발생 한 네트워크 카메라의 식별자 인 Id 속성이 있습니다.Each of these objects has an Id property that is the identifier for the network camera for which the event was fired. 이 ID를 MediafFromIdAsync 메서드에 전달 하 여 카메라에서 프레임을 검색 하는 데 사용할 수 있는 mediaframesourcegroup 개체를 가져옵니다.Pass this ID into the MediaFrameSourceGroup.FromIdAsync method to get a MediaFrameSourceGroup object that you can use to retrieve frames from the camera.

원격 카메라 페어링 도우미 클래스Remote camera pairing helper class

다음 예제에서는 Devicewatcher 를 사용 하 여 System.collections.objectmodel.observablecollectionMediaframesourcegroup 개체를 만들고 업데이트 하는 도우미 클래스를 보여 줍니다 .이 클래스는 카메라 목록에 대 한 데이터 바인딩을 지원 합니다.The following example shows a helper class that uses a DeviceWatcher to create and update an ObservableCollection of MediaFrameSourceGroup objects to support data binding to the list of cameras. 일반적인 앱은 사용자 지정 모델 클래스에서 Mediaframesourcegroup 을 래핑합니다.Typical apps would wrap the MediaFrameSourceGroup in a custom model class. 도우미 클래스는 앱의 CoreDispatcher 에 대 한 참조를 유지 하 고 runasync 호출 내의 카메라 컬렉션을 업데이트 하 여 컬렉션에 바인딩된 ui가 ui 스레드에서 업데이트 되도록 합니다.Note that the helper class maintains a reference to the app's CoreDispatcher and updates the collection of cameras within calls to RunAsync to ensure that the UI bound to the collection is updated on the UI thread.

또한이 예제에서는 추가제거 된 이벤트 외에도 devicewatcher. Updated 이벤트를 처리 합니다.Also, this example handles the DeviceWatcher.Updated event in addition to the Added and Removed events. 업데이트 된 처리기에서 연결 된 원격 카메라 장치가에서 제거 된 다음 컬렉션에 다시 추가 됩니다.In the Updated handler, the associated remote camera device is removed from and then added back to the collection.

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;
};