我们在调屏时很多时候会出现花屏的现象,有的可能和屏有关系,有的时候可能和上层软件有关系,那么我们就要去确认了,到底是屏的问题,还是上层软件问题呢,我们可以通过截屏的方法来验证。
好在Android给我们提供了这样的工具screencap,那么首先来看命令help信息:
那么我们这里只需要-p选项就可以了,把图片保存到一个目录下,然后就可以把它拉出来查看了。
好在Android给我们提供了这样的工具screencap,那么首先来看命令help信息:
# screencap -h usage: screencap [-hp] [-d display-id] [FILENAME] -h: this message -p: save the file as a png. -d: specify the display id to capture, default 0. If FILENAME ends with .png it will be saved as a png. If FILENAME is not given, the results will be printed to stdout.
那么我们这里只需要-p选项就可以了,把图片保存到一个目录下,然后就可以把它拉出来查看了。
# screencap -p /sdcard/screenshot.png $ adb pull /sdcard/screenshot.png .
命令用法很简单的,很有用的一个工具。
除了screencap命令之外,还有个命令screenshot命令,这个命令主要是截取开机logo的命令,猜测是framebuffer并不只是一个缓冲区,有多个(两个),而其中的开机logo缓冲区并没有清掉,screenshot命令则就是截取该缓冲区的数据。
为此,我写了个screenshot.c程序,相当与screenshot命令,只是保存的图片为bmp格式,代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
struct bitmap_fileheader {
unsigned short type;
unsigned int size;
unsigned short reserved1;
unsigned short reserved2;
unsigned int off_bits;
} __attribute__ ((packed));
struct bitmap_infoheader {
unsigned int size;
unsigned int width;
unsigned int height;
unsigned short planes;
unsigned short bit_count;
unsigned int compression;
unsigned int size_image;
unsigned int xpels_per_meter;
unsigned int ypels_per_meter;
unsigned int clr_used;
unsigned int clr_important;
} __attribute__ ((packed));
int saveimage(char *filename, char *fb, int width, int height, int bits_per_pixel)
{
FILE *fp;
struct bitmap_fileheader fh;
struct bitmap_infoheader ih;
int x, y;
fp = fopen(filename, "wb");
if (fp == NULL) {
printf("can't open file %s\n", filename);
return -1;
}
memset(&fh, 0, sizeof(struct bitmap_fileheader));
fh.type = 0x4d42;
fh.off_bits = sizeof(struct bitmap_fileheader) + sizeof(struct bitmap_infoheader);
fh.size = fh.off_bits + width * height * (bits_per_pixel / 8);
fwrite(&fh, 1, sizeof(struct bitmap_fileheader), fp);
memset(&ih, 0, sizeof(struct bitmap_infoheader));
ih.size = sizeof(struct bitmap_infoheader);
ih.width = width;
ih.height = height;
ih.planes = 1;
ih.bit_count = bits_per_pixel;
/* ih.compression = 0;
ih.size_image = 0;
ih.xpels_per_meter = 0;
ih.ypels_per_meter = 0;
ih.clr_used = 0;
ih.clr_important = 0;*/
fwrite(&ih, 1, sizeof(struct bitmap_infoheader), fp);
/* fwrite(fb, 1, width * height * (bits_per_pixel / 8), fp);*/
fb += width * (bits_per_pixel / 8) * (height - 1);
for (y = 0; y < height; y++, fb -= width * (bits_per_pixel / 8)) {
fwrite(fb, 1, width * (bits_per_pixel / 8), fp);
}
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
int fd;
struct fb_var_screeninfo var;
char *fb;
int size;
fd = open("/dev/graphics/fb0", O_RDWR);
if (fd < 0) {
printf("can't open fb0!\n");
return -1;
}
ioctl(fd, FBIOGET_VSCREENINFO, &var);
printf("xres %d yres %d bpp %d\n", var.xres,
var.yres, var.bits_per_pixel);
size = var.xres * var.yres * (var.bits_per_pixel / 8);
fb = (char *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
saveimage(argv[1], fb, var.xres, var.yres, var.bits_per_pixel);
munmap(fb, size);
close(fd);
return 0;
}
注意该程序并没有考虑bmp图片4字节对齐问题,以及颜色反转问题。
我们还注意screencap命令有个-d选项,该选项默认参数为0,但不使用-d选项时,即参数为0时截取的就是屏当前显示的数据,当使用参数值大于等于1时,screencap命令就同screenshot命令一样,也是开机logo的数据。
// 2015.07.25 add
有的时候,可能只是截图不能满足一些场合,例如瞬时发生的闪屏现象,这个时候需要录像才能看清,好在android也提供了一个命令那就是screenrecord命令,可以通过screenrecord --help查看其具体用法,这里只给出一个简单的用法,例如:
screenrecord /sdcard/demo.mp4