mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 00:36:51 +00:00
libs: Introduce GstWinRT library
Adding a helper library for various WinRT specific implementations. Currently this library supports only DeviceWatcher abstraction object which can be used for dynamic device add/remove detection. See also https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher?view=winrt-20348 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/947>
This commit is contained in:
parent
b8d6962c9b
commit
08cb5b482d
6 changed files with 1011 additions and 1 deletions
|
@ -15,7 +15,8 @@ subdir('play')
|
|||
subdir('player')
|
||||
subdir('sctp')
|
||||
subdir('transcoder')
|
||||
subdir('va')
|
||||
subdir('vulkan')
|
||||
subdir('wayland')
|
||||
subdir('webrtc')
|
||||
subdir('va')
|
||||
subdir('winrt')
|
||||
|
|
31
subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h
Normal file
31
subprojects/gst-plugins-bad/gst-libs/gst/winrt/gstwinrt.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_WINRT_H__
|
||||
#define __GST_WINRT_H__
|
||||
|
||||
#ifndef GST_USE_UNSTABLE_API
|
||||
#pragma message ("The winrt library from gst-plugins-bad is unstable API and may change in future.")
|
||||
#pragma message ("You can define GST_USE_UNSTABLE_API to avoid this warning.")
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/winrt/gstwinrtdevicewatcher.h>
|
||||
|
||||
#endif /* __GST_WINRT_H__ */
|
|
@ -0,0 +1,723 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstwinrtdevicewatcher.h"
|
||||
|
||||
/* workaround for GetCurrentTime collision */
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <windows.foundation.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformation IAddedHandler;
|
||||
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IUpdatedHandler;
|
||||
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformationUpdate IRemovedHandler;
|
||||
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IEnumerationCompletedHandler;
|
||||
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable IStoppedHandler;
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::Devices;
|
||||
using namespace ABI::Windows::Devices::Enumeration;
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_winrt_device_watcher_debug);
|
||||
#define GST_CAT_DEFAULT gst_winrt_device_watcher_debug
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformation * info);
|
||||
static void
|
||||
gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformationUpdate * info_update);
|
||||
static void
|
||||
gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformationUpdate * info_update);
|
||||
static void
|
||||
gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher *
|
||||
self);
|
||||
static void
|
||||
gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher *
|
||||
self);
|
||||
|
||||
class AddedHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, IAddedHandler>
|
||||
{
|
||||
public:
|
||||
AddedHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
|
||||
{
|
||||
if (!listenr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
listener_ = listenr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IDeviceWatcher* sender, IDeviceInformation * arg)
|
||||
{
|
||||
gst_winrt_device_watcher_device_added (listener_, arg);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstWinRTDeviceWatcher * listener_;
|
||||
};
|
||||
|
||||
class UpdatedHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, IUpdatedHandler>
|
||||
{
|
||||
public:
|
||||
UpdatedHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
|
||||
{
|
||||
if (!listenr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
listener_ = listenr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IDeviceWatcher* sender, IDeviceInformationUpdate * arg)
|
||||
{
|
||||
gst_winrt_device_watcher_device_updated (listener_, arg);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstWinRTDeviceWatcher * listener_;
|
||||
};
|
||||
|
||||
class RemovedHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, IRemovedHandler>
|
||||
{
|
||||
public:
|
||||
RemovedHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
|
||||
{
|
||||
if (!listenr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
listener_ = listenr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IDeviceWatcher* sender, IDeviceInformationUpdate * arg)
|
||||
{
|
||||
gst_winrt_device_watcher_device_removed (listener_, arg);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstWinRTDeviceWatcher * listener_;
|
||||
};
|
||||
|
||||
class EnumerationCompletedHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, IEnumerationCompletedHandler>
|
||||
{
|
||||
public:
|
||||
EnumerationCompletedHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
|
||||
{
|
||||
if (!listenr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
listener_ = listenr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IDeviceWatcher* sender, IInspectable * arg)
|
||||
{
|
||||
gst_winrt_device_watcher_device_enumeration_completed (listener_);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstWinRTDeviceWatcher * listener_;
|
||||
};
|
||||
|
||||
class StoppedHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, IStoppedHandler>
|
||||
{
|
||||
public:
|
||||
StoppedHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstWinRTDeviceWatcher * listenr)
|
||||
{
|
||||
if (!listenr)
|
||||
return E_INVALIDARG;
|
||||
|
||||
listener_ = listenr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IDeviceWatcher* sender, IInspectable * arg)
|
||||
{
|
||||
gst_winrt_device_watcher_device_enumeration_stopped (listener_);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstWinRTDeviceWatcher * listener_;
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ComPtr < IDeviceWatcher > watcher;
|
||||
|
||||
EventRegistrationToken added_token;
|
||||
EventRegistrationToken updated_token;
|
||||
EventRegistrationToken removed_token;
|
||||
EventRegistrationToken enum_completed_token;
|
||||
EventRegistrationToken stopped_token;
|
||||
} GstWinRTDeviceWatcherInner;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DEVICE_CLASS,
|
||||
};
|
||||
|
||||
#define DEFAULT_DEVICE_CLASS GST_WINRT_DEVICE_CLASS_ALL
|
||||
|
||||
struct _GstWinRTDeviceWatcherPrivate
|
||||
{
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
|
||||
GThread *thread;
|
||||
GMainContext *context;
|
||||
GMainLoop *loop;
|
||||
|
||||
gboolean running;
|
||||
|
||||
GstWinRTDeviceWatcherCallbacks callbacks;
|
||||
gpointer user_data;
|
||||
|
||||
GstWinRTDeviceWatcherInner *inner;
|
||||
|
||||
GstWinRTDeviceClass device_class;
|
||||
};
|
||||
|
||||
GType
|
||||
gst_winrt_device_class_get_type (void)
|
||||
{
|
||||
static gsize device_class_type = 0;
|
||||
|
||||
if (g_once_init_enter (&device_class_type)) {
|
||||
static const GEnumValue classes[] = {
|
||||
{GST_WINRT_DEVICE_CLASS_ALL, "All", "all"},
|
||||
{GST_WINRT_DEVICE_CLASS_AUDIO_CAPTURE, "AudioCapture", "audio-capture"},
|
||||
{GST_WINRT_DEVICE_CLASS_AUDIO_RENDER, "AudioRender", "audio-render"},
|
||||
{GST_WINRT_DEVICE_CLASS_PORTABLE_STORAGE_DEVICE,
|
||||
"PortableStorageDevice", "portable-storage-device"},
|
||||
{GST_WINRT_DEVICE_CLASS_VIDEO_CAPTURE,
|
||||
"VideoCapture", "video-capture"},
|
||||
{0, nullptr, nullptr},
|
||||
};
|
||||
GType tmp = g_enum_register_static ("GstWinRTDeviceClass", classes);
|
||||
g_once_init_leave (&device_class_type, tmp);
|
||||
}
|
||||
|
||||
return (GType) device_class_type;
|
||||
}
|
||||
|
||||
static void gst_winrt_device_watcher_constructed (GObject * object);
|
||||
static void gst_winrt_device_watcher_finalize (GObject * object);
|
||||
static void gst_winrt_device_watcher_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_winrt_device_watcher_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
|
||||
static gpointer
|
||||
gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self);
|
||||
|
||||
#define gst_winrt_device_watcher_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GstWinRTDeviceWatcher, gst_winrt_device_watcher,
|
||||
GST_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_class_init (GstWinRTDeviceWatcherClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = gst_winrt_device_watcher_constructed;
|
||||
gobject_class->finalize = gst_winrt_device_watcher_finalize;
|
||||
gobject_class->set_property = gst_winrt_device_watcher_set_property;
|
||||
gobject_class->get_property = gst_winrt_device_watcher_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_DEVICE_CLASS,
|
||||
g_param_spec_enum ("device-class", "Device Class",
|
||||
"Device class to watch", GST_TYPE_WINRT_DEVICE_CLASS,
|
||||
DEFAULT_DEVICE_CLASS,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_winrt_device_watcher_debug,
|
||||
"winrtdevicewatcher", 0, "winrtdevicewatcher");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_init (GstWinRTDeviceWatcher * self)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv;
|
||||
|
||||
self->priv = priv = (GstWinRTDeviceWatcherPrivate *)
|
||||
gst_winrt_device_watcher_get_instance_private (self);
|
||||
|
||||
g_mutex_init (&priv->lock);
|
||||
g_cond_init (&priv->cond);
|
||||
priv->context = g_main_context_new ();
|
||||
priv->loop = g_main_loop_new (priv->context, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_constructed (GObject * object)
|
||||
{
|
||||
GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
g_mutex_lock (&priv->lock);
|
||||
priv->thread = g_thread_new ("GstWinRTDeviceWatcher",
|
||||
(GThreadFunc) gst_winrt_device_watcher_thread_func, self);
|
||||
while (!g_main_loop_is_running (priv->loop))
|
||||
g_cond_wait (&priv->cond, &priv->lock);
|
||||
g_mutex_unlock (&priv->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_finalize (GObject * object)
|
||||
{
|
||||
GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
g_main_loop_quit (priv->loop);
|
||||
if (g_thread_self () != priv->thread) {
|
||||
g_thread_join (priv->thread);
|
||||
g_main_loop_unref (priv->loop);
|
||||
g_main_context_unref (priv->context);
|
||||
} else {
|
||||
g_warning ("Trying join from self-thread");
|
||||
}
|
||||
|
||||
g_mutex_clear (&priv->lock);
|
||||
g_cond_clear (&priv->cond);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE_CLASS:
|
||||
priv->device_class = (GstWinRTDeviceClass) g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstWinRTDeviceWatcher *self = GST_WINRT_DEVICE_WATCHER (object);
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE_CLASS:
|
||||
g_value_set_enum (value, priv->device_class);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
loop_running_cb (GstWinRTDeviceWatcher * self)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
g_mutex_lock (&priv->lock);
|
||||
g_cond_signal (&priv->cond);
|
||||
g_mutex_unlock (&priv->lock);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_thread_func_inner (GstWinRTDeviceWatcher * self)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
GSource *idle_source;
|
||||
HRESULT hr;
|
||||
GstWinRTDeviceWatcherInner *inner = nullptr;
|
||||
ComPtr < IDeviceInformationStatics > factory;
|
||||
ComPtr < IDeviceWatcher > watcher;
|
||||
ComPtr < IAddedHandler > added_handler;
|
||||
ComPtr < IUpdatedHandler > updated_handler;
|
||||
ComPtr < IRemovedHandler > removed_handler;
|
||||
ComPtr < IEnumerationCompletedHandler > enum_completed_handler;
|
||||
ComPtr < IStoppedHandler > stopped_handler;
|
||||
|
||||
g_main_context_push_thread_default (priv->context);
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_callback (idle_source,
|
||||
(GSourceFunc) loop_running_cb, self, nullptr);
|
||||
g_source_attach (idle_source, priv->context);
|
||||
g_source_unref (idle_source);
|
||||
|
||||
hr = GetActivationFactory (HStringReference
|
||||
(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get (),
|
||||
&factory);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Failed to get IDeviceInformationStatics, hr: 0x%x", (guint) hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = factory->CreateWatcherDeviceClass ((DeviceClass) priv->device_class,
|
||||
&watcher);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Failed to create IDeviceWatcher, hr: 0x%x", (guint) hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = MakeAndInitialize < AddedHandler > (&added_handler, self);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create added handler, hr: 0x%x", hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = MakeAndInitialize < UpdatedHandler > (&updated_handler, self);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create updated handler, hr: 0x%x", hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = MakeAndInitialize < RemovedHandler > (&removed_handler, self);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create removed handler, hr: 0x%x", hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = MakeAndInitialize < EnumerationCompletedHandler >
|
||||
(&enum_completed_handler, self);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Failed to create enumeration completed handler, hr: 0x%x", hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = MakeAndInitialize < StoppedHandler > (&stopped_handler, self);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create stopped handler, hr: 0x%x", hr);
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
inner = new GstWinRTDeviceWatcherInner ();
|
||||
hr = watcher->add_Added (added_handler.Get (), &inner->added_token);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to register added handler, hr: 0x%x", hr);
|
||||
delete inner;
|
||||
inner = nullptr;
|
||||
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = watcher->add_Updated (updated_handler.Get (), &inner->updated_token);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to register updated handler, hr: 0x%x", hr);
|
||||
delete inner;
|
||||
inner = nullptr;
|
||||
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = watcher->add_Removed (removed_handler.Get (), &inner->removed_token);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to register removed handler, hr: 0x%x", hr);
|
||||
delete inner;
|
||||
inner = nullptr;
|
||||
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = watcher->add_EnumerationCompleted (enum_completed_handler.Get (),
|
||||
&inner->enum_completed_token);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Failed to register enumeration completed handler, hr: 0x%x", hr);
|
||||
delete inner;
|
||||
inner = nullptr;
|
||||
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
hr = watcher->add_Stopped (stopped_handler.Get (), &inner->stopped_token);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Failed to register stopped handler, hr: 0x%x", hr);
|
||||
delete inner;
|
||||
inner = nullptr;
|
||||
|
||||
goto run_loop;
|
||||
}
|
||||
|
||||
inner->watcher = watcher;
|
||||
priv->inner = inner;
|
||||
|
||||
run_loop:
|
||||
GST_INFO_OBJECT (self, "Starting loop");
|
||||
g_main_loop_run (priv->loop);
|
||||
GST_INFO_OBJECT (self, "Stopped loop");
|
||||
|
||||
if (inner) {
|
||||
if (priv->running)
|
||||
watcher->Stop ();
|
||||
|
||||
watcher->remove_Added (inner->added_token);
|
||||
watcher->remove_Updated (inner->updated_token);
|
||||
watcher->remove_Removed (inner->removed_token);
|
||||
watcher->remove_EnumerationCompleted (inner->enum_completed_token);
|
||||
watcher->remove_Stopped (inner->stopped_token);
|
||||
|
||||
delete inner;
|
||||
}
|
||||
|
||||
g_main_context_pop_thread_default (priv->context);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_winrt_device_watcher_thread_func (GstWinRTDeviceWatcher * self)
|
||||
{
|
||||
RoInitializeWrapper initialize (RO_INIT_MULTITHREADED);
|
||||
|
||||
/* wrap with another function so that everything can happen
|
||||
* before RoInitializeWrapper is destructed */
|
||||
gst_winrt_device_watcher_thread_func_inner (self);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_added (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformation * info)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Device added");
|
||||
|
||||
if (priv->callbacks.added)
|
||||
priv->callbacks.added (self, info, priv->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_updated (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformationUpdate * info_update)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Device updated");
|
||||
|
||||
if (priv->callbacks.updated)
|
||||
priv->callbacks.updated (self, info_update, priv->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_removed (GstWinRTDeviceWatcher * self,
|
||||
IDeviceInformationUpdate * info_update)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Device removed");
|
||||
|
||||
if (priv->callbacks.removed)
|
||||
priv->callbacks.removed (self, info_update, priv->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_enumeration_completed (GstWinRTDeviceWatcher *
|
||||
self)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv = self->priv;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Enumeration completed");
|
||||
|
||||
if (priv->callbacks.enumeration_completed)
|
||||
priv->callbacks.enumeration_completed (self, priv->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_winrt_device_watcher_device_enumeration_stopped (GstWinRTDeviceWatcher *
|
||||
self)
|
||||
{
|
||||
GST_DEBUG_OBJECT (self, "Stopped");
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_winrt_device_watcher_new:
|
||||
* @device_class: a #GstWinRTDeviceClass to watch
|
||||
* @callbacks: a pointer to #GstWinRTDeviceWatcherCallbacks
|
||||
* @user_data: a user_data argument for the callbacks
|
||||
*
|
||||
* Constructs a new #GstWinRTDeviceWatcher object for watching device update
|
||||
* of @device_class
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a new #GstWinRTDeviceWatcher
|
||||
* or %NULL when failed to create/setup #GstWinRTDeviceWatcher object
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
GstWinRTDeviceWatcher *
|
||||
gst_winrt_device_watcher_new (GstWinRTDeviceClass device_class,
|
||||
const GstWinRTDeviceWatcherCallbacks * callbacks, gpointer user_data)
|
||||
{
|
||||
GstWinRTDeviceWatcher *self;
|
||||
GstWinRTDeviceWatcherPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (callbacks != nullptr, nullptr);
|
||||
|
||||
self = (GstWinRTDeviceWatcher *)
|
||||
g_object_new (GST_TYPE_WINRT_DEVICE_WATCHER, "device-class", device_class,
|
||||
nullptr);
|
||||
|
||||
priv = self->priv;
|
||||
if (!priv->inner) {
|
||||
gst_object_unref (self);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
priv->callbacks = *callbacks;
|
||||
priv->user_data = user_data;
|
||||
|
||||
gst_object_ref_sink (self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_winrt_device_watcher_start:
|
||||
* @device_class: a #GstWinRTDeviceClass to watch
|
||||
*
|
||||
* Starts watching device update.
|
||||
*
|
||||
* Returns: %TRUE if successful
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
gboolean
|
||||
gst_winrt_device_watcher_start (GstWinRTDeviceWatcher * watcher)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv;
|
||||
GstWinRTDeviceWatcherInner *inner;
|
||||
HRESULT hr;
|
||||
|
||||
g_return_val_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher), FALSE);
|
||||
|
||||
priv = watcher->priv;
|
||||
inner = priv->inner;
|
||||
|
||||
GST_DEBUG_OBJECT (watcher, "Start");
|
||||
|
||||
g_mutex_lock (&priv->lock);
|
||||
if (priv->running) {
|
||||
GST_DEBUG_OBJECT (watcher, "Already running");
|
||||
g_mutex_unlock (&priv->lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
hr = inner->watcher->Start ();
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (watcher, "Failed to start watcher, hr: 0x%x", (guint) hr);
|
||||
g_mutex_unlock (&priv->lock);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->running = TRUE;
|
||||
g_mutex_unlock (&priv->lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_winrt_device_watcher_stop:
|
||||
* @device_class: a #GstWinRTDeviceClass to watch
|
||||
*
|
||||
* Stops watching device update.
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
void
|
||||
gst_winrt_device_watcher_stop (GstWinRTDeviceWatcher * watcher)
|
||||
{
|
||||
GstWinRTDeviceWatcherPrivate *priv;
|
||||
GstWinRTDeviceWatcherInner *inner;
|
||||
HRESULT hr;
|
||||
|
||||
g_return_if_fail (GST_IS_WINRT_DEVICE_WATCHER (watcher));
|
||||
|
||||
GST_DEBUG_OBJECT (watcher, "Stop");
|
||||
|
||||
priv = watcher->priv;
|
||||
inner = priv->inner;
|
||||
|
||||
g_mutex_lock (&priv->lock);
|
||||
if (!priv->running) {
|
||||
g_mutex_unlock (&priv->lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
priv->running = FALSE;
|
||||
hr = inner->watcher->Stop ();
|
||||
if (FAILED (hr)) {
|
||||
GST_WARNING_OBJECT (watcher,
|
||||
"Failed to stop watcher, hr: 0x%x", (guint) hr);
|
||||
}
|
||||
g_mutex_unlock (&priv->lock);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_WINRT_DEVICE_WATCHER_H__
|
||||
#define __GST_WINRT_DEVICE_WATCHER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/winrt/winrt-prelude.h>
|
||||
#include <windows.devices.enumeration.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_WINRT_DEVICE_WATCHER (gst_winrt_device_watcher_get_type())
|
||||
#define GST_WINRT_DEVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcher))
|
||||
#define GST_WINRT_DEVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcherClass))
|
||||
#define GST_IS_WINRT_DEVICE_WATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_WINRT_DEVICE_WATCHER))
|
||||
#define GST_IS_WINRT_DEVICE_WATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_WINRT_DEVICE_WATCHER))
|
||||
#define GST_WINRT_DEVICE_WATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_WINRT_DEVICE_WATCHER, GstWinRTDeviceWatcherClass))
|
||||
#define GST_WINRT_DEVICE_WATCHER_CAST(obj) ((GstWinRTDeviceWatcher *)obj)
|
||||
|
||||
typedef struct _GstWinRTDeviceWatcher GstWinRTDeviceWatcher;
|
||||
typedef struct _GstWinRTDeviceWatcherClass GstWinRTDeviceWatcherClass;
|
||||
typedef struct _GstWinRTDeviceWatcherPrivate GstWinRTDeviceWatcherPrivate;
|
||||
|
||||
/* ABI::Windows::Devices::Enumeration::DeviceClass */
|
||||
#define GST_TYPE_WINRT_DEVICE_CLASS (gst_winrt_device_class_get_type ())
|
||||
typedef enum
|
||||
{
|
||||
GST_WINRT_DEVICE_CLASS_ALL = 0,
|
||||
GST_WINRT_DEVICE_CLASS_AUDIO_CAPTURE = 1,
|
||||
GST_WINRT_DEVICE_CLASS_AUDIO_RENDER = 2,
|
||||
GST_WINRT_DEVICE_CLASS_PORTABLE_STORAGE_DEVICE = 3,
|
||||
GST_WINRT_DEVICE_CLASS_VIDEO_CAPTURE = 4,
|
||||
} GstWinRTDeviceClass;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* GstWinRTDeviceWatcherCallbacks::added:
|
||||
* @watcher: a #GstWinRTDeviceWatcher
|
||||
* @info: (transfer none): a IDeviceInformation interface handle
|
||||
* @user_data: a user_data
|
||||
*
|
||||
* Called when a device is added to the collection enumerated by the DeviceWatcher
|
||||
*/
|
||||
void (*added) (GstWinRTDeviceWatcher * watcher,
|
||||
__x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformation * info,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GstWinRTDeviceWatcherCallbacks::updated:
|
||||
* @watcher: a #GstWinRTDeviceWatcher
|
||||
* @info_update: (transfer none): a IDeviceInformationUpdate interface handle
|
||||
* @user_data: a user_data
|
||||
*
|
||||
* Called when a device is updated in the collection of enumerated devices
|
||||
*/
|
||||
void (*updated) (GstWinRTDeviceWatcher * watcher,
|
||||
__x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformationUpdate * info_update,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GstWinRTDeviceWatcherCallbacks::removed:
|
||||
* @watcher: a #GstWinRTDeviceWatcher
|
||||
* @info_update: (transfer none): a IDeviceInformationUpdate interface handle
|
||||
* @user_data: a user_data
|
||||
*
|
||||
* Called when a device is removed from the collection of enumerated devices
|
||||
*/
|
||||
void (*removed) (GstWinRTDeviceWatcher * watcher,
|
||||
__x_ABI_CWindows_CDevices_CEnumeration_CIDeviceInformationUpdate * info_update,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GstWinRTDeviceWatcherCallbacks::removed:
|
||||
* @watcher: a #GstWinRTDeviceWatcher
|
||||
* @user_data: a user_data
|
||||
*
|
||||
* Called when the enumeration of devices completes
|
||||
*/
|
||||
void (*enumeration_completed) (GstWinRTDeviceWatcher * watcher,
|
||||
gpointer user_data);
|
||||
} GstWinRTDeviceWatcherCallbacks;
|
||||
|
||||
struct _GstWinRTDeviceWatcher
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstWinRTDeviceWatcherPrivate *priv;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstWinRTDeviceWatcherClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING_LARGE];
|
||||
};
|
||||
|
||||
GST_WINRT_API
|
||||
GType gst_winrt_device_class_get_type (void);
|
||||
|
||||
GST_WINRT_API
|
||||
GType gst_winrt_device_watcher_get_type (void);
|
||||
|
||||
GST_WINRT_API
|
||||
GstWinRTDeviceWatcher * gst_winrt_device_watcher_new (GstWinRTDeviceClass device_class,
|
||||
const GstWinRTDeviceWatcherCallbacks * callbacks,
|
||||
gpointer user_data);
|
||||
|
||||
GST_WINRT_API
|
||||
gboolean gst_winrt_device_watcher_start (GstWinRTDeviceWatcher * watcher);
|
||||
|
||||
GST_WINRT_API
|
||||
void gst_winrt_device_watcher_stop (GstWinRTDeviceWatcher * watcher);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_WINRT_DEVICE_WATCHER_H__ */
|
86
subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build
Normal file
86
subprojects/gst-plugins-bad/gst-libs/gst/winrt/meson.build
Normal file
|
@ -0,0 +1,86 @@
|
|||
winrt_sources = [
|
||||
'gstwinrtdevicewatcher.cpp',
|
||||
]
|
||||
|
||||
gstwinrt_dep = dependency('', required : false)
|
||||
|
||||
extra_c_args = [
|
||||
'-DCOBJMACROS',
|
||||
]
|
||||
extra_comm_args = [
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
'-DBUILDING_GST_WINRT'
|
||||
]
|
||||
|
||||
if host_system != 'windows'
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
# TODO: Need to bump mingw tool chain
|
||||
if cxx.get_id() != 'msvc'
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
runtimeobject_lib = cc.find_library('runtimeobject', required : false)
|
||||
if not runtimeobject_lib.found()
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
winapi_app = cxx.compiles('''#include <winapifamily.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#error "not winrt"
|
||||
#endif
|
||||
int main (int argc, char ** argv) {
|
||||
return 0;
|
||||
} ''',
|
||||
dependencies: runtimeobject_lib,
|
||||
name: 'building for WinRT')
|
||||
|
||||
if not winapi_app
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
win10_sdk = cxx.compiles('''#include <windows.h>
|
||||
#ifndef WDK_NTDDI_VERSION
|
||||
#error "unknown Windows SDK version"
|
||||
#endif
|
||||
#if (WDK_NTDDI_VERSION < 0x0A000000)
|
||||
#error "Not a Windows 10 SDK"
|
||||
#endif
|
||||
''',
|
||||
name: 'building with Windows 10 SDK')
|
||||
|
||||
if not win10_sdk
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
building_for_win10 = cxx.compiles('''#include <windows.h>
|
||||
#ifndef WINVER
|
||||
#error "unknown minimum supported OS version"
|
||||
#endif
|
||||
#if (WINVER < 0x0A00)
|
||||
#error "Windows 10 API is not guaranteed"
|
||||
#endif
|
||||
''',
|
||||
name: 'building for Windows 10')
|
||||
|
||||
if not building_for_win10
|
||||
message('Bumping target Windows version to Windows 10 for building gstwinrt library')
|
||||
extra_comm_args += ['-DWINVER=0x0A00', '-D_WIN32_WINNT=0x0A00', '-DNTDDI_VERSION=WDK_NTDDI_VERSION']
|
||||
endif
|
||||
|
||||
gstwinrt = library('gstwinrt-' + api_version,
|
||||
winrt_sources,
|
||||
c_args : gst_plugins_bad_args + extra_c_args + extra_comm_args,
|
||||
cpp_args : gst_plugins_bad_args + extra_comm_args,
|
||||
include_directories : [configinc, libsinc],
|
||||
version : libversion,
|
||||
soversion : soversion,
|
||||
install : true,
|
||||
dependencies : [gstbase_dep, runtimeobject_lib]
|
||||
)
|
||||
|
||||
# Still non-public api, should not install headers
|
||||
gstwinrt_dep = declare_dependency(link_with : gstwinrt,
|
||||
include_directories : [libsinc],
|
||||
dependencies : [gstbase_dep, runtimeobject_lib])
|
|
@ -0,0 +1,33 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 GStreamer developers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_WINRT_PRELUDE_H__
|
||||
#define __GST_WINRT_PRELUDE_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#ifndef GST_WINRT_API
|
||||
# ifdef BUILDING_GST_WINRT
|
||||
# define GST_WINRT_API GST_API_EXPORT /* from config.h */
|
||||
# else
|
||||
# define GST_WINRT_API GST_API_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* __GST_WIN32_PRELUDE_H__ */
|
Loading…
Reference in a new issue