~ubuntu-branches/debian/stretch/cheese/stretch

« back to all changes in this revision

Viewing changes to libcheese/cheese-camera-device-monitor.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2010-05-04 17:37:18 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20100504173718-k2rx3nryi4vd0xyx
Tags: 2.30.1-1
* New upstream release.
  - HAL dependency has been dropped. Use (g)udev for v4l capability probing
    on Linux. Closes: #573774
  - Split code into separate libraries.
* debian/control.in
  - Drop Build-Depends on libhal-dev.
  - Drop Build-Depends on libebook1.2-dev.
  - Bump Build-Depends on libgtk2.0-dev to (>= 2.19.1).
  - Bump Build-Depends on libgstreamer*-dev to (>= 0.10.23).
  - Add Build-Depends on libcanberra-gtk-dev.
  - Add Build-Depends on libxtst-dev.
  - Add Build-Depends on libgudev-1.0-dev on Linux.
  - Bump Standards-Version to 3.8.4. No further changes.
* Switch to source format 3.0 (quilt)
  - Add debian/source/format.
* debian/rules
  - Drop lpia specific configure flags, lpia is dead.
* Update package layout (based on work by Ubuntu)
  - Move data files into new cheese-common package.
  - Keep binary along with its desktop and dbus service file in the cheese
    package.
  - Add libcheese-gtk18 and libcheese-gtk-dev package for the new
    libcheese-gtk library. Use a symbols file for improved shlibs
    dependencies.
  - Add Conflicts/Replaces to cheese-common to ensure proper upgrades from
    previous versions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2007,2008 Jaap Haitsma <jaap@haitsma.org>
 
3
 * Copyright © 2007-2009 daniel g. siegel <dgsiegel@gnome.org>
 
4
 * Copyright © 2008 Ryan Zeigler <zeiglerr@gmail.com>
 
5
 * Copyright © 2010 Filippo Argiolas <filippo.argiolas@gmail.com>
 
6
 *
 
7
 * Licensed under the GNU General Public License Version 2
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
#ifdef HAVE_CONFIG_H
 
23
  #include <cheese-config.h>
 
24
#endif
 
25
 
 
26
#include <glib-object.h>
 
27
#include <dbus/dbus-glib-lowlevel.h>
 
28
#include <string.h>
 
29
 
 
30
#ifdef HAVE_UDEV
 
31
  #define G_UDEV_API_IS_SUBJECT_TO_CHANGE 1
 
32
  #include <gudev/gudev.h>
 
33
#else
 
34
  #include <fcntl.h>
 
35
  #include <unistd.h>
 
36
  #include <sys/ioctl.h>
 
37
  #if USE_SYS_VIDEOIO_H > 0
 
38
    #include <sys/types.h>
 
39
    #include <sys/videoio.h>
 
40
  #elif defined (__sun)
 
41
    #include <sys/types.h>
 
42
    #include <sys/videodev2.h>
 
43
  #endif /* USE_SYS_VIDEOIO_H */
 
44
#endif
 
45
 
 
46
#include "cheese-camera-device-monitor.h"
 
47
#include "cheese-marshal.h"
 
48
 
 
49
/**
 
50
 * SECTION:cheese-camera-device-monitor
 
51
 * @short_description: Simple object to enumerate v4l devices
 
52
 * @include: cheese/cheese-camera-device-monitor.h
 
53
 *
 
54
 * #CheeseCameraDeviceMonitor provides a basic interface for
 
55
 * video4linux device enumeration and hotplugging.
 
56
 *
 
57
 * It uses either GUdev or some platform specific code to list video
 
58
 * devices.  It is also capable (right now in linux only, with the
 
59
 * udev backend) to monitor device plugging and emit a
 
60
 * CheeseCameraDeviceMonitor::added or
 
61
 * CheeseCameraDeviceMonitor::removed signal when an event happens.
 
62
 */
 
63
 
 
64
G_DEFINE_TYPE (CheeseCameraDeviceMonitor, cheese_camera_device_monitor, G_TYPE_OBJECT)
 
65
 
 
66
#define CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),                               \
 
67
                                                                                  CHEESE_TYPE_CAMERA_DEVICE_MONITOR, \
 
68
                                                                                  CheeseCameraDeviceMonitorPrivate))
 
69
 
 
70
#define CHEESE_CAMERA_DEVICE_MONITOR_ERROR cheese_camera_device_monitor_error_quark ()
 
71
 
 
72
GST_DEBUG_CATEGORY (cheese_device_monitor_cat);
 
73
#define GST_CAT_DEFAULT cheese_device_monitor_cat
 
74
 
 
75
enum CheeseCameraDeviceMonitorError
 
