Conexión a cámaras remotas

En este artículo se muestra cómo conectarse a una o varias cámaras remotas y obtener un objeto MediaFrameSourceGroup que le permite leer fotogramas de cada cámara. Para obtener más información sobre cómo leer fotogramas de un origen multimedia, vea Procesar fotogramas multimedia con MediaFrameReader. Para obtener más información sobre el emparejamiento con dispositivos, consulte Emparejar dispositivos.

Nota

Las características descritas en este artículo están disponibles a partir de Windows 10, versión 1903.

Creación de una clase DeviceWatcher para watch para cámaras remotas disponibles

La clase DeviceWatcher supervisa los dispositivos disponibles para la aplicación y notifica a la aplicación cuándo se agregan o quitan los dispositivos. Obtenga una instancia de DeviceWatcher llamando a DeviceInformation.CreateWatcher, pasando una cadena de sintaxis de consulta avanzada (AQS) que identifica el tipo de dispositivos que desea supervisar. La cadena de AQS que especifica los dispositivos de cámara de red es el siguiente:

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

Nota

El método auxiliar MediaFrameSourceGroup.GetDeviceSelector devuelve una cadena de AQS que supervisará las cámaras de red remotas y conectadas localmente. Para supervisar solo las cámaras de red, debe usar la cadena de AQS mostrada anteriormente.

Cuando inicie el DeviceWatcher devuelto llamando al método Start , generará el evento Added para cada cámara de red que esté disponible actualmente. Hasta que detenga el monitor llamando a Stop, se generará el evento Added cuando haya nuevos dispositivos de cámara de red disponibles y se generará el evento Removed cuando un dispositivo de cámara deje de estar disponible.

Los argumentos de evento pasados a los controladores de eventos Agregado y Quitado son un objeto DeviceInformation o DeviceInformationUpdate , respectivamente. Cada uno de estos objetos tiene una propiedad Id que es el identificador de la cámara de red para la que se desencadenó el evento. Pase este identificador al método MediaFrameSourceGroup.FromIdAsync para obtener un objeto MediaFrameSourceGroup que puede usar para recuperar fotogramas de la cámara.

Clase auxiliar de emparejamiento de cámara remota

En el ejemplo siguiente se muestra una clase auxiliar que usa un DeviceWatcher para crear y actualizar una clase ObservableCollection de objetos MediaFrameSourceGroup para admitir el enlace de datos a la lista de cámaras. Las aplicaciones típicas encapsularían MediaFrameSourceGroup en una clase de modelo personalizada. Tenga en cuenta que la clase auxiliar mantiene una referencia a CoreDispatcher de la aplicación y actualiza la colección de cámaras dentro de las llamadas a RunAsync para asegurarse de que la interfaz de usuario enlazada a la colección se actualiza en el subproceso de la interfaz de usuario.

Además, este ejemplo controla el evento DeviceWatcher.Updated además de los eventos Added y Removed . En el controlador Actualizado , el dispositivo de cámara remota asociado se quita de y luego se agrega de nuevo a la colección.

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