Подключение к удаленным камерам

В этой статье показано, как подключиться к одной или нескольким удаленным камерам и получить объект MediaFrameSourceGroup , который позволяет считывать кадры с каждой камеры. Дополнительные сведения о чтении кадров из источника мультимедиа см. в разделе Обработка кадров мультимедиа с помощью MediaFrameReader. Дополнительные сведения о связывании с устройствами см. в разделе Связывание устройств.

Примечание

Функции, рассматриваемые в этой статье, доступны начиная с Windows 10 версии 1903.

Создание класса DeviceWatcher для watch доступных удаленных камер

Класс DeviceWatcher отслеживает устройства, доступные вашему приложению, и уведомляет приложение о добавлении или удалении устройств. Получите экземпляр DeviceWatcher , вызвав DeviceInformation.CreateWatcher, передав строку расширенного синтаксиса запросов (AQS), которая определяет тип устройств, которые требуется отслеживать. Строка AQS, указывающая устройства сетевой камеры, имеет следующий формат:

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

Примечание

Вспомогательный метод MediaFrameSourceGroup.GetDeviceSelector возвращает строку AQS, которая будет отслеживать локально подключенные и удаленные сетевые камеры. Для мониторинга только сетевых камер следует использовать приведенную выше строку AQS.

При запуске возвращаемого объекта DeviceWatcher путем вызова метода Start будет вызываться событие Added для каждой доступной сетевой камеры. Пока вы не остановите наблюдатель путем вызова Stop, событие Added будет возникать, когда новые устройства сетевой камеры станут доступными, а событие Removed будет вызвано, когда устройство камеры станет недоступным.

Аргументы событий, передаваемые в обработчики событий Added и Removed , являются объектом DeviceInformation или DeviceInformationUpdate соответственно. Каждый из этих объектов имеет свойство Id , которое является идентификатором сетевой камеры, для которой было запущено событие. Передайте этот идентификатор в метод MediaFrameSourceGroup.FromIdAsync , чтобы получить объект MediaFrameSourceGroup , который можно использовать для извлечения кадров с камеры.

Вспомогательный класс связывания удаленной камеры

В следующем примере показан вспомогательный класс, использующий DeviceWatcher для создания и обновления Объекта ObservableCollection объектов MediaFrameSourceGroup для поддержки привязки данных к списку камер. Типичные приложения заключают MediaFrameSourceGroup в пользовательский класс модели. Обратите внимание, что вспомогательный класс сохраняет ссылку на CoreDispatcher приложения и обновляет коллекцию камер в вызовах RunAsync , чтобы убедиться, что пользовательский интерфейс, привязанный к коллекции, обновляется в потоке пользовательского интерфейса.

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