齐肩梨花头:Android Native Screen capture application using the Framebuffer ? PocketMagic

来源:百度文库 编辑:九乡新闻网 时间:2024/07/15 01:20:43

Android Native Screen capture application using the Framebuffer

By Radu Motisan Posted on November 18th, 2010


It is possible to write a native C application, that opens the framebuffer (/dev/graphics/fb0) to extract bitmap data representing the screen surface image.

It is also possible to modify the framebuffer data and by doing so to do a low level drawing on screen (that is also very fast).

The data must be then converted (aligned/reversed) to standard BMP format, and saved to disc.

The framebuffer grabber:

 static int get_framebuffer(GGLSurface *fb){int fd;void *bits; fd = open("/dev/graphics/fb0", O_RDWR);if(fd < 0) {perror("cannot open fb0");return -1;} if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {perror("failed to get fb0 info");return -1;} if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {perror("failed to get fb0 info");return -1;} //dumpinfo(&fi, &vi); bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(bits == MAP_FAILED) {perror("failed to mmap framebuffer");return -1;} fb->version = sizeof(*fb);fb->width = vi.xres;fb->height = vi.yres;fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);fb->data = bits;fb->format = GGL_PIXEL_FORMAT_RGB_565; fb++; fb->version = sizeof(*fb);fb->width = vi.xres;fb->height = vi.yres;fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);fb->format = GGL_PIXEL_FORMAT_RGB_565; return fd;} 

The BITMAP former:
The first thing to do is to convert the Framebuffer's 16 bit data into24 bit. We're not gaining extra-quality here, we're just "stretching"the colors from:
5 bits blue : 2^5=32 blue color nuances
6 bits green : 2^6=64 green color nuances (in 16bit colors, green hasmore color space since the human eye is more sensitive to green color)
5 bits red : 2^5=32 red color nuances
32x64x32 possible 16bits colors (2^16)
To:
8 bits blue : 2^8 = 256 color nuances
8 bits green : 2^8 = 256 color nuances
8 bits red : 2^8 = 256 color nuances
A total of 2^24 colors, but as I said we're just "stretching" the color intervals without any information gain.

 //convert pixel datauint8_t *rgb24;if (depth == 16){rgb24 = (uint8_t *)malloc(w * h * 3);int i = 0;for (;i RRRRRRRRGGGGGGGGBBBBBBBB// in rgb24 color max is 2^8 per channel (*255/32 *255/64 *255/32)rgb24[3*i+2]   = (255*(pixel16 & 0x001F))/ 32; //Bluergb24[3*i+1]   = (255*((pixel16 & 0x07E0) >> 5))/64;//Greenrgb24[3*i]     = (255*((pixel16 & 0xF800) >> 11))/32; //Red}}elseif (depth == 24){rgb24 = (uint8_t *) gr_framebuffer[0].data;}else{//freeclose(gr_fb_fd);exit(2);};//save RGB 24 Bitmapint bytes_per_pixel = 3;BMPHEAD bh;memset ((char *)&bh,0,sizeof(BMPHEAD)); // sets everything to 0//bh.filesize  =   calculated size of your file (see below)//bh.reserved  = two zero bytesbh.headersize  = 54L;// for 24 bit imagesbh.infoSize  =  0x28L;// for 24 bit imagesbh.width     = w;// width of image in pixelsbh.depth     = h;// height of image in pixelsbh.biPlanes  =  1;// for 24 bit imagesbh.bits      = 8 * bytes_per_pixel;// for 24 bit imagesbh.biCompression = 0L;// no compressionint bytesPerLine;bytesPerLine = w * bytes_per_pixel;  // for 24 bit images//round up to a dword boundaryif (bytesPerLine & 0x0003){bytesPerLine |= 0x0003;++bytesPerLine;}bh.filesize = bh.headersize + (long)bytesPerLine * bh.depth;FILE * bmpfile;//printf("Bytes per line : %d\n", bytesPerLine);bmpfile = fopen("screen.bmp", "wb");if (bmpfile == NULL){close(gr_fb_fd);exit(3);}fwrite("BM",1,2,bmpfile);fwrite((char *)&bh, 1, sizeof (bh), bmpfile);//fwrite(rgb24,1,w*h*3,bmpfile);char *linebuf;linebuf = (char *) calloc(1, bytesPerLine);if (linebuf == NULL){fclose(bmpfile);close(gr_fb_fd);exit(4);} 

Now the next thing to do is to align the BGR triplets and to switch order , to match the BMP RGB24 color format.

 int line,x;for (line = h-1; line >= 0; line --){// fill line linebuf with the image data for that linefor( x =0 ; x < w; x++ ){*(linebuf+x*bytes_per_pixel) = *(rgb24 + (x+line*w)*bytes_per_pixel+2);*(linebuf+x*bytes_per_pixel+1) = *(rgb24 + (x+line*w)*bytes_per_pixel+1);*(linebuf+x*bytes_per_pixel+2) = *(rgb24 + (x+line*w)*bytes_per_pixel+0);}// remember that the order is BGR and if width is not a multiple// of 4 then the last few bytes may be unusedfwrite(linebuf, 1, bytesPerLine, bmpfile);}fclose(bmpfile);close(gr_fb_fd); 

Download the code: NativeScreenCapture
Note that you are not allowed to distribute this code without visiblyindicating it's author (me) and the source (this page) and You may notembedded it in commercial applications.
To compile the code, use the NDK, as presented in this article.
Running the code produces a screen.bmp file:

screen.bmp

Hope this helps.