mediafoundation: Refactor GstMFSourceObject implementation

* Move CoInitializeEx/CoUninitialize pair into thread function in order to
  ensure MTA COM thread
* Move common code to baseclass

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1269>
This commit is contained in:
Seungha Yang 2020-05-14 20:47:06 +09:00 committed by GStreamer Merge Bot
parent c29c71ae9d
commit 8afc283b51
4 changed files with 276 additions and 190 deletions

View file

@ -241,11 +241,13 @@ struct _GstMFCaptureEngine
gboolean flushing; gboolean flushing;
}; };
static void gst_mf_capture_engine_constructed (GObject * object);
static void gst_mf_capture_engine_finalize (GObject * object); static void gst_mf_capture_engine_finalize (GObject * object);
static gboolean gst_mf_capture_engine_open (GstMFSourceObject * object,
IMFActivate * activate);
static gboolean gst_mf_capture_engine_start (GstMFSourceObject * object); static gboolean gst_mf_capture_engine_start (GstMFSourceObject * object);
static gboolean gst_mf_capture_engine_stop (GstMFSourceObject * object); static gboolean gst_mf_capture_engine_stop (GstMFSourceObject * object);
static gboolean gst_mf_capture_engine_close (GstMFSourceObject * object);
static GstFlowReturn gst_mf_capture_engine_fill (GstMFSourceObject * object, static GstFlowReturn gst_mf_capture_engine_fill (GstMFSourceObject * object,
GstBuffer * buffer); GstBuffer * buffer);
static gboolean gst_mf_capture_engine_unlock (GstMFSourceObject * object); static gboolean gst_mf_capture_engine_unlock (GstMFSourceObject * object);
@ -264,11 +266,12 @@ gst_mf_capture_engine_class_init (GstMFCaptureEngineClass * 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_capture_engine_constructed;
gobject_class->finalize = gst_mf_capture_engine_finalize; gobject_class->finalize = gst_mf_capture_engine_finalize;
source_class->open = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_open);
source_class->start = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_start); source_class->start = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_start);
source_class->stop = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_stop); source_class->stop = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_stop);
source_class->close = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_close);
source_class->fill = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_fill); source_class->fill = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_fill);
source_class->unlock = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_unlock); source_class->unlock = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_unlock);
source_class->unlock_stop = source_class->unlock_stop =
@ -283,8 +286,6 @@ gst_mf_capture_engine_init (GstMFCaptureEngine * 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); g_cond_init (&self->cond);
CoInitializeEx (NULL, COINIT_MULTITHREADED);
} }
static gboolean static gboolean
@ -373,9 +374,10 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
} }
static gboolean static gboolean
gst_mf_capture_engine_create (GstMFCaptureEngine * self, gst_mf_capture_engine_open (GstMFSourceObject * object,
IMFActivate * activate) IMFActivate * activate)
{ {
GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object);
GList *iter; GList *iter;
ComPtr<IMFCaptureEngineClassFactory> factory; ComPtr<IMFCaptureEngineClassFactory> factory;
ComPtr<IMFCaptureEngine> engine; ComPtr<IMFCaptureEngine> engine;
@ -469,63 +471,36 @@ gst_mf_capture_engine_create (GstMFCaptureEngine * self,
return TRUE; return TRUE;
} }
static void static gboolean
gst_mf_capture_engine_constructed (GObject * object) gst_mf_capture_engine_close (GstMFSourceObject * object)
{ {
GstMFSourceObject *source = GST_MF_SOURCE_OBJECT (object);
GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object); GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object);
GList *activate_list = NULL;
GstMFDeviceActivate *target = NULL;
GList *iter;
if (!gst_mf_source_enum_device_activate (source->soure_type, &activate_list)) { gst_clear_caps (&self->supported_caps);
GST_WARNING_OBJECT (self, "No available video capture device");
return;
}
#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\"", if (self->media_types) {
activate->index, GST_STR_NULL (activate->name), g_list_free_full (self->media_types,
GST_STR_NULL (activate->path)); (GDestroyNotify) gst_mf_stream_media_type_free);
} self->media_types = NULL;
#endif
for (iter = activate_list; iter; iter = g_list_next (iter)) {
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
gboolean match;
if (source->device_path && strlen (source->device_path) > 0) {
match = g_ascii_strcasecmp (activate->path, source->device_path) == 0;
} else if (source->device_name && strlen (source->device_name) > 0) {
match = g_ascii_strcasecmp (activate->name, source->device_name) == 0;
} else if (source->device_index >= 0) {
match = activate->index == source->device_index;
} else {
/* pick the first entry */
match = TRUE;
} }
if (match) { if (self->callback_obj) {
target = activate; self->callback_obj->Release ();
break; self->callback_obj = NULL;
}
} }
if (target) if (self->engine) {
gst_mf_capture_engine_create (self, target->handle); self->engine->Release ();
self->engine = NULL;
}
if (activate_list) if (self->source) {
g_list_free_full (activate_list, self->source->Shutdown ();
(GDestroyNotify) gst_mf_device_activate_free); self->source->Release ();
} self->source = NULL;
}
static void return TRUE;
release_mf_buffer (IMFMediaBuffer * buffer)
{
if (buffer)
buffer->Release ();
} }
static void static void
@ -533,32 +508,10 @@ gst_mf_capture_engine_finalize (GObject * object)
{ {
GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object); GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object);
gst_clear_caps (&self->supported_caps); g_queue_free (self->queue);
if (self->media_types)
g_list_free_full (self->media_types,
(GDestroyNotify) gst_mf_stream_media_type_free);
gst_mf_capture_engine_stop (GST_MF_SOURCE_OBJECT (self));
g_queue_free_full (self->queue, (GDestroyNotify) release_mf_buffer);
if (self->callback_obj) {
self->callback_obj->Release ();
}
if (self->engine)
self->engine->Release ();
if (self->source) {
self->source->Shutdown ();
self->source->Release ();
}
g_mutex_clear (&self->lock); g_mutex_clear (&self->lock);
g_cond_clear (&self->cond); g_cond_clear (&self->cond);
CoUninitialize ();
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -712,6 +665,11 @@ gst_mf_capture_engine_stop (GstMFSourceObject * object)
} }
} }
while (!g_queue_is_empty (self->queue)) {
IMFMediaBuffer *buffer = (IMFMediaBuffer *) g_queue_pop_head (self->queue);
buffer->Release ();
}
return TRUE; return TRUE;
} }
@ -866,7 +824,7 @@ GstMFSourceObject *
gst_mf_capture_engine_new (GstMFSourceType type, gint device_index, gst_mf_capture_engine_new (GstMFSourceType type, gint device_index,
const gchar * device_name, const gchar * device_path) const gchar * device_name, const gchar * device_path)
{ {
GstMFCaptureEngine *self; GstMFSourceObject *self;
gchar *name; gchar *name;
gchar *path; gchar *path;
@ -876,7 +834,7 @@ gst_mf_capture_engine_new (GstMFSourceType type, gint device_index,
name = device_name ? g_strdup (device_name) : g_strdup (""); name = device_name ? g_strdup (device_name) : g_strdup ("");
path = device_path ? g_strdup (device_path) : g_strdup (""); path = device_path ? g_strdup (device_path) : g_strdup ("");
self = (GstMFCaptureEngine *) g_object_new (GST_TYPE_MF_CAPTURE_ENGINE, self = (GstMFSourceObject *) g_object_new (GST_TYPE_MF_CAPTURE_ENGINE,
"source-type", type, "device-index", device_index, "device-name", name, "source-type", type, "device-index", device_index, "device-name", name,
"device-path", path, NULL); "device-path", path, NULL);
@ -884,10 +842,11 @@ gst_mf_capture_engine_new (GstMFSourceType type, gint device_index,
g_free (name); g_free (name);
g_free (path); g_free (path);
if (!self->source) { if (!self->opend) {
gst_clear_object (&self); GST_WARNING_OBJECT (self, "Couldn't open device");
gst_object_unref (self);
return NULL; return NULL;
} }
return GST_MF_SOURCE_OBJECT (self); return self;
} }

View file

@ -58,14 +58,36 @@ gst_mf_source_type_get_type (void)
return source_type; return source_type;
} }
struct _GstMFSourceObjectPrivate
{
GstMFSourceType soure_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);
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);
#define gst_mf_source_object_parent_class parent_class #define gst_mf_source_object_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE (GstMFSourceObject, gst_mf_source_object, G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstMFSourceObject, gst_mf_source_object,
GST_TYPE_OBJECT); GST_TYPE_OBJECT);
static void static void
@ -73,6 +95,8 @@ 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;
@ -99,17 +123,65 @@ 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)
{ {
self->device_index = DEFAULT_DEVICE_INDEX; GstMFSourceObjectPrivate *priv;
self->soure_type = DEFAULT_SOURCE_TYPE;
self->priv = priv = gst_mf_source_object_get_instance_private (self);
priv->device_index = DEFAULT_DEVICE_INDEX;
priv->soure_type = DEFAULT_SOURCE_TYPE;
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_mf_source_object_constructed (GObject * object)
{
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
GstMFSourceObjectPrivate *priv = self->priv;
/* Create thread so that ensure 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);
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_free (self->device_path); g_mutex_clear (&priv->lock);
g_free (self->device_name); g_cond_clear (&priv->cond);
g_free (priv->device_path);
g_free (priv->device_name);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -119,19 +191,20 @@ 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:
g_value_set_string (value, self->device_path); g_value_set_string (value, priv->device_path);
break; break;
case PROP_DEVICE_NAME: case PROP_DEVICE_NAME:
g_value_set_string (value, self->device_name); g_value_set_string (value, priv->device_name);
break; break;
case PROP_DEVICE_INDEX: case PROP_DEVICE_INDEX:
g_value_set_int (value, self->device_index); g_value_set_int (value, priv->device_index);
break; break;
case PROP_SOURCE_TYPE: case PROP_SOURCE_TYPE:
g_value_set_enum (value, self->soure_type); g_value_set_enum (value, priv->soure_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);
@ -144,21 +217,22 @@ 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:
g_free (self->device_path); g_free (priv->device_path);
self->device_path = g_value_dup_string (value); priv->device_path = g_value_dup_string (value);
break; break;
case PROP_DEVICE_NAME: case PROP_DEVICE_NAME:
g_free (self->device_name); g_free (priv->device_name);
self->device_name = g_value_dup_string (value); priv->device_name = g_value_dup_string (value);
break; break;
case PROP_DEVICE_INDEX: case PROP_DEVICE_INDEX:
self->device_index = g_value_get_int (value); priv->device_index = g_value_get_int (value);
break; break;
case PROP_SOURCE_TYPE: case PROP_SOURCE_TYPE:
self->soure_type = g_value_get_enum (value); priv->soure_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);
@ -166,6 +240,101 @@ 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;
}
static gpointer
gst_mf_source_object_thread_func (GstMFSourceObject * self)
{
GstMFSourceObjectPrivate *priv = self->priv;
GstMFSourceObjectClass *klass = GST_MF_SOURCE_OBJECT_GET_CLASS (self);
GSource *source;
GList *activate_list = NULL;
GstMFDeviceActivate *target = NULL;
GList *iter;
g_assert (klass->open != NULL);
g_assert (klass->close != NULL);
CoInitializeEx (NULL, COINIT_MULTITHREADED);
g_main_context_push_thread_default (priv->context);
source = g_idle_source_new ();
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->soure_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
for (iter = activate_list; iter; iter = g_list_next (iter)) {
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
gboolean match;
if (priv->device_path && strlen (priv->device_path) > 0) {
match = g_ascii_strcasecmp (activate->path, priv->device_path) == 0;
} else if (priv->device_name && strlen (priv->device_name) > 0) {
match = g_ascii_strcasecmp (activate->name, priv->device_name) == 0;
} else if (priv->device_index >= 0) {
match = activate->index == priv->device_index;
} else {
/* pick the first entry */
match = TRUE;
}
if (match) {
target = activate;
break;
}
}
if (target)
self->opend = klass->open (self, target->handle);
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;
}
gboolean gboolean
gst_mf_source_object_start (GstMFSourceObject * object) gst_mf_source_object_start (GstMFSourceObject * object)
{ {
@ -251,9 +420,9 @@ gst_mf_source_object_get_caps (GstMFSourceObject * object)
return klass->get_caps (object); return klass->get_caps (object);
} }
gboolean static gboolean
gst_mf_source_enum_device_activate (GstMFSourceType source_type, gst_mf_source_enum_device_activate (GstMFSourceObject * self,
GList ** device_sources) GstMFSourceType source_type, GList ** device_sources)
{ {
HRESULT hr; HRESULT hr;
GList *ret = NULL; GList *ret = NULL;
@ -272,7 +441,7 @@ gst_mf_source_enum_device_activate (GstMFSourceType source_type,
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
break; break;
default: default:
GST_ERROR ("Unknown source type %d", source_type); GST_ERROR_OBJECT (self, "Unknown source type %d", source_type);
return FALSE; return FALSE;
} }
@ -332,7 +501,7 @@ done:
return ! !ret; return ! !ret;
} }
void static void
gst_mf_device_activate_free (GstMFDeviceActivate * activate) gst_mf_device_activate_free (GstMFDeviceActivate * activate)
{ {
g_return_if_fail (activate != NULL); g_return_if_fail (activate != NULL);

View file

@ -35,6 +35,7 @@ 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
{ {
@ -56,21 +57,24 @@ struct _GstMFSourceObject
{ {
GstObject parent; GstObject parent;
GstMFSourceType soure_type; gboolean opend;
gchar *device_path; GstMFSourceObjectPrivate *priv;
gchar *device_name;
gint device_index;
}; };
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);
@ -101,12 +105,6 @@ 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);
/* Utils */
gboolean gst_mf_source_enum_device_activate (GstMFSourceType source_type,
GList ** device_activates);
void gst_mf_device_activate_free (GstMFDeviceActivate * activate);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMFSourceObject, gst_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstMFSourceObject, gst_object_unref)
G_END_DECLS G_END_DECLS

View file

@ -67,11 +67,13 @@ 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 gboolean gst_mf_source_reader_unlock (GstMFSourceObject * object); static gboolean gst_mf_source_reader_unlock (GstMFSourceObject * object);
@ -90,11 +92,12 @@ 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->unlock = GST_DEBUG_FUNCPTR (gst_mf_source_reader_unlock); source_class->unlock = GST_DEBUG_FUNCPTR (gst_mf_source_reader_unlock);
source_class->unlock_stop = source_class->unlock_stop =
@ -108,8 +111,6 @@ 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);
CoInitializeEx (NULL, COINIT_MULTITHREADED);
} }
static gboolean static gboolean
@ -185,8 +186,9 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
} }
static gboolean static gboolean
gst_mf_source_reader_create (GstMFSourceReader * self, IMFActivate * activate) gst_mf_source_reader_open (GstMFSourceObject * object, IMFActivate * activate)
{ {
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
GList *iter; GList *iter;
HRESULT hr; HRESULT hr;
ComPtr<IMFSourceReader> reader; ComPtr<IMFSourceReader> reader;
@ -235,63 +237,31 @@ gst_mf_source_reader_create (GstMFSourceReader * self, IMFActivate * activate)
return TRUE; return TRUE;
} }
static void static gboolean
gst_mf_source_reader_constructed (GObject * object) gst_mf_source_reader_close (GstMFSourceObject * object)
{ {
GstMFSourceObject *source = GST_MF_SOURCE_OBJECT (object);
GstMFSourceReader *self = GST_MF_SOURCE_READER (object); GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
GList *activate_list = NULL;
GstMFDeviceActivate *target = NULL;
GList *iter;
if (!gst_mf_source_enum_device_activate (source->soure_type, &activate_list)) { gst_clear_caps (&self->supported_caps);
GST_WARNING_OBJECT (self, "No available video capture device");
return;
}
#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\"", if (self->media_types) {
activate->index, GST_STR_NULL (activate->name), g_list_free_full (self->media_types,
GST_STR_NULL (activate->path)); (GDestroyNotify) gst_mf_stream_media_type_free);
} self->media_types = NULL;
#endif
for (iter = activate_list; iter; iter = g_list_next (iter)) {
GstMFDeviceActivate *activate = (GstMFDeviceActivate *) iter->data;
gboolean match;
if (source->device_path && strlen (source->device_path) > 0) {
match = g_ascii_strcasecmp (activate->path, source->device_path) == 0;
} else if (source->device_name && strlen (source->device_name) > 0) {
match = g_ascii_strcasecmp (activate->name, source->device_name) == 0;
} else if (source->device_index >= 0) {
match = activate->index == source->device_index;
} else {
/* pick the first entry */
match = TRUE;
} }
if (match) { if (self->reader) {
target = activate; self->reader->Release ();
break; self->reader = NULL;
}
} }
if (target) if (self->source) {
gst_mf_source_reader_create (self, target->handle); self->source->Shutdown ();
self->source->Release ();
self->source = NULL;
}
if (activate_list) return TRUE;
g_list_free_full (activate_list,
(GDestroyNotify) gst_mf_device_activate_free);
}
static void
release_mf_buffer (IMFMediaBuffer * buffer)
{
if (buffer)
buffer->Release ();
} }
static void static void
@ -299,27 +269,9 @@ gst_mf_source_reader_finalize (GObject * object)
{ {
GstMFSourceReader *self = GST_MF_SOURCE_READER (object); GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
gst_clear_caps (&self->supported_caps); g_queue_free (self->queue);
if (self->media_types)
g_list_free_full (self->media_types,
(GDestroyNotify) gst_mf_stream_media_type_free);
gst_mf_source_reader_stop (GST_MF_SOURCE_OBJECT (self));
g_queue_free_full (self->queue, (GDestroyNotify) release_mf_buffer);
if (self->reader)
self->reader->Release ();
if (self->source) {
self->source->Shutdown ();
self->source->Release ();
}
g_mutex_clear (&self->lock); g_mutex_clear (&self->lock);
CoUninitialize ();
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -357,6 +309,13 @@ gst_mf_source_reader_start (GstMFSourceObject * object)
static gboolean static gboolean
gst_mf_source_reader_stop (GstMFSourceObject * object) gst_mf_source_reader_stop (GstMFSourceObject * object)
{ {
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
while (!g_queue_is_empty (self->queue)) {
IMFMediaBuffer *buffer = (IMFMediaBuffer *) g_queue_pop_head (self->queue);
buffer->Release ();
}
return TRUE; return TRUE;
} }
@ -530,7 +489,7 @@ 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)
{ {
GstMFSourceReader *self; GstMFSourceObject *self;
gchar *name; gchar *name;
gchar *path; gchar *path;
@ -540,7 +499,7 @@ gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
name = device_name ? g_strdup (device_name) : g_strdup (""); name = device_name ? g_strdup (device_name) : g_strdup ("");
path = device_path ? g_strdup (device_path) : g_strdup (""); path = device_path ? g_strdup (device_path) : g_strdup ("");
self = (GstMFSourceReader *) g_object_new (GST_TYPE_MF_SOURCE_READER, self = (GstMFSourceObject *) g_object_new (GST_TYPE_MF_SOURCE_READER,
"source-type", type, "device-index", device_index, "device-name", name, "source-type", type, "device-index", device_index, "device-name", name,
"device-path", path, NULL); "device-path", path, NULL);
@ -548,10 +507,11 @@ gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
g_free (name); g_free (name);
g_free (path); g_free (path);
if (!self->source) { if (!self->opend) {
gst_clear_object (&self); GST_WARNING_OBJECT (self, "Couldn't open device");
gst_object_unref (self);
return NULL; return NULL;
} }
return GST_MF_SOURCE_OBJECT (self); return self;
} }