76
{
 
77
  CHEESE_CAMERA_DEVICE_MONITOR_ERROR_UNKNOWN,
 
78
  CHEESE_CAMERA_DEVICE_MONITOR_ERROR_ELEMENT_NOT_FOUND
 
79
};
 
80
 
 
81
typedef struct
 
82
{
 
83
#ifdef HAVE_UDEV
 
84
  GUdevClient *client;
 
85
#else
 
86
  guint filler;
 
87
#endif /* HAVE_UDEV */
 
88
} CheeseCameraDeviceMonitorPrivate;
 
89
 
 
90
enum
 
91
{
 
92
  ADDED,
 
93
  REMOVED,
 
94
  LAST_SIGNAL
 
95
};
 
96
 
 
97
static guint monitor_signals[LAST_SIGNAL];
 
98
 
 
99
GQuark
 
100
cheese_camera_device_monitor_error_quark (void)
 
101
{
 
102
  return g_quark_from_static_string ("cheese-camera-error-quark");
 
103
}
 
104
 
 
105
#ifdef HAVE_UDEV
 
106
static void
 
107
cheese_camera_device_monitor_added (CheeseCameraDeviceMonitor *monitor,
 
108
                                    GUdevDevice               *udevice)
 
109
{
 
110
  const char         *device_file;
 
111
  const char         *product_name;
 
112
  const char         *vendor;
 
113
  const char         *product;
 
114
  const char         *bus;
 
115
  gint                vendor_id   = 0;
 
116
  gint                product_id  = 0;
 
117
  gint                v4l_version = 0;
 
118
 
 
119
  const gchar *devpath = g_udev_device_get_property (udevice, "DEVPATH");
 
120
 
 
121
  GST_INFO ("Checking udev device '%s'", devpath);
 
122
 
 
123
  bus = g_udev_device_get_property (udevice, "ID_BUS");
 
124
  if (g_strcmp0 (bus, "usb") == 0)
 
125
  {
 
126
    vendor = g_udev_device_get_property (udevice, "ID_VENDOR_ID");
 
127
    if (vendor != NULL)
 
128
      vendor_id = g_ascii_strtoll (vendor, NULL, 16);
 
129
    product = g_udev_device_get_property (udevice, "ID_MODEL_ID");
 
130
    if (product != NULL)
 
131
      product_id = g_ascii_strtoll (vendor, NULL, 16);
 
132
    if (vendor_id == 0 || product_id == 0)
 
133
    {
 
134
      GST_WARNING ("Error getting vendor and product id");
 
135
    }
 
136
    else
 
137
    {
 
138
      GST_INFO ("Found device %04x:%04x, getting capabilities...", vendor_id, product_id);
 
139
    }
 
140
  }
 
141
  else
 
142
  {
 
143
    GST_INFO ("Not an usb device, skipping vendor and model id retrieval");
 
144
  }
 
145
 
 
146
  device_file = g_udev_device_get_device_file (udevice);
 
147
  if (device_file == NULL)
 
148
  {
 
149
    GST_WARNING ("Error getting V4L device");
 
150
    return;
 
151
  }
 
152
 
 
153
  /* vbi devices support capture capability too, but cannot be used,
 
154
   * so detect them by device name */
 
155
  if (strstr (device_file, "vbi"))
 
156
  {
 
157
    GST_INFO ("Skipping vbi device: %s", device_file);
 
158
    return;
 
159
  }
 
160
 
 
161
  v4l_version = g_udev_device_get_property_as_int (udevice, "ID_V4L_VERSION");
 
162
  if (v4l_version == 2 || v4l_version == 1)
 
163
  {
 
164
    const char *caps;
 
165
 
 
166
    caps = g_udev_device_get_property (udevice, "ID_V4L_CAPABILITIES");
 
167
    if (caps == NULL || strstr (caps, ":capture:") == NULL)
 
168
    {
 
169
      GST_WARNING ("Device %s seems to not have the capture capability, (radio tuner?)"
 
170
                   "Removing it from device list.", device_file);
 
171
      return;
 
172
    }
 
173
    product_name  = g_udev_device_get_property (udevice, "ID_V4L_PRODUCT");
 
174
  }
 
175
  else if (v4l_version == 0)
 
176
  {
 
177
    GST_ERROR ("Fix your udev installation to include v4l_id, ignoring %s", device_file);
 
178
    return;
 
179
  }
 
180
  else
 
181
  {
 
182
    g_assert_not_reached ();
 
183
  }
 
184
 
 
185
  g_signal_emit (monitor, monitor_signals[ADDED], 0,
 
186
                 devpath,
 
187
                 device_file,
 
188
                 product_name,
 
189
                 v4l_version);
 
190
}
 
191
 
 
192
static void
 
193
cheese_camera_device_monitor_removed (CheeseCameraDeviceMonitor *monitor,
 
194
                                      GUdevDevice               *udevice)
 
