| /* |
| * Copyright (C) 2014 Collabora Ltd. |
| * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> |
| * |
| * 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 "v4l2-utils.h" |
| |
| /**************************/ |
| /* Common device iterator */ |
| /**************************/ |
| |
| #ifdef HAVE_GUDEV |
| #include <gudev/gudev.h> |
| |
| struct _GstV4l2GUdevIterator |
| { |
| GstV4l2Iterator parent; |
| GList *devices; |
| GUdevDevice *device; |
| GUdevClient *client; |
| }; |
| |
| GstV4l2Iterator * |
| gst_v4l2_iterator_new (void) |
| { |
| static const gchar *subsystems[] = { "video4linux", NULL }; |
| struct _GstV4l2GUdevIterator *it; |
| |
| it = g_slice_new0 (struct _GstV4l2GUdevIterator); |
| |
| it->client = g_udev_client_new (subsystems); |
| it->devices = g_udev_client_query_by_subsystem (it->client, "video4linux"); |
| |
| return (GstV4l2Iterator *) it; |
| } |
| |
| gboolean |
| gst_v4l2_iterator_next (GstV4l2Iterator * _it) |
| { |
| struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it; |
| const gchar *device_name; |
| |
| if (it->device) |
| g_object_unref (it->device); |
| |
| it->device = NULL; |
| it->parent.device_path = NULL; |
| it->parent.device_name = NULL; |
| |
| if (it->devices == NULL) |
| return FALSE; |
| |
| it->device = it->devices->data; |
| it->devices = g_list_delete_link (it->devices, it->devices); |
| |
| device_name = g_udev_device_get_property (it->device, "ID_V4L_PRODUCT"); |
| if (!device_name) |
| device_name = g_udev_device_get_property (it->device, "ID_MODEL_ENC"); |
| if (!device_name) |
| device_name = g_udev_device_get_property (it->device, "ID_MODEL"); |
| |
| it->parent.device_path = g_udev_device_get_device_file (it->device); |
| it->parent.device_name = device_name; |
| it->parent.sys_path = g_udev_device_get_sysfs_path (it->device); |
| |
| return TRUE; |
| } |
| |
| void |
| gst_v4l2_iterator_free (GstV4l2Iterator * _it) |
| { |
| struct _GstV4l2GUdevIterator *it = (struct _GstV4l2GUdevIterator *) _it; |
| g_list_free_full (it->devices, g_object_unref); |
| gst_object_unref (it->client); |
| g_slice_free (struct _GstV4l2GUdevIterator, it); |
| } |
| |
| #else /* No GUDEV */ |
| |
| struct _GstV4l2FsIterator |
| { |
| GstV4l2Iterator parent; |
| gint base_idx; |
| gint video_idx; |
| gchar *device; |
| }; |
| |
| GstV4l2Iterator * |
| gst_v4l2_iterator_new (void) |
| { |
| struct _GstV4l2FsIterator *it; |
| |
| it = g_slice_new0 (struct _GstV4l2FsIterator); |
| it->base_idx = 0; |
| it->video_idx = -1; |
| it->device = NULL; |
| |
| return (GstV4l2Iterator *) it; |
| } |
| |
| gboolean |
| gst_v4l2_iterator_next (GstV4l2Iterator * _it) |
| { |
| struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it; |
| static const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL }; |
| gchar *device = NULL; |
| |
| g_free ((gchar *) it->parent.device_path); |
| it->parent.device_path = NULL; |
| |
| while (device == NULL) { |
| it->video_idx++; |
| |
| if (it->video_idx >= 64) { |
| it->video_idx = 0; |
| it->base_idx++; |
| } |
| |
| if (dev_base[it->base_idx] == NULL) { |
| it->video_idx = 0; |
| break; |
| } |
| |
| device = g_strdup_printf ("%s%d", dev_base[it->base_idx], it->video_idx); |
| |
| if (g_file_test (device, G_FILE_TEST_EXISTS)) { |
| it->parent.device_path = device; |
| break; |
| } |
| |
| g_free (device); |
| device = NULL; |
| } |
| |
| return it->parent.device_path != NULL; |
| } |
| |
| void |
| gst_v4l2_iterator_free (GstV4l2Iterator * _it) |
| { |
| struct _GstV4l2FsIterator *it = (struct _GstV4l2FsIterator *) _it; |
| g_free ((gchar *) it->parent.device_path); |
| g_slice_free (struct _GstV4l2FsIterator, it); |
| } |
| |
| #endif |
| |
| void |
| gst_v4l2_clear_error (GstV4l2Error * v4l2err) |
| { |
| if (v4l2err) { |
| g_clear_error (&v4l2err->error); |
| g_free (v4l2err->dbg_message); |
| v4l2err->dbg_message = NULL; |
| } |
| } |
| |
| void |
| gst_v4l2_error (gpointer element, GstV4l2Error * v4l2err) |
| { |
| GError *error; |
| |
| if (!v4l2err || !v4l2err->error) |
| return; |
| |
| error = v4l2err->error; |
| |
| if (error->message) |
| GST_WARNING_OBJECT (element, "error: %s", error->message); |
| |
| if (v4l2err->dbg_message) |
| GST_WARNING_OBJECT (element, "error: %s", v4l2err->dbg_message); |
| |
| gst_element_message_full (GST_ELEMENT (element), GST_MESSAGE_ERROR, |
| error->domain, error->code, error->message, v4l2err->dbg_message, |
| v4l2err->file, v4l2err->func, v4l2err->line); |
| |
| error->message = NULL; |
| v4l2err->dbg_message = NULL; |
| |
| gst_v4l2_clear_error (v4l2err); |
| } |