本文期望达到的目的:
- 了解screencap使用
- 了解screencap实现基础原理
- 为后续screencap源码修改和其他应用做准备
源码位置:
android4.0之后内置了截图工具screencap,一般位于/system/bin/screencap
源码路径:frameworks/base/cmds/screencap/
使用介绍:
帮助文档:
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.
使用相当简单:
adb shell screencap -p/sdcard/testscreen.png
备注:
- -d 参数为支持扩展的display设备
- 如果文件名以.png结尾时,它将保存为png文件,如果文件名没有给出,则结果被会被输出到stdout(导出会相当的卡)
如果手机没有连接adb,我们也可以用以下代码去完成调用:
源码分析:
核心代码:
整个程序最核心的代码就是上图。
获取截图信息的流程是通过ScreenshotClient对象,如果发现ScreenshotClient获取失败则读取/dev/graphics/fb0文件。
不知道/dev/graphics/fb0是什么文件,可以google下。
1、 fb0读取比较容易看懂:(如果有兴趣的话可以继续去看linux内核文件中的显示文件)
- 直接open()打开文件
- 通过fb_var_screeninfo结构体来定位fb0的文件头格式
- 根据偏移地址把一贞的数据读到一个mmap中,
- base = (void const *)((char const *)mapbase + offset);
2、ScreenshotClient:
- 创建ScreenshotClient screenshot
- 直接调用screenshot.update()
- base = screenshot.getPixels();
后续我们再继续阅读ScreenshotClient类,了解它是如何显示屏幕显示获取的:
ScreenshotClient类位于frameworks/native/libs/gui/SurfaceComposerClient.cpp中。
这个类提供了updata()函数:
从567行来看,该函数是直接调用了SurfaceFlinger服务的代理对象中的captureScreen()函数。
其中getComposerService()函数的源码:
从代码上可以看出,instance.mComposerService是SurfaceFlinger服务的代理对象。
如果有兴趣的话可以继续跟进去里面的代码,会发现上面的第5行代码就是通过getService("SurfaceFlinger", &mComposerService)获取服务代理对象。
说到“SurfaceFlinger”服务,这个服务器是比较庞大的架构。主要的作用是进行UI绘制。(后续可以深入分析)
所以:
Screencap的实现就是通过访问“SurfaceFlinger”服务或者读取fb0文件进行截屏的。
最后我们看看Screencap保存图片的代码:
程序只提供了png后缀的图片格式,如果想要返回其他的图片格式,需要要进行类型type的修改。
图片格式:
1、SkImageEncoder 中的Type 枚举(注意有些android版本是没有完全实现的)
2、kDefaultQuality默认值为80 图片的清晰度
如果想提高这个工具的截屏效率,可以通过选择图片格式或者选择图片的质量。
总结:
- 经实际测试,1s 不到10帧,screencap效率是相当差的(包含保存为jpeg等格式)。
- 如果需要修改保存图片的格式,需要修改源码重新编译。