diff -up cheese-2.23.91/src/cheese-webcam.c.orig cheese-2.23.91/src/cheese-webcam.c --- cheese-2.23.91/src/cheese-webcam.c.orig 2008-09-01 20:47:10.000000000 +0200 +++ cheese-2.23.91/src/cheese-webcam.c 2008-09-03 20:27:25.000000000 +0200 @@ -33,6 +33,11 @@ #include #include #include +/* for ioctl query */ +#include +#include +#include +#include #include "cheese-webcam.h" #include "cheese-flash.h" @@ -235,16 +240,13 @@ cheese_webcam_get_video_devices_from_hal { CheeseWebcamPrivate *priv = CHEESE_WEBCAM_GET_PRIVATE (webcam); - int i; - int num_udis; - int num_devices; /* Devices we actually create formats for; can either be the - * number of webcams detected, or 1 if none were. The one - * refers to a fake device so that resolution changing still - * works even if the computer doesn't have a webcam. */ + int i, fd, ok; + int num_udis = 0; char **udis; DBusError error; LibHalContext *hal_ctx; + priv->num_webcam_devices = 0; dbus_error_init (&error); hal_ctx = libhal_ctx_new (); @@ -252,14 +254,14 @@ cheese_webcam_get_video_devices_from_hal { g_error ("error: libhal_ctx_new"); dbus_error_free (&error); - return; + goto fallback; } if (!libhal_ctx_set_dbus_connection (hal_ctx, dbus_bus_get (DBUS_BUS_SYSTEM, &error))) { g_error ("error: libhal_ctx_set_dbus_connection: %s: %s", error.name, error.message); dbus_error_free (&error); - return; + goto fallback; } if (!libhal_ctx_init (hal_ctx, &error)) @@ -271,53 +273,113 @@ cheese_webcam_get_video_devices_from_hal } g_error ("Could not initialise connection to hald.\n" "Normally this means the HAL daemon (hald) is not running or not ready"); - return; + goto fallback; } udis = libhal_find_device_by_capability (hal_ctx, "video4linux", &num_udis, &error); if (dbus_error_is_set (&error)) { - g_error ("error: %s: %s\n", error.name, error.message); + g_error ("error: libhal_find_device_by_capability: %s: %s\n", error.name, error.message); dbus_error_free (&error); - return; + goto fallback; } /* Initialize webcam structures */ + priv->webcam_devices = g_new0 (CheeseWebcamDevice, num_udis); - if (num_udis > 0) - priv->num_webcam_devices = num_devices = num_udis; - else - { - num_devices = 1; - priv->num_webcam_devices = num_udis; /* We don't have any real cameras-- - * this is important when we create - * the pipeline. */ - } - - priv->webcam_devices = g_new0 (CheeseWebcamDevice, num_devices); - for (i = 0; i < num_devices; i++) - { - priv->webcam_devices[i].num_video_formats = 0; - priv->webcam_devices[i].video_formats = g_array_new (FALSE, FALSE, sizeof (CheeseVideoFormat)); - priv->webcam_devices[i].hal_udi = g_strdup (udis[i]); - } - - for (i = 0; i < priv->num_webcam_devices; i++) + for (i = 0; i < num_udis; i++) { char *device; + char *gstreamer_src, *product_name; + struct v4l2_capability v2cap; + struct video_capability v1cap; device = libhal_device_get_property_string (hal_ctx, udis[i], "video4linux.device", &error); - if (dbus_error_is_set (&error)) + if (dbus_error_is_set (&error)) { - g_error ("error: %s: %s\n", error.name, error.message); + g_error ("error geting device for %s: %s: %s\n", udis[i], error.name, error.message); dbus_error_free (&error); - return; + continue; + } + + /* vbi devices support capture capability too, but cannot be used, + so detect them by device name */ + if (strstr(device, "vbi")) + { + g_print ("Skipping vbi device: %s\n", device); + libhal_free_string (device); + continue; + } + + if ((fd = open(device, O_RDONLY | O_NONBLOCK)) < 0) + { + g_error ("Failed to open %s: %s\n", device, strerror(errno)); + libhal_free_string (device); + continue; + } + ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap); + if (ok < 0) { + ok = ioctl (fd, VIDIOCGCAP, &v1cap); + if (ok < 0) { + g_error ("Error while probing v4l capabilities for %s: %s\n", + device, strerror (errno)); + libhal_free_string (device); + close(fd); + continue; + } + g_print ("Detected v4l device: %s\n", v1cap.name); + g_print ("Device type: %d\n", v1cap.type); + gstreamer_src = "v4lsrc"; + product_name = v1cap.name; + } + else + { + guint cap = v2cap.capabilities; + g_print ("Detected v4l2 device: %s\n", v2cap.card); + g_print ("Driver: %s, version: %d\n", v2cap.driver, v2cap.version); + g_print ("Bus info: %s\n", v2cap.bus_info); + g_print ("Capabilities: 0x%08X\n", v2cap.capabilities); + if (!(cap & V4L2_CAP_VIDEO_CAPTURE)) + { + g_print ("Device %s seems to not have the capture capability, (radio tuner?)\n" + "Removing it from device list.\n", device); + libhal_free_string (device); + close(fd); + continue; + } + gstreamer_src = "v4l2src"; + product_name = (char *)v2cap.card; } - priv->webcam_devices[i].video_device = g_strdup (device); + + priv->webcam_devices[priv->num_webcam_devices].hal_udi = g_strdup (udis[i]); + priv->webcam_devices[priv->num_webcam_devices].video_device = g_strdup (device); + priv->webcam_devices[priv->num_webcam_devices].gstreamer_src = g_strdup (gstreamer_src); + priv->webcam_devices[priv->num_webcam_devices].product_name = g_strdup (product_name); + priv->webcam_devices[priv->num_webcam_devices].num_video_formats = 0; + priv->webcam_devices[priv->num_webcam_devices].video_formats = + g_array_new (FALSE, FALSE, sizeof (CheeseVideoFormat)); + priv->num_webcam_devices++; + libhal_free_string (device); + close(fd); } libhal_free_string_array (udis); + + if (priv->num_webcam_devices == 0) + { + /* Create a fake device so that resolution changing stil works even if the + computer doesn't have a webcam. */ +fallback: + if (num_udis == 0) + { + priv->webcam_devices = g_new0 (CheeseWebcamDevice, 1); + } + priv->webcam_devices[0].num_video_formats = 0; + priv->webcam_devices[0].video_formats = + g_array_new (FALSE, FALSE, sizeof (CheeseVideoFormat)); + priv->webcam_devices[0].hal_udi = g_strdup ("cheese_fake_videodevice"); + } } static void @@ -479,19 +541,11 @@ cheese_webcam_get_webcam_device_data (Ch GstStateChangeReturn ret; GstMessage *msg; GstBus *bus; - gboolean pipeline_works = FALSE; int i, j; - static const char *GSTREAMER_VIDEO_SOURCES[] = { - "v4l2src", - "v4lsrc" - }; - - i = 0; - while (!pipeline_works && (i < G_N_ELEMENTS (GSTREAMER_VIDEO_SOURCES))) { pipeline_desc = g_strdup_printf ("%s name=source device=%s ! fakesink", - GSTREAMER_VIDEO_SOURCES[i], + webcam_device->gstreamer_src, webcam_device->video_device); err = NULL; pipeline = gst_parse_launch (pipeline_desc, &err); @@ -513,10 +567,8 @@ cheese_webcam_get_webcam_device_data (Ch char *name; GstCaps *caps; - pipeline_works = TRUE; gst_element_set_state (pipeline, GST_STATE_PAUSED); - webcam_device->gstreamer_src = g_strdup (GSTREAMER_VIDEO_SOURCES[i]); src = gst_bin_get_by_name (GST_BIN (pipeline), "source"); g_object_get (G_OBJECT (src), "device-name", &name, NULL); @@ -524,7 +576,6 @@ cheese_webcam_get_webcam_device_data (Ch name = "Unknown"; g_print ("Detected webcam: %s\n", name); - webcam_device->product_name = g_strdup (name); pad = gst_element_get_pad (src, "src"); caps = gst_pad_get_caps (pad); gst_object_unref (pad); @@ -538,8 +589,8 @@ cheese_webcam_get_webcam_device_data (Ch g_error_free (err); g_free (pipeline_desc); - i++; } + g_print ("device: %s\n", webcam_device->video_device); for (i = 0; i < webcam_device->num_video_formats; i++) {