【源码解读】Screencap源码分析-基础篇

来源:互联网 发布:青岛网络在线问政 编辑:程序博客网 时间:2024/05/17 07:35

由于工作的关联关系,本文将针对Android screencap的源码进行分析,此文是基础篇,为后续对源码的修改做知识储备。


本文期望达到的目的:

  1. 了解screencap使用
  2. 了解screencap实现基础原理
  3. 为后续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


备注:

  1. -d 参数为支持扩展的display设备
  2. 如果文件名以.png结尾时,它将保存为png文件,如果文件名没有给出,则结果被会被输出到stdout(导出会相当的卡)


如果手机没有连接adb,我们也可以用以下代码去完成调用:

public Boolean DoScreenShot(){Process process = null;DataOutputStream os = null;try {}catch (Exception e){return false;}finally {Try {process = Runtime.getRuntime().exec(“su”);os = new DataOutputStream(process.getOutputStream());os.writeBytes(“serccncap –p ” + strFileFullPath);os.flush();process.waitFor();If (os != null) {os.close();}process.destroy();}catch (Exception e){}}return true;}

源码分析:

核心代码:


整个程序最核心的代码就是上图。


获取截图信息的流程是通过ScreenshotClient对象,如果发现ScreenshotClient获取失败则读取/dev/graphics/fb0文件。


不知道/dev/graphics/fb0是什么文件,可以google下。

1、 fb0读取比较容易看懂:(如果有兴趣的话可以继续去看linux内核文件中的显示文件)   

  1. 直接open()打开文件
  2. 通过fb_var_screeninfo结构体来定位fb0的文件头格式
  3. 根据偏移地址把一贞的数据读到一个mmap中,
  4. base = (void const *)((char const *)mapbase + offset);

2、ScreenshotClient:

  1. 创建ScreenshotClient screenshot
  2. 直接调用screenshot.update()
  3. 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版本是没有完全实现的)

enum Type{kUnknown_Type,kBMP_Type,kGIF_Type,kICO_Type,kJPEG_Type,kPNG_Type,kWBMP_Type,kWEBP_Type,kKTX_Type,};


2、kDefaultQuality默认值为80 图片的清晰度

如果想提高这个工具的截屏效率,可以通过选择图片格式或者选择图片的质量。


总结:

  1. 经实际测试,1s 不到10帧,screencap效率是相当差的(包含保存为jpeg等格式)。
  2. 如果需要修改保存图片的格式,需要修改源码重新编译。

1 1