8
votes

Capture d'écran à l'aide d'OpenGL et / ou X11

J'essaie d'obtenir une capture d'écran de l'écran ou une fenêtre. J'ai essayé d'utiliser des fonctions de x11 et ça marche bien. Le problème est que l'obtention des pixels de Ximage prend beaucoup de temps. Que j'ai essayé de rechercher des réponses sur la façon de le faire en utilisant OpenGL. Voici ce que j'ai:

#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>


int main(int argc, char **argv)
{

int width=1200;
int height=800; 
//_____________________________----
 Display *dpy;
  Window root;
  GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  XVisualInfo *vi;
  GLXContext glc;

  dpy = XOpenDisplay(NULL);

  if ( !dpy ) {
    printf("\n\tcannot connect to X server\n\n");
    exit(0);
  }

  root = DefaultRootWindow(dpy);
  vi = glXChooseVisual(dpy, 0, att);

  if (!vi) {
    printf("\n\tno appropriate visual found\n\n");
    exit(0);
  }

glXMakeCurrent(dpy, root, glc);
  glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);


  printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));

//____________________________________________
glXMakeCurrent(dpy, root, glc);

glEnable(GL_DEPTH_TEST); 
GLubyte* pixelBuffer = new GLubyte[sizeof(GLubyte)*width*height*3*3];

glReadBuffer(GL_FRONT); 

GLint ReadBuffer;
glGetIntegerv(GL_READ_BUFFER,&ReadBuffer);
glPixelStorei(GL_READ_BUFFER,GL_RGB);

GLint PackAlignment;
glGetIntegerv(GL_PACK_ALIGNMENT,&PackAlignment); 
glPixelStorei(GL_PACK_ALIGNMENT,1);

glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_INT, pixelBuffer);

int i;

for (i=0;i<100;i++) printf("%u\n",((unsigned int *)pixelBuffer)[i]);



return 0;
}


2 commentaires

Qu'est-ce qui vous fait que l'utilisation de GL va le rendre plus rapide? Cela devrait être le même.


Combien de temps faut-il? Y a-t-il une transmission réseau impliquée? Êtes-vous juste en train de regarder stdout dans un terminal? Essayez de rediriger vers un fichier et utilisez la commande . Les caractères d'impression sur le terminal utilisent le même serveur X qui essaie désespérément de copier une image et de le marshall sur un protocole. Heisenberg peut s'appliquer; Votre technique d'inspection peut déformer les informations mêmes que vous recherchez.


3 Réponses :


8
votes

Je ne pense pas ce que vous essayez de faire est possible. Vous ne pouvez pas utiliser OpenGL pour lire des pixels de la fenêtre que vous ne possédez pas et que vous n'utilisez probablement pas OpenGL. Vous devez vous tenir à X11.

Si vous avez ximage Vous pouvez obtenir des pixels bruts à partir de xImage-> données . Assurez-vous simplement que vous le lisez au format correct.

http://tronche.com/gui/x/xlib/graphics/ images.html


3 commentaires

Merci pour la réponse.Mais est-il possible de l'accélérer? Je ne pense pas que les pixels de ximage soient présentés linéairement par les données XImage->. Je pense que les pixels sont composés de multiples bits dispersés sur plusieurs octets. Vous avez donc besoin de nombreuses opérations de bits pour obtenir des valeurs de pixels. J'utilise la fonction xgepixel et xypixmap, image = xgetimage (DIS, DEFAULTIMAGEWINDOWWINDOW (DIS), 0, 0, Largeur, Hauteur, Allplanes, XYPIXMAP) ;. Peut-être que je shodld utiliser différents pixmap, tels que ZPIXMAP? Je dois obtenir des valeurs de pixels dans certains millisecondes, mais l'obtention de tous les pixels prend parfois une seconde. Est-ce que quelqu'un a des suggestions?


Utilisez XSHMGETImage () pour une méthode plus rapide. Pour un exemple, voir le code dans lien < / a>


xypixmap est un très mauvais format. Ce que vous voulez, c'est zpixmap , dans lequel les pixels sont présentés linéairement par le tampon ximage-> data , comme vous le dites. Vous pouvez utiliser xcb_image_get () , mais j'utilise xcb_image_shm_get () et je peux obtenir tout 1920 * 1080 pixels à environ 600 fps ( c'est-à-dire moins de 2 ms) ( xcb_image_get () me donne 200 fps)




0
votes

Les travaux suivants sont exécutés une fois à 140 fps sur ma plate-forme. xcb_image_get () code> (appelé avec xcb_image_format_z_pixmap x />) stockera tous les pixels dans ximg-> données code>, pixel par pixel. Sur ma plate-forme, chaque pixel est de 32 bits, chaque canal est de 8 bits, et il y a 3 canaux (à 8 bits par pixel n'est pas utilisé).

/*
gcc ss.c -o ss -lxcb -lxcb-image && ./ss
*/

#include <stdio.h>
#include <xcb/xcb_image.h>

xcb_screen_t* xcb_get_screen(xcb_connection_t* connection){
  const xcb_setup_t* setup = xcb_get_setup(connection);  // I think we don't need to free/destroy this!
  return xcb_setup_roots_iterator(setup).data;
}

void xcb_image_print(xcb_image_t* ximg){
  printf("xcb_image_print()  Printing a (%u,%u) `xcb_image_t` of %u bytes\n\n", ximg->height, ximg->width, ximg->size);
  for(int i=0; i < ximg->size; i += 4){
    printf(" ");
    printf("%02x", ximg->data[i+3]);
    printf("%02x", ximg->data[i+2]);
    printf("%02x", ximg->data[i+1]);
    printf("%02x", ximg->data[i+0]);
  }
  puts("\n");
}

int main(){
  // Connect to the X server
  xcb_connection_t* connection = xcb_connect(NULL, NULL);
  xcb_screen_t* screen         = xcb_get_screen(connection);

  // Get pixels!
  xcb_image_t* ximg = xcb_image_get(connection, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
  // ... Now all pixels are in ximg->data!

  xcb_image_print(ximg);

  // Clean-up
  xcb_image_destroy(ximg);
  xcb_disconnect(connection);
}


2 commentaires

Bonjour, Savez-vous pourquoi la taille de l'image n'est pas 1024 * 768 * 3? (3 Parce que RVB) Sortie: xcb_image_print () Impression A (1024 768) xcb_image_t de 1572864 octets, profondeur: 16, BPP: 16


Je pense que c'est toujours 1024 * 768 * 4 , car chaque pixel est rembourré pour occuper exactement 4 octets. Donc, chaque pixel a 3 canaux (parce que RVB), mais il occupe 4 octets (un octet est donc toujours zéro). Je pense que c'est comme ça que ça se passe, bien que cela dépend probablement de votre chauffeur graphique ...