2

Je dois traiter les images envoyées à l'écran vidéo de mon ordinateur portable, et je dois envoyer une entrée clavier à mon système Linux, en utilisant un programme C++ ou shell.Capture d'images d'affichage/de surveillance, envoi de données clavier sous Linux

Mon objectif est de traiter les images qui font partie d'un jeu FPS, puis de prendre des mesures à l'intérieur de ce jeu (d'où la saisie au clavier) sur la base de ces images. Au lieu d'essayer de comprendre (si c'est possible) comment s'interfacer au jeu X ou Y, en utilisant une API, je me suis dit que c'était le moyen le plus rapide de s'interfacer avec n'importe quel jeu.

Y at-il un moyen de le faire sans noyau ou pilote de périphérique de piratage? J'ai utilisé recordmydesktop pour enregistrer mon bureau en tant que vidéo auparavant, je suppose que je pourrais pirater son code et essayer d'inverser quelque chose à partir de ça. D'autres idées? Je suis sur Ubuntu 11.

Related Question

Répondre

0

J'ai enfin une solution. Je crois que UrT charge OpenGL seul de sorte que des choses telles que wallhacks, etc ne sont pas possibles. Ensuite, la meilleure option restante consiste à prendre des captures d'écran X. Cela a fonctionné assez rapidement, même à partir d'un langage de script comme Python. Le code suivant prend des captures d'écran successives et les affiche comme une animation via OpenCV. Vous devez démarrer UrT en mode minimisé, bien sûr. The rest of the details are in my project.

import gtk.gdk 
import PIL 
from opencv.cv import * 
from opencv.highgui import * 
from opencv.adaptors import PIL2Ipl 

w = gtk.gdk.get_default_root_window() 
sz = w.get_size() 
print "The size of the window is %d x %d" % sz 

size_x = 600 
size_y = 400 
start_x = 0 
start_y = 100 
end_x = start_x+size_x 
end_y = start_y+size_y 
box = (start_x, start_y, start_x+size_x, start_y+size_y) 

while True: 
    pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1]) 
    pb = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1]) 
    width,height = pb.get_width(),pb.get_height() 
    im = PIL.Image.fromstring("RGB",(width,height),pb.get_pixels()) 
    im = im.crop(box) 
    cv_img = PIL2Ipl(im) 
    cvNamedWindow("fps") 
    cvShowImage("fps", cv_img) 
    cvWaitKey(30) 

En outre, pour l'envoi de clés du jeu, la méthode ci-dessus ne fonctionne pas, je devais utiliser xdotool afin d'envoyer avant de marcher clé UrT,

xdotool search --name ioUrbanTerror windowactivate keydown W 
+0

Si elle charge OpenGL directement avec 'dlopen()', vous pouvez toujours remplacer la libGL.so dans/usr/lib par votre propre libGL.so, bien que votre solution soit probablement une solution plus simple. – Flexo

+0

vous avez probablement raison. Je devrais entrer dans plus de codage C, je pense que je vais aller de l'avant avec ma solution. La performance n'est pas trop mauvaise, étonnamment. – user423805

5

Vous n'avez pas besoin de faire quoi que ce soit aussi bas niveau que les pilotes du noyau ou l'appareil pour le faire.

Vous pouvez utiliser le XTest X11 extension pour simuler des événements d'entrée par programme, par exemple (à partir de this posting, il y a another example for keyboard).

#include <X11/extensions/XTest.h> 
#include <unistd.h> 

int main() 
{ 
    Display *dpy = NULL; 
    XEvent event; 

    dpy = XOpenDisplay (NULL); 

    /* Get the current pointer position */ 
    XQueryPointer (dpy, RootWindow (dpy, 0), 
     &event.xbutton.root, &event.xbutton.window, 
     &event.xbutton.x_root, &event.xbutton.y_root, 
     &event.xbutton.x, &event.xbutton.y, 
     &event.xbutton.state); 

    /* Fake the pointer movement to new relative position */ 
    XTestFakeMotionEvent (dpy, 0, event.xbutton.x + 100, 
     event.xbutton.y + 50, CurrentTime); 
    XSync(dpy, 0); 
    XCloseDisplay (dpy); 
    return 0; 
} 

Pour capturer les images de la façon la plus simple est d'utiliser function interposition (via LD_PRELOAD) à « intercepter » les appels à glXSwapBuffers, qui sera appelée une fois chaque image est tirée. De là, vous pouvez copier le contenu du framebuffer, en utilisant glReadPixels et faire avec ce que vous voulez.

