снимок экрана с использованием openGL и / или X11 - PullRequest
8 голосов
/ 19 мая 2011

Я пытаюсь получить скриншот экрана или окна. Я пытался использовать функции из X11 и работает нормально. Проблема в том, что получение пикселей из XImage занимает много времени. Затем я попытался найти ответы на некоторые вопросы о том, как это сделать с помощью openGL. Вот что у меня есть:

#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;
}

когда я запускаю программу, она возвращает ошибку: X Ошибка неудавшегося запроса: BadAccess (попытка доступа к частному ресурсу отклонена) Главный код операции невыполненного запроса: 199 () Незначительный код операции для неудавшегося запроса: 26 Серийный номер неудавшегося запроса: 20 Текущий серийный номер в выходном потоке: 20

если я закомментирую строку с glXMakeCurrent (dpy, root, glc); before glc = glXCreateContext (dpy, vi, NULL, GL_TRUE); он не возвращает ошибок, но все пиксели равны 0.

Как мне решить эту проблему? Я новичок в openGL и, возможно, мне здесь не хватает чего-то важного. Может быть, существует другой способ получения пикселей с экрана или определенного окна?

Ответы [ 3 ]

7 голосов
/ 19 мая 2011

Я не думаю, что вы пытаетесь сделать это возможно.Вы не можете использовать OpenGL для чтения пикселей из окна, которое вам не принадлежит и которое, вероятно, даже не использует OpenGL.Вам нужно придерживаться X11.

Если у вас XImage, вы можете получить необработанные пиксели от ximage->data.Просто убедитесь, что вы читаете его в правильном формате.

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

4 голосов
/ 19 августа 2012

Вы можете использовать XShmGetImage, но сначала вам нужно запросить расширения сервера X11, чтобы убедиться, что расширение MIT-SHM доступно. Для этого вам также необходимо знать, как настроить и использовать сегмент совместно используемой памяти.

Запрос расширения:

http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l224

Получение изображения:

http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l537

0 голосов
/ 15 мая 2018

Следующее выполняется на моей платформе один раз со скоростью 140 кадров в секунду.xcb_image_get() (вызывается с XCB_IMAGE_FORMAT_Z_PIXMAP) будет хранить все пиксели в ximg->data, пиксель за пикселем.На моей платформе каждый пиксель составляет 32 бита, каждый канал - 8 бит, и есть 3 канала (до 8 бит на пиксель не используются).

/*
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);
}
...