/* GStreamer * Copyright (C) 2019 Seungha Yang * Copyright (C) 2020 Seungha Yang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstmfconfig.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); #define GST_CAT_DEFAULT gst_mf_source_object_debug enum { PROP_0, PROP_DEVICE_PATH, PROP_DEVICE_NAME, PROP_DEVICE_INDEX, PROP_SOURCE_TYPE, }; #define DEFAULT_DEVICE_PATH NULL #define DEFAULT_DEVICE_NAME NULL #define DEFAULT_DEVICE_INDEX -1 #define DEFAULT_SOURCE_TYPE GST_MF_SOURCE_TYPE_VIDEO GType gst_mf_source_type_get_type (void) { static GType source_type = 0; static const GEnumValue source_types[] = { {GST_MF_SOURCE_TYPE_VIDEO, "Video", "video"}, {0, NULL, NULL} }; if (!source_type) { source_type = g_enum_register_static ("GstMFSourceMode", source_types); } return source_type; } 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); #define gst_mf_source_object_parent_class parent_class G_DEFINE_ABSTRACT_TYPE (GstMFSourceObject, gst_mf_source_object, GST_TYPE_OBJECT); static void gst_mf_source_object_class_init (GstMFSourceObjectClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 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; g_object_class_install_property (gobject_class, PROP_DEVICE_PATH, g_param_spec_string ("device-path", "Device Path", "The device path", DEFAULT_DEVICE_PATH, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, g_param_spec_string ("device-name", "Device Name", "The human-readable device name", DEFAULT_DEVICE_NAME, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX, g_param_spec_int ("device-index", "Device Index", "The zero-based device index", -1, G_MAXINT, DEFAULT_DEVICE_INDEX, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_SOURCE_TYPE, g_param_spec_enum ("source-type", "Source Type", "Source Type", GST_TYPE_MF_SOURCE_TYPE, DEFAULT_SOURCE_TYPE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } static void gst_mf_source_object_init (GstMFSourceObject * self) { self->device_index = DEFAULT_DEVICE_INDEX; self->source_type = DEFAULT_SOURCE_TYPE; } static void gst_mf_source_object_finalize (GObject * object) { GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object); g_free (self->device_path); g_free (self->device_name); G_OBJECT_CLASS (parent_class)->finalize (object); } static void gst_mf_source_object_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object); switch (prop_id) { case PROP_DEVICE_PATH: g_value_set_string (value, self->device_path); break; case PROP_DEVICE_NAME: g_value_set_string (value, self->device_name); break; case PROP_DEVICE_INDEX: g_value_set_int (value, self->device_index); break; case PROP_SOURCE_TYPE: g_value_set_enum (value, self->source_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_mf_source_object_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstMFSourceObject *self = GST_MF_SOURCE_OBJECT (object); switch (prop_id) { case PROP_DEVICE_PATH: g_free (self->device_path); self->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); break; case PROP_DEVICE_INDEX: self->device_index = g_value_get_int (value); break; case PROP_SOURCE_TYPE: self->source_type = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } gboolean gst_mf_source_object_start (GstMFSourceObject * object) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), FALSE); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->start != NULL); return klass->start (object); } gboolean gst_mf_source_object_stop (GstMFSourceObject * object) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), FALSE); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->stop != NULL); return klass->stop (object); } GstFlowReturn gst_mf_source_object_fill (GstMFSourceObject * object, GstBuffer * buffer) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->fill != NULL); return klass->fill (object, buffer); } GstFlowReturn gst_mf_source_object_create (GstMFSourceObject * object, GstBuffer ** buffer) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), GST_FLOW_ERROR); g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->create != NULL); return klass->create (object, buffer); } void gst_mf_source_object_set_flushing (GstMFSourceObject * object, gboolean flushing) { GstMFSourceObjectClass *klass; g_return_if_fail (GST_IS_MF_SOURCE_OBJECT (object)); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); if (flushing) { if (klass->unlock) klass->unlock (object); } else { if (klass->unlock_stop) klass->unlock_stop (object); } } gboolean gst_mf_source_object_set_caps (GstMFSourceObject * object, GstCaps * caps) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), FALSE); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->set_caps != NULL); return klass->set_caps (object, caps); } GstCaps * gst_mf_source_object_get_caps (GstMFSourceObject * object) { GstMFSourceObjectClass *klass; g_return_val_if_fail (GST_IS_MF_SOURCE_OBJECT (object), NULL); klass = GST_MF_SOURCE_OBJECT_GET_CLASS (object); g_assert (klass->get_caps != NULL); return klass->get_caps (object); } static gboolean gst_mf_source_object_use_winrt_api (void) { static gsize check_once = 0; static gboolean ret = FALSE; if (g_once_init_enter (&check_once)) { #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; env = g_getenv ("GST_USE_MF_WINRT_CAPTURE"); if (env && g_str_has_prefix (env, "1")) ret = TRUE; else ret = FALSE; } #endif #endif g_once_init_leave (&check_once, 1); } return ret; } GstMFSourceObject * gst_mf_source_object_new (GstMFSourceType type, gint device_index, const gchar * device_name, const gchar * device_path) { #if (!GST_MF_WINAPI_APP) GST_INFO ("Try IMFSourceReader implementation"); return gst_mf_source_reader_new (type, device_index, device_name, device_path); #else #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 { GST_INFO ("Both Desktop and WinRT APIs were enabled, default: IMFSourceReader"); return gst_mf_source_reader_new (type, device_index, device_name, device_path); } #endif #endif g_assert_not_reached (); return NULL; }