Подключение к удаленным камерамConnect to remote cameras

В этой статье показано, как подключиться к одной или нескольким удаленным камерам и получить объект медиафрамесаурцеграуп , позволяющий считывать кадры с каждой камеры.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. Дополнительные сведения о чтении кадров из источника мультимедиа см. в разделе Обработка кадров мультимедиа с помощью медиафрамереадер.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.

Создание класса Девицеватчер для отслеживания доступных удаленных камерCreate a DeviceWatcher class to watch for available remote cameras

Класс девицеватчер отслеживает устройства, доступные для приложения, и уведомляет ваше приложение о добавлении или удалении устройств.The DeviceWatcher class monitors the devices available to your app and notifies your app when devices are added or removed. Получите экземпляр девицеватчер , вызвав девицеинформатион. креатеватчер, передав строку расширенного синтаксиса запросов (АКС), определяющую тип устройств, которые требуется отслеживать.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. Ниже приведены строки АКС, указывающие устройства сетевой камеры.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"

Примечание

Вспомогательный метод медиафрамесаурцеграуп. жетдевицеселектор ВОЗВРАЩАЕТ строку АКС, которая будет отслеживать локально подключенные и удаленные сетевые камеры.The helper method MediaFrameSourceGroup.GetDeviceSelector returns an AQS string that will monitor locally-connected and remote network cameras. Чтобы отслеживать только сетевые камеры, следует использовать строку АКС, показанную выше.To monitor only network cameras, you should use the AQS string shown above.

При запуске возвращенного девицеватчер путем вызова метода Start будет вызвано Добавление события для каждой доступной в данный момент сетевой камеры.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.

Аргументы события, передаваемые в обработчики событий добавления и удаления , — это объект девицеинформатион или девицеинформатионупдате , соответственно.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. Передайте этот идентификатор в метод медиафрамесаурцеграуп. фромидасинк , чтобы получить объект медиафрамесаурцеграуп , который можно использовать для получения кадров от камеры.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

В следующем примере показан вспомогательный класс, который использует девицеватчер для создания и обновления ObservableCollection объектов медиафрамесаурцеграуп для поддержки привязки данных к списку камер.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. Типичные приложения заключают медиафрамесаурцеграуп в пользовательский класс модели.Typical apps would wrap the MediaFrameSourceGroup in a custom model class. Обратите внимание, что вспомогательный класс поддерживает ссылку на CoreDispatcher приложения и обновляет коллекцию камер в рамках вызовов RunAsync , чтобы обеспечить обновление пользовательского интерфейса, привязанного к коллекции, в потоке пользовательского интерфейса.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.

Кроме того, в этом примере обрабатывается событие девицеватчер. Updates в дополнение к добавленным и удаляемым событиям.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;
};