jueves, julio 03, 2014

De cómo utilicé udev para fijar unos parámetros en una cámara web "Creative vf0070"

Al conectar la cámara web en la computadora, las imágenes que se reproducían en la pantalla se veían muy mal[1]: con mucho brillo y no se podían entender bien.
[1] Utilicé el programa Cheese para poder observar las imágenes.


El programa Cheese tiene unos controles que permiten modificar distintos valores de las imágenes con los que se puede intentar corregir los defectos. Estos controles se alcanzan en las preferencias de la aplicación, en una sección llamada "Imagen". Sin embargo, en mi caso no pude corregir las imágenes con estos controles.


La razón es que estos controles realizan un proceso posterior a la captura de las imágenes y los defectos que tenían las que estaba viendo se debían, supongo, a problemas que sucedían al momento de capturar las imágenes. Es decir, estos controles permiten "editar" las imágenes ya capturadas, como si de una herramienta de edición de imágenes se tratase (como Gimp o PhotoShop). Sin embargo, debía corregir la captura misma de las imágenes para poder apreciar bien las mismas.

Para realizar las correcciones de captura mencionadas, utilicé un programa llamado Video4Linux Control Panel. Para instalarlo, ejecuté el siguiente comando:

$ sudo apt install v4l2ucp

Este programa es unas simple herramienta que te presenta en una interfaz gráfica unos controles que te permiten modificar los parámetros de captura de imágenes de la cámara web.

En mi caso corregí las imágenes modificando el valor de exposición (Exposure) y ganancia (Gain), que son parámetros establecidos en la cámara misma, y también modifiqué el parámetro Gamma y el balance de blancos (White valance), que según indica la aplicación, son parámetros a nivel del software (ver la captura de pantalla). Estas modificaciones las hacía mientras veía los efectos en las imágenes reproducidas por Cheese.


El asunto parecía resuelto hasta que desconecté y conecté de nuevo la cámara. Obtuve el siguiente resultado:


Si comparan los parámetros de las últimas dos capturas de pantalla, pueden observar que los valores etiquetados como "software" permanecieron iguales, pero que la exposición (Exposure) y la ganancia (Gain) cambiaron. Aún más, al observar la última y antepenúltima captura de pantalla, pueden ver que los valores de exposición y ganancia son iguales.

Este fenómeno se repetía una y otra vez cada vez que apagaba la computadora o cambiaba la cámara de una computadora a otra (en cuyo caso, todos los valores se perdían y se establecían a los que observan en la antepenúltima captura de pantalla).

¿Por qué pasa esto?. No lo se. Pero sospecho que los valores que no dicen "software" son valores almacenados directamente en la cámara web, y esta tal vez no esté diseñada con una memoria persistente.

En todo caso, mi interés era que los valores que se establecieran una vez fueran permanentes.

udev al rescate

Al programa Video4Linux Control Panel lo acompaña una pequeña herramienta llamada v4l2ctrl. Este programa permite guardar en un archivo los valores de los parámetros establecidos de la cámara para poder restablecerlos en un momento futuro.

Así, para guardar esos valores, se ejecuta el siguiente comando:

$ v4l2ctrl -s valores

De esta manera, los valores que está utilizando en el momento de ejecutar el comando, son guardados en el archivo "valores".

Entonces, cuando se desee en otro momento establecer esos valores a la cámara, basta con utilizar el mismo comando de la siguiente forma:

$ v4l2ctrl -l valores

La diferencia es la opción -l (del inglés "load" o "cargar")en vez de la opción -s (del inglés "save" o "guardar").

Claro, estar "cargando" la configuración que queremos fijar de manera permanente, cada vez que iniciemos la computadora o cada vez que conectemos la cámara es una situación indeseable.

Lo que hice para lograr el efecto de "persistencia" en la configuración fue configurar la computadora para que cada vez que se detecte que la cámara web se conectó, se ejecute el comando "v4l2ctrl" para que "cargue" un archivo que coloqué en un lugar fijo.

Esto se logra con "udev". Específicamente, con una regla que diga exactamente lo que expliqué: en lo que se detecte la conexión de la cámara web, ejecutar el comando.

