如何通过adb尽可能快地捕捉屏幕?

最近,我写了一个PC客户端,可以使用adb实时显示和控制我的android手机屏幕。 我用猴子来控制设备,它工作正常。 问题是如何抓住手机屏幕并顺利显示。

我提出的第一个解决scheme是通过adb不断获取framebuffer (如DDMS的屏幕捕获function)。 现在当我这样做时,performance是相当不能接受的。 从framebuffer捕获的帧速率低至每秒5(帧大小为800 * 480)。 当我滑动手机时,我的程序看起来像打嗝。

我的程序是用java写的,用ddmslib抓取framebuffer

加:
我发现将原始framebuffer数据编码为.png格式非常慢,否则这将是传输压缩原始图像的一种快速方法。

我怎样才能提高捕捉屏幕的速度到一个平稳的水平?

Solutions Collecting From Web of "如何通过adb尽可能快地捕捉屏幕?"

 adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png 

资源:

http://blog.shvetsov.com/2013/02/grab-android-screenshot-to-computer-via.html

你可以使用:

$ adb shell screencap -p> sc.png

这不幸的是不工作(文件已损坏),所以你的select剩下的是

 $ adb shell screencap -p /mnt/sdcard/sc.png $ adb pull /mnt/sdcard/sc.png 

虽然这是相对较快的,但可能不如您所需要的那么快。

如果缓慢的部分是原始的PNG转换( time adb shell screencap -p /sdcard/x.pngtime adb shell screencap /sdcard/nonpng.raw ,因为我有它在游戏中)相当慢,png是没有必要的,那么你可以这样做https://github.com/sowcow/shot 。 它将原始数据转换为简单的ppm格式,并在获取原始数据后使用imagemagick将ppm转换为bmp,而几乎没有开销

UPD:

这个max_plenert的shell脚本就是一个比较好的例子:

 adb shell screencap /sdcard/mytmp/rock.raw adb pull /sdcard/mytmp/rock.raw adb shell rm /sdcard/mytmp/rock.raw // remove the header tail -c +13 rock.raw > rock.rgba // extract width height and pixelformat: hexdump -e '/4 "%d"' -s 0 -n 4 rock.raw hexdump -e '/4 "%d"' -s 4 -n 4 rock.raw hexdump -e '/4 "%d"' -s 8 -n 4 rock.raw convert -size 480x800 -depth 8 rock.rgba rock.png 

在我的mac上.bash_profile:

 function droidShot() { /full_path_to_droid_sdk/platform-tools/adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > $1.png } 

用法:

 droidshot whatever 

文件显示在whatever.png中

使用这种方法,我的应用程序继续以全帧率运行

 adb pull /dev/graphics/fb0 

这将从帧缓冲区中取出原始数据。 它看起来和屏幕宽度一样,但是高度被填充了。 我的设备上的帧缓冲区似乎是RGBA8888格式。 要准确得到屏幕上显示的内容,您应该忽略Alpha通道。

请注意,这需要0.8秒左右的时间来下载(resoultion:480×854),但是如果我在连续的循环下载它,它不会影响设备的帧速率。

这是一个缓慢的解决scheme,我相信这是在基于adb的解决scheme中可以find的更快的方式,

 # this line require a superuser privilege: adb shell "su -c 'cat /dev/graphics/fb0 > /sdcard/capture.raw'" adb pull /sdcard/capture.raw ffmpeg -loglevel panic -f rawvideo -pix_fmt bgr32 -s 320x480 -i \ capture.raw -vcodec png -vframes 1 capture.png; 

这是我的web应用程序相同的代码

从文档 :

以设备截图

screencap命令是一个用于截取设备显示的屏幕截图。 在shell中,语法是:

 screencap <filename> 

要从命令行使用screencap,请键入以下内容:

 $ adb shell screencap /sdcard/screen.png 

下面是一个示例截图会话,使用adb shell捕获屏幕截图,并使用pull命令从设备下载文件:

 $ adb shell shell@ $ screencap /sdcard/screen.png shell@ $ exit $ adb pull /sdcard/screen.png 

录制设备屏幕

screenrecord命令是一个shell实用程序,用于logging运行Android 4.4(API级别19)及更高版本的设备的显示。 该实用程序将屏幕活动logging到MPEG-4文件。

 Note: Audio is not recorded with the video file. 

开发人员可以使用此文件创build宣传或培训video。 在shell中,语法是:

 screenrecord [options] <filename> 

要从命令行使用screenrecord,请键入以下内容:

 $ adb shell screenrecord /sdcard/demo.mp4 

通过按Ctrl-C停止屏幕录制,否则录制将在三分钟后自动停止,或由–time-limit设置的时间限制

要开始录制设备屏幕,请运行screenrecord命令来录制video。 然后,运行pull命令将video从设备下载到主机。 以下是一个logging会话示例:

 $ adb shell shell@ $ screenrecord --verbose /sdcard/demo.mp4 (press Ctrl-C to stop) shell@ $ exit $ adb pull /sdcard/demo.mp4 

screenrecord实用程序可以按照您请求的任何支持的分辨率和比特率进行录制,同时保留设备显示的高宽比。 该实用程序默认以本机显示分辨率和方向进行logging,最长为三分钟。

screenrecord实用程序有一些已知的限制,您在使用时应该知道这些限制:

某些设备可能无法以本机显示分辨率进行录制。 如果您遇到屏幕录制问题,请尝试使用较低的屏幕分辨率。 不支持在录制过程中旋转屏幕。 如果在录制过程中屏幕旋转,则录制中的某些屏幕被切断。

我已经改进了@ steveha的解决scheme:

创build一个shell脚本说:' android-screenshot '与以下内容:

 adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen-`date +%Y-%m-%d_%X`.png 

把这个文件放在你的本地bin目录或者你喜欢的任何其他$ PATH中

这将允许您在当前目录中保存带有时间戳的文件。

请记住使用shell脚本来执行

 chmod +x android-screenshot 

那么有些人在Perl中说有很多方法可以做一件事。 :-)无论如何,这个可能会更好(因为没有正则expression式),并且可能会解决MS Windows中的Cygwin问题(其Perl定义为CRLF):

 adb shell screencap -p | perl -pe 'BEGIN { $/="\cM\cJ"; $\="\cJ"; } chomp;' > screen-$(date +%Y%m%d_%H%M%S).png 

从Android 4.4开始有一个screenrecord程序

 adb shell screenrecord /data/local/tmp/test-video.m4v adb pull /data/local/tmp/test-video.m4v ~/test-video.m4v 

adb shell screenrecord –bit-rate 8000000 –time-limit 30 /sdcard/example.mp4

您也可以更改比特率并更改video持续时间。

 adb shell screencap /sdcard/screen.png && adb pull /sdcard/screen.png my_screen01.png