mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
mfvideosrc: Enable WinRT capture impl. for desktop target
... if target OS version was specified as Windows 10. When enabled, desktop application can select target capture implementation between WinRT and Win32 via GST_USE_MF_WINRT_CAPTURE environment (e,g., GST_USE_MF_WINRT_CAPTURE=1 for WinRT impl.). Default is Win32 implementation in case of desktop target. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1434>
This commit is contained in:
parent
2d71ad49f8
commit
a43d6f6cd9
9 changed files with 337 additions and 334 deletions
|
@ -128,7 +128,6 @@ gst_mf_capture_winrt_constructed (GObject * object)
|
||||||
g_cond_wait (&self->cond, &self->lock);
|
g_cond_wait (&self->cond, &self->lock);
|
||||||
g_mutex_unlock (&self->lock);
|
g_mutex_unlock (&self->lock);
|
||||||
|
|
||||||
done:
|
|
||||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,7 @@
|
||||||
|
|
||||||
#include "gstmfvideosrc.h"
|
#include "gstmfvideosrc.h"
|
||||||
#include "gstmfutils.h"
|
#include "gstmfutils.h"
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
#include "gstmfsourceobject.h"
|
||||||
#include "gstmfcapturewinrt.h"
|
|
||||||
#else /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
#include "gstmfsourcereader.h"
|
|
||||||
#endif /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
|
|
||||||
#include "gstmfdevice.h"
|
#include "gstmfdevice.h"
|
||||||
|
|
||||||
|
@ -180,12 +176,7 @@ gst_mf_device_provider_probe (GstDeviceProvider * provider)
|
||||||
gchar *device_name = NULL;
|
gchar *device_name = NULL;
|
||||||
gchar *device_path = NULL;
|
gchar *device_path = NULL;
|
||||||
|
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
obj = gst_mf_source_object_new (GST_MF_SOURCE_TYPE_VIDEO, i, NULL, NULL);
|
||||||
obj = gst_mf_capture_winrt_new (GST_MF_SOURCE_TYPE_VIDEO, i, NULL, NULL);
|
|
||||||
#else /* !GST_MF_WINAPI_ONLY_APP */
|
|
||||||
obj = gst_mf_source_reader_new (GST_MF_SOURCE_TYPE_VIDEO, i, NULL, NULL);
|
|
||||||
#endif /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,13 @@
|
||||||
|
|
||||||
#include "gstmfsourceobject.h"
|
#include "gstmfsourceobject.h"
|
||||||
|
|
||||||
|
#if GST_MF_WINAPI_APP
|
||||||
|
#include "gstmfcapturewinrt.h"
|
||||||
|
#endif
|
||||||
|
#if GST_MF_WINAPI_DESKTOP
|
||||||
|
#include "gstmfsourcereader.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (gst_mf_source_object_debug);
|
GST_DEBUG_CATEGORY_EXTERN (gst_mf_source_object_debug);
|
||||||
#define GST_CAT_DEFAULT gst_mf_source_object_debug
|
#define GST_CAT_DEFAULT gst_mf_source_object_debug
|
||||||
|
|
||||||
|
@ -60,38 +67,14 @@ gst_mf_source_type_get_type (void)
|
||||||
return source_type;
|
return source_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _GstMFSourceObjectPrivate
|
|
||||||
{
|
|
||||||
GstMFSourceType source_type;
|
|
||||||
|
|
||||||
gchar *device_path;
|
|
||||||
gchar *device_name;
|
|
||||||
gint device_index;
|
|
||||||
|
|
||||||
GThread *thread;
|
|
||||||
GMutex lock;
|
|
||||||
GCond cond;
|
|
||||||
GMainContext *context;
|
|
||||||
GMainLoop *loop;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void gst_mf_source_object_constructed (GObject * object);
|
|
||||||
static void gst_mf_source_object_dispose (GObject * object);
|
|
||||||
static void gst_mf_source_object_finalize (GObject * object);
|
static void gst_mf_source_object_finalize (GObject * object);
|
||||||
static void gst_mf_source_object_get_property (GObject * object, guint prop_id,
|
static void gst_mf_source_object_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static void gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
static void gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
#if !(GST_MF_WINAPI_ONLY_APP)
|
|
||||||
static gpointer gst_mf_source_object_thread_func (GstMFSourceObject * self);
|
|
||||||
static gboolean gst_mf_source_enum_device_activate (GstMFSourceObject * self,
|
|
||||||
GstMFSourceType source_type, GList ** device_activates);
|
|
||||||
static void gst_mf_device_activate_free (GstMFDeviceActivate * activate);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define gst_mf_source_object_parent_class parent_class
|
#define gst_mf_source_object_parent_class parent_class
|
||||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstMFSourceObject, gst_mf_source_object,
|
G_DEFINE_ABSTRACT_TYPE (GstMFSourceObject, gst_mf_source_object,
|
||||||
GST_TYPE_OBJECT);
|
GST_TYPE_OBJECT);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -99,8 +82,6 @@ gst_mf_source_object_class_init (GstMFSourceObjectClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
gobject_class->constructed = gst_mf_source_object_constructed;
|
|
||||||
gobject_class->dispose = gst_mf_source_object_dispose;
|
|
||||||
gobject_class->finalize = gst_mf_source_object_finalize;
|
gobject_class->finalize = gst_mf_source_object_finalize;
|
||||||
gobject_class->get_property = gst_mf_source_object_get_property;
|
gobject_class->get_property = gst_mf_source_object_get_property;
|
||||||
gobject_class->set_property = gst_mf_source_object_set_property;
|
gobject_class->set_property = gst_mf_source_object_set_property;
|
||||||
|
@ -127,64 +108,14 @@ gst_mf_source_object_class_init (GstMFSourceObjectClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_mf_source_object_init (GstMFSourceObject * self)
|
gst_mf_source_object_init (GstMFSourceObject * self)
|
||||||
{
|
{
|
||||||
GstMFSourceObjectPrivate *priv;
|
|
||||||
|
|
||||||
self->priv = priv = gst_mf_source_object_get_instance_private (self);
|
|
||||||
|
|
||||||
self->device_index = DEFAULT_DEVICE_INDEX;
|
self->device_index = DEFAULT_DEVICE_INDEX;
|
||||||
priv->source_type = DEFAULT_SOURCE_TYPE;
|
self->source_type = DEFAULT_SOURCE_TYPE;
|
||||||
|
|
||||||
g_mutex_init (&priv->lock);
|
|
||||||
g_cond_init (&priv->cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_mf_source_object_constructed (GObject * object)
|
|
||||||
{
|
|
||||||
#if !(GST_MF_WINAPI_ONLY_APP)
|
|
||||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
priv->context = g_main_context_new ();
|
|
||||||
priv->loop = g_main_loop_new (priv->context, FALSE);
|
|
||||||
|
|
||||||
/* Create a new thread to ensure that COM thread can be MTA thread */
|
|
||||||
g_mutex_lock (&priv->lock);
|
|
||||||
priv->thread = g_thread_new ("GstMFSourceObject",
|
|
||||||
(GThreadFunc) gst_mf_source_object_thread_func, self);
|
|
||||||
while (!g_main_loop_is_running (priv->loop))
|
|
||||||
g_cond_wait (&priv->cond, &priv->lock);
|
|
||||||
g_mutex_unlock (&priv->lock);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_mf_source_object_dispose (GObject * object)
|
|
||||||
{
|
|
||||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
if (priv->loop) {
|
|
||||||
g_main_loop_quit (priv->loop);
|
|
||||||
g_thread_join (priv->thread);
|
|
||||||
g_main_loop_unref (priv->loop);
|
|
||||||
g_main_context_unref (priv->context);
|
|
||||||
priv->loop = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mf_source_object_finalize (GObject * object)
|
gst_mf_source_object_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
g_mutex_clear (&priv->lock);
|
|
||||||
g_cond_clear (&priv->cond);
|
|
||||||
|
|
||||||
g_free (self->device_path);
|
g_free (self->device_path);
|
||||||
g_free (self->device_name);
|
g_free (self->device_name);
|
||||||
|
@ -197,7 +128,6 @@ gst_mf_source_object_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec)
|
GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_DEVICE_PATH:
|
case PROP_DEVICE_PATH:
|
||||||
|
@ -210,7 +140,7 @@ gst_mf_source_object_get_property (GObject * object, guint prop_id,
|
||||||
g_value_set_int (value, self->device_index);
|
g_value_set_int (value, self->device_index);
|
||||||
break;
|
break;
|
||||||
case PROP_SOURCE_TYPE:
|
case PROP_SOURCE_TYPE:
|
||||||
g_value_set_enum (value, priv->source_type);
|
g_value_set_enum (value, self->source_type);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -223,7 +153,6 @@ gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_DEVICE_PATH:
|
case PROP_DEVICE_PATH:
|
||||||
|
@ -238,7 +167,7 @@ gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
||||||
self->device_index = g_value_get_int (value);
|
self->device_index = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case PROP_SOURCE_TYPE:
|
case PROP_SOURCE_TYPE:
|
||||||
priv->source_type = g_value_get_enum (value);
|
self->source_type = g_value_get_enum (value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -246,20 +175,6 @@ gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_mf_source_object_main_loop_running_cb (GstMFSourceObject * self)
|
|
||||||
{
|
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
|
||||||
|
|
||||||
GST_TRACE_OBJECT (self, "Main loop running now");
|
|
||||||
|
|
||||||
g_mutex_lock (&priv->lock);
|
|
||||||
g_cond_signal (&priv->cond);
|
|
||||||
g_mutex_unlock (&priv->lock);
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_mf_source_object_start (GstMFSourceObject * object)
|
gst_mf_source_object_start (GstMFSourceObject * object)
|
||||||
{
|
{
|
||||||
|
@ -359,193 +274,67 @@ gst_mf_source_object_get_caps (GstMFSourceObject * object)
|
||||||
return klass->get_caps (object);
|
return klass->get_caps (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(GST_MF_WINAPI_ONLY_APP)
|
static gboolean
|
||||||
static gpointer
|
gst_mf_source_object_use_winrt_api (void)
|
||||||
gst_mf_source_object_thread_func (GstMFSourceObject * self)
|
|
||||||
{
|
{
|
||||||
GstMFSourceObjectPrivate *priv = self->priv;
|
static gsize check_once = 0;
|
||||||
GstMFSourceObjectClass *klass = GST_MF_SOURCE_OBJECT_GET_CLASS (self);
|
static gboolean ret = FALSE;
|
||||||
GSource *source;
|
|
||||||
GList *activate_list = NULL;
|
|
||||||
GstMFDeviceActivate *target = NULL;
|
|
||||||
GList *iter;
|
|
||||||
|
|
||||||
g_assert (klass->open != NULL);
|
if (g_once_init_enter (&check_once)) {
|
||||||
g_assert (klass->close != NULL);
|
#if (!GST_MF_WINAPI_APP)
|
||||||
|
/* WinRT is not supported, always false */
|
||||||
|
ret = FALSE;
|
||||||
|
#else
|
||||||
|
#if (!GST_MF_WINAPI_DESKTOP)
|
||||||
|
/* WinRT is supported but desktop API was disabled,
|
||||||
|
* always true */
|
||||||
|
ret = TRUE;
|
||||||
|
#else
|
||||||
|
/* Both app and desktop APIs were enabled, check user choice */
|
||||||
|
{
|
||||||
|
const gchar *env;
|
||||||
|
|
||||||
CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
env = g_getenv ("GST_USE_MF_WINRT_CAPTURE");
|
||||||
|
if (env && g_str_has_prefix (env, "1"))
|
||||||
g_main_context_push_thread_default (priv->context);
|
ret = TRUE;
|
||||||
|
else
|
||||||
source = g_idle_source_new ();
|
ret = FALSE;
|
||||||
g_source_set_callback (source,
|
|
||||||
(GSourceFunc) gst_mf_source_object_main_loop_running_cb, self, NULL);
|
|
||||||
g_source_attach (source, priv->context);
|
|
||||||
g_source_unref (source);
|
|
||||||
|
|
||||||
if (!gst_mf_source_enum_device_activate (self,
|
|
||||||
priv->source_type, &activate_list)) {
|
|
||||||
GST_WARNING_OBJECT (self, "No available video capture device");
|
|
||||||
goto run_loop;
|
|
||||||
}
|
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
|
||||||
for (iter = activate_list; iter; iter = g_list_next (iter)) {
|
|
||||||
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "device %d, name: \"%s\", path: \"%s\"",
|
|
||||||
activate->index, GST_STR_NULL (activate->name),
|
|
||||||
GST_STR_NULL (activate->path));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
g_once_init_leave (&check_once, 1);
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self,
|
return ret;
|
||||||
"Requested device index: %d, name: \"%s\", path \"%s\"",
|
}
|
||||||
self->device_index, GST_STR_NULL (self->device_name),
|
|
||||||
GST_STR_NULL (self->device_path));
|
|
||||||
|
|
||||||
for (iter = activate_list; iter; iter = g_list_next (iter)) {
|
GstMFSourceObject *
|
||||||
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
|
gst_mf_source_object_new (GstMFSourceType type, gint device_index,
|
||||||
gboolean match;
|
const gchar * device_name, const gchar * device_path)
|
||||||
|
{
|
||||||
if (self->device_path) {
|
#if (!GST_MF_WINAPI_APP)
|
||||||
match = g_ascii_strcasecmp (activate->path, self->device_path) == 0;
|
GST_INFO ("Try IMFSourceReader implementation");
|
||||||
} else if (self->device_name) {
|
return gst_mf_source_reader_new (type,
|
||||||
match = g_ascii_strcasecmp (activate->name, self->device_name) == 0;
|
device_index, device_name, device_path);
|
||||||
} else if (self->device_index >= 0) {
|
#else
|
||||||
match = activate->index == self->device_index;
|
#if (!GST_MF_WINAPI_DESKTOP)
|
||||||
|
GST_INFO ("Try WinRT implementation");
|
||||||
|
return gst_mf_capture_winrt_new (type,
|
||||||
|
device_index, device_name, device_path);
|
||||||
|
#else
|
||||||
|
if (gst_mf_source_object_use_winrt_api ()) {
|
||||||
|
GST_INFO ("Both Desktop and WinRT APIs were enabled, user choice: WinRT");
|
||||||
|
return gst_mf_capture_winrt_new (type,
|
||||||
|
device_index, device_name, device_path);
|
||||||
} else {
|
} else {
|
||||||
/* pick the first entry */
|
GST_INFO
|
||||||
match = TRUE;
|
("Both Desktop and WinRT APIs were enabled, default: IMFSourceReader");
|
||||||
|
return gst_mf_source_reader_new (type,
|
||||||
|
device_index, device_name, device_path);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (match) {
|
#endif
|
||||||
target = activate;
|
g_assert_not_reached ();
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target) {
|
|
||||||
self->opened = klass->open (self, target->handle);
|
|
||||||
|
|
||||||
g_free (self->device_path);
|
|
||||||
self->device_path = g_strdup (target->path);
|
|
||||||
|
|
||||||
g_free (self->device_name);
|
|
||||||
self->device_name = g_strdup (target->name);
|
|
||||||
|
|
||||||
self->device_index = target->index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activate_list)
|
|
||||||
g_list_free_full (activate_list,
|
|
||||||
(GDestroyNotify) gst_mf_device_activate_free);
|
|
||||||
|
|
||||||
run_loop:
|
|
||||||
GST_TRACE_OBJECT (self, "Starting main loop");
|
|
||||||
g_main_loop_run (priv->loop);
|
|
||||||
GST_TRACE_OBJECT (self, "Stopped main loop");
|
|
||||||
|
|
||||||
klass->stop (self);
|
|
||||||
klass->close (self);
|
|
||||||
|
|
||||||
g_main_context_pop_thread_default (priv->context);
|
|
||||||
|
|
||||||
CoUninitialize ();
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_mf_source_enum_device_activate (GstMFSourceObject * self,
|
|
||||||
GstMFSourceType source_type, GList ** device_sources)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
GList *ret = NULL;
|
|
||||||
IMFAttributes *attr = NULL;
|
|
||||||
IMFActivate **devices = NULL;
|
|
||||||
UINT32 i, count = 0;
|
|
||||||
|
|
||||||
hr = MFCreateAttributes (&attr, 1);
|
|
||||||
if (!gst_mf_result (hr)) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (source_type) {
|
|
||||||
case GST_MF_SOURCE_TYPE_VIDEO:
|
|
||||||
hr = IMFAttributes_SetGUID (attr, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
|
||||||
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GST_ERROR_OBJECT (self, "Unknown source type %d", source_type);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gst_mf_result (hr))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
hr = MFEnumDeviceSources (attr, &devices, &count);
|
|
||||||
if (!gst_mf_result (hr)) {
|
|
||||||
IMFAttributes_Release (attr);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
GstMFDeviceActivate *entry;
|
|
||||||
LPWSTR name;
|
|
||||||
UINT32 name_len;
|
|
||||||
IMFActivate *activate = devices[i];
|
|
||||||
|
|
||||||
switch (source_type) {
|
|
||||||
case GST_MF_SOURCE_TYPE_VIDEO:
|
|
||||||
hr = IMFActivate_GetAllocatedString (activate,
|
|
||||||
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
|
||||||
&name, &name_len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = g_new0 (GstMFDeviceActivate, 1);
|
|
||||||
entry->index = i;
|
|
||||||
entry->handle = activate;
|
|
||||||
|
|
||||||
if (gst_mf_result (hr)) {
|
|
||||||
entry->path = g_utf16_to_utf8 ((const gunichar2 *) name,
|
|
||||||
-1, NULL, NULL, NULL);
|
|
||||||
CoTaskMemFree (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IMFActivate_GetAllocatedString (activate,
|
|
||||||
&MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_len);
|
|
||||||
if (gst_mf_result (hr)) {
|
|
||||||
entry->name = g_utf16_to_utf8 ((const gunichar2 *) name,
|
|
||||||
-1, NULL, NULL, NULL);
|
|
||||||
CoTaskMemFree (name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = g_list_prepend (ret, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
ret = g_list_reverse (ret);
|
|
||||||
CoTaskMemFree (devices);
|
|
||||||
|
|
||||||
*device_sources = ret;
|
|
||||||
|
|
||||||
return ! !ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_mf_device_activate_free (GstMFDeviceActivate * activate)
|
|
||||||
{
|
|
||||||
g_return_if_fail (activate != NULL);
|
|
||||||
|
|
||||||
if (activate->handle)
|
|
||||||
IMFActivate_Release (activate->handle);
|
|
||||||
|
|
||||||
g_free (activate->name);
|
|
||||||
g_free (activate->path);
|
|
||||||
g_free (activate);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct _GstMFSourceObject GstMFSourceObject;
|
typedef struct _GstMFSourceObject GstMFSourceObject;
|
||||||
typedef struct _GstMFSourceObjectClass GstMFSourceObjectClass;
|
typedef struct _GstMFSourceObjectClass GstMFSourceObjectClass;
|
||||||
typedef struct _GstMFSourceObjectPrivate GstMFSourceObjectPrivate;
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -45,40 +44,26 @@ typedef enum
|
||||||
#define GST_TYPE_MF_SOURCE_TYPE (gst_mf_source_type_get_type())
|
#define GST_TYPE_MF_SOURCE_TYPE (gst_mf_source_type_get_type())
|
||||||
GType gst_mf_source_type_get_type (void);
|
GType gst_mf_source_type_get_type (void);
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
IMFActivate *handle;
|
|
||||||
guint index;
|
|
||||||
gchar *name;
|
|
||||||
gchar *path;
|
|
||||||
} GstMFDeviceActivate;
|
|
||||||
|
|
||||||
struct _GstMFSourceObject
|
struct _GstMFSourceObject
|
||||||
{
|
{
|
||||||
GstObject parent;
|
GstObject parent;
|
||||||
|
|
||||||
gboolean opened;
|
gboolean opened;
|
||||||
|
|
||||||
|
GstMFSourceType source_type;
|
||||||
gchar *device_path;
|
gchar *device_path;
|
||||||
gchar *device_name;
|
gchar *device_name;
|
||||||
gint device_index;
|
gint device_index;
|
||||||
|
|
||||||
GstMFSourceObjectPrivate *priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMFSourceObjectClass
|
struct _GstMFSourceObjectClass
|
||||||
{
|
{
|
||||||
GstObjectClass parent_class;
|
GstObjectClass parent_class;
|
||||||
|
|
||||||
gboolean (*open) (GstMFSourceObject * object,
|
|
||||||
IMFActivate * activate);
|
|
||||||
|
|
||||||
gboolean (*start) (GstMFSourceObject * object);
|
gboolean (*start) (GstMFSourceObject * object);
|
||||||
|
|
||||||
gboolean (*stop) (GstMFSourceObject * object);
|
gboolean (*stop) (GstMFSourceObject * object);
|
||||||
|
|
||||||
gboolean (*close) (GstMFSourceObject * object);
|
|
||||||
|
|
||||||
GstFlowReturn (*fill) (GstMFSourceObject * object,
|
GstFlowReturn (*fill) (GstMFSourceObject * object,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
@ -117,6 +102,12 @@ GstCaps * gst_mf_source_object_get_caps (GstMFSourceObject * object);
|
||||||
gboolean gst_mf_source_object_set_caps (GstMFSourceObject * object,
|
gboolean gst_mf_source_object_set_caps (GstMFSourceObject * object,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
|
||||||
|
/* A factory method for subclass impl. selection */
|
||||||
|
GstMFSourceObject * gst_mf_source_object_new (GstMFSourceType type,
|
||||||
|
gint device_index,
|
||||||
|
const gchar * device_name,
|
||||||
|
const gchar * device_path);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMFSourceObject, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMFSourceObject, gst_object_unref)
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -49,11 +49,23 @@ typedef struct _GstMFStreamMediaType
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
} GstMFStreamMediaType;
|
} GstMFStreamMediaType;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
IMFActivate *handle;
|
||||||
|
guint index;
|
||||||
|
gchar *name;
|
||||||
|
gchar *path;
|
||||||
|
} GstMFDeviceActivate;
|
||||||
|
|
||||||
struct _GstMFSourceReader
|
struct _GstMFSourceReader
|
||||||
{
|
{
|
||||||
GstMFSourceObject parent;
|
GstMFSourceObject parent;
|
||||||
|
|
||||||
|
GThread *thread;
|
||||||
GMutex lock;
|
GMutex lock;
|
||||||
|
GCond cond;
|
||||||
|
GMainContext *context;
|
||||||
|
GMainLoop *loop;
|
||||||
|
|
||||||
/* protected by lock */
|
/* protected by lock */
|
||||||
GQueue *queue;
|
GQueue *queue;
|
||||||
|
@ -69,13 +81,11 @@ struct _GstMFSourceReader
|
||||||
gboolean flushing;
|
gboolean flushing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void gst_mf_source_reader_constructed (GObject * object);
|
||||||
static void gst_mf_source_reader_finalize (GObject * object);
|
static void gst_mf_source_reader_finalize (GObject * object);
|
||||||
|
|
||||||
static gboolean gst_mf_source_reader_open (GstMFSourceObject * object,
|
|
||||||
IMFActivate * activate);
|
|
||||||
static gboolean gst_mf_source_reader_start (GstMFSourceObject * object);
|
static gboolean gst_mf_source_reader_start (GstMFSourceObject * object);
|
||||||
static gboolean gst_mf_source_reader_stop (GstMFSourceObject * object);
|
static gboolean gst_mf_source_reader_stop (GstMFSourceObject * object);
|
||||||
static gboolean gst_mf_source_reader_close (GstMFSourceObject * object);
|
|
||||||
static GstFlowReturn gst_mf_source_reader_fill (GstMFSourceObject * object,
|
static GstFlowReturn gst_mf_source_reader_fill (GstMFSourceObject * object,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
static GstFlowReturn gst_mf_source_reader_create (GstMFSourceObject * object,
|
static GstFlowReturn gst_mf_source_reader_create (GstMFSourceObject * object,
|
||||||
|
@ -86,6 +96,14 @@ static GstCaps * gst_mf_source_reader_get_caps (GstMFSourceObject * object);
|
||||||
static gboolean gst_mf_source_reader_set_caps (GstMFSourceObject * object,
|
static gboolean gst_mf_source_reader_set_caps (GstMFSourceObject * object,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
|
||||||
|
static gboolean gst_mf_source_reader_open (GstMFSourceReader * object,
|
||||||
|
IMFActivate * activate);
|
||||||
|
static gboolean gst_mf_source_reader_close (GstMFSourceReader * object);
|
||||||
|
static gpointer gst_mf_source_reader_thread_func (GstMFSourceReader * self);
|
||||||
|
static gboolean gst_mf_source_enum_device_activate (GstMFSourceReader * self,
|
||||||
|
GstMFSourceType source_type, GList ** device_activates);
|
||||||
|
static void gst_mf_device_activate_free (GstMFDeviceActivate * activate);
|
||||||
|
|
||||||
#define gst_mf_source_reader_parent_class parent_class
|
#define gst_mf_source_reader_parent_class parent_class
|
||||||
G_DEFINE_TYPE (GstMFSourceReader, gst_mf_source_reader,
|
G_DEFINE_TYPE (GstMFSourceReader, gst_mf_source_reader,
|
||||||
GST_TYPE_MF_SOURCE_OBJECT);
|
GST_TYPE_MF_SOURCE_OBJECT);
|
||||||
|
@ -96,12 +114,11 @@ gst_mf_source_reader_class_init (GstMFSourceReaderClass * klass)
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
GstMFSourceObjectClass *source_class = GST_MF_SOURCE_OBJECT_CLASS (klass);
|
GstMFSourceObjectClass *source_class = GST_MF_SOURCE_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->constructed = gst_mf_source_reader_constructed;
|
||||||
gobject_class->finalize = gst_mf_source_reader_finalize;
|
gobject_class->finalize = gst_mf_source_reader_finalize;
|
||||||
|
|
||||||
source_class->open = GST_DEBUG_FUNCPTR (gst_mf_source_reader_open);
|
|
||||||
source_class->start = GST_DEBUG_FUNCPTR (gst_mf_source_reader_start);
|
source_class->start = GST_DEBUG_FUNCPTR (gst_mf_source_reader_start);
|
||||||
source_class->stop = GST_DEBUG_FUNCPTR (gst_mf_source_reader_stop);
|
source_class->stop = GST_DEBUG_FUNCPTR (gst_mf_source_reader_stop);
|
||||||
source_class->close = GST_DEBUG_FUNCPTR (gst_mf_source_reader_close);
|
|
||||||
source_class->fill = GST_DEBUG_FUNCPTR (gst_mf_source_reader_fill);
|
source_class->fill = GST_DEBUG_FUNCPTR (gst_mf_source_reader_fill);
|
||||||
source_class->create = GST_DEBUG_FUNCPTR (gst_mf_source_reader_create);
|
source_class->create = GST_DEBUG_FUNCPTR (gst_mf_source_reader_create);
|
||||||
source_class->unlock = GST_DEBUG_FUNCPTR (gst_mf_source_reader_unlock);
|
source_class->unlock = GST_DEBUG_FUNCPTR (gst_mf_source_reader_unlock);
|
||||||
|
@ -116,6 +133,24 @@ gst_mf_source_reader_init (GstMFSourceReader * self)
|
||||||
{
|
{
|
||||||
self->queue = g_queue_new ();
|
self->queue = g_queue_new ();
|
||||||
g_mutex_init (&self->lock);
|
g_mutex_init (&self->lock);
|
||||||
|
g_cond_init (&self->cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_mf_source_reader_constructed (GObject * object)
|
||||||
|
{
|
||||||
|
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
||||||
|
|
||||||
|
self->context = g_main_context_new ();
|
||||||
|
self->loop = g_main_loop_new (self->context, FALSE);
|
||||||
|
|
||||||
|
/* Create a new thread to ensure that COM thread can be MTA thread */
|
||||||
|
g_mutex_lock (&self->lock);
|
||||||
|
self->thread = g_thread_new ("GstMFSourceReader",
|
||||||
|
(GThreadFunc) gst_mf_source_reader_thread_func, self);
|
||||||
|
while (!g_main_loop_is_running (self->loop))
|
||||||
|
g_cond_wait (&self->cond, &self->lock);
|
||||||
|
g_mutex_unlock (&self->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -191,9 +226,8 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_mf_source_reader_open (GstMFSourceObject * object, IMFActivate * activate)
|
gst_mf_source_reader_open (GstMFSourceReader * self, IMFActivate * activate)
|
||||||
{
|
{
|
||||||
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
|
||||||
GList *iter;
|
GList *iter;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
ComPtr<IMFSourceReader> reader;
|
ComPtr<IMFSourceReader> reader;
|
||||||
|
@ -243,10 +277,8 @@ gst_mf_source_reader_open (GstMFSourceObject * object, IMFActivate * activate)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_mf_source_reader_close (GstMFSourceObject * object)
|
gst_mf_source_reader_close (GstMFSourceReader * self)
|
||||||
{
|
{
|
||||||
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
|
||||||
|
|
||||||
gst_clear_caps (&self->supported_caps);
|
gst_clear_caps (&self->supported_caps);
|
||||||
|
|
||||||
if (self->media_types) {
|
if (self->media_types) {
|
||||||
|
@ -274,8 +306,15 @@ gst_mf_source_reader_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
||||||
|
|
||||||
|
g_main_loop_quit (self->loop);
|
||||||
|
g_thread_join (self->thread);
|
||||||
|
g_main_loop_unref (self->loop);
|
||||||
|
g_main_context_unref (self->context);
|
||||||
|
|
||||||
g_queue_free (self->queue);
|
g_queue_free (self->queue);
|
||||||
|
gst_clear_caps (&self->supported_caps);
|
||||||
g_mutex_clear (&self->lock);
|
g_mutex_clear (&self->lock);
|
||||||
|
g_cond_clear (&self->cond);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -545,6 +584,201 @@ gst_mf_source_reader_set_caps (GstMFSourceObject * object, GstCaps * caps)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_mf_source_reader_main_loop_running_cb (GstMFSourceReader * self)
|
||||||
|
{
|
||||||
|
GST_INFO_OBJECT (self, "Main loop running now");
|
||||||
|
|
||||||
|
g_mutex_lock (&self->lock);
|
||||||
|
g_cond_signal (&self->cond);
|
||||||
|
g_mutex_unlock (&self->lock);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
gst_mf_source_reader_thread_func (GstMFSourceReader * self)
|
||||||
|
{
|
||||||
|
GstMFSourceObject *object = GST_MF_SOURCE_OBJECT (self);
|
||||||
|
GSource *source;
|
||||||
|
GList *activate_list = NULL;
|
||||||
|
GstMFDeviceActivate *target = NULL;
|
||||||
|
GList *iter;
|
||||||
|
|
||||||
|
CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||||||
|
|
||||||
|
g_main_context_push_thread_default (self->context);
|
||||||
|
|
||||||
|
source = g_idle_source_new ();
|
||||||
|
g_source_set_callback (source,
|
||||||
|
(GSourceFunc) gst_mf_source_reader_main_loop_running_cb, self, NULL);
|
||||||
|
g_source_attach (source, self->context);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
if (!gst_mf_source_enum_device_activate (self,
|
||||||
|
object->source_type, &activate_list)) {
|
||||||
|
GST_WARNING_OBJECT (self, "No available video capture device");
|
||||||
|
goto run_loop;
|
||||||
|
}
|
||||||
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
|
for (iter = activate_list; iter; iter = g_list_next (iter)) {
|
||||||
|
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (self, "device %d, name: \"%s\", path: \"%s\"",
|
||||||
|
activate->index, GST_STR_NULL (activate->name),
|
||||||
|
GST_STR_NULL (activate->path));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (self,
|
||||||
|
"Requested device index: %d, name: \"%s\", path \"%s\"",
|
||||||
|
object->device_index, GST_STR_NULL (object->device_name),
|
||||||
|
GST_STR_NULL (object->device_path));
|
||||||
|
|
||||||
|
for (iter = activate_list; iter; iter = g_list_next (iter)) {
|
||||||
|
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
|
||||||
|
gboolean match;
|
||||||
|
|
||||||
|
if (object->device_path) {
|
||||||
|
match = g_ascii_strcasecmp (activate->path, object->device_path) == 0;
|
||||||
|
} else if (object->device_name) {
|
||||||
|
match = g_ascii_strcasecmp (activate->name, object->device_name) == 0;
|
||||||
|
} else if (object->device_index >= 0) {
|
||||||
|
match = activate->index == object->device_index;
|
||||||
|
} else {
|
||||||
|
/* pick the first entry */
|
||||||
|
match = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
target = activate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
object->opened = gst_mf_source_reader_open (self, target->handle);
|
||||||
|
|
||||||
|
g_free (object->device_path);
|
||||||
|
object->device_path = g_strdup (target->path);
|
||||||
|
|
||||||
|
g_free (object->device_name);
|
||||||
|
object->device_name = g_strdup (target->name);
|
||||||
|
|
||||||
|
object->device_index = target->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activate_list)
|
||||||
|
g_list_free_full (activate_list,
|
||||||
|
(GDestroyNotify) gst_mf_device_activate_free);
|
||||||
|
|
||||||
|
run_loop:
|
||||||
|
GST_DEBUG_OBJECT (self, "Starting main loop");
|
||||||
|
g_main_loop_run (self->loop);
|
||||||
|
GST_DEBUG_OBJECT (self, "Stopped main loop");
|
||||||
|
|
||||||
|
gst_mf_source_reader_stop (object);
|
||||||
|
gst_mf_source_reader_close (self);
|
||||||
|
|
||||||
|
g_main_context_pop_thread_default (self->context);
|
||||||
|
|
||||||
|
CoUninitialize ();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_mf_source_enum_device_activate (GstMFSourceReader * self,
|
||||||
|
GstMFSourceType source_type, GList ** device_sources)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
GList *ret = NULL;
|
||||||
|
ComPtr<IMFAttributes> attr;
|
||||||
|
IMFActivate **devices = NULL;
|
||||||
|
UINT32 i, count = 0;
|
||||||
|
|
||||||
|
hr = MFCreateAttributes (&attr, 1);
|
||||||
|
if (!gst_mf_result (hr)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (source_type) {
|
||||||
|
case GST_MF_SOURCE_TYPE_VIDEO:
|
||||||
|
hr = attr->SetGUID (MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||||
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_ERROR_OBJECT (self, "Unknown source type %d", source_type);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_mf_result (hr))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hr = MFEnumDeviceSources (attr.Get (), &devices, &count);
|
||||||
|
if (!gst_mf_result (hr))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
GstMFDeviceActivate *entry;
|
||||||
|
LPWSTR name;
|
||||||
|
UINT32 name_len;
|
||||||
|
IMFActivate *activate = devices[i];
|
||||||
|
|
||||||
|
switch (source_type) {
|
||||||
|
case GST_MF_SOURCE_TYPE_VIDEO:
|
||||||
|
hr = activate->GetAllocatedString (
|
||||||
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
||||||
|
&name, &name_len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = g_new0 (GstMFDeviceActivate, 1);
|
||||||
|
entry->index = i;
|
||||||
|
entry->handle = activate;
|
||||||
|
|
||||||
|
if (gst_mf_result (hr)) {
|
||||||
|
entry->path = g_utf16_to_utf8 ((const gunichar2 *) name,
|
||||||
|
-1, NULL, NULL, NULL);
|
||||||
|
CoTaskMemFree (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = activate->GetAllocatedString (MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
|
||||||
|
&name, &name_len);
|
||||||
|
if (gst_mf_result (hr)) {
|
||||||
|
entry->name = g_utf16_to_utf8 ((const gunichar2 *) name,
|
||||||
|
-1, NULL, NULL, NULL);
|
||||||
|
CoTaskMemFree (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = g_list_prepend (ret, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
ret = g_list_reverse (ret);
|
||||||
|
CoTaskMemFree (devices);
|
||||||
|
|
||||||
|
*device_sources = ret;
|
||||||
|
|
||||||
|
return ! !ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_mf_device_activate_free (GstMFDeviceActivate * activate)
|
||||||
|
{
|
||||||
|
g_return_if_fail (activate != NULL);
|
||||||
|
|
||||||
|
if (activate->handle)
|
||||||
|
activate->handle->Release ();
|
||||||
|
|
||||||
|
g_free (activate->name);
|
||||||
|
g_free (activate->path);
|
||||||
|
g_free (activate);
|
||||||
|
}
|
||||||
|
|
||||||
GstMFSourceObject *
|
GstMFSourceObject *
|
||||||
gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
|
gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
|
||||||
const gchar * device_name, const gchar * device_path)
|
const gchar * device_name, const gchar * device_path)
|
||||||
|
|
|
@ -569,7 +569,7 @@ gst_mf_guid_to_static_string (const GUID& guid)
|
||||||
/* WAVE_FORMAT_MPEG_ADTS_AAC */
|
/* WAVE_FORMAT_MPEG_ADTS_AAC */
|
||||||
GST_MF_IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS);
|
GST_MF_IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS);
|
||||||
|
|
||||||
#if !GST_MF_WINAPI_ONLY_APP
|
#if GST_MF_WINAPI_DESKTOP
|
||||||
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
|
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
|
||||||
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
|
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
|
||||||
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
|
GST_MF_IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
|
||||||
|
|
|
@ -42,17 +42,13 @@
|
||||||
|
|
||||||
#include "gstmfvideosrc.h"
|
#include "gstmfvideosrc.h"
|
||||||
#include "gstmfutils.h"
|
#include "gstmfutils.h"
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
#include "gstmfsourceobject.h"
|
||||||
#include "gstmfcapturewinrt.h"
|
|
||||||
#else /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
#include "gstmfsourcereader.h"
|
|
||||||
#endif /* !GST_MF_WINAPI_ONLY_APP */
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_mf_video_src_debug);
|
GST_DEBUG_CATEGORY (gst_mf_video_src_debug);
|
||||||
#define GST_CAT_DEFAULT gst_mf_video_src_debug
|
#define GST_CAT_DEFAULT gst_mf_video_src_debug
|
||||||
|
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
#if (GST_MF_WINAPI_APP && !GST_MF_WINAPI_DESKTOP)
|
||||||
/* FIXME: need support JPEG for UWP */
|
/* FIXME: need support JPEG for UWP */
|
||||||
#define SRC_TEMPLATE_CAPS \
|
#define SRC_TEMPLATE_CAPS \
|
||||||
GST_VIDEO_CAPS_MAKE (GST_MF_VIDEO_FORMATS)
|
GST_VIDEO_CAPS_MAKE (GST_MF_VIDEO_FORMATS)
|
||||||
|
@ -242,13 +238,8 @@ gst_mf_video_src_start (GstBaseSrc * src)
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Start");
|
GST_DEBUG_OBJECT (self, "Start");
|
||||||
|
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
self->source = gst_mf_source_object_new (GST_MF_SOURCE_TYPE_VIDEO,
|
||||||
self->source = gst_mf_capture_winrt_new (GST_MF_SOURCE_TYPE_VIDEO,
|
|
||||||
self->device_index, self->device_name, self->device_path);
|
self->device_index, self->device_name, self->device_path);
|
||||||
#else /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
self->source = gst_mf_source_reader_new (GST_MF_SOURCE_TYPE_VIDEO,
|
|
||||||
self->device_index, self->device_name, self->device_path);
|
|
||||||
#endif /* GST_MF_WINAPI_ONLY_APP */
|
|
||||||
|
|
||||||
self->first_pts = GST_CLOCK_TIME_NONE;
|
self->first_pts = GST_CLOCK_TIME_NONE;
|
||||||
self->n_frames = 0;
|
self->n_frames = 0;
|
||||||
|
|
|
@ -89,7 +89,7 @@ winapi_desktop = cxx.compiles('''#include <winapifamily.h>
|
||||||
#error "not win32"
|
#error "not win32"
|
||||||
#endif''',
|
#endif''',
|
||||||
dependencies: mf_lib_deps,
|
dependencies: mf_lib_deps,
|
||||||
name: 'checking if building for Win32')
|
name: 'building for Win32')
|
||||||
|
|
||||||
if runtimeobject_lib.found()
|
if runtimeobject_lib.found()
|
||||||
winapi_app = cxx.compiles('''#include <winapifamily.h>
|
winapi_app = cxx.compiles('''#include <winapifamily.h>
|
||||||
|
@ -97,24 +97,32 @@ if runtimeobject_lib.found()
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||||
#error "not winrt"
|
#error "not winrt"
|
||||||
|
#endif
|
||||||
|
#ifndef WINVER
|
||||||
|
#error "unknown minimum supported OS version"
|
||||||
|
#endif
|
||||||
|
#if (WINVER < 0x0A00)
|
||||||
|
#error "Windows 10 API is not guaranteed"
|
||||||
#endif''',
|
#endif''',
|
||||||
dependencies: [mf_lib_deps, runtimeobject_lib],
|
dependencies: [mf_lib_deps, runtimeobject_lib],
|
||||||
name: 'checking if building for WinRT')
|
name: 'building for WinRT')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if not winapi_desktop and not winapi_app
|
if not winapi_desktop and not winapi_app
|
||||||
error('Neither Desktop partition nor App partition')
|
error('Neither Desktop partition nor App partition')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
winapi_app_only = winapi_app and not winapi_desktop
|
if winapi_app
|
||||||
if winapi_app_only
|
|
||||||
mf_sources += mf_app_sources
|
mf_sources += mf_app_sources
|
||||||
mf_lib_deps += [runtimeobject_lib]
|
mf_lib_deps += [runtimeobject_lib]
|
||||||
else
|
endif
|
||||||
|
|
||||||
|
if winapi_desktop
|
||||||
mf_sources += mf_desktop_sources
|
mf_sources += mf_desktop_sources
|
||||||
endif
|
endif
|
||||||
|
|
||||||
mf_config.set10('GST_MF_WINAPI_ONLY_APP', winapi_app_only)
|
mf_config.set10('GST_MF_WINAPI_APP', winapi_app)
|
||||||
|
mf_config.set10('GST_MF_WINAPI_DESKTOP', winapi_desktop)
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
output: 'gstmfconfig.h',
|
output: 'gstmfconfig.h',
|
||||||
|
|
|
@ -70,7 +70,7 @@ plugin_init (GstPlugin * plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mfvideosrc should be primary rank for UWP */
|
/* mfvideosrc should be primary rank for UWP */
|
||||||
#if GST_MF_WINAPI_ONLY_APP
|
#if (GST_MF_WINAPI_APP && !GST_MF_WINAPI_DESKTOP)
|
||||||
rank = GST_RANK_PRIMARY + 1;
|
rank = GST_RANK_PRIMARY + 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue