Conexión a cámaras remotasConnect to remote cameras

En este artículo se muestra cómo conectarse a una o varias cámaras remotas y cómo obtener un objeto MediaFrameSourceGroup que le permita leer fotogramas de cada cámara.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. Para obtener más información sobre cómo leer fotogramas de un origen multimedia, consulte procesar fotogramas multimedia con MediaFrameReader.For more information on reading frames from a media source, see Process media frames with MediaFrameReader. Para obtener más información sobre el emparejamiento con dispositivos, consulte Pair Devices.For more information on pairing with devices, see Pair devices.

Nota

Las características que se describen en este artículo están disponibles a partir de Windows 10, versión 1903.The features discussed in this article are available starting with Windows 10, version 1903.

Cree una clase DeviceWatcher para ver las cámaras remotas disponiblesCreate a DeviceWatcher class to watch for available remote cameras

La clase DeviceWatcher supervisa los dispositivos disponibles para la aplicación y notifica a la aplicación cuando se agregan o quitan dispositivos.The DeviceWatcher class monitors the devices available to your app and notifies your app when devices are added or removed. 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.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. La cadena AQS que especifica dispositivos de cámara de red es la siguiente: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"

Nota

El método auxiliar MediaFrameSourceGroup. GetDeviceSelector devuelve una cadena AQS que supervisará las cámaras de red remotas y conectadas localmente.The helper method MediaFrameSourceGroup.GetDeviceSelector returns an AQS string that will monitor locally-connected and remote network cameras. Para supervisar solo las cámaras de red, debe usar la cadena AQS mostrada anteriormente.To monitor only network cameras, you should use the AQS string shown above.

Al iniciar la DeviceWatcher devuelta llamando al método Start , se generará el evento Added para cada cámara de red que esté disponible actualmente.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. Hasta que detenga el monitor mediante una llamada a Stop, el evento agregado se generará cuando haya nuevos dispositivos de cámara de red disponibles y el evento eliminado se generará cuando un dispositivo de cámara deje de estar disponible.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.

Los argumentos del evento que se pasan a los controladores de eventos agregados y quitados son un objeto DeviceInformation o DeviceInformationUpdate , respectivamente.The event args passed into the Added and Removed event handlers are a DeviceInformation or a DeviceInformationUpdate object, respectively. Cada uno de estos objetos tiene una propiedad ID que es el identificador de la cámara de red para la que se activó el evento.Each of these objects has an Id property that is the identifier for the network camera for which the event was fired. Pase este identificador al método MediaFrameSourceGroup. FromIdAsync para obtener un objeto MediaFrameSourceGroup que pueda usar para recuperar fotogramas de la cámara.Pass this ID into the MediaFrameSourceGroup.FromIdAsync method to get a MediaFrameSourceGroup object that you can use to retrieve frames from the camera.

Clase auxiliar de emparejamiento de cámara remotoRemote camera pairing helper class

En el ejemplo siguiente se muestra una clase auxiliar que utiliza un objeto DeviceWatcher para crear y actualizar un ObservableCollection de objetos MediaFrameSourceGroup para admitir el enlace de datos a la lista de cámaras.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. Las aplicaciones típicas encapsularían MediaFrameSourceGroup en una clase de modelo personalizado.Typical apps would wrap the MediaFrameSourceGroup in a custom model class. Tenga en cuenta que la clase auxiliar mantiene una referencia al 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.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.

Además, este ejemplo controla el evento DeviceWatcher. Updated , además de los eventos agregados y quitados .Also, this example handles the DeviceWatcher.Updated event in addition to the Added and Removed events. En el controlador actualizado , el dispositivo de cámara remota asociado se quita de y, a continuación, se vuelve a agregar a la colección.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;
};