/* GStreamer * Copyright (C) 2018 Joshua M. Doe * * dshowdeviceprovider.cpp: DirectShow device probing * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstdshow.h" #include "gstdshowvideosrc.h" #include "dshowdeviceprovider.h" #include #include GST_DEBUG_CATEGORY_EXTERN (dshowsrcwrapper_debug); #define GST_CAT_DEFAULT dshowsrcwrapper_debug static GstDevice *gst_dshow_device_new (guint id, const gchar * device_name, GstCaps * caps, const gchar * device_path, GstDshowDeviceType type); G_DEFINE_TYPE (GstDshowDeviceProvider, gst_dshow_device_provider, GST_TYPE_DEVICE_PROVIDER); static void gst_dshow_device_provider_dispose (GObject * gobject); static GList *gst_dshow_device_provider_probe (GstDeviceProvider * provider); static gboolean gst_dshow_device_provider_start (GstDeviceProvider * provider); static void gst_dshow_device_provider_stop (GstDeviceProvider * provider); static void gst_dshow_device_provider_class_init (GstDshowDeviceProviderClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass); gobject_class->dispose = gst_dshow_device_provider_dispose; dm_class->probe = gst_dshow_device_provider_probe; dm_class->start = gst_dshow_device_provider_start; dm_class->stop = gst_dshow_device_provider_stop; gst_device_provider_class_set_static_metadata (dm_class, "DirectShow Device Provider", "Source/Audio/Video", "List and provide DirectShow source devices", "Руслан Ижбулатов "); } static void gst_dshow_device_provider_init (GstDshowDeviceProvider * self) { CoInitializeEx (NULL, COINIT_MULTITHREADED); } static void gst_dshow_device_provider_dispose (GObject * gobject) { CoUninitialize (); } static GstDevice * new_video_source (const DshowDeviceEntry * info) { g_assert (info && info->device != NULL); return gst_dshow_device_new (info->device_index, info->device_name, info->caps, info->device, GST_DSHOW_DEVICE_TYPE_VIDEO_SOURCE); } static GList * gst_dshow_device_provider_probe (GstDeviceProvider * provider) { /*GstDshowDeviceProvider *self = GST_DSHOW_DEVICE_PROVIDER (provider); */ GList *devices, *cur; GList *result; result = NULL; devices = gst_dshow_enumerate_devices (&CLSID_VideoInputDeviceCategory, TRUE); if (devices == NULL) return result; /* TODO: try and sort camera first like ksvideosrc? */ for (cur = devices; cur != NULL; cur = cur->next) { GstDevice *source; DshowDeviceEntry *entry = (DshowDeviceEntry *) cur->data; source = new_video_source (entry); if (source) result = g_list_prepend (result, gst_object_ref_sink (source)); } result = g_list_reverse (result); gst_dshow_device_list_free (devices); return result; } static gboolean gst_dshow_device_provider_start (GstDeviceProvider * provider) { GList *devs; GList *dev; GstDshowDeviceProvider *self = GST_DSHOW_DEVICE_PROVIDER (provider); devs = gst_dshow_device_provider_probe (provider); for (dev = devs; dev; dev = dev->next) { if (dev->data) gst_device_provider_device_add (provider, (GstDevice *) dev->data); } g_list_free (devs); return TRUE; } static void gst_dshow_device_provider_stop (GstDeviceProvider * provider) { } enum { PROP_0, PROP_DEVICE, PROP_DEVICE_NAME, PROP_DEVICE_INDEX }; G_DEFINE_TYPE (GstDshowDevice, gst_dshow_device, GST_TYPE_DEVICE); static void gst_dshow_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_dshow_device_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_dshow_device_finalize (GObject * object); static GstElement *gst_dshow_device_create_element (GstDevice * device, const gchar * name); static void gst_dshow_device_class_init (GstDshowDeviceClass * klass) { GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); dev_class->create_element = gst_dshow_device_create_element; object_class->get_property = gst_dshow_device_get_property; object_class->set_property = gst_dshow_device_set_property; object_class->finalize = gst_dshow_device_finalize; g_object_class_install_property (object_class, PROP_DEVICE, g_param_spec_string ("device", "Device", "DirectShow device path (@..classID/name)", "", (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); g_object_class_install_property (object_class, PROP_DEVICE_NAME, g_param_spec_string ("device-name", "Device name", "Human-readable name of the audio/video device", "", (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); g_object_class_install_property (object_class, PROP_DEVICE_INDEX, g_param_spec_int ("device-index", "Device index", "Index of the enumerated audio/video device", 0, G_MAXINT, 0, (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); } static void gst_dshow_device_init (GstDshowDevice * device) { } static void gst_dshow_device_finalize (GObject * object) { GstDshowDevice *device = GST_DSHOW_DEVICE (object); g_free (device->device); g_free (device->device_name); G_OBJECT_CLASS (gst_dshow_device_parent_class)->finalize (object); } static GstElement * gst_dshow_device_create_element (GstDevice * device, const gchar * name) { GstDshowDevice *dev = GST_DSHOW_DEVICE (device); GstElement *elem; elem = gst_element_factory_make (dev->element, name); g_object_set (elem, "device", dev->device, NULL); g_object_set (elem, "device-name", dev->device_name, NULL); return elem; } static GstDevice * gst_dshow_device_new (guint device_index, const gchar * device_name, GstCaps * caps, const gchar * device_path, GstDshowDeviceType type) { GstDshowDevice *gstdev; const gchar *element = NULL; const gchar *klass = NULL; g_return_val_if_fail (device_name, NULL); g_return_val_if_fail (device_path, NULL); g_return_val_if_fail (caps, NULL); switch (type) { case GST_DSHOW_DEVICE_TYPE_VIDEO_SOURCE: element = "dshowvideosrc"; klass = "Video/Source"; break; case GST_DSHOW_DEVICE_TYPE_AUDIO_SOURCE: element = "dshowaudiosrc"; klass = "Audio/Source"; break; default: g_assert_not_reached (); break; } /* set props of parent device class */ gstdev = (GstDshowDevice *) g_object_new (GST_TYPE_DSHOW_DEVICE, "display-name", device_name, "caps", caps, "device-class", klass, NULL); gstdev->type = type; gstdev->device = g_strdup (device_path); gstdev->device_name = g_strdup (device_name); gstdev->device_index = device_index; gstdev->element = element; return GST_DEVICE (gstdev); } static void gst_dshow_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDshowDevice *device; device = GST_DSHOW_DEVICE_CAST (object); switch (prop_id) { case PROP_DEVICE: g_value_set_string (value, device->device); break; case PROP_DEVICE_NAME: g_value_set_string (value, device->device_name); break; case PROP_DEVICE_INDEX: g_value_set_int (value, device->device_index); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_dshow_device_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstDshowDevice *device; device = GST_DSHOW_DEVICE_CAST (object); switch (prop_id) { case PROP_DEVICE: device->device = g_value_dup_string (value); break; case PROP_DEVICE_NAME: device->device_name = g_value_dup_string (value); break; case PROP_DEVICE_INDEX: device->device_index = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }