Mostrando entradas con la etiqueta Linux-UVC. Mostrar todas las entradas
Mostrando entradas con la etiqueta Linux-UVC. Mostrar todas las entradas

viernes, 21 de mayo de 2010

Detección de las cabeceras de los flujos de vídeo que son capaces de capturar imágenes fijas

uvc_device = uvc_streaming + ....
uvc_straming = uvc_straming_header + ...

uvc_straming_header = bStillCaptureMethod + ... 
Detalle de algunas estructuras de linux-uvc


He realizado un pequeño ejemplo de como podría detectarse las cabeceras de los flujos de vídeo que son capaces de capturar imágenes fijas. Este ejemplo es similar a la función uvc_stream_by_id.

Digo ejemplo, ya que no sé como pudiera abrir la estructura
uvc_device, que es necesaria para la detección de dichos flujos de vídeo que se encuentran en la estructura uvc_streaming.
De ellos se desprenden la estructura
uvc_streaming_header donde se encuentra el byte bStillCaptureMethod, que es la información que se necesita para filtrar las cabeceras.

Para usar las estructuras, he pensado que una
lista como las incluidas en Linux pudiera ser lo más intuitivo.


En cuanto pudiera leer el uvc_device, quisiera depurar el ejemplo para que así ya pueda pasar a leer las resoluciones de las imágenes fijas.





Ejemplo:

//  We will need uvcvideo.h                                                                           
#include "uvcvideo.h"                                                                                 




//  This function will print all information of a header
void print_streaming_header (uvc_streaming_header header)
{                                                        
  printf("######################\n");                    
  printf("bNumFormats:        %d\n", header.bNumFormats);
  printf("bEndpointAddress:   %d\n", header.bEndPointAddress);
  printf("bTerminalLink:      %d\n", header.bTerminalLink);   
  printf("bControlSize:       %d\n", header.bControlSize);    
  printf("bmaControls:        %d\n", header.bmaControls);     
  printf("bmInfo:             %d\n", header.bmInfo);          
  printf("bStillCaptureMethod:%d\n",header.bStillCaptureMethod);
  printf("bTriggerSupport:    %d\n", header.bTriggerSupport);   
  printf("bTriggerSupport:    %d\n", header.bTriggerSupport);   
  printf("bTriggerUsage:      %d\n", header.bTriggerUsage);     
  printf("~~~~~~~~~~~~~~~~~~~~~~\n");                           
  return;                                                       
}                                                               




//  This function will print all headers that are in a list
void print_streaming_all_streams_headers (                 
                                       list_head *list_streams);
{                                                               
  struct uvc_streaming_header *header;                          
  list_for_each_entry(header, list_streams->header, list) {
    print_streaming_header(&header);
  }
  return;
}




//  This function will return all streams that are usefull for
//  capturing still image
void uvc_still_bStillCaptureMethod (struct uvc_device *dev,
                               list_head *list_uvc_stream_still)
{
  struct uvc_streaming *stream;


  //  We need to init our list ( linux/list.h )
  LIST_HEAD_INIT(&list_uvc_stream_still);


  list_for_each_entry (stream, &dev->streams, list) {
    //  We need all stream that you
    if (stream->header.bStillCaptureMethod == 2)
      list_add_tail(list_uvc_stream_still, stream);
  }
}




int main (){
  struct uvc_device dev;
  struct list_head  list_uvc_stream_still;


  //  How can I open my webcam dev?
  //  open_dev(dev);


  uvc_still_bStillCaptureMethod(&dev, &list_uvc_stream_still);
  print_streaming_all_streams_headers (list_uvc_stream_still);
}

jueves, 11 de febrero de 2010

Estudio automático del código fuente: Rats y cppcheck

Rats

rats -i -r -w 3 --html --columns --context /usr/src/linux/drivers/media/video/uvc > ~/rats_results.html && chromium ~/rats_results.html


Entries in perl database: 33
Entries in python database: 62
Entries in c database: 334
Entries in php database: 55
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_queue.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_driver.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_isight.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_status.c
Analyzing /usr/src/linux/drivers/media/video/uvc/uvc_video.c
/usr/src/linux/drivers/media/video/uvc/uvc_status.c:102[9]: High: fixed size local buffer
char *attrs[3] = { "value", "info", "failure" };
Extra care should be taken to ensure that character arrays that are allocated
on the stack are used safely.  They are prime targets for buffer overflow
attacks.


/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:1067[10]: Medium: non-function call reference: open
.open = uvc_vm_open,
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:1135[10]: Medium: non-function call reference: open
.open = uvc_v4l2_open,
A function call is not being made here, but a reference is being made to a name
that is normally a vulnerable function.  It could be being assigned as a
pointer to function.


/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:1138[10]: Medium: non-function call reference: read
.read = uvc_v4l2_read,
A function call is not being made here, but a reference is being made to a name
that is normally a vulnerable function.  It could be being assigned as a
pointer to function.


