Update Chinese (Taiwan) translation
[cheese.git] / libcheese / cheese-camera-device.c
blobe994c5f5c1549701634a09bea1c73aa2bdb7eccb
1 /*
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/>.
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <glib.h>
28 #include <glib/gi18n-lib.h>
29 #include <gio/gio.h>
31 #include "cheese-camera-device.h"
33 /**
34 * SECTION:cheese-camera-device
35 * @short_description: Object to represent a video capture device
36 * @stability: Unstable
37 * @include: cheese/cheese-camera-device.h
39 * #CheeseCameraDevice provides an abstraction of a video capture device.
42 static void cheese_camera_device_initable_iface_init (GInitableIface *iface);
43 static gboolean cheese_camera_device_initable_init (GInitable *initable,
44 GCancellable *cancellable,
45 GError **error);
47 #define CHEESE_CAMERA_DEVICE_ERROR cheese_camera_device_error_quark ()
50 * CheeseCameraDeviceError:
51 * @CHEESE_CAMERA_DEVICE_ERROR_UNKNOWN: unknown error
52 * @CHEESE_CAMERA_DEVICE_ERROR_NOT_SUPPORTED: cancellation of device
53 * initialisation was requested, but is not supported
54 * @CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS: unsupported GStreamer
55 * capabilities
56 * @CHEESE_CAMERA_DEVICE_ERROR_FAILED_INITIALIZATION: the device failed to
57 * initialize for capability probing
59 * Errors that can occur during device initialization.
61 enum CheeseCameraDeviceError
63 CHEESE_CAMERA_DEVICE_ERROR_UNKNOWN,
64 CHEESE_CAMERA_DEVICE_ERROR_NOT_SUPPORTED,
65 CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS,
66 CHEESE_CAMERA_DEVICE_ERROR_FAILED_INITIALIZATION
69 GST_DEBUG_CATEGORY (cheese_camera_device_cat);
70 #define GST_CAT_DEFAULT cheese_camera_device_cat
72 static const gchar const *supported_formats[] = {
73 "video/x-raw",
74 NULL
77 /* FIXME: make this configurable */
79 * CHEESE_MAXIMUM_RATE:
81 * The maximum framerate, in frames per second.
83 static const guint CHEESE_MAXIMUM_RATE = 30;
85 enum
87 PROP_0,
88 PROP_NAME,
89 PROP_DEVICE,
90 PROP_LAST
93 static GParamSpec *properties[PROP_LAST];
95 typedef struct
97 GstDevice *device;
98 gchar *name;
99 GstCaps *caps;
100 GList *formats; /* list members are CheeseVideoFormatFull structs. */
102 GError *construct_error;
103 } CheeseCameraDevicePrivate;
105 G_DEFINE_TYPE_WITH_CODE (CheeseCameraDevice, cheese_camera_device,
106 G_TYPE_OBJECT,
107 G_ADD_PRIVATE (CheeseCameraDevice)
108 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
109 cheese_camera_device_initable_iface_init))
112 * This is our private version of CheeseVideoFormat, with extra fields added
113 * at the end. IMPORTANT the first fields *must* be kept in sync with the
114 * public CheeseVideoFormat, since in various places we cast pointers to
115 * CheeseVideoFormatFull to CheeseVideoFormat.
117 typedef struct
119 /* CheeseVideoFormat members keep synced with cheese-camera-device.h! */
120 gint width;
121 gint height;
122 /*< private >*/
123 gint fr_numerator;
124 gint fr_denominator;
125 } CheeseVideoFormatFull;
127 GQuark cheese_camera_device_error_quark (void);
129 GQuark
130 cheese_camera_device_error_quark (void)
132 return g_quark_from_static_string ("cheese-camera-device-error-quark");
135 /* CheeseVideoFormat */
137 static CheeseVideoFormat *
138 cheese_video_format_copy (const CheeseVideoFormat *format)
140 return g_slice_dup (CheeseVideoFormat, format);
143 static void
144 cheese_video_format_free (CheeseVideoFormat *format)
146 if (G_LIKELY (format != NULL))
147 g_slice_free (CheeseVideoFormat, format);
150 G_DEFINE_BOXED_TYPE (CheeseVideoFormat, cheese_video_format,
151 cheese_video_format_copy, cheese_video_format_free)
153 /* the rest */
155 static gint
156 compare_formats (gconstpointer a, gconstpointer b)
158 const CheeseVideoFormatFull *c = a;
159 const CheeseVideoFormatFull *d = b;
161 /* descending sort for rectangle area */
162 return (d->width * d->height - c->width * c->height);
166 * cheese_camera_device_filter_caps:
167 * @device: the #CheeseCameraDevice
168 * @caps: the #GstCaps that the device supports
169 * @formats: an array of strings of video formats, in the form axb, where a and
170 * b are in units of pixels
172 * Filter the supplied @caps with %CHEESE_MAXIMUM_RATE to only allow @formats
173 * which can reach the desired framerate.
175 * Returns: the filtered #GstCaps
177 static GstCaps *
178 cheese_camera_device_filter_caps (CheeseCameraDevice *device,
179 GstCaps *caps,
180 const gchar const *formats[])
182 GstCaps *filter;
183 GstCaps *allowed;
184 gsize i;
186 filter = gst_caps_new_empty ();
188 for (i = 0; formats[i] != NULL; i++)
190 gst_caps_append (filter,
191 gst_caps_new_simple (formats[i],
192 "framerate", GST_TYPE_FRACTION_RANGE,
193 0, 1, CHEESE_MAXIMUM_RATE, 1,
194 NULL));
197 allowed = gst_caps_intersect (caps, filter);
199 GST_DEBUG ("Supported caps %" GST_PTR_FORMAT, caps);
200 GST_DEBUG ("Filter caps %" GST_PTR_FORMAT, filter);
201 GST_DEBUG ("Filtered caps %" GST_PTR_FORMAT, allowed);
203 gst_caps_unref (filter);
205 return allowed;
209 * cheese_camera_device_get_highest_framerate:
210 * @framerate: a #GValue holding a framerate cap
211 * @numerator: destination to store the numerator of the highest rate
212 * @denominator: destination to store the denominator of the highest rate
214 * Get the numerator and denominator for the highest framerate stored in
215 * a framerate cap.
217 * Note this function does not handle framerate ranges, if @framerate
218 * contains a range it will return 0/0 as framerate
220 static void
221 cheese_camera_device_get_highest_framerate (const GValue *framerate,
222 gint *numerator, gint *denominator)
224 *numerator = 0;
225 *denominator = 0;
227 if (GST_VALUE_HOLDS_FRACTION (framerate))
229 *numerator = gst_value_get_fraction_numerator (framerate);
230 *denominator = gst_value_get_fraction_denominator (framerate);
232 else if (GST_VALUE_HOLDS_ARRAY (framerate))
234 float curr, highest = 0;
235 guint i, size = gst_value_array_get_size (framerate);
237 for (i = 0; i < size; i++)
239 const GValue *val = gst_value_array_get_value (framerate, i);
241 if (!GST_VALUE_HOLDS_FRACTION (val) ||
242 gst_value_get_fraction_denominator (val) == 0) {
243 continue;
246 curr = (float)gst_value_get_fraction_numerator (val) /
247 (float)gst_value_get_fraction_denominator (val);
249 if (curr > highest && curr <= CHEESE_MAXIMUM_RATE)
251 highest = curr;
252 *numerator = gst_value_get_fraction_numerator (val);
253 *denominator = gst_value_get_fraction_denominator (val);
257 else if (GST_VALUE_HOLDS_LIST (framerate))
259 float curr, highest = 0;
260 guint i, size = gst_value_list_get_size (framerate);
262 for (i = 0; i < size; i++)
264 const GValue *val = gst_value_list_get_value(framerate, i);
266 if (!GST_VALUE_HOLDS_FRACTION (val) ||
267 gst_value_get_fraction_denominator (val) == 0)
269 continue;
272 curr = (float)gst_value_get_fraction_numerator (val) /
273 (float)gst_value_get_fraction_denominator (val);
275 if (curr > highest && curr <= CHEESE_MAXIMUM_RATE)
277 highest = curr;
278 *numerator = gst_value_get_fraction_numerator (val);
279 *denominator = gst_value_get_fraction_denominator (val);
283 else if (GST_VALUE_HOLDS_FRACTION_RANGE (framerate))
285 const GValue *val = gst_value_get_fraction_range_max (framerate);
287 if (GST_VALUE_HOLDS_FRACTION (val))
289 *numerator = gst_value_get_fraction_numerator (val);
290 *denominator = gst_value_get_fraction_denominator (val);
296 * cheese_camera_device_format_update_framerate:
297 * @format: the #CheeseVideoFormatFull to update the framerate of
298 * @framerate: a #GValue holding a framerate cap
300 * This function updates the framerate in @format with the highest framerate
301 * from @framerate, if @framerate contains a framerate higher then the
302 * framerate currently stored in @format.
304 static void
305 cheese_camera_device_format_update_framerate (CheeseVideoFormatFull *format,
306 const GValue *framerate)
308 float high, curr = (float)format->fr_numerator / format->fr_denominator;
309 gint high_numerator, high_denominator;
311 cheese_camera_device_get_highest_framerate (framerate, &high_numerator,
312 &high_denominator);
313 if (high_denominator == 0)
314 return;
316 high = (float)high_numerator / (float)high_denominator;
318 if (high > curr) {
319 format->fr_numerator = high_numerator;
320 format->fr_denominator = high_denominator;
321 GST_INFO ("%dx%d new framerate %d/%d", format->width, format->height,
322 format->fr_numerator, format->fr_denominator);
327 * cheese_camera_device_find_full_format:
328 * @device: a #CheeseCameraDevice
329 * @format: #CheeseVideoFormat to find the matching #CheeseVideoFormatFull for
331 * Find a #CheeseVideoFormatFull matching the passed in #CheeseVideoFormat.
333 static CheeseVideoFormatFull *
334 cheese_camera_device_find_full_format (CheeseCameraDevice *device,
335 CheeseVideoFormat* format)
337 CheeseCameraDevicePrivate *priv;
338 GList *l;
340 priv = cheese_camera_device_get_instance_private (device);
342 for (l = priv->formats; l != NULL; l = g_list_next (l))
344 CheeseVideoFormatFull *item = l->data;
346 if ((item != NULL) &&
347 (item->width == format->width) && (item->height == format->height))
349 return item;
353 return NULL;
357 * cheese_camera_device_add_format:
358 * @device: a #CheeseCameraDevice
359 * @format: the #CheeseVideoFormatFull to add
361 * Add the supplied @format to the list of formats supported by the @device.
363 static void
364 cheese_camera_device_add_format (CheeseCameraDevice *device,
365 CheeseVideoFormatFull *format,
366 const GValue *framerate)
368 CheeseCameraDevicePrivate *priv;
369 CheeseVideoFormatFull *existing;
371 priv = cheese_camera_device_get_instance_private (device);
372 existing = cheese_camera_device_find_full_format (device,
373 (CheeseVideoFormat *)format);
375 if (existing)
377 g_slice_free (CheeseVideoFormatFull, format);
378 cheese_camera_device_format_update_framerate (existing, framerate);
379 return;
382 cheese_camera_device_get_highest_framerate (framerate, &format->fr_numerator,
383 &format->fr_denominator);
384 GST_INFO ("%dx%d framerate %d/%d", format->width, format->height,
385 format->fr_numerator, format->fr_denominator);
387 priv->formats = g_list_insert_sorted (priv->formats, format,
388 compare_formats);
392 * free_format_list_foreach:
393 * @data: the #CheeseVideoFormatFull to free
395 * Free the individual #CheeseVideoFormatFull.
397 static void
398 free_format_list_foreach (gpointer data)
400 g_slice_free (CheeseVideoFormatFull, data);
404 * free_format_list:
405 * @device: a #CheeseCameraDevice
407 * Free the list of video formats for the @device.
409 static void
410 free_format_list (CheeseCameraDevice *device)
412 CheeseCameraDevicePrivate *priv;
414 priv = cheese_camera_device_get_instance_private (device);
416 g_list_free_full (priv->formats, free_format_list_foreach);
417 priv->formats = NULL;
421 * cheese_camera_device_update_format_table:
422 * @device: a #CheeseCameraDevice
424 * Clear the current list of video formats supported by the @device and create
425 * it anew.
427 static void
428 cheese_camera_device_update_format_table (CheeseCameraDevice *device)
430 CheeseCameraDevicePrivate *priv;
432 guint i;
433 guint num_structures;
435 free_format_list (device);
437 priv = cheese_camera_device_get_instance_private (device);
438 num_structures = gst_caps_get_size (priv->caps);
439 for (i = 0; i < num_structures; i++)
441 GstStructure *structure;
442 const GValue *width, *height, *framerate;
443 structure = gst_caps_get_structure (priv->caps, i);
445 width = gst_structure_get_value (structure, "width");
446 height = gst_structure_get_value (structure, "height");
447 framerate = gst_structure_get_value (structure, "framerate");
449 if (G_VALUE_HOLDS_INT (width))
451 CheeseVideoFormatFull *format = g_slice_new0 (CheeseVideoFormatFull);
453 gst_structure_get_int (structure, "width", &(format->width));
454 gst_structure_get_int (structure, "height", &(format->height));
455 cheese_camera_device_add_format (device, format, framerate);
457 else if (GST_VALUE_HOLDS_INT_RANGE (width))
459 gint min_width, max_width, min_height, max_height;
460 gint cur_width, cur_height;
462 min_width = gst_value_get_int_range_min (width);
463 max_width = gst_value_get_int_range_max (width);
464 min_height = gst_value_get_int_range_min (height);
465 max_height = gst_value_get_int_range_max (height);
467 /* Some devices report a very small min_width / height down to reporting
468 * 0x0 as minimum resolution, which causes an infinte loop below, limit
469 * these to something reasonable. */
470 if (min_width < 160)
471 min_width = 160;
472 if (min_height < 120)
473 min_height = 120;
475 if (max_width > 5120)
476 max_width = 5120;
477 if (max_height > 3840)
478 max_height = 3840;
480 cur_width = min_width;
481 cur_height = min_height;
483 /* Gstreamer will sometimes give us a range with min_xxx == max_xxx,
484 * we use <= here (and not below) to make this work */
485 while (cur_width <= max_width && cur_height <= max_height)
487 CheeseVideoFormatFull *format = g_slice_new0 (CheeseVideoFormatFull);
489 /* Gstreamer wants resolutions for YUV formats where the width is
490 * a multiple of 8, and the height is a multiple of 2 */
491 format->width = cur_width & ~7;
492 format->height = cur_height & ~1;
494 cheese_camera_device_add_format (device, format, framerate);
496 cur_width *= 2;
497 cur_height *= 2;
500 cur_width = max_width;
501 cur_height = max_height;
502 while (cur_width > min_width && cur_height > min_height)
504 CheeseVideoFormatFull *format = g_slice_new0 (CheeseVideoFormatFull);
506 /* Gstreamer wants resolutions for YUV formats where the width is
507 * a multiple of 8, and the height is a multiple of 2 */
508 format->width = cur_width & ~7;
509 format->height = cur_height & ~1;
511 cheese_camera_device_add_format (device, format, framerate);
513 cur_width /= 2;
514 cur_height /= 2;
517 else
519 g_critical ("GValue type %s, cannot be handled for resolution width", G_VALUE_TYPE_NAME (width));
525 * cheese_camera_device_get_caps:
526 * @device: a #CheeseCameraDevice
528 * Probe the #GstCaps that the @device supports.
530 static void
531 cheese_camera_device_get_caps (CheeseCameraDevice *device)
533 CheeseCameraDevicePrivate *priv;
534 GstCaps *caps;
536 priv = cheese_camera_device_get_instance_private (device);
538 caps = gst_device_get_caps (priv->device);
539 if (caps == NULL)
540 caps = gst_caps_new_empty_simple ("video/x-raw");
542 gst_caps_unref (priv->caps);
543 priv->caps = cheese_camera_device_filter_caps (device, caps, supported_formats);
545 if (!gst_caps_is_empty (priv->caps))
546 cheese_camera_device_update_format_table (device);
547 else
549 g_set_error_literal (&priv->construct_error,
550 CHEESE_CAMERA_DEVICE_ERROR,
551 CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS,
552 _("Device capabilities not supported"));
554 gst_caps_unref (caps);
557 static void
558 cheese_camera_device_constructed (GObject *object)
560 CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
562 cheese_camera_device_get_caps (device);
564 if (G_OBJECT_CLASS (cheese_camera_device_parent_class)->constructed)
565 G_OBJECT_CLASS (cheese_camera_device_parent_class)->constructed (object);
568 static void
569 cheese_camera_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
571 CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
572 CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device);
574 switch (prop_id)
576 case PROP_NAME:
577 g_value_set_string (value, priv->name);
578 break;
579 case PROP_DEVICE:
580 g_value_set_object (value, priv->device);
581 break;
582 default:
583 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
584 break;
588 static void
589 cheese_camera_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
591 CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
592 CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device);
594 switch (prop_id)
596 case PROP_NAME:
597 g_free (priv->name);
598 priv->name = g_value_dup_string (value);
599 break;
600 case PROP_DEVICE:
601 if (priv->device)
602 g_object_unref (priv->device);
603 priv->device = g_value_dup_object (value);
604 g_free (priv->name);
605 priv->name = gst_device_get_display_name (priv->device);
606 break;
607 default:
608 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
609 break;
613 static void
614 cheese_camera_device_finalize (GObject *object)
616 CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object);
617 CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device);
619 g_object_unref (priv->device);
620 g_free (priv->name);
622 gst_caps_unref (priv->caps);
623 free_format_list (device);
625 G_OBJECT_CLASS (cheese_camera_device_parent_class)->finalize (object);
628 static void
629 cheese_camera_device_class_init (CheeseCameraDeviceClass *klass)
631 GObjectClass *object_class = G_OBJECT_CLASS (klass);
633 if (cheese_camera_device_cat == NULL)
634 GST_DEBUG_CATEGORY_INIT (cheese_camera_device_cat,
635 "cheese-camera-device",
636 0, "Cheese Camera Device");
638 object_class->finalize = cheese_camera_device_finalize;
639 object_class->get_property = cheese_camera_device_get_property;
640 object_class->set_property = cheese_camera_device_set_property;
641 object_class->constructed = cheese_camera_device_constructed;
644 * CheeseCameraDevice:name:
646 * Human-readable name of the video capture device, for display to the user.
648 properties[PROP_NAME] = g_param_spec_string ("name",
649 "Name of the device",
650 "Human-readable name of the video capture device",
651 NULL,
652 G_PARAM_READWRITE |
653 G_PARAM_CONSTRUCT_ONLY |
654 G_PARAM_STATIC_STRINGS);
657 * CheeseCameraDevice:device:
659 * GStreamer device object of the video capture device.
661 properties[PROP_DEVICE] = g_param_spec_object ("device",
662 "Device",
663 "The GStreamer device object of the video capture device",
664 GST_TYPE_DEVICE,
665 G_PARAM_READWRITE |
666 G_PARAM_CONSTRUCT_ONLY |
667 G_PARAM_STATIC_STRINGS);
669 g_object_class_install_properties (object_class, PROP_LAST, properties);
672 static void
673 cheese_camera_device_initable_iface_init (GInitableIface *iface)
675 iface->init = cheese_camera_device_initable_init;
678 static void
679 cheese_camera_device_init (CheeseCameraDevice *device)
681 CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device);
683 priv->name = g_strdup (_("Unknown device"));
684 priv->caps = gst_caps_new_empty ();
687 static gboolean
688 cheese_camera_device_initable_init (GInitable *initable,
689 GCancellable *cancellable,
690 GError **error)
692 CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (initable);
693 CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device);
695 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (initable), FALSE);
697 if (cancellable != NULL)
699 g_set_error_literal (error,
700 CHEESE_CAMERA_DEVICE_ERROR,
701 CHEESE_CAMERA_DEVICE_ERROR_NOT_SUPPORTED,
702 _("Cancellable initialization not supported"));
703 return FALSE;
706 if (priv->construct_error)
708 if (error)
709 *error = g_error_copy (priv->construct_error);
710 return FALSE;
713 return TRUE;
716 /* public methods */
719 * cheese_camera_device_new:
720 * @device: The GStreamer the device, as supplied by GstDeviceMonitor
721 * @error: a location to store errors
723 * Tries to create a new #CheeseCameraDevice with the supplied device. If
724 * construction fails, %NULL is returned, and @error is set.
726 * Returns: a new #CheeseCameraDevice, or %NULL
728 CheeseCameraDevice *
729 cheese_camera_device_new (GstDevice *device,
730 GError **error)
732 return CHEESE_CAMERA_DEVICE (g_initable_new (CHEESE_TYPE_CAMERA_DEVICE,
733 NULL, error,
734 "device", device,
735 NULL));
739 * cheese_camera_device_get_format_list:
740 * @device: a #CheeseCameraDevice
742 * Get the sorted list of #CheeseVideoFormat that the @device supports.
744 * Returns: (element-type Cheese.VideoFormat) (transfer container): list of
745 * #CheeseVideoFormat
747 GList *
748 cheese_camera_device_get_format_list (CheeseCameraDevice *device)
750 CheeseCameraDevicePrivate *priv;
752 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL);
754 priv = cheese_camera_device_get_instance_private (device);
756 return g_list_copy (priv->formats);
760 * cheese_camera_device_get_name:
761 * @device: a #CheeseCameraDevice
763 * Get a human-readable name for the device, as reported by udev, which is
764 * suitable for display to a user.
766 * Returns: (transfer none): the human-readable name of the video capture device
768 const gchar *
769 cheese_camera_device_get_name (CheeseCameraDevice *device)
771 CheeseCameraDevicePrivate *priv;
773 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL);
775 priv = cheese_camera_device_get_instance_private (device);
777 return priv->name;
781 * cheese_camera_device_get_src:
782 * @device: a #CheeseCameraDevice
784 * Get the source GStreamer element for the @device.
786 * Returns: (transfer full): the source GStreamer element
788 GstElement *
789 cheese_camera_device_get_src (CheeseCameraDevice *device)
791 CheeseCameraDevicePrivate *priv;
793 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL);
795 priv = cheese_camera_device_get_instance_private (device);
797 return gst_device_create_element (priv->device, NULL);
801 * cheese_camera_device_get_best_format:
802 * @device: a #CheeseCameraDevice
804 * Get the #CheeseVideoFormat with the highest resolution with a width greater
805 * than 640 pixels and a framerate of greater than 15 FPS for this @device. If
806 * no such format is found, get the highest available resolution instead.
808 * Returns: (transfer full): the highest-resolution supported
809 * #CheeseVideoFormat
811 CheeseVideoFormat *
812 cheese_camera_device_get_best_format (CheeseCameraDevice *device)
814 CheeseCameraDevicePrivate *priv;
815 CheeseVideoFormatFull *format = NULL;
816 GList *l;
818 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL);
820 priv = cheese_camera_device_get_instance_private (device);
822 /* Check for the highest resolution with width >= 640 and FPS >= 15. */
823 for (l = priv->formats; l != NULL; l = g_list_next (l))
825 CheeseVideoFormatFull *item = l->data;
826 float frame_rate = (float)item->fr_numerator
827 / (float)item->fr_denominator;
829 if (item->width >= 640 && frame_rate >= 15)
831 format = item;
832 break;
836 /* Else simply return the highest resolution. */
837 if (!format)
839 format = priv->formats->data;
842 GST_INFO ("%dx%d@%d/%d", format->width, format->height,
843 format->fr_numerator, format->fr_denominator);
845 return g_boxed_copy (CHEESE_TYPE_VIDEO_FORMAT, format);
848 static GstCaps *
849 cheese_camera_device_format_to_caps (const char *media_type,
850 CheeseVideoFormatFull *format)
852 if (format->fr_numerator != 0 && format->fr_denominator != 0)
854 return gst_caps_new_simple (media_type,
855 "framerate", GST_TYPE_FRACTION,
856 format->fr_numerator, format->fr_denominator,
857 "width", G_TYPE_INT, format->width,
858 "height", G_TYPE_INT, format->height, NULL);
860 else
862 return gst_caps_new_simple (media_type,
863 "width", G_TYPE_INT, format->width,
864 "height", G_TYPE_INT, format->height, NULL);
869 * cheese_camera_device_get_caps_for_format:
870 * @device: a #CheeseCameraDevice
871 * @format: a #CheeseVideoFormat
873 * Get the #GstCaps for the given @format on the @device.
875 * Returns: (transfer full): the #GstCaps for the given @format
877 GstCaps *
878 cheese_camera_device_get_caps_for_format (CheeseCameraDevice *device,
879 CheeseVideoFormat *format)
881 CheeseCameraDevicePrivate *priv;
882 CheeseVideoFormatFull *full_format;
883 GstCaps *desired_caps;
884 GstCaps *subset_caps;
885 gsize i;
887 g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL);
889 full_format = cheese_camera_device_find_full_format (device, format);
891 if (!full_format)
893 GST_INFO ("Getting caps for %dx%d: no such format!",
894 format->width, format->height);
895 return gst_caps_new_empty ();
898 GST_INFO ("Getting caps for %dx%d @ %d/%d fps",
899 full_format->width, full_format->height,
900 full_format->fr_numerator, full_format->fr_denominator);
902 desired_caps = gst_caps_new_empty ();
904 for (i = 0; supported_formats[i] != NULL; i++)
906 gst_caps_append (desired_caps,
907 cheese_camera_device_format_to_caps (supported_formats[i],
908 full_format));
911 priv = cheese_camera_device_get_instance_private (device);
912 subset_caps = gst_caps_intersect (desired_caps, priv->caps);
913 subset_caps = gst_caps_simplify (subset_caps);
914 gst_caps_unref (desired_caps);
916 GST_INFO ("Got %" GST_PTR_FORMAT, subset_caps);
918 return subset_caps;