195
{
 
196
  g_signal_emit (monitor, monitor_signals[REMOVED], 0,
 
197
                 g_udev_device_get_property (udevice, "DEVPATH"));
 
198
}
 
199
 
 
200
static void
 
201
cheese_camera_device_monitor_uevent_cb (GUdevClient               *client,
 
202
                                        const gchar               *action,
 
203
                                        GUdevDevice               *udevice,
 
204
                                        CheeseCameraDeviceMonitor *monitor)
 
205
{
 
206
  if (g_str_equal (action, "remove"))
 
207
    cheese_camera_device_monitor_removed (monitor, udevice);
 
208
  else if (g_str_equal (action, "add"))
 
209
    cheese_camera_device_monitor_added (monitor, udevice);
 
210
}
 
211
 
 
212
/**
 
213
 * cheese_camera_device_monitor_coldplug:
 
214
 * @monitor: a #CheeseCameraDeviceMonitor object.
 
215
 *
 
216
 * Will actively look for plugged in cameras and emit
 
217
 * ::added for those new cameras.
 
218
 * This is only required when your program starts, so as to connect
 
219
 * to those signals before they are emitted.
 
220
 */
 
221
void
 
222
cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor)
 
223
{
 
224
  CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
 
225
  GList                            *devices, *l;
 
226
  gint                              i = 0;
 
227
 
 
228
  if (priv->client == NULL)
 
229
    return;
 
230
 
 
231
  GST_INFO ("Probing devices with udev...");
 
232
 
 
233
  devices = g_udev_client_query_by_subsystem (priv->client, "video4linux");
 
234
 
 
235
  /* Initialize camera structures */
 
236
  for (l = devices; l != NULL; l = l->next)
 
237
  {
 
238
    cheese_camera_device_monitor_added (monitor, l->data);
 
239
    g_object_unref (l->data);
 
240
    i++;
 
241
  }
 
242
  g_list_free (devices);
 
243
 
 
244
  if (i == 0) GST_WARNING ("No device found");
 
245
}
 
246
 
 
247
#else /* HAVE_UDEV */
 
248
void
 
249
cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor)
 
250
{
 
251
  #if 0
 
252
  CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
 
253
  struct v4l2_capability            v2cap;
 
254
  struct video_capability           v1cap;
 
255
  int                               fd, ok;
 
256
 
 
257
  if ((fd = open (device_path, O_RDONLY | O_NONBLOCK)) < 0)
 
258
  {
 
259
    g_warning ("Failed to open %s: %s", device_path, strerror (errno));
 
260
    return;
 
261
  }
 
262
  ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap);
 
263
  if (ok < 0)
 
264
  {
 
265
    ok = ioctl (fd, VIDIOCGCAP, &v1cap);
 
266
    if (ok < 0)
 
267
    {
 
268
      g_warning ("Error while probing v4l capabilities for %s: %s",
 
269
                 device_path, strerror (errno));
 
270
      close (fd);
 
271
      return;
 
272
    }
 
273
    g_print ("Detected v4l device: %s\n", v1cap.name);
 
274
    g_print ("Device type: %d\n", v1cap.type);
 
275
    gstreamer_src = "v4lsrc";
 
276
    product_name  = v1cap.name;
 
277
  }
 
278
  else
 
279
  {
 
280
    guint cap = v2cap.capabilities;
 
281
    g_print ("Detected v4l2 device: %s\n", v2cap.card);
 
282
    g_print ("Driver: %s, version: %d\n", v2cap.driver, v2cap.version);
 
283
 
 
284
    /* g_print ("Bus info: %s\n", v2cap.bus_info); */ /* Doesn't seem anything useful */
 
285
    g_print ("Capabilities: 0x%08X\n", v2cap.capabilities);
 
286
    if (!(cap & V4L2_CAP_VIDEO_CAPTURE))
 
287
    {
 
288
      g_print ("Device %s seems to not have the capture capability, (radio tuner?)\n"
 
289
               "Removing it from device list.\n", device_path);
 
290
      close (fd);
 
291
      return;
 
292
    }
 
293
    gstreamer_src = "v4l2src";
 
294
    product_name  = (char *) v2cap.card;
 
295
  }
 
296
  close (fd);
 
297
 
 
298
  GList *devices, *l;
 
299
 
 
300
  g_print ("Probing devices with udev...\n");
 
301
 
 
302
  if (priv->client == NULL)
 
303
    return;
 
304
 
 
305
  devices = g_udev_client_query_by_subsystem (priv->client, "video4linux");
 
306
 
 
307
  /* Initialize camera structures */
 
308
  for (l = devices; l != NULL; l = l->next)
 
309
  {
 
310
    cheese_camera_device_monitor_added (monitor, l->data);
 
311
    g_object_unref (l->data);
 
312
  }
 
313
  g_list_free (devices);
 
