v4l.c
Upload User: shyika
Upload Date: 2017-11-25
Package Size: 1227k
Code Size: 27k
Category:

Video Capture

Development Platform:

Unix_Linux

  1. /*
  2.     unicap
  3.     Copyright (C) 2004  Arne Caspari
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.     This program is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.     GNU General Public License for more details.
  12.     You should have received a copy of the GNU General Public License
  13.     along with this program; if not, write to the Free Software
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15. */
  16. #include "config.h"
  17. #include <unicap.h>
  18. #include <unicap_status.h>
  19. #include <unicap_cpi.h>
  20. #include <queue.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/mman.h>
  29. #include <fcntl.h>
  30. #include <dirent.h>
  31. #include <semaphore.h>
  32. #include <pthread.h>
  33. #include <errno.h>
  34. #include <sys/time.h>
  35. #include <time.h>
  36. #if V4L_DEBUG
  37. #define DEBUG
  38. #endif
  39. #include <debug.h>
  40. #include <linux/videodev.h>
  41. #include <linux/videodev2.h> // for v4l2 checks
  42. #include "v4l.h"
  43. unsigned int v4l_palette_array[] =
  44. {
  45. VIDEO_PALETTE_GREY,
  46. VIDEO_PALETTE_HI240,
  47. VIDEO_PALETTE_RGB565,
  48. VIDEO_PALETTE_RGB555,
  49. VIDEO_PALETTE_RGB24,
  50. VIDEO_PALETTE_RGB32,
  51. VIDEO_PALETTE_YUV422,
  52. VIDEO_PALETTE_YUYV,
  53. VIDEO_PALETTE_UYVY,
  54. VIDEO_PALETTE_YUV420,
  55. VIDEO_PALETTE_YUV411,
  56. VIDEO_PALETTE_RAW,
  57. VIDEO_PALETTE_YUV422P,
  58. VIDEO_PALETTE_YUV411P,
  59. };
  60. static unicap_status_t v4l_enumerate_devices( unicap_device_t *device, int index );
  61. static unicap_status_t v4l_open( void **cpi_data, unicap_device_t *device );
  62. static unicap_status_t v4l_close( void *cpi_data );
  63. static unicap_status_t v4l_reenumerate_formats( void *cpi_data, int *count );
  64. static unicap_status_t v4l_enumerate_formats( void *cpi_data, unicap_format_t *format, int index );
  65. static unicap_status_t v4l_set_format( void *cpi_data, unicap_format_t *format );
  66. static unicap_status_t v4l_get_format( void *cpi_data, unicap_format_t *format );
  67. static unicap_status_t v4l_reenumerate_properties( void *cpi_data, int *count );
  68. static unicap_status_t v4l_enumerate_properties( void *cpi_data, unicap_property_t *property, int index );
  69. static unicap_status_t v4l_set_property( void *cpi_data, unicap_property_t *property );
  70. static unicap_status_t v4l_get_property( void *cpi_data, unicap_property_t *property );
  71. static unicap_status_t v4l_capture_start( void *cpi_data );
  72. static unicap_status_t v4l_capture_stop( void *cpi_data );
  73. static unicap_status_t v4l_queue_buffer( void *cpi_data, unicap_data_buffer_t *buffer );
  74. static unicap_status_t v4l_dequeue_buffer( void *cpi_data, unicap_data_buffer_t **buffer );
  75. static unicap_status_t v4l_wait_buffer( void *cpi_data, unicap_data_buffer_t **buffer );
  76. static unicap_status_t v4l_poll_buffer( void *cpi_data, int *count );
  77. static unicap_status_t v4l_set_event_notify( void *cpi_data, 
  78.      unicap_event_callback_t func, 
  79.      unicap_handle_t unicap_handle );
  80. static void v4l_capture_thread( v4l_handle_t handle );
  81. static int queue_buffer( v4l_handle_t v4lhandle, int b );
  82. static struct _unicap_cpi cpi_s = 
  83. {
  84.    cpi_version: 1<<16,
  85.    cpi_capabilities: 0x3ffff,
  86.    
  87.    cpi_enumerate_devices: v4l_enumerate_devices,
  88.    cpi_open: v4l_open, 
  89.    cpi_close: v4l_close,
  90.    
  91.    cpi_reenumerate_formats: v4l_reenumerate_formats, 
  92.    cpi_enumerate_formats: v4l_enumerate_formats,   
  93.    cpi_set_format: v4l_set_format,    
  94.    cpi_get_format: v4l_get_format,          
  95.    
  96.    cpi_reenumerate_properties: v4l_reenumerate_properties,
  97.    cpi_enumerate_properties: v4l_enumerate_properties,
  98.    cpi_set_property: v4l_set_property,
  99.    cpi_get_property: v4l_get_property,
  100.    
  101.    cpi_capture_start: v4l_capture_start,
  102.    cpi_capture_stop: v4l_capture_stop,
  103.    
  104.    cpi_queue_buffer: v4l_queue_buffer,
  105.    cpi_dequeue_buffer: v4l_dequeue_buffer,
  106.    cpi_wait_buffer: v4l_wait_buffer,
  107.    cpi_poll_buffer: v4l_poll_buffer,
  108.    
  109.    cpi_set_event_notify: v4l_set_event_notify,
  110. };
  111. #if ENABLE_STATIC_CPI
  112. void unicap_v4l_register_static_cpi( struct _unicap_cpi **cpi )
  113. {
  114.    *cpi = &cpi_s;
  115. }
  116. #else
  117. unicap_status_t cpi_register( struct _unicap_cpi *reg_data )
  118. {
  119.    memcpy( reg_data, &cpi_s, sizeof( struct _unicap_cpi ) );
  120. /*  reg_data->cpi_version = 1<<16; */
  121. /*  reg_data->cpi_capabilities = 0x3ffff; */
  122. /*  reg_data->cpi_enumerate_devices = v4l_enumerate_devices; */
  123. /*  reg_data->cpi_open = v4l_open;  */
  124. /*  reg_data->cpi_close = v4l_close; */
  125. /*  reg_data->cpi_reenumerate_formats = v4l_reenumerate_formats;  */
  126. /*  reg_data->cpi_enumerate_formats = v4l_enumerate_formats;    */
  127. /*  reg_data->cpi_set_format = v4l_set_format;     */
  128. /*  reg_data->cpi_get_format = v4l_get_format;           */
  129. /*  reg_data->cpi_reenumerate_properties = v4l_reenumerate_properties; */
  130. /*  reg_data->cpi_enumerate_properties = v4l_enumerate_properties; */
  131. /*  reg_data->cpi_set_property = v4l_set_property; */
  132. /*  reg_data->cpi_get_property = v4l_get_property; */
  133. /*  reg_data->cpi_capture_start = v4l_capture_start; */
  134. /*  reg_data->cpi_capture_stop = v4l_capture_stop; */
  135. /*  reg_data->cpi_queue_buffer = v4l_queue_buffer; */
  136. /*  reg_data->cpi_dequeue_buffer = v4l_dequeue_buffer; */
  137. /*  reg_data->cpi_wait_buffer = v4l_wait_buffer; */
  138. /*  reg_data->cpi_poll_buffer = v4l_poll_buffer; */
  139. /*  reg_data->cpi_set_event_notify = v4l_set_event_notify; */
  140. return STATUS_SUCCESS;
  141. }
  142. #endif//ENABLE_STATIC_CPI
  143. static int file_filter( const struct dirent *a )
  144. {
  145.    int match = 0;
  146.    
  147.    // match: 'videoXY' where X = {0..9} and Y = {0..9}
  148.    if( !strncmp( a->d_name, "video", 5 ) )
  149.    {
  150.       if( strlen( a->d_name ) > 5 )
  151.       {
  152.  if( ( a->d_name[5] >= '0' ) && ( a->d_name[5] <= '9' ) ) // match
  153.       // the 'X'
  154.  {
  155.     match = 1;
  156.  }
  157.  
  158.  if( strlen( a->d_name ) > 6 )
  159.  {
  160.     match = 0;
  161.     
  162.     if( ( a->d_name[6] >= '0' ) && ( a->d_name[6] <= '9' ) )
  163.     {
  164.        match = 1;
  165.     }
  166.  }
  167.  
  168.  if( strlen( a->d_name ) > 7 )
  169.  {
  170.     match = 0;
  171.  }
  172.       }
  173.    }
  174.    
  175.    return match;
  176. }
  177. static unicap_status_t v4l_enumerate_devices( unicap_device_t *device, int index )
  178. {
  179.    int fd;
  180.    char devname[256];
  181.    struct dirent **namelist;
  182.    int n;
  183.    int found = -1;
  184.    int i = 0;
  185.    int dev_index = -1;
  186.    struct video_capability v4lcap;
  187.    struct v4l2_capability v4l2caps;
  188.    
  189.    TRACE( "*** v4l enumerate devicesn" );
  190.    n = scandir( "/dev", &namelist, file_filter, alphasort );
  191.    if( n < 0 )
  192.    {
  193.       TRACE( "Failed to scan directory '/dev' n" );
  194.       return STATUS_NO_DEVICE;
  195.    }
  196.    
  197.    while( ( found != index ) && n-- )
  198.    {      
  199.       sprintf( devname, "/dev/%s", namelist[n]->d_name );
  200. /*       free( namelist[n]->d_name ); */
  201.       TRACE( "v4l: open %sn", devname );
  202.       if( ( fd = open( devname, O_RDONLY | O_NONBLOCK ) ) == -1 )
  203.       {
  204.  TRACE( "v4l_cpi: open(%s): %sn", devname, strerror( errno ) );
  205.  continue;
  206.       }
  207.       
  208.       if( ioctl( fd, VIDIOC_QUERYCAP, &v4l2caps ) == 0 )
  209.       {
  210.  
  211.  TRACE( "v4l2 ioctls succeededn" );
  212.  close( fd );
  213.  continue;
  214.       }
  215.       
  216.       if( (v4l2caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) )
  217.       {
  218.  // v4l version two device
  219.  close( fd );
  220.  continue;
  221.       }
  222.       if( ioctl( fd, VIDIOCGCAP, &v4lcap ) < 0 )
  223.       {
  224.  TRACE( "VIDIOCGCAP ioctl failed!n" );
  225.  close( fd );
  226.  continue;
  227.       }
  228.       if( !(v4lcap.type & VID_TYPE_CAPTURE ) )
  229.       {
  230.  // no capture to memory capability
  231.  close( fd );
  232.  continue;
  233.       }
  234.       found++;
  235.       close( fd );
  236.    }
  237. /*    free( namelist ); */
  238.       
  239.    if( found != index )
  240.    {
  241.       return STATUS_NO_DEVICE;
  242.    }
  243.    sprintf( device->identifier, "%s [%d]", v4lcap.name, index );
  244.    strcpy( device->device, devname );
  245.    strcpy( device->model_name, v4lcap.name );
  246.    strcpy( device->vendor_name, "v4l" );
  247.    device->model_id = 1;
  248.    device->vendor_id = 0xffff0000;
  249.    device->flags = UNICAP_CPI_SERIALIZED;
  250.    return STATUS_SUCCESS;
  251. }
  252. static unicap_status_t v4l_open( void **cpi_data, unicap_device_t *device )
  253. {
  254. v4l_handle_t v4lhandle;
  255. *cpi_data = malloc( sizeof( struct _v4l_handle ) );
  256. if( !cpi_data )
  257. {
  258. TRACE( "malloc failedn" );
  259. return STATUS_FAILURE;
  260. }
  261. v4lhandle = *cpi_data;
  262. memset( v4lhandle, 0x0, sizeof( struct _v4l_handle ) );
  263. if( sem_init( &v4lhandle->sema, 0, 1 ) )
  264. {
  265.    TRACE( "sem_init failedn" );
  266.    free( v4lhandle );
  267.    return STATUS_FAILURE;
  268. }
  269. if( sem_init( &v4lhandle->out_sema, 0, 0 ) )
  270. {
  271.    TRACE( "sem_init failed!n" );
  272.    sem_destroy( &v4lhandle->sema );
  273.    free( v4lhandle );
  274.    return STATUS_FAILURE;
  275. }
  276. v4lhandle->fd = open( device->device, O_RDWR );
  277. if( v4lhandle->fd == -1 )
  278. {
  279. TRACE( "open failed, device = %sn", device->device );
  280. TRACE( "error was: %sn", strerror( errno ) );
  281. return STATUS_FAILURE;
  282. }
  283. if( ioctl( v4lhandle->fd, VIDIOCGCAP, &v4lhandle->v4lcap ) )
  284. {
  285. // failed v4l ioctl, look for next device
  286. close( v4lhandle->fd );
  287. return STATUS_FAILURE;
  288. }
  289. v4l_reenumerate_formats( v4lhandle, NULL );
  290. v4l_reenumerate_properties( v4lhandle, NULL );
  291. v4lhandle->in_queue = malloc( sizeof( struct _unicap_queue ) );
  292. v4lhandle->out_queue = malloc( sizeof( struct _unicap_queue ) );
  293. _init_queue( v4lhandle->in_queue );
  294. _init_queue( v4lhandle->out_queue );
  295. return STATUS_SUCCESS;
  296. }
  297. static unicap_status_t v4l_close( void *cpi_data )
  298. {
  299. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  300. close( v4lhandle->fd );
  301. sem_destroy( &v4lhandle->sema );
  302. sem_destroy( &v4lhandle->out_sema );
  303. if( v4lhandle->unicap_handle )
  304. {
  305.    // handle is a copy!!
  306.    free( v4lhandle->unicap_handle );
  307. }
  308. free( v4lhandle );
  309. return STATUS_SUCCESS;
  310. }
  311. static unicap_status_t v4l_reenumerate_formats( void *cpi_data, int *_pcount )
  312. {
  313. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  314. struct video_picture v4lpict;
  315. int count = 0;
  316. int p_count = sizeof( v4l_palette_array ) / sizeof( unsigned int );
  317. int i;
  318. if( ioctl( v4lhandle->fd, VIDIOCGPICT, &v4lhandle->v4lpict ) )
  319. {
  320. TRACE( "ioctl failedn" );
  321. return STATUS_FAILURE;
  322. }
  323. memset( &v4lhandle->palette, 0x0, 32 * sizeof( unsigned int ) );
  324. memcpy( &v4lpict, &v4lhandle->v4lpict, sizeof( struct video_picture ) );
  325. for( i = 0; i < p_count; i++ )
  326. {
  327. v4lpict.palette = v4l_palette_array[i];
  328. TRACE( "try palette: %dn", v4lpict.palette );
  329. if( !ioctl( v4lhandle->fd, VIDIOCSPICT, &v4lpict ) )
  330. {
  331. TRACE( "succeeded palette: %dn", v4lpict.palette );
  332. v4lhandle->palette[i] = v4lpict.palette;
  333. count++;
  334. }
  335. }
  336. if( _pcount )
  337. {
  338. *_pcount = count;
  339. }
  340. return STATUS_SUCCESS;
  341. }
  342. static unicap_status_t v4l_enumerate_formats( void *cpi_data, unicap_format_t *format, int index )
  343. {
  344. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  345. unsigned int p = 0xffffffff;
  346. int p_count = sizeof( v4l_palette_array ) / sizeof( unsigned int );
  347. int i, j = -1;
  348. int tmp;
  349. if( v4lhandle->v4lpict.palette == 0 )
  350. {
  351. v4l_reenumerate_formats( cpi_data, &tmp );
  352. }
  353. for( i = 0; i < p_count; i++ )
  354. {
  355. if( v4lhandle->palette[i] )
  356. {
  357. j++;
  358. }
  359. if( j == index )
  360. {
  361. p = v4lhandle->palette[i];
  362. TRACE( "p: %dn", p );
  363. break;
  364. }
  365. }
  366. if( p == 0xffffffff )
  367. {
  368. return STATUS_NO_MATCH;
  369. }
  370. switch( p )
  371. {
  372. case VIDEO_PALETTE_GREY:
  373. strcpy( format->identifier, "Grey ( Mono 8pp )" );
  374. format->fourcc = FOURCC( 'G', 'R', 'E', 'Y' );
  375. format->bpp = 8;
  376. break;
  377. case VIDEO_PALETTE_HI240:
  378. strcpy( format->identifier, "HI240 Bt848 8Bit color cube" );
  379. format->fourcc = FOURCC( 'H', '2', '4', '0' );
  380. format->bpp = 8;
  381. break;
  382. case VIDEO_PALETTE_RGB565:
  383. strcpy( format->identifier, "RGB 16bpp" );
  384. format->fourcc = FOURCC( 'R', 'G', 'B', '6' );
  385. format->bpp = 16;
  386. break;
  387. case VIDEO_PALETTE_RGB555:
  388. strcpy( format->identifier, "RGB 15bpp" );
  389. format->fourcc = FOURCC( 'R', 'G', 'B', '5' );
  390. format->bpp = 15;
  391. break;
  392. case VIDEO_PALETTE_RGB24:
  393. strcpy( format->identifier, "BGR 24bpp" );
  394. format->fourcc = FOURCC( 'B', 'G', 'R', '3' );
  395. format->bpp = 24;
  396. break;
  397. case VIDEO_PALETTE_RGB32:
  398. strcpy( format->identifier, "RGB 32bpp" );
  399. format->fourcc = FOURCC( 'R', 'G', 'B', '4' );
  400. format->bpp = 32;
  401. break;
  402. case VIDEO_PALETTE_YUV422:
  403. strcpy( format->identifier, "YUV 4:2:2" );
  404. format->fourcc = FOURCC( 'Y', '4', '2', '2' );
  405. format->bpp = 16;
  406. break;
  407. case VIDEO_PALETTE_YUYV:
  408. strcpy( format->identifier, "YUYV" );
  409. format->fourcc = FOURCC( 'Y', 'U', 'Y', 'V' );
  410. format->bpp = 16;
  411. break;
  412. case VIDEO_PALETTE_UYVY:
  413. strcpy( format->identifier, "UYVY" );
  414. format->fourcc = FOURCC( 'U', 'Y', 'V', 'Y' );
  415. format->bpp = 16;
  416. break;
  417. case VIDEO_PALETTE_YUV420:
  418. strcpy( format->identifier, "Y 4:2:0" );
  419. format->fourcc = FOURCC( 'Y', '4', '2', '0' );
  420. format->bpp = 16;
  421. break;
  422. case VIDEO_PALETTE_YUV411:
  423. strcpy( format->identifier, "Y 4:1:1" );
  424. format->fourcc = FOURCC( 'Y', '4', '1', '1' );
  425. format->bpp = 12;
  426. break;
  427. case VIDEO_PALETTE_RAW:
  428. strcpy( format->identifier, "Bt848 raw format" );
  429. format->fourcc = FOURCC( 'R', 'A', 'W', ' ' );
  430. format->bpp = 8;
  431. break;
  432. case VIDEO_PALETTE_YUV422P:
  433. strcpy( format->identifier, "Y 4:2:2 planar" );
  434. format->fourcc = FOURCC( 'Y', '4', '2', 'P' );
  435. format->bpp = 16;
  436. break;
  437. case VIDEO_PALETTE_YUV411P:
  438. strcpy( format->identifier, "Y 4:1:1 planar" );
  439. format->fourcc = FOURCC( '4', '1', '1', 'P' );
  440. format->bpp = 12;
  441. break;
  442. default:
  443. TRACE( "unknown format / wrong indexn" );
  444. return STATUS_FAILURE;
  445. }
  446. format->size.width = v4lhandle->v4lcap.maxwidth;
  447. format->size.height = v4lhandle->v4lcap.maxheight;
  448. format->min_size.width = v4lhandle->v4lcap.minwidth;
  449. format->max_size.width = v4lhandle->v4lcap.maxwidth;
  450. format->min_size.height = v4lhandle->v4lcap.minheight;
  451. format->max_size.height = v4lhandle->v4lcap.maxheight;
  452. format->buffer_size = format->size.width * format->size.height * format->bpp / 8;
  453. format->sizes = 0;
  454. format->size_count = 0;
  455. format->h_stepping = 0;
  456. format->v_stepping = 0;
  457. #ifdef DEBUG
  458. TRACE( "bsize: %d, wxhxb: %dx%dx%dn", format->buffer_size, format->size.width, format->size.height, format->bpp );
  459. {
  460.    char str[1024];
  461.    int s = 1024;
  462.    unicap_describe_format( format, str, &s );
  463.    printf( str );
  464. }
  465. #endif
  466. return STATUS_SUCCESS;
  467. }
  468. static unicap_status_t v4l_set_format( void *cpi_data, unicap_format_t *format )
  469. {
  470. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  471. unsigned int p;
  472. switch( format->fourcc )
  473. {
  474. case FOURCC( 'G', 'R', 'E', 'Y' ):
  475. p = VIDEO_PALETTE_GREY;
  476. break;
  477. case FOURCC( 'H', '2', '4', '0' ):
  478. p = VIDEO_PALETTE_HI240;
  479. break;
  480. case FOURCC( 'R', 'G', 'B', '6' ):
  481. p = VIDEO_PALETTE_RGB565;
  482. break;
  483. case FOURCC( 'R', 'G', 'B', '5' ):
  484. p = VIDEO_PALETTE_RGB555;
  485. break;
  486. case FOURCC( 'B', 'G', 'R', '3' ):
  487. p = VIDEO_PALETTE_RGB24;
  488. break;
  489. case FOURCC( 'R', 'G', 'B', '4' ):
  490. p = VIDEO_PALETTE_RGB32;
  491. break;
  492. case FOURCC( 'Y', '4', '2', '2' ):
  493. p = VIDEO_PALETTE_YUV422;
  494. break;
  495. case FOURCC( 'Y', 'U', 'Y', 'V' ):
  496. p = VIDEO_PALETTE_YUYV;
  497. break;
  498. case FOURCC( 'U', 'Y', 'V', 'Y' ):
  499. p = VIDEO_PALETTE_UYVY;
  500. break;
  501. case FOURCC( 'Y', '4', '2', '0' ):
  502. p = VIDEO_PALETTE_YUV420;
  503. break;
  504. case FOURCC( 'Y', '4', '1', '1' ):
  505. p = VIDEO_PALETTE_YUV411;
  506. break;
  507. case FOURCC( 'R', 'A', 'W', ' ' ):
  508. p = VIDEO_PALETTE_RAW;
  509. break;
  510. case FOURCC( 'Y', '4', '2', 'P' ):
  511. p = VIDEO_PALETTE_YUV422P;
  512. break;
  513. case FOURCC( '4', '1', '1', 'P' ):
  514. p = VIDEO_PALETTE_YUV411P;
  515. break;
  516. default:
  517. TRACE( "set format with unknown fourccn" );
  518. return STATUS_FAILURE;
  519. break;
  520. }
  521. // get current settings for brightness etc.
  522. if( ioctl( v4lhandle->fd, VIDIOCGPICT, &v4lhandle->v4lpict ) )
  523. {
  524. TRACE( "ioctl failed: %sn", strerror( errno ) );
  525. return STATUS_FAILURE;
  526. }
  527. v4lhandle->v4lpict.palette = p;
  528. v4lhandle->v4lpict.depth = format->bpp;
  529. TRACE( "ioctl VIDIOCSPICTn" );
  530. if( ioctl( v4lhandle->fd, VIDIOCSPICT, &v4lhandle->v4lpict ) )
  531. {
  532. TRACE( "ioctl failed: %sn", strerror( errno ) );
  533. TRACE( "p: %dn", v4lhandle->v4lpict.palette );
  534. return STATUS_FAILURE;
  535. }
  536. if( ioctl( v4lhandle->fd, VIDIOCGPICT, &v4lhandle->v4lpict ) )
  537. {
  538. TRACE( "ioctl failed: %sn", strerror( errno ) );
  539. TRACE( "p: %dn", v4lhandle->v4lpict.palette );
  540. return STATUS_FAILURE;
  541. }
  542. TRACE( "result: depth: %d palette: %dn", v4lhandle->v4lpict.depth, v4lhandle->v4lpict.palette );
  543. memset( &v4lhandle->v4lwindow, 0x0, sizeof( struct video_window ) );
  544. v4lhandle->v4lwindow.width = format->size.width;
  545. v4lhandle->v4lwindow.height = format->size.height;
  546. TRACE( "ioctl VIDIOCSWIN size: %dx%dn", v4lhandle->v4lwindow.width, v4lhandle->v4lwindow.height );
  547. if( ioctl( v4lhandle->fd, VIDIOCSWIN, &v4lhandle->v4lwindow ) )
  548. {
  549. TRACE( "ioctl failed: %sn", strerror( errno ) );
  550. return STATUS_FAILURE;
  551. }
  552. if( ioctl( v4lhandle->fd, VIDIOCGWIN, &v4lhandle->v4lwindow ) )
  553. {
  554. TRACE( "ioctl failed: %sn", strerror( errno ) );
  555. return STATUS_FAILURE;
  556. }
  557. TRACE( "succeeded: size: %dx%d n", v4lhandle->v4lwindow.x, v4lhandle->v4lwindow.y );
  558. unicap_copy_format( &v4lhandle->current_format, format );
  559. return STATUS_SUCCESS;
  560. }
  561. static unicap_status_t v4l_get_format( void *cpi_data, unicap_format_t *format )
  562. {
  563. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  564. memcpy( format, &v4lhandle->current_format, sizeof( unicap_format_t ) );
  565. return STATUS_SUCCESS;
  566. }
  567. static unicap_status_t v4l_reenumerate_properties( void *cpi_data, int *_pcount )
  568. {
  569. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  570. if( ioctl( v4lhandle->fd, VIDIOCGPICT, &v4lhandle->v4lpict_default ) )
  571. {
  572. TRACE( "ioctl failed: %sn", strerror( errno ) );
  573. return STATUS_FAILURE;
  574. }
  575. if( _pcount )
  576. {
  577. *_pcount = 5;
  578. }
  579. return STATUS_SUCCESS;
  580. }
  581. static unicap_status_t v4l_enumerate_properties( void *cpi_data, unicap_property_t *property, int index )
  582. {
  583. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  584. memset( property, 0x0, sizeof( unicap_property_t ) );
  585. switch( index )
  586. {
  587. case 0:
  588. strcpy( property->identifier, "brightness" );
  589. property->value = v4lhandle->v4lpict_default.brightness;
  590. break;
  591. case 1:
  592. strcpy( property->identifier, "hue" );
  593. property->value = v4lhandle->v4lpict_default.hue;
  594. break;
  595. case 2:
  596. strcpy( property->identifier, "colour" );
  597. property->value = v4lhandle->v4lpict_default.colour;
  598. break;
  599. case 3:
  600. strcpy( property->identifier, "contrast" );
  601. property->value = v4lhandle->v4lpict_default.contrast;
  602. break;
  603. case 4:
  604. strcpy( property->identifier, "whiteness" );
  605. property->value = v4lhandle->v4lpict_default.whiteness;
  606. break;
  607. default:
  608. return STATUS_NO_MATCH;
  609. }
  610. property->range.min = 0.0f;
  611. property->range.max = 1.0f;
  612. property->value = property->value / 65535.0f;
  613. property->flags = UNICAP_FLAGS_MANUAL;
  614. property->flags_mask = UNICAP_FLAGS_MANUAL;
  615. property->stepping = 1.0f/256.0f;
  616. strcpy( property->category, "video" );
  617. return STATUS_SUCCESS;
  618. }
  619. static unicap_status_t v4l_set_property( void *cpi_data, unicap_property_t *property )
  620. {
  621. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  622. int value = property->value * 65535;
  623. if( !strcmp( property->identifier, "brightness" ) )
  624. {
  625. v4lhandle->v4lpict.brightness = value;
  626. }
  627. else if( !strcmp( property->identifier, "hue" ) )
  628. {
  629. v4lhandle->v4lpict.hue = value;
  630. }
  631. else if( !strcmp( property->identifier, "colour" ) )
  632. {
  633. v4lhandle->v4lpict.colour = value;
  634. }
  635. else if( !strcmp( property->identifier, "contrast" ) )
  636. {
  637. v4lhandle->v4lpict.contrast = value;
  638. }
  639. else if( !strcmp( property->identifier, "whiteness" ) )
  640. {
  641. v4lhandle->v4lpict.whiteness = value;
  642. else 
  643. {
  644. return STATUS_FAILURE;
  645. }
  646. if( ioctl( v4lhandle->fd, VIDIOCSPICT, &v4lhandle->v4lpict ) )
  647. {
  648. TRACE( "ioctl failed: %sn", strerror( errno ) );
  649. return STATUS_FAILURE;
  650. }
  651. return STATUS_SUCCESS;
  652. }
  653. static unicap_status_t v4l_get_property( void *cpi_data, unicap_property_t *property )
  654. {
  655. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  656. double value;
  657. if( ioctl( v4lhandle->fd, VIDIOCGPICT, &v4lhandle->v4lpict ) )
  658. {
  659. TRACE( "ioctl failed: %sn", strerror( errno ) );
  660. return STATUS_FAILURE;
  661. }
  662. if( !strcmp( property->identifier, "brightness" ) )
  663. {
  664. value = v4lhandle->v4lpict.brightness;
  665. }
  666. else if( !strcmp( property->identifier, "hue" ) )
  667. {
  668. value = v4lhandle->v4lpict.hue;
  669. }
  670. else if( !strcmp( property->identifier, "colour" ) )
  671. {
  672. value = v4lhandle->v4lpict.colour;
  673. }
  674. else if( !strcmp( property->identifier, "contrast" ) )
  675. {
  676. value = v4lhandle->v4lpict.contrast;
  677. }
  678. else if( !strcmp( property->identifier, "whiteness" ) )
  679. {
  680. value = v4lhandle->v4lpict.whiteness;
  681. else 
  682. {
  683. return STATUS_FAILURE;
  684. }
  685. property->range.min = 0.0f;
  686. property->range.max = 1.0f;
  687. property->value = value / 65535.0f;
  688. property->flags = UNICAP_FLAGS_MANUAL;
  689. property->flags_mask = UNICAP_FLAGS_MANUAL;
  690. property->stepping = 1.0f/256.0f;
  691. strcpy( property->category, "video" );
  692. return STATUS_SUCCESS;
  693. }
  694. static unicap_status_t v4l_capture_start( void *cpi_data )
  695. {
  696. v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  697. int i;
  698. if( ioctl( v4lhandle->fd, VIDIOCGMBUF, &v4lhandle->v4lmbuf ) == -1 )
  699. {
  700.    TRACE( "ioctl failed: %sn", strerror( errno ) );
  701.    return STATUS_FAILURE;
  702. }
  703. TRACE( "mbuf: size: %d, frames: %dn", v4lhandle->v4lmbuf.size, v4lhandle->v4lmbuf.frames );
  704. for( i = 0; i < v4lhandle->v4lmbuf.frames; i++ )
  705. {
  706. TRACE( "offset %d: %xn", i, v4lhandle->v4lmbuf.offsets[i] );
  707. }
  708. v4lhandle->map = mmap( 0, v4lhandle->v4lmbuf.size, PROT_WRITE | PROT_READ, MAP_SHARED, v4lhandle->fd, 0 );
  709. if( v4lhandle->map == MAP_FAILED )
  710. {
  711. /*  ERROR( "mmap failed: %snCapture can not start!n", strerror( errno ) ); */
  712. return STATUS_FAILURE;
  713. }
  714. TRACE( "map: %pn", v4lhandle->map );
  715. v4lhandle->ready_buffer = -1;
  716. for( i = 0; i < v4lhandle->v4lmbuf.frames; i++ )
  717. {
  718.    queue_buffer( v4lhandle, i );
  719. }
  720. v4lhandle->quit_capture_thread = 0;
  721. pthread_create( &v4lhandle->capture_thread, NULL, v4l_capture_thread, v4lhandle );
  722. v4lhandle->capture_running = 1;
  723. return STATUS_SUCCESS;
  724. }
  725. static unicap_status_t v4l_capture_stop( void *cpi_data )
  726. {
  727.    v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  728.    if( v4lhandle->capture_running )
  729.    {
  730.       
  731.       v4lhandle->quit_capture_thread = 1;
  732.       sem_post( &v4lhandle->out_sema );
  733.       pthread_join( v4lhandle->capture_thread, NULL );
  734.       
  735.       if( v4lhandle->map )
  736.       {
  737.  munmap( v4lhandle->map, v4lhandle->v4lmbuf.size );
  738.  v4lhandle->map = 0;
  739.       }
  740.       
  741.       v4lhandle->capture_running = 0;
  742.    }
  743.    
  744.    return STATUS_SUCCESS;
  745. }
  746. static unicap_status_t v4l_queue_buffer( void *cpi_data, unicap_data_buffer_t *buffer )
  747. {
  748.    v4l_handle_t v4lhandle = ( v4l_handle_t ) cpi_data;
  749.    struct _unicap_queue *entry;
  750.    entry = malloc( sizeof( struct _unicap_queue ) );
  751.    entry->data = buffer;
  752.    _insert_back_queue( v4lhandle->in_queue, entry );
  753.    
  754.    return STATUS_SUCCESS;
  755. }
  756. static unicap_status_t v4l_dequeue_buffer( void *cpi_data, unicap_data_buffer_t **buffer )
  757. {
  758. v4l_handle_t handle = ( v4l_handle_t ) cpi_data;
  759. unicap_status_t status;
  760. TRACE( "dequeue buffern" );
  761. if( handle->capture_running )
  762. {
  763.    TRACE( "dequeue while capturingn" );
  764.    return STATUS_FAILURE;
  765. }
  766. return STATUS_NOT_IMPLEMENTED;
  767. }
  768. static unicap_status_t v4l_wait_buffer( void *cpi_data, unicap_data_buffer_t **buffer )
  769. {
  770.    v4l_handle_t handle = ( v4l_handle_t ) cpi_data;
  771.    unicap_status_t status = STATUS_FAILURE;
  772.    *buffer = NULL;
  773.    if( !handle->out_queue->next &&! handle->capture_running )
  774.    {
  775.       TRACE( "Wait->capture stopped" );
  776.       return STATUS_IS_STOPPED;
  777.    }
  778.    sem_wait( &handle->out_sema );
  779.    
  780.    if( handle->out_queue->next )
  781.    {
  782.       unicap_data_buffer_t *returned_buffer;
  783.       struct _unicap_queue *entry;
  784.       
  785.       entry = _get_front_queue( handle->out_queue );
  786.       returned_buffer = ( unicap_data_buffer_t * ) entry->data;
  787.       free( entry );
  788.       
  789.       *buffer = returned_buffer;
  790.       status = STATUS_SUCCESS;
  791.    }
  792.    return status;
  793. }
  794. static unicap_status_t v4l_poll_buffer( void *data, int *count )
  795. {
  796. TRACE( "poll buffern" );
  797. return STATUS_NOT_IMPLEMENTED;
  798. }
  799. static unicap_status_t v4l_set_event_notify( void *cpi_data, unicap_event_callback_t func, unicap_handle_t unicap_handle )
  800. {
  801.    v4l_handle_t handle = ( v4l_handle_t )cpi_data;
  802.    
  803.    handle->event_callback = func;
  804.    handle->unicap_handle = unicap_handle;
  805.    
  806.    return STATUS_SUCCESS;
  807. }
  808. static int queue_buffer( v4l_handle_t v4lhandle, int buffer )
  809. {
  810.    struct video_mmap v4lmmap;
  811.    unicap_status_t status;
  812.    int frame;
  813.    
  814.    frame = buffer;
  815.    
  816.    TRACE( "queue buffer, frame: %dn", frame );
  817.    
  818.    v4lmmap.frame = frame;
  819.    v4lmmap.width = v4lhandle->current_format.size.width;
  820.    v4lmmap.height = v4lhandle->current_format.size.height;
  821.    v4lmmap.format = v4lhandle->v4lpict.palette;
  822.       
  823.    if( ioctl( v4lhandle->fd, VIDIOCMCAPTURE, &v4lmmap ) == -1 )
  824.    {
  825.       TRACE( "ioctl failed: %sn", strerror( errno ) );
  826.       return 0;
  827.    }
  828.       
  829.    return 1;
  830. }
  831. static int wait_buffer( v4l_handle_t v4lhandle, unicap_data_buffer_t *data_buffer )
  832. {
  833.    int frame;
  834.    struct _unicap_queue *entry;
  835.    v4lhandle->ready_buffer = ( v4lhandle->ready_buffer + 1 ) % v4lhandle->v4lmbuf.frames;
  836.    frame = v4lhandle->ready_buffer;
  837.    TRACE( "wait buffer, frame: %dn", frame );
  838.    if( ioctl( v4lhandle->fd, VIDIOCSYNC, &frame ) == -1 )
  839.    {
  840.       TRACE( "ioctl failed: %sn", strerror( errno ) );
  841.       return 0;
  842.    }
  843.    data_buffer->data = v4lhandle->map + v4lhandle->v4lmbuf.offsets[frame];   
  844.    gettimeofday( &data_buffer->fill_time, NULL );
  845.    return 1;
  846. }
  847. static void v4l_capture_thread( v4l_handle_t handle )
  848. {
  849.    unicap_data_buffer_t new_frame_buffer;
  850.    int i = 0;
  851.    
  852.    unicap_copy_format( &new_frame_buffer.format, &handle->current_format );
  853.    new_frame_buffer.buffer_size = handle->current_format.buffer_size;
  854.    new_frame_buffer.type = UNICAP_BUFFER_TYPE_SYSTEM;
  855.    while( !handle->quit_capture_thread )
  856.    {
  857.       struct _unicap_queue *entry;
  858.       
  859.       if( sem_wait( &handle->sema ) )
  860.       {
  861.  TRACE( "SEM_WAIT_FAILED" );
  862.       }
  863.       
  864.       if( !wait_buffer( handle, &new_frame_buffer ) )
  865.       {
  866.  sem_post( &handle->sema );
  867.  continue;
  868.       }
  869.       sem_post( &handle->sema );
  870.       if( handle->event_callback )
  871.       {
  872.  handle->event_callback( handle->unicap_handle, UNICAP_EVENT_NEW_FRAME, &new_frame_buffer );
  873.       }
  874.       
  875.       entry = _get_front_queue( handle->in_queue );
  876.       if( entry )
  877.       {
  878.  unicap_data_buffer_t *data_buffer = ( unicap_data_buffer_t * ) entry->data;
  879.  struct _unicap_queue *outentry = malloc( sizeof( struct _unicap_queue ) );
  880.  free( entry );
  881.  data_buffer->buffer_size = new_frame_buffer.buffer_size;
  882.  unicap_copy_format( &data_buffer->format, &new_frame_buffer.format );
  883.  if( data_buffer->type == UNICAP_BUFFER_TYPE_SYSTEM )
  884.  {
  885.     data_buffer->data = new_frame_buffer.data;
  886.  }
  887.  else
  888.  {
  889.     memcpy( data_buffer->data, new_frame_buffer.data, new_frame_buffer.buffer_size );
  890.  }
  891.  outentry->data = data_buffer;
  892.  memcpy( &data_buffer->fill_time, &new_frame_buffer.fill_time, sizeof( struct timeval ) );
  893.  _insert_back_queue( handle->out_queue, outentry );
  894.  sem_post( &handle->out_sema );
  895.       }
  896.       
  897.       if( sem_wait( &handle->sema ) )
  898.       {
  899.  TRACE( "SEM_WAIT_FAILED" );
  900.       }
  901.       
  902.       queue_buffer( handle, handle->ready_buffer );
  903.       
  904.       sem_post( &handle->sema );
  905.    }   
  906. }