分享

Android Native Screen capture application using the Framebuffer ? PocketMagic

 shaobin0604@163.com 2011-08-11

Android Native Screen capture application using the Framebuffer

By Radu Motisan Posted on November 18th, 2010

Share

android native screen capture tool screen 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 into 24 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 has more 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 data
uint8_t *rgb24;
if (depth == 16)
{
rgb24 = (uint8_t *)malloc(w * h * 3);
int i = 0;
for (;i<w*h;i++)
{
uint16_t pixel16 = ((uint16_t *)gr_framebuffer[0].data)[i];
// RRRRRGGGGGGBBBBBB -> RRRRRRRRGGGGGGGGBBBBBBBB
// in rgb24 color max is 2^8 per channel (*255/32 *255/64 *255/32)
rgb24[3*i+2]   = (255*(pixel16 & 0x001F))/ 32; 		//Blue
rgb24[3*i+1]   = (255*((pixel16 & 0x07E0) >> 5))/64;	//Green
rgb24[3*i]     = (255*((pixel16 & 0xF800) >> 11))/32; 	//Red
}
}
else
if (depth == 24)
{
rgb24 = (uint8_t *) gr_framebuffer[0].data;
}
else
{
//free
close(gr_fb_fd);
exit(2);
};
//save RGB 24 Bitmap
int 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 bytes
bh.headersize  = 54L;			// for 24 bit images
bh.infoSize  =  0x28L;		// for 24 bit images
bh.width     = w;			// width of image in pixels
bh.depth     = h;			// height of image in pixels
bh.biPlanes  =  1;			// for 24 bit images
bh.bits      = 8 * bytes_per_pixel;	// for 24 bit images
bh.biCompression = 0L;		// no compression
int bytesPerLine;
bytesPerLine = w * bytes_per_pixel;  	// for 24 bit images
//round up to a dword boundary
if (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 line
for( 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 unused
fwrite(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 visibly indicating it's author (me) and the source (this page) and You may not embedded it in commercial applications.
To compile the code, use the NDK, as presented in this article.
Running the code produces a screen.bmp file:
android native screen capture tool

screen.bmp
android native screen capture tool screen

Hope this helps.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多