314
  #endif
 
315
}
 
316
 
 
317
#endif /* HAVE_UDEV */
 
318
 
 
319
static void
 
320
cheese_camera_device_monitor_finalize (GObject *object)
 
321
{
 
322
#ifdef HAVE_UDEV
 
323
  CheeseCameraDeviceMonitor *monitor;
 
324
 
 
325
  monitor = CHEESE_CAMERA_DEVICE_MONITOR (object);
 
326
  CheeseCameraDeviceMonitorPrivate *priv = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
 
327
 
 
328
  if (priv->client != NULL)
 
329
  {
 
330
    g_object_unref (priv->client);
 
331
    priv->client = NULL;
 
332
  }
 
333
#endif /* HAVE_UDEV */
 
334
  G_OBJECT_CLASS (cheese_camera_device_monitor_parent_class)->finalize (object);
 
335
}
 
336
 
 
337
static void
 
338
cheese_camera_device_monitor_class_init (CheeseCameraDeviceMonitorClass *klass)
 
339
{
 
340
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
341
 
 
342
  if (cheese_device_monitor_cat == NULL)
 
343
    GST_DEBUG_CATEGORY_INIT (cheese_device_monitor_cat,
 
344
                             "cheese-device-monitor",
 
345
                             0, "Cheese Camera Device Monitor");
 
346
 
 
347
  object_class->finalize = cheese_camera_device_monitor_finalize;
 
348
 
 
349
  /**
 
350
   * CheeseCameraDeviceMonitor::added:
 
351
   * @device: A private object representing the newly added camera.
 
352
   * @id: Device unique identifier.
 
353
   * @device: Device file name  (e.g. /dev/video2).
 
354
   * @product_name: Device product name (human readable, intended to be displayed in a UI).
 
355
   * @api_version: Supported video4linux API: 1 for v4l, 2 for v4l2.
 
356
   *
 
357
   * The ::added signal is emitted when a camera is added, or on start-up
 
358
   * after #cheese_camera_device_monitor_colplug is called.
 
359
   **/
 
360
  monitor_signals[ADDED] = g_signal_new ("added", G_OBJECT_CLASS_TYPE (klass),
 
361
                                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
362
                                         G_STRUCT_OFFSET (CheeseCameraDeviceMonitorClass, added),
 
363
                                         NULL, NULL,
 
364
                                         _cheese_marshal_VOID__STRING_STRING_STRING_INT,
 
365
                                         G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
 
366
 
 
367
  /**
 
368
   * CheeseCameraDeviceMonitor::removed:
 
369
   * @device: A private object representing the newly added camera
 
370
   * @id: Device unique identifier.
 
371
   *
 
372
   * The ::removed signal is emitted when a camera is un-plugged, or
 
373
   * disabled on the system.
 
374
   **/
 
375
  monitor_signals[REMOVED] = g_signal_new ("removed", G_OBJECT_CLASS_TYPE (klass),
 
376
                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
377
                                           G_STRUCT_OFFSET (CheeseCameraDeviceMonitorClass, removed),
 
378
                                           NULL, NULL,
 
379
                                           g_cclosure_marshal_VOID__STRING,
 
380
                                           G_TYPE_NONE, 1, G_TYPE_STRING);
 
381
 
 
382
  g_type_class_add_private (klass, sizeof (CheeseCameraDeviceMonitorPrivate));
 
383
}
 
384
 
 
385
static void
 
386
cheese_camera_device_monitor_init (CheeseCameraDeviceMonitor *monitor)
 
387
{
 
388
#ifdef HAVE_UDEV
 
389
  CheeseCameraDeviceMonitorPrivate *priv         = CHEESE_CAMERA_DEVICE_MONITOR_GET_PRIVATE (monitor);
 
390
  const gchar *const                subsystems[] = {"video4linux", NULL};
 
391
 
 
392
  priv->client = g_udev_client_new (subsystems);
 
393
  g_signal_connect (G_OBJECT (priv->client), "uevent",
 
394
                    G_CALLBACK (cheese_camera_device_monitor_uevent_cb), monitor);
 
395
#endif /* HAVE_UDEV */
 
396
}
 
397
 
 
398
/**
 
399
 * cheese_camera_device_monitor_new:
 
400
 *
 
401
 * Returns a new #CheeseCameraDeviceMonitor object.
 
402
 *
 
403
 * Return value: a new #CheeseCameraDeviceMonitor object.
 
404
 **/
 
405
CheeseCameraDeviceMonitor *
 
406
cheese_camera_device_monitor_new (void)
 
407
{
 
408
  return g_object_new (CHEESE_TYPE_CAMERA_DEVICE_MONITOR, NULL);
 
409
}
 
410
 
 
411
/*
 
412
 * vim: sw=2 ts=8 cindent noai bs=2
 
413
 */