miércoles, 30 de diciembre de 2009

uvc_video_resume = resumir el vídeo


Continuemos estudiando como resumir o continuar el flujo de vídeo descrito en la función uvc_video_resume:


/*
 * Reconfigure the video interface and restart streaming if it was enabled
 * before suspend.
 *
 * If an error occurs, disable the video queue. This will wake all pending
 * buffers, making sure userspace applications are notified of the problem
 * instead of waiting forever.
 */
int uvc_video_resume(struct uvc_streaming *stream)
{
int ret;

stream->frozen = 0;

ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0) {
uvc_queue_enable(&stream->queue, 0);
return ret;
}

if (!uvc_queue_streaming(&stream->queue))
return 0;

ret = uvc_init_video(stream, GFP_NOIO);
if (ret < 0)
uvc_queue_enable(&stream->queue, 0);

return ret;
}


Y ahora voy a comentar el código para hacerlo más legible:

/**
 * uvc_video_resume - Reconfigure the video interface and restart streaming if
 * it was enabled before suspend.
 * @stream: the stream that will be resumed
 *
 * If an error occurs, disable the video queue. This will wake all pending
 * buffers, making sure userspace applications are notified of the problem
 * instead of waiting forever.
 */
int uvc_video_resume(struct uvc_streaming *stream)
{
int ret;

        //  It could be interesting to compare if it was frozen before with a
        //  if (stream->frozen == 1)
        //    return "?";
stream->frozen = 0;  // stream knows if it's frozen

        //  uvc_commit_video will overwrite controls of our stream
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0) {
                //  It will cancel the queue, put it in a IDLE state and delete
                //  the streaming label from queue flag
uvc_queue_enable(&stream->queue, 0);
return ret;
}

        //  if queue is not streaming
if (!uvc_queue_streaming(&stream->queue))
return 0;

        //  if queue is streaming we have to init video
        //  payload can be put in a packet?
ret = uvc_init_video(stream, GFP_NOIO);
if (ret < 0)
                //  We need to enable the queue of @stream
uvc_queue_enable(&stream->queue, 0);

return ret;
}


Además para comprender bien la continuación de la captura de vídeo hay que estudiar cómo funciona las colas (que he tenido que comentar parte de su código para entenderlo completamente), pero eso ya es un poco más difícil de entender. En otro artículo lo comentaré.

lunes, 28 de diciembre de 2009

Los vectores


En algunos momentos tenemos que manejar una lista de cosas, eso implica un orden y luego hay que seguirlo. Lo más natural sería lo ilustrado arriba, primero viene el elemento 1, luego el 2, ... y para terminar el último.



Pero los ordenadores "prefieren" empezar en 0 y además que sean nombres cortos por ejemplo d, por lo que el d0 sería el elemento 1.



Además también es muy común que el orden vaya al revés, es decir que los dígitos más importantes vayan antes. Esto sucede como en las matemáticas: centenas, decenas y unidades, las centenas van delante porque las centenas son más importantes que las decenas y estas a su vez preceden a las unidades porque son más importantes que ellas.


Algo similar me sucede a mi con le código de linux-uvc, que hay veces que toca trabajar con máscaras de bits y hay que tener mucho cuidado con el orden y que significa cada elemento o dígito de la máscara.

lunes, 14 de diciembre de 2009

Calculando mi primer parche


Como visteis he comentado un poco el código de linux-uvc y es que Laurent Pinchart no suele ser comentar mucho (el mantenedor de linux-uvc).

Así que me decido a calcular mi primer parche con esos comentarios, pero antes cabe exponer que es un parche.

Un parche es un fichero de texto que contiene la diferencia al estilo del juego de las diferencias. Las diferencias van precedidas con signos negativos y positivos para saber que se quita y que se pone de una versión a otra.

En el ejemplo que os he puesto encima, el parche entre los dos dibujos sería del estilo de: redondea un poco el borde del cuadrado más exterior y convierte en círculo el cuadrado más interior.

