mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-03 15:06:34 +00:00
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:
parent
c29c71ae9d
commit
8afc283b51
4 changed files with 276 additions and 190 deletions
|
@ -241,11 +241,13 @@ struct _GstMFCaptureEngine
|
|||
gboolean flushing;
|
||||
};
|
||||
|
||||
static void gst_mf_capture_engine_constructed (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_stop (GstMFSourceObject * object);
|
||||
static gboolean gst_mf_capture_engine_close (GstMFSourceObject * object);
|
||||
static GstFlowReturn gst_mf_capture_engine_fill (GstMFSourceObject * object,
|
||||
GstBuffer * buffer);
|
||||
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);
|
||||
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;
|
||||
|
||||
source_class->open = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_open);
|
||||
source_class->start = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_start);
|
||||
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->unlock = GST_DEBUG_FUNCPTR (gst_mf_capture_engine_unlock);
|
||||
source_class->unlock_stop =
|
||||
|
@ -283,8 +286,6 @@ gst_mf_capture_engine_init (GstMFCaptureEngine * self)
|
|||
self->queue = g_queue_new ();
|
||||
g_mutex_init (&self->lock);
|
||||
g_cond_init (&self->cond);
|
||||
|
||||
CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -373,9 +374,10 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_mf_capture_engine_create (GstMFCaptureEngine * self,
|
||||
gst_mf_capture_engine_open (GstMFSourceObject * object,
|
||||
IMFActivate * activate)
|
||||
{
|
||||
GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object);
|
||||
GList *iter;
|
||||
ComPtr<IMFCaptureEngineClassFactory> factory;
|
||||
ComPtr<IMFCaptureEngine> engine;
|
||||
|
@ -469,63 +471,36 @@ gst_mf_capture_engine_create (GstMFCaptureEngine * self,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mf_capture_engine_constructed (GObject * object)
|
||||
static gboolean
|
||||
gst_mf_capture_engine_close (GstMFSourceObject * object)
|
||||
{
|
||||
GstMFSourceObject *source = GST_MF_SOURCE_OBJECT (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_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_clear_caps (&self->supported_caps);
|
||||
|
||||
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 (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) {
|
||||
target = activate;
|
||||
break;
|
||||
}
|
||||
if (self->media_types) {
|
||||
g_list_free_full (self->media_types,
|
||||
(GDestroyNotify) gst_mf_stream_media_type_free);
|
||||
self->media_types = NULL;
|
||||
}
|
||||
|
||||
if (target)
|
||||
gst_mf_capture_engine_create (self, target->handle);
|
||||
if (self->callback_obj) {
|
||||
self->callback_obj->Release ();
|
||||
self->callback_obj = NULL;
|
||||
}
|
||||
|
||||
if (activate_list)
|
||||
g_list_free_full (activate_list,
|
||||
(GDestroyNotify) gst_mf_device_activate_free);
|
||||
}
|
||||
if (self->engine) {
|
||||
self->engine->Release ();
|
||||
self->engine = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
release_mf_buffer (IMFMediaBuffer * buffer)
|
||||
{
|
||||
if (buffer)
|
||||
buffer->Release ();
|
||||
if (self->source) {
|
||||
self->source->Shutdown ();
|
||||
self->source->Release ();
|
||||
self->source = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -533,32 +508,10 @@ gst_mf_capture_engine_finalize (GObject * object)
|
|||
{
|
||||
GstMFCaptureEngine *self = GST_MF_CAPTURE_ENGINE (object);
|
||||
|
||||
gst_clear_caps (&self->supported_caps);
|
||||
|
||||
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_queue_free (self->queue);
|
||||
g_mutex_clear (&self->lock);
|
||||
g_cond_clear (&self->cond);
|
||||
|
||||
CoUninitialize ();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -866,7 +824,7 @@ GstMFSourceObject *
|
|||
gst_mf_capture_engine_new (GstMFSourceType type, gint device_index,
|
||||
const gchar * device_name, const gchar * device_path)
|
||||
{
|
||||
GstMFCaptureEngine *self;
|
||||
GstMFSourceObject *self;
|
||||
gchar *name;
|
||||
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 ("");
|
||||
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,
|
||||
"device-path", path, NULL);
|
||||
|
||||
|
@ -884,10 +842,11 @@ gst_mf_capture_engine_new (GstMFSourceType type, gint device_index,
|
|||
g_free (name);
|
||||
g_free (path);
|
||||
|
||||
if (!self->source) {
|
||||
gst_clear_object (&self);
|
||||
if (!self->opend) {
|
||||
GST_WARNING_OBJECT (self, "Couldn't open device");
|
||||
gst_object_unref (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GST_MF_SOURCE_OBJECT (self);
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -58,14 +58,36 @@ gst_mf_source_type_get_type (void)
|
|||
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_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_mf_source_object_set_property (GObject * object, guint prop_id,
|
||||
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
|
||||
G_DEFINE_ABSTRACT_TYPE (GstMFSourceObject, gst_mf_source_object,
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstMFSourceObject, gst_mf_source_object,
|
||||
GST_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
|
@ -73,6 +95,8 @@ gst_mf_source_object_class_init (GstMFSourceObjectClass * 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->get_property = gst_mf_source_object_get_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
|
||||
gst_mf_source_object_init (GstMFSourceObject * self)
|
||||
{
|
||||
self->device_index = DEFAULT_DEVICE_INDEX;
|
||||
self->soure_type = DEFAULT_SOURCE_TYPE;
|
||||
GstMFSourceObjectPrivate *priv;
|
||||
|
||||
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
|
||||
gst_mf_source_object_finalize (GObject * object)
|
||||
{
|
||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||
GstMFSourceObjectPrivate *priv = self->priv;
|
||||
|
||||
g_free (self->device_path);
|
||||
g_free (self->device_name);
|
||||
g_mutex_clear (&priv->lock);
|
||||
g_cond_clear (&priv->cond);
|
||||
|
||||
g_free (priv->device_path);
|
||||
g_free (priv->device_name);
|
||||
|
||||
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)
|
||||
{
|
||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||
GstMFSourceObjectPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE_PATH:
|
||||
g_value_set_string (value, self->device_path);
|
||||
g_value_set_string (value, priv->device_path);
|
||||
break;
|
||||
case PROP_DEVICE_NAME:
|
||||
g_value_set_string (value, self->device_name);
|
||||
g_value_set_string (value, priv->device_name);
|
||||
break;
|
||||
case PROP_DEVICE_INDEX:
|
||||
g_value_set_int (value, self->device_index);
|
||||
g_value_set_int (value, priv->device_index);
|
||||
break;
|
||||
case PROP_SOURCE_TYPE:
|
||||
g_value_set_enum (value, self->soure_type);
|
||||
g_value_set_enum (value, priv->soure_type);
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
{
|
||||
GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object);
|
||||
GstMFSourceObjectPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE_PATH:
|
||||
g_free (self->device_path);
|
||||
self->device_path = g_value_dup_string (value);
|
||||
g_free (priv->device_path);
|
||||
priv->device_path = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_DEVICE_NAME:
|
||||
g_free (self->device_name);
|
||||
self->device_name = g_value_dup_string (value);
|
||||
g_free (priv->device_name);
|
||||
priv->device_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_DEVICE_INDEX:
|
||||
self->device_index = g_value_get_int (value);
|
||||
priv->device_index = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_SOURCE_TYPE:
|
||||
self->soure_type = g_value_get_enum (value);
|
||||
priv->soure_type = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
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
|
||||
gst_mf_source_object_start (GstMFSourceObject * object)
|
||||
{
|
||||
|
@ -251,9 +420,9 @@ gst_mf_source_object_get_caps (GstMFSourceObject * object)
|
|||
return klass->get_caps (object);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_mf_source_enum_device_activate (GstMFSourceType source_type,
|
||||
GList ** device_sources)
|
||||
static gboolean
|
||||
gst_mf_source_enum_device_activate (GstMFSourceObject * self,
|
||||
GstMFSourceType source_type, GList ** device_sources)
|
||||
{
|
||||
HRESULT hr;
|
||||
GList *ret = NULL;
|
||||
|
@ -272,7 +441,7 @@ gst_mf_source_enum_device_activate (GstMFSourceType source_type,
|
|||
&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
||||
break;
|
||||
default:
|
||||
GST_ERROR ("Unknown source type %d", source_type);
|
||||
GST_ERROR_OBJECT (self, "Unknown source type %d", source_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -332,7 +501,7 @@ done:
|
|||
return ! !ret;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
gst_mf_device_activate_free (GstMFDeviceActivate * activate)
|
||||
{
|
||||
g_return_if_fail (activate != NULL);
|
||||
|
|
|
@ -35,6 +35,7 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _GstMFSourceObject GstMFSourceObject;
|
||||
typedef struct _GstMFSourceObjectClass GstMFSourceObjectClass;
|
||||
typedef struct _GstMFSourceObjectPrivate GstMFSourceObjectPrivate;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -56,21 +57,24 @@ struct _GstMFSourceObject
|
|||
{
|
||||
GstObject parent;
|
||||
|
||||
GstMFSourceType soure_type;
|
||||
gboolean opend;
|
||||
|
||||
gchar *device_path;
|
||||
gchar *device_name;
|
||||
gint device_index;
|
||||
GstMFSourceObjectPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstMFSourceObjectClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
|
||||
gboolean (*open) (GstMFSourceObject * object,
|
||||
IMFActivate * activate);
|
||||
|
||||
gboolean (*start) (GstMFSourceObject * object);
|
||||
|
||||
gboolean (*stop) (GstMFSourceObject * object);
|
||||
|
||||
gboolean (*close) (GstMFSourceObject * object);
|
||||
|
||||
GstFlowReturn (*fill) (GstMFSourceObject * object,
|
||||
GstBuffer * buffer);
|
||||
|
||||
|
@ -101,12 +105,6 @@ GstCaps * gst_mf_source_object_get_caps (GstMFSourceObject * object);
|
|||
gboolean gst_mf_source_object_set_caps (GstMFSourceObject * object,
|
||||
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_END_DECLS
|
||||
|
|
|
@ -67,11 +67,13 @@ struct _GstMFSourceReader
|
|||
gboolean flushing;
|
||||
};
|
||||
|
||||
static void gst_mf_source_reader_constructed (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_stop (GstMFSourceObject * object);
|
||||
static gboolean gst_mf_source_reader_close (GstMFSourceObject * object);
|
||||
static GstFlowReturn gst_mf_source_reader_fill (GstMFSourceObject * object,
|
||||
GstBuffer * buffer);
|
||||
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);
|
||||
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;
|
||||
|
||||
source_class->open = GST_DEBUG_FUNCPTR (gst_mf_source_reader_open);
|
||||
source_class->start = GST_DEBUG_FUNCPTR (gst_mf_source_reader_start);
|
||||
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->unlock = GST_DEBUG_FUNCPTR (gst_mf_source_reader_unlock);
|
||||
source_class->unlock_stop =
|
||||
|
@ -108,8 +111,6 @@ gst_mf_source_reader_init (GstMFSourceReader * self)
|
|||
{
|
||||
self->queue = g_queue_new ();
|
||||
g_mutex_init (&self->lock);
|
||||
|
||||
CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -185,8 +186,9 @@ gst_mf_stream_media_type_free (GstMFStreamMediaType * media_type)
|
|||
}
|
||||
|
||||
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;
|
||||
HRESULT hr;
|
||||
ComPtr<IMFSourceReader> reader;
|
||||
|
@ -235,63 +237,31 @@ gst_mf_source_reader_create (GstMFSourceReader * self, IMFActivate * activate)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mf_source_reader_constructed (GObject * object)
|
||||
static gboolean
|
||||
gst_mf_source_reader_close (GstMFSourceObject * object)
|
||||
{
|
||||
GstMFSourceObject *source = GST_MF_SOURCE_OBJECT (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_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_clear_caps (&self->supported_caps);
|
||||
|
||||
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 (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) {
|
||||
target = activate;
|
||||
break;
|
||||
}
|
||||
if (self->media_types) {
|
||||
g_list_free_full (self->media_types,
|
||||
(GDestroyNotify) gst_mf_stream_media_type_free);
|
||||
self->media_types = NULL;
|
||||
}
|
||||
|
||||
if (target)
|
||||
gst_mf_source_reader_create (self, target->handle);
|
||||
if (self->reader) {
|
||||
self->reader->Release ();
|
||||
self->reader = NULL;
|
||||
}
|
||||
|
||||
if (activate_list)
|
||||
g_list_free_full (activate_list,
|
||||
(GDestroyNotify) gst_mf_device_activate_free);
|
||||
}
|
||||
if (self->source) {
|
||||
self->source->Shutdown ();
|
||||
self->source->Release ();
|
||||
self->source = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
release_mf_buffer (IMFMediaBuffer * buffer)
|
||||
{
|
||||
if (buffer)
|
||||
buffer->Release ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -299,27 +269,9 @@ gst_mf_source_reader_finalize (GObject * object)
|
|||
{
|
||||
GstMFSourceReader *self = GST_MF_SOURCE_READER (object);
|
||||
|
||||
gst_clear_caps (&self->supported_caps);
|
||||
|
||||
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_queue_free (self->queue);
|
||||
g_mutex_clear (&self->lock);
|
||||
|
||||
CoUninitialize ();
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -357,6 +309,13 @@ gst_mf_source_reader_start (GstMFSourceObject * object)
|
|||
static gboolean
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -530,7 +489,7 @@ GstMFSourceObject *
|
|||
gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
|
||||
const gchar * device_name, const gchar * device_path)
|
||||
{
|
||||
GstMFSourceReader *self;
|
||||
GstMFSourceObject *self;
|
||||
gchar *name;
|
||||
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 ("");
|
||||
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,
|
||||
"device-path", path, NULL);
|
||||
|
||||
|
@ -548,10 +507,11 @@ gst_mf_source_reader_new (GstMFSourceType type, gint device_index,
|
|||
g_free (name);
|
||||
g_free (path);
|
||||
|
||||
if (!self->source) {
|
||||
gst_clear_object (&self);
|
||||
if (!self->opend) {
|
||||
GST_WARNING_OBJECT (self, "Couldn't open device");
|
||||
gst_object_unref (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GST_MF_SOURCE_OBJECT (self);
|
||||
return self;
|
||||
}
|
Loading…
Reference in a new issue