リモート カメラへの接続Connect to remote cameras

この記事では、1つまたは複数のリモートカメラに接続して、各カメラからフレームを読み取ることができる Mediaframesourcegroup オブジェクトを取得する方法について説明します。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. メディアソースからのフレームの読み取りの詳細については、「 MediaFrameReader を使用したメディアフレームの処理」を参照してください。For more information on reading frames from a media source, see Process media frames with MediaFrameReader. デバイスとのペアリングの詳細については、「 ペアリングデバイス」を参照してください。For more information on pairing with devices, see Pair devices.

注意

この記事で説明されている機能は、Windows 10 バージョン1903以降で使用できます。The features discussed in this article are available starting with Windows 10, version 1903.

使用可能なリモートカメラを監視する DeviceWatcher クラスを作成するCreate a DeviceWatcher class to watch for available remote cameras

Devicewatcherクラスは、アプリで使用可能なデバイスを監視し、デバイスが追加または削除されたときにアプリに通知します。The DeviceWatcher class monitors the devices available to your app and notifies your app when devices are added or removed. Devicewatcher のインスタンスDeviceWatcherを取得するには、 Devicewatcher. createwatcherを呼び出して、監視するデバイスの種類を識別する Advanced Query 構文 (aqs) 文字列を渡します。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. ネットワークカメラデバイスを指定する AQS 文字列は、次のとおりです。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"

注意

ヘルパーメソッド Mediaframesourcegroup. GetDeviceSelector は、ローカルに接続されたリモートネットワークカメラを監視する aqs 文字列を返します。The helper method MediaFrameSourceGroup.GetDeviceSelector returns an AQS string that will monitor locally-connected and remote network cameras. ネットワークカメラだけを監視するには、上に示した AQS 文字列を使用する必要があります。To monitor only network cameras, you should use the AQS string shown above.

Startメソッドを呼び出すことによって返されたdevicewatcherを開始すると、現在使用可能なすべてのネットワークカメラに対して追加されたイベントが発生します。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. Stopを呼び出してウォッチャーを停止するまで、追加されたイベントは、新しいネットワークカメラデバイスが使用可能になったときに発生し、カメラデバイスが使用できなくなったときに削除されたイベントが発生します。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.

追加および削除されたイベントハンドラーに渡されるイベント引数は、それぞれDeviceinformationまたはdeviceinformationupdateオブジェクトです。The event args passed into the Added and Removed event handlers are a DeviceInformation or a DeviceInformationUpdate object, respectively. これらの各オブジェクトには、イベントが発生したネットワークカメラの識別子である Id プロパティがあります。Each of these objects has an Id property that is the identifier for the network camera for which the event was fired. この ID を mediaframesourcegroup. FromIdAsync メソッドに渡して、カメラからフレームを取得するために使用できる mediaframesourcegroup オブジェクトを取得します。Pass this ID into the MediaFrameSourceGroup.FromIdAsync method to get a MediaFrameSourceGroup object that you can use to retrieve frames from the camera.

リモートカメラペアリングヘルパークラスRemote camera pairing helper class

次の例は、 Devicewatcherを使用してMediaframesourcegroupオブジェクトのsystem.collections.objectmodel.observablecollectionを作成および更新し、カメラのリストへのデータバインドをサポートするヘルパークラスを示しています。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. 一般的なアプリでは、カスタムモデルクラスに Mediaframesourcegroup がラップされます。Typical apps would wrap the MediaFrameSourceGroup in a custom model class. ヘルパークラスは、アプリの CoreDispatcher への参照を保持し、 runasync の呼び出し内のカメラのコレクションを更新して、コレクションにバインドされた ui が ui スレッドで確実に更新されるようにします。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.

また、この例では、追加および削除されたイベントに加えて、 devicewatcher も更新されたイベントを処理します。Also, this example handles the DeviceWatcher.Updated event in addition to the Added and Removed events. 更新されたハンドラーで、関連付けられているリモートカメラデバイスがから削除され、コレクションに戻されます。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;
};