E.g. contours non testés pour intercepter des trames OpenGL:

// Function pointer to the *real* glXSwapBuffers 
static void (*glx_fptr)(Display*, GLXDrawable) = NULL; 

// Make sure init gets called when the shared object is loaded. GCC specific. 
static void init(void) __attribute__((constructor)); 

static void init(void) { 
    dlerror(); 
    // find the real glXSwapBuffers 
    glx_fptr = dlsym(RTLD_NEXT, "glXSwapBuffers"); 
    if (NULL == glx_fptr) 
     fprintf(stderr, "[glvidcap] %s\n", dlerror()); 
} 

void glXSwapBuffers(Display *dpy, GLXDrawable drawable) { 
    unsigned int w = 0; 
    unsigned int h = 0; 
    static int x,y; 
    static Window win; 
    static unsigned int border,depth; 
    // Find the window size. (You could skip this and make it all static if you 
    // Trust the window not to change size 
    XGetGeometry(dpy, drawable, &win, &x, &y, &w, &h, &border, &depth); 

    // Assuming frame is some memory you want the frame dumped to: 
    glReadPixels(0,0,w,h,GL_BGR,GL_UNSIGNED_BYTE, frame); 

    // Call the real function: 
    assert(glx_fptr); 
    glx_fptr(dpy, drawable); 
} 

Alors, vous voulez compiler comme objet partagé et LD_PRELOAD qui a partagé l'objet avant d'exécuter quelque jeu que vous regardez.

S'il s'agit d'une application SDL, vous pouvez intercepter les appels à SDL_Flip ou SDL_UpdateRect selon le cas.

+2

glReadPixels est par rapport au moment définir la fenêtre. Vous devez d'abord lire les toutes dernières dimensions de viewport (glGetIntegerv (GL_VIEWPORT)), définir la taille de la fenêtre sur les dimensions de la fenêtre, récupérer le tampon de lecture, (glGetIntegerv (GL_READ_BUFFER)), définir le tampon de lecture sur GL_BACK, puis appeler glReadPixels. Après cela, remettre les choses à l'état précédent. – datenwolf

+0

@awoodland, en utilisant un code de démonstration OpenGL, je peux capturer et écrire des fichiers image en utilisant glcapture. Sur UrbanTerror cependant seulement gettimeofday est appelé, glXSwapBuffers ne l'est pas. Avez-vous une idée de pourquoi cela pourrait être? Mon code est ici - http://goo.gl/Gxyha – user423805

+0

@ user423805 - Je suppose que c'est faire un appel alternatif au lieu de simplement swapbuffers. Vous pourriez être en mesure de déterminer ce que c'est avec quelque chose pour renifler des appels X11, par exemple. http://xmsgtrace.sourceforge.net/ ou http://www.x.org/archive/X11R7.5/doc/man/man1/xscope.1.html mais ils peuvent ne pas fonctionner correctement avec les applications OpenGL. – Flexo

1

Merci à la réponse de @ awoodland, je cherchais des ressources connexes, et ont trouvé cet

http://bzr.sesse.net/glcapture/glcapture.c

je compile ce code comme

gcc -shared -fPIC -o glcapture.so glcapture.c -ldl 

et le charger pour le jeu FPS Urban Terror dans un script comme

LD_PRELOAD=`pwd`/glcapture.so [DIR]/UrbanTerror/ioUrbanTerror.i386 

Le moment où ce script est exécuté, le jeu est chargé. Pour une raison quelconque, les graphismes du jeu ne s'affichent pas, mais je peux l'améliorer plus tard. Quand je quitte le jeu, je vois des messages gettimeofday imprimés sur la console, ce qui me dit que le crochet a fonctionné. Je fournirai plus de détails pendant que je continue à travailler ce code.

Pour l'envoi de touches, j'ai suivi le lien

http://bharathisubramanian.wordpress.com/2010/03/14/x11-fake-key-event-generation-using-xtest-ext/

Après avoir installé le package nécessaire sur Ubuntu avec

sudo apt-get install libxtst-dev 

Ensuite fakeKey.c compilé et fonctionne sans problème.

Note: Je started a project on Github for this, tout le monde est le bienvenu à la fourchette, aide, etc.

Questions connexes