/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:789[9]: Low: strlcpy: read
strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:315[25]: Low: strlcpy: read
strlcpy(format->name, fmtdesc->name,
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:346[17]: Low: strlcpy: read
strlcpy(format->name, "MJPEG", sizeof format->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:364[25]: Low: strlcpy: read
strlcpy(format->name, "SD-DV", sizeof format->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:367[25]: Low: strlcpy: read
strlcpy(format->name, "SDL-DV", sizeof format->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:370[25]: Low: strlcpy: read
strlcpy(format->name, "HD-DV", sizeof format->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1509[9]: Low: strlcpy: read
strlcpy(vdev->name, dev->name, sizeof vdev->name);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1605[17]: Low: strlcpy: read
strlcpy(dev->name, udev->product, sizeof dev->name);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:64[9]: Low: strlcpy: read
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:507[17]: Low: strlcpy: read
strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:508[17]: Low: strlcpy: read
strlcpy(cap->card, vdev->name, sizeof cap->card);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:650[17]: Low: strlcpy: read
strlcpy(input->name, iterm->name, sizeof input->name);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:718[17]: Low: strlcpy: read
strlcpy(fmt->description, format->name,
Double check that your buffer is as big as you specify


/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:923[25]: Low: memcpy: read
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:1039[17]: Low: memcpy: read
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:1108[9]: Low: memcpy: read
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:1131[17]: Low: memcpy: read
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
/usr/src/linux/drivers/media/video/uvc/uvc_queue.c:192[9]: Low: memcpy: read
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:638[9]: Low: memcpy: read
memcpy(streaming->header.bmaControls, &buffer[size], p*n);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:823[17]: Low: memcpy: read
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:827[17]: Low: memcpy: read
memcpy(unit->extension.baSourceID, &buffer[22], p);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:832[17]: Low: memcpy: read
memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:944[25]: Low: memcpy: read
memcpy(term->camera.bmControls, &buffer[15], n);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:951[25]: Low: memcpy: read
memcpy(term->media.bmControls, &buffer[9], n);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:952[25]: Low: memcpy: read
memcpy(term->media.bmTransportModes, &buffer[10+n], p);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1023[17]: Low: memcpy: read
memcpy(unit->selector.baSourceID, &buffer[5], p);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1056[17]: Low: memcpy: read
memcpy(unit->processing.bmControls, &buffer[8], n);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1086[17]: Low: memcpy: read
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1090[17]: Low: memcpy: read
memcpy(unit->extension.baSourceID, &buffer[22], p);
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1093[17]: Low: memcpy: read
memcpy(unit->extension.bmControls, &buffer[23+p], n);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:261[9]: Low: memcpy: read
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:320[9]: Low: memcpy: read
memcpy(&probe, &video->streaming->ctrl, sizeof probe);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:332[9]: Low: memcpy: read
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:973[17]: Low: memcpy: read
memcpy(info->entity, xinfo->entity, sizeof info->entity);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:1001[17]: Low: memcpy: read
memcpy(map->name, xmap->name, sizeof map->name);
/usr/src/linux/drivers/media/video/uvc/uvc_v4l2.c:1002[17]: Low: memcpy: read
memcpy(map->entity, xmap->entity, sizeof map->entity);
/usr/src/linux/drivers/media/video/uvc/uvc_isight.c:89[17]: Low: memcpy: read
memcpy(mem, data, nbytes);
/usr/src/linux/drivers/media/video/uvc/uvc_video.c:459[9]: Low: memcpy: read
memcpy(mem, data, nbytes);
/usr/src/linux/drivers/media/video/uvc/uvc_video.c:515[9]: Low: memcpy: read
memcpy(data, mem, nbytes);
/usr/src/linux/drivers/media/video/uvc/uvc_video.c:595[25]: Low: memcpy: read
memcpy(video->bulk.header, mem, ret);
Double check that your buffer is as big as you specify.
When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string.


/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:322[25]: Low: snprintf: read
snprintf(format->name, sizeof format->name,
/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:1607[17]: Low: snprintf: read
snprintf(dev->name, sizeof dev->name,
Double check that your buffer is as big as you specify.
When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string.


/usr/src/linux/drivers/media/video/uvc/uvc_driver.c:380[17]: Low: strlcat: read
strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
/usr/src/linux/drivers/media/video/uvc/uvc_status.c:35[9]: Low: strlcat: read
strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
Double check that your buffer is as big as you specify


Total lines analyzed: 6748
Total time 0.010565 seconds
638712 lines per second



Cppcheck

cppcheck --enable=all /usr/src/linux/drivers/media/video/uvc/ 2> ~/err.txt && kwrite ~/err.txt


[/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:970]: (style) The scope of the variable ret can be limited
[/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:1009]: (style) The scope of the variable ret can be limited
[/usr/src/linux/drivers/media/video/uvc/uvc_video.c:572]: (style) The scope of the variable ret can be limited
[/usr/src/linux/drivers/media/video/uvc/uvc_ctrl.c:1]: (style) The function '__uvc_ctrl_commit' is never used

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, 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

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

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!