Condividi tramite


Connettere alle fotocamere remote

Questo articolo illustra come connettersi a una o più fotocamere remote e ottenere un oggetto MediaFrameSourceGroup che consente di leggere fotogrammi da ogni fotocamera. Per altre informazioni sulla lettura dei fotogrammi da un'origine multimediale, vedere Elaborare fotogrammi multimediali con MediaFrameReader. Per ulteriori informazioni sull'associazione ai dispositivi, consultare Associare i dispositivi.

Nota

Le funzionalità descritte in questo articolo sono disponibili a partire da Windows 10 versione 1903.

Creare una classe DeviceWatcher per controllare la disponibilità di fotocamere remote disponibili

La classe DeviceWatcher monitora i dispositivi disponibili per l'app e invia una notifica all'app quando i dispositivi vengono aggiunti o rimossi. Ottieni un'istanza di DeviceWatcher chiamando DeviceInformation.CreateWatchere passando una stringa AQS (Advanced Query Syntax) che identifica il tipo di dispositivi che desideri monitorare. La stringa AQS che specifica i dispositivi della fotocamera di rete è la seguente:

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

Nota

Il metodo helper MediaFrameSourceGroup.GetDeviceSelector restituisce una stringa AQS che monitorerà le fotocamere di rete connesse in locale e remote. Per monitorare solo le fotocamere di rete, è consigliabile usare la stringa AQS illustrata in precedenza.

Quando si avvia il DeviceWatcher restituito chiamando il metodo Start, verrà generato l'evento Addedper ogni telecamera di rete attualmente disponibile. Finché non si arresta il watcher chiamando Stop, l'evento Added verrà generato quando i nuovi dispositivi delle telecamere di rete diventano disponibili e l'evento Removed verrà generato quando un dispositivo telecamera diventa non disponibile.

Gli argomenti dell'evento passati nei gestori di eventi Added e Removed sono rispettivamente un oggetto DeviceInformation o DeviceInformationUpdate. Ognuno di questi oggetti ha una proprietà Id che serve come identificatore per la fotocamera di rete per la quale è stato generato l'evento. Passare questo ID al metodo MediaFrameSourceGroup.FromIdAsync per ottenere un oggetto MediaFrameSourceGroup che è possibile usare per recuperare fotogrammi dalla fotocamera.

Classe di supporto per l'associazione di fotocamere remote

L'esempio seguente illustra una classe di supporto che usa un DeviceWatcher per creare e aggiornare una ObservableCollection di oggetti MediaFrameSourceGroup al fine di supportare il data binding all'elenco delle fotocamere. Le app tipiche racchiudono il MediaFrameSourceGroup all'interno di una classe di modello personalizzata. Si noti che la classe helper mantiene un riferimento all'DispatcherQueue dell'app e aggiorna la raccolta di fotocamere nel thread dell'interfaccia utente.

Inoltre, questo esempio gestisce l'evento DeviceWatcher.Updated oltre agli eventi Aggiunto e Rimosso. Nel gestore aggiornato , il dispositivo della fotocamera remota associato viene rimosso e quindi reintrodotto nella raccolta.

class RemoteCameraPairingHelper : IDisposable
{
    private DispatcherQueue _dispatcherQueue;
    private DeviceWatcher _watcher;
    private ObservableCollection<MediaFrameSourceGroup> _remoteCameraCollection;

    public RemoteCameraPairingHelper(DispatcherQueue uiDispatcherQueue)
    {
        _dispatcherQueue = uiDispatcherQueue;
        _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)
        {
            _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () => {
                _remoteCameraCollection.Add(group);
            });
        }
    }
    private async Task RemoveDevice(string id)
    {
        _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
        {
            var existing = _remoteCameraCollection.FirstOrDefault(item => item.Id == id);
            if (existing != null)
            {
                _remoteCameraCollection.Remove(existing);
            }
        });
    }
struct RemoteCameraPairingHelper
{
    RemoteCameraPairingHelper(DispatcherQueue uiDispatcher) :
        m_dispatcherQueue(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, nullptr);

        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_dispatcherQueue;
            co_await wil::resume_foreground(m_dispatcherQueue);
            m_remoteCameraCollection.Append(group);
        }
    }
    Windows::Foundation::IAsyncAction RemoveDevice(winrt::hstring id)
    {
        //co_await m_dispatcherQueue;
        co_await wil::resume_foreground(m_dispatcherQueue);

        uint32_t ix{ 0 };
        for (auto const&& item : m_remoteCameraCollection)
        {
            if (item.Id() == id)
            {
                m_remoteCameraCollection.RemoveAt(ix);
                break;
            }
            ++ix;
        }
    }

private:
    DispatcherQueue m_dispatcherQueue{ nullptr };
    DeviceWatcher m_watcher{ nullptr };
    IObservableVector<MediaFrameSourceGroup> m_remoteCameraCollection;
    DeviceWatcher::Added_revoker m_watcherAddedAutoRevoker;
    DeviceWatcher::Removed_revoker m_watcherRemovedAutoRevoker;
    DeviceWatcher::Updated_revoker m_watcherUpdatedAutoRevoker;
};