Las reglas udev se escriben en un archivo que termine en .rules, que debe estar ubicado en la carpeta /etc/udev/rules.d . Un artículo que utilicé para guiarme en la escritura de las reglas udev fue Writing udev rules por Daniel Drake (dsd). En mi caso, escribí un archivo llamado local.rules con el siguiente contenido:

SYMLINK=="/dev/v4l/by-id/usb-SQ_Tech_CO.__LTD._USB_2.0_PC_camera-video-index0", RUN+="/usr/bin/v4l2ctrl -l /opt/webcam_creative_values"
 
Y luego de reiniciar la máquina[1], cada vez que se detecte la cámara web, automáticamente se cargará la configuración contenida en el archivo /opt/webcam_creative_values . 
[1] Intenté no reiniciarla, reiniciando sólo el servicio udev, pero no me funcionó.

Este archivo webcam_creative_values, se crea previamente con el comando v4l2ctrl y la opción de "guardar", luego de estar conforme con los valores establecidos.

El contenido de mi archivo local.rules representa una regla udev, que está conformada en este caso por una clave de coincidencia ("match key" en inglés) y una asignación.

La clave de coincidencia es:

SYMLINK=="/dev/v4l/by-id/usb-SQ_Tech_CO.__LTD._USB_2.0_PC_camera-video-index0"

Que significa: si el dispositivo tiene el enlace simbólico "/dev/v4l/by-id/usb-Bison_HD_Webcam-video-index0" entonces se ejecutará la siguiente asignación.

La asignación es:

RUN+="/usr/bin/v4l2ctrl -l /opt/webcam_creative_values"

Que significa: a la lista de comandos a ejecutar, añade el siguiente comando: "/usr/bin/v4l2ctrl -l /opt/webcam_creative_values", que es el que carga los valores deseados en la cámara.

¿Cómo supe la ruta dentro de /dev/ de la cámara?

Un poco de cultura general de Linux es suficiente para saber que todos los dispositivos de la computadora están en algún lugar dentro del directorio /dev. Ahí se encuentran subdirectorios para los discos, el ratón, teclado, etc. Incluso, tiene un directorio dedicado a los dispositivos de entrada de video, como la cámara web. Este directorio es /dev/video0. Si hubieran más dispositivos de entrada de video, el cero (0) se cambiaría por un uno (1) para el siguiente dispositivo, un dos (2) para el que le sigue, y así. Ejemplo: /dev/video1, /dev/video2.

udev provee nombres persistentes para los dispositivos, para que no haya duda a la hora de escribir las reglas. Por ejemplo, /dev/video0 es la primera cámara web que conectamos y /dev/video1 es la segunda. Pero si se quiere escribir una regla para una cámara específica (tal marca, tal modelo, etc.), como en mi caso, se puede sacar provecho a los nombres persistentes que genera udev. Ellos están en algún subdirectorio llamado by-id. Para conseguir el nombre persistente de la cámara /dev/video0, por ejemplo, se ejecuta el siguiente comando:

$ udevadm info -q symlink -n /dev/video0

Este comando muestra todos los otros nombres que tiene asignada la cámara en este instante:

v4l/by-id/usb-SQ_Tech_CO.__LTD._USB_2.0_PC_camera-video-index0
v4l/by-path/pci-0000:00:1d.7-usb-0:8:1.0-video-index0

Se utilizaría entonces el que tiene by-id en la regla udev.

Pendiente

Esta solución no está del todo completa. Cada vez que modifique los parámetros de la cámara debo guardarlos con el programa v4l2ctrl en el el directorio /opt/webcam_creative_values, porque así lo establece la regla que yo mismo escribí.

Me gustaría que fuera automático. Como pasa con los otros parámetros de tipo "software": que yo no hago nada, esos valores se mantienen.

Creo que pudiera investigar dos cosas:
  1. ¿Dónde se almacenan los valores de esos parámetros? para ver como forzar la persistencia en ese lugar de los parámetros ganancia y exposición.
  2. ¿Cómo disparar un comando sólo cuando se desconecta un dispositivo?. Tal vez sea posible guardar los valores que están establecidos para la cámara después que se desconecte, sobrescribiendo el archivo en /opt, y logrando que la próxima vez que se conecte la cámara se restauren esos valores.