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.
Crear una clase DeviceWatcher para ver las 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. Para obtener una instancia de DeviceWatcher, llame a DeviceInformation.CreateWatcher y pase una cadena de sintaxis de consulta avanzada (AQS) que identifique el tipo de dispositivos que desea supervisar. La cadena AQS que especifica dispositivos de cámara de red es la 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 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 que se muestra 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 detengas el monitor llamando a Stop, se generará el evento Added cuando los nuevos dispositivos de cámara de red estén disponibles y se generará el evento Removed cuando un dispositivo de cámara deje de estar disponible.
Los argumentos de eventos pasados a los controladores de eventos Agregados y Eliminados 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 deviceWatcher para crear y actualizar un 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 interfaz de usuario.
Además, en este ejemplo se controla el evento DeviceWatcher.Updated además de los eventos Agregados y Eliminados. 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.
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;
};