2
* Copyright © 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
3
* Copyright © 2007,2008 Jaap Haitsma <jaap@haitsma.org>
4
* Copyright © 2007-2009 daniel g. siegel <dgsiegel@gnome.org>
5
* Copyright © 2008 Ryan Zeigler <zeiglerr@gmail.com>
7
* Licensed under the GNU General Public License Version 2
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.
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.
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/>.
24
#include <cheese-config.h>
28
#include <glib/gi18n.h>
31
#include "cheese-camera-device.h"
33
static void cheese_camera_device_initable_iface_init (GInitableIface *iface);
34
static gboolean cheese_camera_device_initable_init (GInitable *initable,
35
GCancellable *cancellable,
38
G_DEFINE_TYPE_WITH_CODE (CheeseCameraDevice, cheese_camera_device, G_TYPE_OBJECT,
39
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
40
cheese_camera_device_initable_iface_init))
42
#define CHEESE_CAMERA_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_CAMERA_DEVICE, \
43
CheeseCameraDevicePrivate))
45
#define CHEESE_CAMERA_DEVICE_ERROR cheese_camera_device_error_quark ()
47
enum CheeseCameraDeviceError
49
CHEESE_CAMERA_DEVICE_ERROR_UNKNOWN,
50
CHEESE_CAMERA_DEVICE_ERROR_NOT_SUPPORTED,
51
CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS
54
GST_DEBUG_CATEGORY (cheese_camera_device_cat);
55
#define GST_CAT_DEFAULT cheese_camera_device_cat
57
static gchar *supported_formats[] = {
63
/* FIXME: make this configurable */
64
#define CHEESE_MAXIMUM_RATE 30 /* fps */
85
GError *construct_error;
86
} CheeseCameraDevicePrivate;
89
cheese_camera_device_error_quark (void)
91
return g_quark_from_static_string ("cheese-camera-device-error-quark");
94
/* CheeseVideoFormat */
96
static CheeseVideoFormat *
97
cheese_video_format_copy (const CheeseVideoFormat *format)
99
return g_slice_dup (CheeseVideoFormat, format);
103
cheese_video_format_free (CheeseVideoFormat *format)
105
if (G_LIKELY (format != NULL))
106
g_slice_free (CheeseVideoFormat, format);
110
cheese_video_format_get_type (void)
112
static GType our_type = 0;
114
if (G_UNLIKELY (our_type == 0))
116
g_boxed_type_register_static ("CheeseVideoFormat",
117
(GBoxedCopyFunc) cheese_video_format_copy,
118
(GBoxedFreeFunc) cheese_video_format_free);
125
compare_formats (gconstpointer a, gconstpointer b)
127
const CheeseVideoFormat *c = a;
128
const CheeseVideoFormat *d = b;
130
/* descending sort for rectangle area */
131
return (d->width * d->height - c->width * c->height);
136
cheese_webcam_device_filter_caps (CheeseCameraDevice *device, const GstCaps *caps, GStrv formats)
138
/* CheeseCameraDevicePrivate *priv =
139
* CHEESE_CAMERA_DEVICE_GET_PRIVATE (device); */
144
filter = gst_caps_new_simple (formats[0],
145
"framerate", GST_TYPE_FRACTION_RANGE,
146
0, 1, CHEESE_MAXIMUM_RATE, 1,
149
for (i = 1; i < g_strv_length (formats); i++)
151
gst_caps_append (filter,
152
gst_caps_new_simple (formats[i],
153
"framerate", GST_TYPE_FRACTION_RANGE,
154
0, 1, CHEESE_MAXIMUM_RATE, 1,
158
allowed = gst_caps_intersect (caps, filter);
160
GST_DEBUG ("Supported caps %" GST_PTR_FORMAT, caps);
161
GST_DEBUG ("Filter caps %" GST_PTR_FORMAT, filter);
162
GST_DEBUG ("Filtered caps %" GST_PTR_FORMAT, allowed);
164
gst_caps_unref (filter);
170
cheese_camera_device_add_format (CheeseCameraDevice *device, CheeseVideoFormat *format)
172
CheeseCameraDevicePrivate *priv =
173
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
176
for (l = priv->formats; l != NULL; l = l->next)
178
CheeseVideoFormat *item = l->data;
179
if ((item != NULL) &&
180
(item->width == format->width) &&
181
(item->height == format->height)) return;
184
GST_INFO ("%dx%d", format->width, format->height);
186
priv->formats = g_list_append (priv->formats, format);
190
free_format_list (CheeseCameraDevice *device)
192
CheeseCameraDevicePrivate *priv =
193
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
197
for (l = priv->formats; l != NULL; l = l->next)
199
g_list_free (priv->formats);
200
priv->formats = NULL;
204
cheese_webcam_device_update_format_table (CheeseCameraDevice *device)
206
CheeseCameraDevicePrivate *priv =
207
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
212
free_format_list (device);
214
num_structures = gst_caps_get_size (priv->caps);
215
for (i = 0; i < num_structures; i++)
217
GstStructure *structure;
218
const GValue *width, *height;
219
structure = gst_caps_get_structure (priv->caps, i);
221
width = gst_structure_get_value (structure, "width");
222
height = gst_structure_get_value (structure, "height");
224
if (G_VALUE_HOLDS_INT (width))
226
CheeseVideoFormat *format = g_new0 (CheeseVideoFormat, 1);
228
gst_structure_get_int (structure, "width", &(format->width));
229
gst_structure_get_int (structure, "height", &(format->height));
230
cheese_camera_device_add_format (device, format);
232
else if (GST_VALUE_HOLDS_INT_RANGE (width))
234
int min_width, max_width, min_height, max_height;
235
int cur_width, cur_height;
237
min_width = gst_value_get_int_range_min (width);
238
max_width = gst_value_get_int_range_max (width);
239
min_height = gst_value_get_int_range_min (height);
240
max_height = gst_value_get_int_range_max (height);
242
cur_width = min_width;
243
cur_height = min_height;
245
/* Gstreamer will sometimes give us a range with min_xxx == max_xxx,
246
* we use <= here (and not below) to make this work */
247
while (cur_width <= max_width && cur_height <= max_height)
249
CheeseVideoFormat *format = g_new0 (CheeseVideoFormat, 1);
251
format->width = cur_width;
252
format->height = cur_height;
254
cheese_camera_device_add_format (device, format);
260
cur_width = max_width;
261
cur_height = max_height;
262
while (cur_width > min_width && cur_height > min_height)
264
CheeseVideoFormat *format = g_new0 (CheeseVideoFormat, 1);
266
format->width = cur_width;
267
format->height = cur_height;
269
cheese_camera_device_add_format (device, format);
277
g_critical ("GValue type %s, cannot be handled for resolution width", G_VALUE_TYPE_NAME (width));
283
cheese_camera_device_get_caps (CheeseCameraDevice *device)
285
CheeseCameraDevicePrivate *priv =
286
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
288
gchar *pipeline_desc;
289
GstElement *pipeline;
290
GstStateChangeReturn ret;
295
pipeline_desc = g_strdup_printf ("%s name=source device=%s ! fakesink",
296
priv->src, priv->device);
297
pipeline = gst_parse_launch (pipeline_desc, &err);
298
if ((pipeline != NULL) && (err == NULL))
300
/* Start the pipeline and wait for max. 10 seconds for it to start up */
301
gst_element_set_state (pipeline, GST_STATE_READY);
302
ret = gst_element_get_state (pipeline, NULL, NULL, 10 * GST_SECOND);
304
/* Check if any error messages were posted on the bus */
305
bus = gst_element_get_bus (pipeline);
306
msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR);
307
gst_object_unref (bus);
309
if ((msg == NULL) && (ret == GST_STATE_CHANGE_SUCCESS))
315
src = gst_bin_get_by_name (GST_BIN (pipeline), "source");
317
GST_LOG ("Device: %s (%s)\n", priv->name, priv->device);
318
pad = gst_element_get_pad (src, "src");
319
caps = gst_pad_get_caps (pad);
320
priv->caps = cheese_webcam_device_filter_caps (device, caps, supported_formats);
321
if (!gst_caps_is_empty (priv->caps))
322
cheese_webcam_device_update_format_table (device);
324
g_set_error_literal (&priv->construct_error,
325
CHEESE_CAMERA_DEVICE_ERROR,
326
CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS,
327
_("Device capabilities not supported"));
331
gst_object_unref (pad);
332
gst_caps_unref (caps);
334
gst_element_set_state (pipeline, GST_STATE_NULL);
335
gst_object_unref (pipeline);
341
g_free (pipeline_desc);
345
cheese_camera_device_constructed (GObject *object)
347
CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
348
CheeseCameraDevicePrivate *priv =
349
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
351
priv->src = (priv->api == 2) ? "v4l2src" : "v4lsrc";
353
cheese_camera_device_get_caps (device);
355
if (G_OBJECT_CLASS (cheese_camera_device_parent_class)->constructed)
356
G_OBJECT_CLASS (cheese_camera_device_parent_class)->constructed (object);
360
cheese_camera_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
362
CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
363
CheeseCameraDevicePrivate *priv =
364
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
369
g_value_set_string (value, priv->name);
372
g_value_set_string (value, priv->device);
375
g_value_set_string (value, priv->id);
378
g_value_set_int (value, priv->api);
381
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
387
cheese_camera_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
389
CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
390
CheeseCameraDevicePrivate *priv =
391
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
398
priv->name = g_value_dup_string (value);
403
priv->id = g_value_dup_string (value);
407
g_free (priv->device);
408
priv->device = g_value_dup_string (value);
411
priv->api = g_value_get_int (value);
414
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
420
cheese_camera_device_finalize (GObject *object)
422
CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
423
CheeseCameraDevicePrivate *priv =
424
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
426
g_free (priv->device);
430
gst_caps_unref (priv->caps);
431
free_format_list (device);
433
G_OBJECT_CLASS (cheese_camera_device_parent_class)->finalize (object);
437
cheese_camera_device_class_init (CheeseCameraDeviceClass *klass)
439
GObjectClass *object_class = G_OBJECT_CLASS (klass);
441
if (cheese_camera_device_cat == NULL)
442
GST_DEBUG_CATEGORY_INIT (cheese_camera_device_cat,
443
"cheese-camera-device",
444
0, "Cheese Camera Device");
446
object_class->finalize = cheese_camera_device_finalize;
447
object_class->get_property = cheese_camera_device_get_property;
448
object_class->set_property = cheese_camera_device_set_property;
449
object_class->constructed = cheese_camera_device_constructed;
451
g_object_class_install_property (object_class, PROP_NAME,
452
g_param_spec_string ("name",
454
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
456
g_object_class_install_property (object_class, PROP_FILE,
457
g_param_spec_string ("device-file",
459
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
461
g_object_class_install_property (object_class, PROP_ID,
462
g_param_spec_string ("device-id",
464
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
466
g_object_class_install_property (object_class, PROP_API,
467
g_param_spec_int ("api", NULL, NULL,
469
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
470
g_type_class_add_private (klass, sizeof (CheeseCameraDevicePrivate));
474
cheese_camera_device_initable_iface_init (GInitableIface *iface)
476
iface->init = cheese_camera_device_initable_init;
480
cheese_camera_device_init (CheeseCameraDevice *device)
482
CheeseCameraDevicePrivate *priv =
483
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
488
priv->name = g_strdup (_("Unknown device"));
489
priv->caps = gst_caps_new_empty ();
491
priv->formats = NULL;
493
priv->construct_error = NULL;
497
cheese_camera_device_initable_init (GInitable *initable,
498
GCancellable *cancellable,
501
CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (initable);
502
CheeseCameraDevicePrivate *priv =
503
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
505
g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (initable), FALSE);
507
if (cancellable != NULL)
509
g_set_error_literal (error,
510
CHEESE_CAMERA_DEVICE_ERROR,
511
CHEESE_CAMERA_DEVICE_ERROR_NOT_SUPPORTED,
512
_("Cancellable initialization not supported"));
516
if (priv->construct_error)
519
*error = g_error_copy (priv->construct_error);
527
cheese_camera_device_new (const gchar *device_id,
528
const gchar *device_file,
529
const gchar *product_name,
533
return CHEESE_CAMERA_DEVICE (g_initable_new (CHEESE_TYPE_CAMERA_DEVICE,
535
"device-id", device_id,
536
"device-file", device_file,
537
"name", product_name,
545
cheese_camera_device_get_format_list (CheeseCameraDevice *device)
547
CheeseCameraDevicePrivate *priv =
548
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
550
return g_list_sort (g_list_copy (priv->formats), compare_formats);
554
cheese_camera_device_get_name (CheeseCameraDevice *device)
556
CheeseCameraDevicePrivate *priv =
557
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
563
cheese_camera_device_get_id (CheeseCameraDevice *device)
565
CheeseCameraDevicePrivate *priv =
566
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
572
cheese_camera_device_get_src (CheeseCameraDevice *device)
574
CheeseCameraDevicePrivate *priv =
575
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
581
cheese_camera_device_get_device_file (CheeseCameraDevice *device)
583
CheeseCameraDevicePrivate *priv =
584
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
590
cheese_camera_device_get_best_format (CheeseCameraDevice *device)
592
CheeseVideoFormat *format = g_boxed_copy (CHEESE_TYPE_VIDEO_FORMAT,
593
cheese_camera_device_get_format_list (device)->data);
595
GST_INFO ("%dx%d", format->width, format->height);
600
cheese_camera_device_get_caps_for_format (CheeseCameraDevice *device,
601
CheeseVideoFormat *format)
603
CheeseCameraDevicePrivate *priv =
604
CHEESE_CAMERA_DEVICE_GET_PRIVATE (device);
605
GstCaps *desired_caps;
606
GstCaps *subset_caps;
609
GST_INFO ("Getting caps for %dx%d", format->width, format->height);
611
desired_caps = gst_caps_new_simple (supported_formats[0],
614
"height", G_TYPE_INT,
618
for (i = 1; i < g_strv_length (supported_formats); i++)
620
gst_caps_append (desired_caps,
621
gst_caps_new_simple (supported_formats[i],
624
"height", G_TYPE_INT,
629
subset_caps = gst_caps_intersect (desired_caps, priv->caps);
630
gst_caps_unref (desired_caps);
632
GST_INFO ("Got %" GST_PTR_FORMAT, subset_caps);