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

Video Capture

Development Platform:

Unix_Linux

  1. /* unicap
  2.  *
  3.  * Copyright (C) 2004 Arne Caspari ( arne_caspari@users.sourceforge.net )
  4.  *
  5.  This program is free software; you can redistribute it and/or modify
  6.  it under the terms of the GNU General Public License as published by
  7.  the Free Software Foundation; either version 2 of the License, or
  8.  (at your option) any later version.
  9.  This program is distributed in the hope that it will be useful,
  10.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  GNU General Public License for more details.
  13.  You should have received a copy of the GNU General Public License
  14.  along with this program; if not, write to the Free Software
  15.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  16. */
  17. #include "config.h"
  18. #include <stdlib.h>
  19. #include <linux/types.h>
  20. #include <stdlib.h>
  21. #include <linux/types.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <sys/time.h>
  26. #include <time.h>
  27. #include <X11/Xlib.h>
  28. #include <X11/extensions/XShm.h>
  29. #include <X11/extensions/Xvlib.h>
  30. #include <X11/X.h>
  31. #include <sys/ipc.h>
  32. #include <sys/shm.h>
  33. #include "colorspace.h"
  34. #include "unicap.h"
  35. #include "ucil.h"
  36. #include <glib.h>
  37. #include <gtk/gtk.h>
  38. #include <gdk/gdkx.h>
  39. #include <semaphore.h>
  40. #include <unicapgtk.h>
  41. #include "backend.h"
  42. #include "backend_xv.h"
  43. #if UNICAPGTK_DEBUG
  44. #define DEBUG
  45. #endif
  46. #include <debug.h>
  47. #define MAX_IMAGE_BUFFERS 12
  48. #define MAX_XV_PORTS 64
  49. static int g_used_ports[MAX_XV_PORTS];
  50. static int g_initialized = 0;
  51. static gboolean match_fourcc( unsigned int a, unsigned int b );
  52. static gboolean lookup_fcc( unsigned int fcc, unsigned int *list );
  53. typedef struct _xv_fourcc
  54. {
  55.       unsigned int fourcc;
  56.       char guid[16];
  57. } xv_fourcc_t;
  58. struct xv_backend_data
  59. {
  60.       XvAdaptorInfo *p_adaptor_info;
  61.       unsigned int num_adaptors;
  62.       XvPortID port_id;
  63.       unsigned int xv_mode_id;
  64.       XvImage *image[MAX_IMAGE_BUFFERS];
  65.       unicap_data_buffer_t data_buffers[MAX_IMAGE_BUFFERS];
  66.       int use_shm;
  67.       XShmSegmentInfo shminfo[MAX_IMAGE_BUFFERS];
  68.       int width;
  69.       int height;
  70.       
  71.       gint output_width;
  72.       gint output_height;
  73.       gint crop_x;
  74.       gint crop_y;
  75.       gint crop_w;
  76.       gint crop_h;
  77.       int window_width;
  78.       int window_height;
  79.       Atom atom_colorkey;
  80.       Atom atom_brightness;
  81.       Atom atom_hue;
  82.       Atom atom_contrast;
  83.       int brightness_min;
  84.       int brightness_max;
  85.       int hue_min;
  86.       int hue_max;
  87.       int contrast_max;
  88.       int contrast_min;
  89.       unsigned int colorkey;
  90.       volatile int current_buffer;
  91.       volatile int next_display_buffer;
  92.       Display *display;
  93.       Drawable drawable;
  94.       GC       gc;
  95.       GdkGC   *gdkgc;
  96.       GtkWidget *widget;
  97.       GdkWindow *overlay_window;
  98.       GC overlay_gc;
  99.       gboolean scale_to_fit;
  100.       gint redisplay_timerid;
  101.       gboolean pause_state;
  102.       sem_t sema;
  103.       int used_port;
  104.       unicap_new_frame_callback_t new_frame_callback;
  105.       void * new_frame_callback_data;
  106.       unicap_handle_t new_frame_callback_handle;
  107. };
  108. static XvImage *allocate_image( Display *display, 
  109. XvPortID port_id, 
  110. unsigned int xv_mode_id,
  111. XShmSegmentInfo *shminfo, 
  112. int width, 
  113. int height, 
  114. int *use_shm )
  115. {
  116.    XvImage *image = 0;
  117.    if( shminfo )
  118.    {
  119.       image = XvShmCreateImage( display, 
  120. port_id, 
  121. xv_mode_id, 
  122. (char*)NULL, 
  123. width,
  124. height, 
  125. shminfo );
  126.       if( image )
  127.       {
  128.  shminfo->shmid = shmget( IPC_PRIVATE, image->data_size, IPC_CREAT | 0777 );
  129.  if( shminfo->shmid == -1 )
  130.  {
  131.     return 0;
  132.  }
  133.  shminfo->shmaddr = image->data = shmat( shminfo->shmid, 0, 0 );
  134.  shmctl(shminfo->shmid, IPC_RMID, 0);
  135.  if( shminfo->shmaddr == ( void * ) -1 )
  136.  {
  137.     return 0;
  138.  }
  139.  shminfo->readOnly = False;
  140.  if( !XShmAttach( display, shminfo ) )
  141.  {
  142.     shmdt( shminfo->shmaddr );
  143.     XFree( image );
  144.     return 0;
  145.  }
  146.  *use_shm = 1;
  147.       }
  148.    }
  149.    else
  150.    {
  151.       image = XvCreateImage( display, 
  152.      port_id, 
  153.      xv_mode_id, 
  154.      (char*)NULL, 
  155.      width,
  156.      height );
  157.       if( image )
  158.       {
  159.  g_assert( image->data_size );
  160.  image->data = g_slice_alloc( image->data_size );
  161.       }
  162.       *use_shm = 0;
  163.    }
  164.   
  165.    return image;
  166. }
  167. gint backend_xv_get_merit()
  168. {
  169.    return BACKEND_MERIT_XV;
  170. }
  171. static gboolean redraw_timeout( gpointer _data )
  172. {
  173.    backend_xv_redraw( _data );
  174.    return TRUE;
  175. }
  176. static GdkGC *create_gc( GtkWidget *widget, int r, int g, int b )
  177. {
  178.    GdkGCValues values;
  179.    GdkColormap *colormap;
  180.    GdkGC *gc;
  181.    values.foreground.red = ( r << 8 ) | r;
  182.    values.foreground.green = ( g << 8 ) | g ;
  183.    values.foreground.blue = ( b << 8 ) | b;
  184.    values.foreground.pixel = 0;
  185.    colormap = gtk_widget_get_colormap( widget );
  186.    gdk_rgb_find_color( colormap, &values.foreground );
  187.    gc = gdk_gc_new_with_values( widget->window,
  188. &values, GDK_GC_FOREGROUND );
  189.    return gc;
  190. }
  191. static void set_colorkey( struct xv_backend_data *data,  unsigned int r, unsigned int g, unsigned int b )
  192. {
  193.    unsigned int val = ( ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff) );
  194.    if( data->atom_colorkey )
  195.    {
  196.       XvSetPortAttribute( data->display,
  197.   data->port_id,
  198.   data->atom_colorkey,
  199.   val );
  200.       XvGetPortAttribute( data->display,
  201.   data->port_id, 
  202.   data->atom_colorkey,
  203.   (int*)&data->colorkey );
  204.    }
  205.    else
  206.    {
  207.       data->colorkey = val;
  208.    }
  209. }
  210. void backend_xv_size_allocate( gpointer _data, GtkWidget *widget, GtkAllocation *allocation )
  211. {
  212.    struct xv_backend_data *data = _data;
  213.    if( data->scale_to_fit )
  214.    {      
  215.       data->output_width = allocation->width;
  216.       data->output_height = allocation->height;
  217.    }
  218. }
  219. unsigned int yuy2_equiv_fccs[] =
  220. {
  221.    UCIL_FOURCC( 'Y', 'U', 'Y', '2' ), 
  222.    UCIL_FOURCC( 'Y', 'U', 'Y', 'V' ), 
  223.    0
  224. };
  225. unsigned int *equiv_fccs[] =
  226. {
  227.    yuy2_equiv_fccs, 
  228.    NULL
  229. };
  230. static gboolean lookup_fcc( unsigned int fcc, unsigned int *list )
  231. {
  232.    int i;
  233.    
  234.    for( i = 0; list[i]; i++ )
  235.    {
  236.       if( list[i] == fcc )
  237.       {
  238.  return TRUE;
  239.       }
  240.    }
  241.    
  242.    return FALSE;
  243. }
  244. static gboolean match_fourcc( unsigned int a, unsigned int b )
  245. {
  246.    int i;
  247.    
  248.    if( a == b )
  249.    {
  250.       return TRUE;
  251.    }
  252.    
  253.    for( i = 0; equiv_fccs[i]; i++ )
  254.    {
  255.       if( lookup_fcc( a, equiv_fccs[i] ) && lookup_fcc( b, equiv_fccs[i] ) )
  256.       {
  257.  return TRUE;
  258.       }
  259.    }
  260.    
  261.    return FALSE;
  262. }
  263. gboolean backend_xv_init( GtkWidget *widget, unicap_format_t *format, guint32 req_fourcc, gpointer *_data, GError **err )
  264. {
  265.    unsigned int version, release;
  266.    unsigned int request_base, event_base, error_base;
  267.    int i;
  268.    Display *dpy;
  269.    struct xv_backend_data *data;
  270.    int use_shm = 1;
  271.    unsigned int target_fourcc = format->fourcc;
  272.    int numPorts;
  273.    GKeyFile *keyfile;
  274.    gchar *keyfile_path;
  275.    gchar *userconf_path;
  276.    gchar *cval;
  277.    unsigned int r,g,b;
  278.    XGCValues values;
  279.    TRACE( "Backend xv: initn" );
  280.    if( !g_initialized )
  281.    {
  282.       TRACE( "Initialize Xv port listn" );
  283.       memset( g_used_ports, 0x0, sizeof( g_used_ports ) );
  284.       g_initialized = 1;
  285.    }
  286.    g_assert( GTK_WIDGET_REALIZED( widget ) );   
  287.    data = g_new0( struct xv_backend_data, 1 );
  288.    dpy = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display( widget ) );
  289.    if( XvQueryExtension( dpy, 
  290.  &version, &release, &request_base, &event_base, &error_base ) != Success )
  291.    {
  292.       TRACE( "XvQueryExtension failedn" );
  293.       free( data );
  294.       return FALSE;
  295.    }
  296.    if( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ), &data->num_adaptors, &data->p_adaptor_info ) != Success )
  297.    {
  298.       TRACE( "XvQueryAdaptors failedn" );
  299.       free( data );
  300.       return FALSE;
  301.    }
  302.    if( data->num_adaptors == 0 )
  303.    {
  304.       XFree( data->p_adaptor_info );
  305.       free( data );
  306.       return FALSE;
  307.    }
  308.    data->port_id = -1;
  309.    userconf_path = unicapgtk_get_user_config_path( );
  310.    keyfile_path = g_build_path( G_DIR_SEPARATOR_S, userconf_path, "unicapgtk.conf", NULL );
  311.    g_free( userconf_path );
  312. /*    if( !g_file_test( keyfile_path, G_FILE_TEST_EXISTS ) ) */
  313. /*    { */
  314. /*       g_free( keyfile_path ); */
  315. /*       keyfile_path = g_build_path( G_DIR_SEPARATOR_S, SYSCONFDIR, "unicap", "unicapgtk.conf", NULL ); */
  316. /*    } */
  317.    
  318.    keyfile = g_key_file_new();
  319.    g_key_file_load_from_file( keyfile, keyfile_path, 0, NULL );
  320.    g_free( keyfile_path );
  321.    if( !req_fourcc )
  322.    {
  323.       cval = g_key_file_get_value( keyfile, "display_backend_xv", "force_fourcc", NULL );
  324.       if( cval )
  325.       {
  326.  req_fourcc = cval[0] + (cval[1]<<8) + (cval[2]<<16) + (cval[3]<<24);
  327.  g_free( cval );
  328.       }
  329.    }
  330.    
  331.    if( req_fourcc )
  332.    {
  333.       if( ucil_conversion_supported( target_fourcc, req_fourcc ) )
  334.       {
  335.  target_fourcc = req_fourcc;
  336.       }
  337.    }
  338.    if( !ucil_conversion_supported( target_fourcc, format->fourcc ) )
  339.    {
  340.       g_key_file_free( keyfile );
  341.       TRACE( "No conversion from format->fourcc[%08x] to target_fourcc[%08x]n", format->fourcc, target_fourcc );
  342.       XFree( data->p_adaptor_info );
  343.       free( data );
  344.       return FALSE;
  345.    }
  346.    
  347.    numPorts = 0;
  348.    for( i = 0; i < data->num_adaptors; i++ )
  349.    {
  350.       numPorts += data->p_adaptor_info[i].num_ports;
  351.    }   
  352.    for( i = 0; ( i < numPorts ) && ( data->port_id == -1 ) ; i++ )
  353.    {
  354.       XvAttribute *at;
  355.       int num_attributes;
  356.       int attribute;
  357.       XvImageFormatValues *xvimage_formats;
  358.       int num_xvimage_formats;
  359.       int f;
  360.       XvPortID tmp_port_id = -1;
  361.       tmp_port_id = data->p_adaptor_info[0].base_id + i;
  362.       TRACE( "port id: %08xn:", (unsigned int )tmp_port_id );  
  363.       xvimage_formats = XvListImageFormats( dpy, 
  364.     tmp_port_id, 
  365.     &num_xvimage_formats );
  366.       for( f = 0; f < num_xvimage_formats; f++ )
  367.       {
  368.  char imageName[5] = {0, 0, 0, 0, 0};
  369.  memcpy(imageName, &(xvimage_formats[f].id), 4);
  370.  TRACE( "      id: 0x%x", xvimage_formats[f].id);
  371.  if( isprint( imageName[0]) && isprint(imageName[1]) &&
  372.      isprint( imageName[2]) && isprint(imageName[3])) 
  373.  {
  374.     DBGOUT(" (%s)n", imageName);
  375.  } else {
  376.     DBGOUT("n");
  377.  }
  378.  if( match_fourcc( xvimage_formats[f].id, target_fourcc ) )
  379.  {
  380.     data->xv_mode_id = xvimage_formats[f].id;
  381.     data->port_id = tmp_port_id;
  382.     TRACE( " using fourcc for display: %08xn", xvimage_formats[f].id );
  383.     break;
  384.  }
  385.       }
  386.       if( !match_fourcc( data->xv_mode_id, target_fourcc ) )
  387.       {
  388.  for( f = 0; f < num_xvimage_formats; f++ )
  389.  {
  390.     if( ucil_conversion_supported( target_fourcc, xvimage_formats[f].id ) )
  391.     {
  392.        target_fourcc = data->xv_mode_id = xvimage_formats[f].id;
  393.        data->port_id = tmp_port_id;
  394.     }
  395.  }
  396.       }
  397.       
  398.       XFree( xvimage_formats );
  399.       if( target_fourcc && !match_fourcc( data->xv_mode_id, target_fourcc ) )
  400.       {
  401.  continue;
  402.       }
  403.       if( !g_used_ports[i] && ( data->port_id != -1 ) )
  404.       {
  405.  if( XvGrabPort( dpy, tmp_port_id, CurrentTime ) 
  406.      != Success )
  407.  {
  408.     TRACE( "can not grab port: %dn", (unsigned int)tmp_port_id );
  409.     data->port_id = -1;
  410.     continue;
  411.  }
  412.  TRACE( "lock port: %dn", i );
  413.  g_used_ports[i] = 1;
  414.  data->used_port = i;
  415.       }
  416.       else
  417.       {
  418.  TRACE( "port %d is in use!n", i );
  419.  data->port_id = -1;
  420.  continue;
  421.       }
  422.       
  423.       at = XvQueryPortAttributes( dpy, tmp_port_id, &num_attributes );
  424. /*       TRACE( "num_attributes: %dn", num_attributes ); */
  425.       for( attribute = 0; attribute < num_attributes; attribute++ )
  426.       {
  427.  
  428.  if( !strcmp( at[attribute].name, "XV_COLORKEY" ) )
  429.  {
  430.     int val;
  431.     Atom atom;
  432.     atom = (Atom)XInternAtom( dpy, at[attribute].name, 0 );
  433.     XvGetPortAttribute( dpy, 
  434. tmp_port_id, 
  435. atom, 
  436. &val );
  437.     data->colorkey = val;
  438.     data->atom_colorkey = atom;
  439.     TRACE( "found xv_colorkeyn" );
  440.  }
  441.  
  442.  if( !strcmp( at[attribute].name, "XV_DOUBLE_BUFFER" ) )
  443.  {
  444.     Atom _atom;
  445.     _atom = XInternAtom( dpy, at[attribute].name, 0 );
  446.     XvSetPortAttribute( dpy, tmp_port_id, _atom, 1 );
  447.     TRACE( "Xv: DOUBLE_BUFFER availablen" );
  448.  }
  449.  cval = g_key_file_get_value( keyfile, "display_backend_xv", at[attribute].name, NULL );
  450.  if( cval )
  451.  {
  452.     int val;
  453.     Atom atom;
  454.     atom = (Atom)XInternAtom( dpy, at[attribute].name, 0 );
  455.     val = atoi( cval );
  456.     XvSetPortAttribute( dpy, tmp_port_id, atom, val );
  457.     TRACE( "Set Attribute for: %s to %dn", at[attribute].name, val );
  458.  }
  459.       }
  460.       XFree( at );
  461.    }
  462.    if( data->port_id == -1 )
  463.    {
  464.       TRACE( "No suitable port foundn" );
  465.       XFree( data->p_adaptor_info );
  466.       free( data );
  467.       return FALSE;
  468.    }
  469.    TRACE( "Using port: %dn", (unsigned int )data->port_id );
  470.    data->display = dpy;
  471.    data->width = format->size.width;
  472.    data->height = format->size.height;
  473.    data->output_width = data->width;
  474.    data->output_height = data->height;
  475.    data->crop_x = 0;
  476.    data->crop_y = 0;
  477.    data->crop_w = data->width;
  478.    data->crop_h = data->height;
  479.    data->widget = widget;
  480.    data->current_buffer = -1;
  481.    
  482.    set_colorkey( data, 0x5, 0x5, 0xfe );
  483.    if( data->atom_colorkey )
  484.    {
  485.       r = ( data->colorkey >> 16 ) & 0xff;
  486.       g = ( data->colorkey >>  8 ) & 0xff;
  487.       b = ( data->colorkey ) & 0xff;
  488.       data->gdkgc = create_gc( widget, r, g, b );
  489.    }
  490.    else
  491.    {
  492.       data->gdkgc = create_gc( widget, 0xff, 0xff, 0 );
  493.    }
  494.    for( i = 0; i < MAX_IMAGE_BUFFERS; i++ )
  495.    {
  496.       memset( &data->shminfo[i], 0, sizeof( XShmSegmentInfo ) );
  497.    
  498.       data->image[i] = allocate_image( data->display, 
  499.        data->port_id,
  500.        data->xv_mode_id, 
  501.        &data->shminfo[i], 
  502.        data->width, 
  503.        data->height, 
  504.        &use_shm );
  505.       memset( &data->data_buffers[i], 0, sizeof( unicap_data_buffer_t ) );
  506.       if( !data->image[i] )
  507.       {
  508.  g_assert( "Failed to allocate image" == FALSE );
  509.       }
  510.    }
  511.    data->use_shm = use_shm;
  512.    *_data = data;
  513.    XSync( dpy, FALSE );
  514.    g_key_file_free( keyfile );
  515.    sem_init( &data->sema, 0, 1 );
  516.    data->overlay_window = widget->window;
  517.    data->overlay_gc = XCreateGC( data->display,
  518.  GDK_WINDOW_XWINDOW( data->overlay_window ),
  519.  0, &values );
  520.    g_assert( data->overlay_gc );
  521.    gtk_widget_set_double_buffered( widget, FALSE );
  522.    gdk_window_show( data->overlay_window );
  523.    return TRUE;
  524. }
  525. void backend_xv_destroy( gpointer _data )
  526. {
  527.    struct xv_backend_data *data = _data;
  528.    
  529.    int i;
  530.    TRACE( "xv_destroyn" );
  531.    XSync( data->display, FALSE );
  532.    XFreeGC( data->display, data->overlay_gc );
  533.    if( data->gdkgc )
  534.    {
  535.       g_object_unref( data->gdkgc );
  536.    }
  537.  
  538.    for( i = 0; i < MAX_IMAGE_BUFFERS; i++ )
  539.    {
  540.       shmdt( data->shminfo[i].shmaddr );
  541.       XFree( data->image[i] );
  542.    }
  543.    XvUngrabPort( data->display, data->port_id, CurrentTime );
  544.    XFree( data->p_adaptor_info );
  545.    g_used_ports[data->used_port] = 0;
  546.    g_free( data );
  547. }
  548. void backend_xv_set_crop( gpointer _data, int crop_x, int crop_y, int crop_w, int crop_h )
  549. {
  550.    struct xv_backend_data *data = _data;
  551.    
  552.    data->crop_x = crop_x;
  553.    data->crop_y = crop_y;
  554.    data->crop_w = crop_w;
  555.    data->crop_h = crop_h;
  556. }
  557. void backend_xv_redraw( gpointer _data )
  558. {
  559.    struct xv_backend_data *data = _data;
  560.    if( data->atom_colorkey )
  561.    {
  562.       int width, height;
  563.       
  564.       width = data->widget->allocation.width < data->output_width ? data->widget->allocation.width : data->output_width;
  565.       height = data->widget->allocation.height < data->output_height ? data->widget->allocation.height : data->output_height;
  566.       
  567. /*       gdk_draw_rectangle( data->widget->window, */
  568. /*    data->gdkgc, */
  569. /*    TRUE, */
  570. /*    0, 0, */
  571. /*    width, height ); */
  572. /*       printf( "draw_rectanglen" ); */
  573.       
  574.    }
  575.    
  576.    if( data->current_buffer >= 0 )
  577.    {
  578.       if( data->use_shm )
  579.       {
  580.  XvShmPutImage( data->display,
  581. data->port_id,
  582. GDK_WINDOW_XWINDOW( data->overlay_window ),
  583. data->overlay_gc,
  584. data->image[data->current_buffer],
  585. data->crop_x, data->crop_y, data->crop_w, data->crop_h,
  586. 0, 0, data->output_width, data->output_height,
  587. 1 );
  588.       }
  589.       else
  590.       {
  591.  
  592.  XvPutImage( data->display,
  593.      data->port_id,
  594.      GDK_WINDOW_XWINDOW( data->overlay_window ),
  595.      data->overlay_gc,
  596.      data->image[data->current_buffer],
  597.      data->crop_x, data->crop_y, data->crop_w, data->crop_h,
  598.      0, 0, data->output_width, data->output_height );
  599.       }
  600.    }
  601. }
  602. void backend_xv_update_image( gpointer _data, unicap_data_buffer_t *data_buffer, GError **err )
  603. {
  604.    struct xv_backend_data *data = _data;
  605.    int start, tmp, i;
  606.    gboolean nr_unlocked_buffers = 0;
  607.    start = ( data->current_buffer + 1 ) % MAX_IMAGE_BUFFERS;
  608.    // find the first buffer not locked
  609.    for( tmp = start; 
  610. ( tmp != data->current_buffer ) && ( ( data->data_buffers[tmp].flags & UNICAP_FLAGS_BUFFER_LOCKED ) || ( tmp == ( data->current_buffer ) ) ); 
  611. tmp = ( tmp+1 ) % MAX_IMAGE_BUFFERS )
  612.    {
  613.    }
  614.    if( tmp == MAX_IMAGE_BUFFERS )
  615.    {
  616.       TRACE( "No free buffers! ( Should never get here !!! )n" );
  617.       return;
  618.    }   
  619.    
  620.    
  621.    unicap_copy_format( &data->data_buffers[tmp].format, &data_buffer->format );
  622.    data->data_buffers[tmp].data = ( unsigned char * )data->image[tmp]->data;
  623.    if( data_buffer->format.fourcc != data->xv_mode_id )
  624.    {
  625.       data->data_buffers[tmp].format.fourcc = data->xv_mode_id;
  626.       
  627.       ucil_convert_buffer( &data->data_buffers[tmp], data_buffer );
  628.    }
  629.    else
  630.    {
  631.       g_memmove( data->data_buffers[tmp].data, 
  632.  data_buffer->data, 
  633.  data_buffer->buffer_size );
  634.    }
  635.    data->data_buffers[tmp].format.fourcc = data->xv_mode_id;
  636.    data->data_buffers[tmp].buffer_size = data->data_buffers[tmp].format.buffer_size =
  637.       data_buffer->format.size.width * data_buffer->format.size.height * data->data_buffers[tmp].format.bpp / 8;   
  638.    
  639.    memcpy( &data->data_buffers[tmp].fill_time, &data_buffer->fill_time, sizeof( struct timeval) );
  640. /*    printf( "tmp: %d current: %d  fourcc: %08x   bpp: %dn", tmp, data->current_buffer, data->data_buffers[tmp].format.fourcc,  */
  641. /*     data->data_buffers[tmp].format.bpp); */
  642.    for( i = 0; i < MAX_IMAGE_BUFFERS; i++ )
  643.    {
  644.       if( !(data->data_buffers[i].flags & UNICAP_FLAGS_BUFFER_LOCKED ) )
  645.       {
  646.  nr_unlocked_buffers++;
  647.       }
  648.    }
  649. /*    printf( "nr: %dn", nr_unlocked_buffers ); */
  650.    if( data->new_frame_callback && ( nr_unlocked_buffers > 2 ) )
  651.    {
  652.       data->new_frame_callback( UNICAP_EVENT_NEW_FRAME, data->new_frame_callback_handle, &data->data_buffers[tmp], data->new_frame_callback_data );
  653.    }
  654.    data->next_display_buffer = tmp;
  655.    
  656. }
  657. void backend_xv_display_image( gpointer _data )
  658. {
  659.    struct xv_backend_data *data = _data;
  660. /*    printf( "disp: next = %d curr = %dn", data->next_display_buffer, data->current_buffer ); */
  661.    data->current_buffer = data->next_display_buffer;
  662.    backend_xv_redraw( _data );
  663. }
  664. void backend_xv_expose_event( gpointer _data, GtkWidget *da, GdkEventExpose *event )
  665. {
  666.    struct xv_backend_data *data = _data;
  667.    if( data->gdkgc )
  668.    {
  669.       gdk_draw_rectangle( da->window,
  670.   data->gdkgc,
  671.   TRUE,
  672.   event->area.x, event->area.y,
  673.   event->area.width, event->area.height );
  674.    }
  675.    
  676.    backend_xv_redraw( _data );
  677. /*    { */
  678. /*       int width, height; */
  679. /*       GdkGC *foogc = create_gc( data->widget, 0xff, 0xff, 0 ); */
  680.       
  681. /*       width = data->widget->allocation.width < data->output_width ? data->widget->allocation.width : data->output_width; */
  682. /*       height = data->widget->allocation.height < data->output_height ? data->widget->allocation.height : data->output_height; */
  683. /*       gdk_draw_rectangle( data->widget->window, */
  684. /*    foogc, */
  685. /*    TRUE, */
  686. /*    5, 5, */
  687. /*    width-10, height-10 ); */
  688. /*       g_object_unref( foogc ); */
  689. /*    } */
  690. }
  691. void backend_xv_get_image_data( gpointer _data, unicap_data_buffer_t *data_buffer, int b )
  692. {
  693.    struct xv_backend_data *data = _data;
  694.    if( b == 0 )
  695.    {
  696.       memcpy( data_buffer, &data->data_buffers[data->current_buffer], sizeof( unicap_data_buffer_t ) );
  697.    }
  698.    else
  699.    {
  700.       memcpy( data_buffer, &data->data_buffers[data->next_display_buffer], sizeof( unicap_data_buffer_t ) );
  701.    }
  702.    
  703.    sprintf( data_buffer->format.identifier, "%c%c%c%c", 
  704.     ( data_buffer->format.fourcc >> 0 ) & 0xff, 
  705.     ( data_buffer->format.fourcc >> 8 ) & 0xff, 
  706.     ( data_buffer->format.fourcc >> 16 ) & 0xff, 
  707.     ( data_buffer->format.fourcc >> 24 ) & 0xff );
  708. }
  709. void backend_xv_lock( gpointer _data )
  710. {
  711.    struct xv_backend_data *data = _data;
  712.    sem_wait( &data->sema );
  713. }
  714. void backend_xv_unlock( gpointer _data )
  715. {
  716.    struct xv_backend_data *data = _data;
  717.    sem_post( &data->sema );
  718. }
  719. void backend_xv_set_scale_to_fit( gpointer _data, gboolean scale_to_fit )
  720. {
  721.    struct xv_backend_data *data = _data;
  722.    data->scale_to_fit = scale_to_fit;
  723.    if( !scale_to_fit )
  724.    {
  725.       data->output_width = data->width;
  726.       data->output_height = data->height;
  727.    }
  728.    else
  729.    {
  730.       data->output_width = data->widget->allocation.width;
  731.       data->output_height = data->widget->allocation.height;
  732.    }
  733.    
  734. }
  735. void backend_xv_set_pause_state( gpointer _data, gboolean state )
  736. {
  737.    struct xv_backend_data *data = _data;
  738.    if( data->redisplay_timerid )
  739.    {
  740.       g_source_remove( data->redisplay_timerid );
  741.       data->redisplay_timerid = 0;
  742.    }
  743.    TRACE( "set pause: %dn", state );
  744.    
  745.    if( state )
  746.    {
  747.       data->redisplay_timerid = g_timeout_add( 300, (GSourceFunc)redraw_timeout, _data );
  748.    }
  749.    data->pause_state = state;
  750.    
  751. }
  752. guint backend_xv_get_flags( gpointer _data )
  753. {
  754.    return BACKEND_FLAGS_SCALING_SUPPORTED;
  755. }
  756. unicap_new_frame_callback_t backend_xv_set_new_frame_callback( void *_backend_data, 
  757.        unicap_new_frame_callback_t cb, 
  758.        unicap_handle_t handle, 
  759.        void *data )
  760. {
  761.    unicap_new_frame_callback_t old_cb;
  762.    struct xv_backend_data *backend_data = ( struct xv_backend_data * )_backend_data;
  763.    
  764.    old_cb = backend_data->new_frame_callback;
  765.    backend_data->new_frame_callback = NULL;
  766.    backend_data->new_frame_callback_data = data;
  767.    backend_data->new_frame_callback_handle = handle;
  768.    backend_data->new_frame_callback = cb;
  769.    
  770.    return old_cb;
  771. }