En el ejemplo de uvc_video_suspend sería:
--- /home/palmax/palmax-uvc/uvc/uvc_video.c     2009-12-14 17:35:53.000000000 +0100
+++ /home/palmax/palmax-uvc/palmax/palmax-mod/uvc_video.c       2009-12-14 17:41:10.000000000 +0100
@@ -1031,8 +1031,9 @@ static int uvc_init_video(struct uvc_str
  * Suspend/resume
  */

-/*
- * Stop streaming without disabling the video queue.
+/**
+ * uvc_video_suspend - Stop streaming without disabling the video queue.
+ * @stream: the stream that will be suspended
  *
  * To let userspace applications resume without trouble, we must not touch the
  * video buffers in any way. We mark the device as frozen to make sure the URB
@@ -1040,11 +1041,12 @@ static int uvc_init_video(struct uvc_str
  */
 int uvc_video_suspend(struct uvc_streaming *stream)
 {
-       if (!uvc_queue_streaming(&stream->queue))
+       if (!uvc_queue_streaming(&stream->queue))  // if queue is STREAMING
                return 0;

-       stream->frozen = 1;
-       uvc_uninit_video(stream, 0);
+       stream->frozen = 1;  //  uvc_video_device knowns if it's frozen or not
+       uvc_uninit_video(stream, 0);  //  it will kill all URBs and free them
+        //  it will alternate to the 0 alternative setting
        usb_set_interface(stream->dev->udev, stream->intfnum, 0);
        return 0;
 }

Arriba indica de que dos ficheros es la diferencia y desde que línea, para que así luego se pueda obtener el segundo desde el primero y el parche.


Lo he generado como se explica en el libro "Understanding the Linux Virtual Memory Manager". En este caso ha bastado con:
diff -up ~/palmax-uvc/uvc/uvc_video.c ~/palmax-uvc/palmax/palmax-mod/uvc_video.c > patches/uvc_video.c.patch

uvc_video_suspend



Ahora vamos a estudiar uvc_video_suspend:
/* --------------------------------------------------------------------------
 * Suspend/resume
 */

/*
 * Stop streaming without disabling the video queue.
 *
 * To let userspace applications resume without trouble, we must not touch the
 * video buffers in any way. We mark the device as frozen to make sure the URB
 * completion handler won't try to cancel the queue when we kill the URBs.
 */
int uvc_video_suspend(struct uvc_streaming *stream)
{
    if (!uvc_queue_streaming(&stream->queue))
        return 0;

    stream->frozen = 1;
    uvc_uninit_video(stream, 0);
    usb_set_interface(stream->dev->udev, stream->intfnum, 0);
    return 0;
}


Ahora voy a ir comentándolo para hacerlo más legible:
/* --------------------------------------------------------------------------
 * Suspend/resume
 */

/**
 * uvc_video_suspend - Stop streaming without disabling the video queue.
 * @stream: the stream that will be suspended
 *
 * To let userspace applications resume without trouble, we must not touch the
 * video buffers in any way. We mark the device as frozen to make sure the URB
 * completion handler won't try to cancel the queue when we kill the URBs.
 */
int uvc_video_suspend(struct uvc_streaming *stream)
{
    if (!uvc_queue_streaming(&stream->queue))  // if queue is STREAMING
        return 0;

    stream->frozen = 1;  //  uvc_video_device knowns if it's frozen or not
    uvc_uninit_video(stream, 0);  //  it will kill all URBs and free them
        //  it will alternate to the 0 alternative setting
    usb_set_interface(stream->dev->udev, stream->intfnum, 0);
    return 0;
}


No es muy complejo, pero es curioso que exista una alternativa de configuración número 0 que se use en este caso.

Estudiando cómo se suspenden y resumen los flujos de vídeo



Como vimos, el primer paso sería suspender el flujo de vídeo para comenzar nuestra captura de la foto fija.

Para realizar este objetivo, el código de linux-uvc trae dos funciones muy interesantes: uvc_video_suspend y uvc_video_resume.

En próximos artículos explicaré como funcionan.

jueves, 3 de diciembre de 2009

Diagrama de secuencia del método 2 de Imágenes Fijas



Como base para estudiar el método 2 de Imágenes Fijas hice un diagrama de secuencia. Si bien no es 100% acorde a lo que se refiere un diagrama de secuencia, ya que utilizo objetos distintos cuando simplemente son subfunciones, expone los pasos que debe hacerse de una forma muy sencilla y eficaz.

Este diagrama lo he creado a partir de lo expuesto en la especificación de los dispositivos de la clase de vídeo USB (USB Video Class o directamente UVC) y utilizando el programa Umbrello.

Enlaces

Como hace mucho que no ponía nada, hoy he cambiado el diseño del blog por uno más amigable. Además he puesto un montón de enlaces interesantes, bien porque traten el tema de los controladores en Linux o bien porque hacen referencia a UVC.

Estos enlaces creo que pudieran resultar de gran interés para entender las entradas que escriba, así que los tenéis a un simple ¡click!