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

30

最近,我编写了一个PC客户端,可以使用adb实时显示和控制我的安卓手机屏幕。我使用monkey来控制设备,这个方案运行良好。问题在于如何流畅地抓取并显示手机屏幕。

我想到的第一个解决方案是通过adb不断地抓取framebuffer(类似DDMS的屏幕捕获功能)。但是目前的性能表现相当糟糕,从framebuffer中捕获的帧率只有5帧每秒(帧大小为800*480)。当我在手机上滑动时,程序看起来像是在卡顿。

我的程序是用Java编写的,使用ddmslib来获取framebuffer。

补充说明:
我发现将原始的framebuffer数据编码成.png格式非常慢,否则这将是传输压缩原始图像的快速方式。

如何提高屏幕截取的速度,以达到流畅的效果?


也在寻找这个问题的答案。 - Ron
12个回答

27

6
对于我来说(使用Cygwin的Windows 7),使用sed的那个命令有效,而perl会导致文件损坏:adb shell screencap -p | sed 's/\r$//' > screen.png - Mikaël Mayer
在我的 Mac 上也起作用了。 - ieselisra
1
这对我来说似乎需要很长时间,使用安卓4.3的三星Galaxy S5完成命令并将图像保存到我的电脑需要3至8秒。 - jenovachild
可以在OSX上运行,但不作为别名: alias adbscreenshot='adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen_$(date +%Y%m%d_%H%M%S).png' - VivienG
对我来说,它就像这样工作:adb shell screencap -p。花了2个小时搜索为什么perl和sed不起作用。 - Bilow

12

你可以使用:

$ adb exec-out screencap -p > test.png

更新

Android 11引入了无线调试功能,并加速了一些操作。

$ time adb exec-out screencap -p > test.png

real    0m0.661s
user    0m0.050s
sys 0m0.066s

2021年9月更新

使用take-screenshot来自CulebraTester2,您可以实现更高的帧率。

./take-screenshot 

 Image in file:///tmp/culebra.zSSYZ6VG.png


是的,这是一种可行的方法。但它几乎和抓取“帧缓冲区”一样快。 - Robot Dreamer

9
如果慢的部分是从原始数据转换为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,几乎没有额外开销。

更新:

这个由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

4
在我的 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中。


4
使用这种方法,我的应用程序仍然以完整的帧率运行。
adb pull /dev/graphics/fb0

这将从帧缓冲区中提取原始数据。它似乎与屏幕宽度相同,但高度已填充。我的设备上的帧缓冲区似乎是RGBA8888格式的。如果要获取屏幕上显示的内容,应忽略alpha通道。

请注意,对于我来说,这需要大约0.8秒来下载(分辨率:480x854),但如果我将其连续下载,它不会影响设备的帧率。


3
这是一个较慢的解决方案,但我确定它是你在基于adb的解决方案中能找到的最快速度了。
# 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; 

this is the same code into my web application


1

来自docs

拍摄设备截图

screencap命令是一种用于拍摄设备显示屏幕截图的Shell实用程序。 在Shell中,语法为:

screencap <filename>

要从命令行使用屏幕截图,请输入以下内容:

$ adb shell screencap /sdcard/screen.png

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

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

录制设备屏幕

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

Note: Audio is not recorded with the video file.

开发者可以使用此文件创建推广或培训视频。在 shell 中,其语法为:

screenrecord [options] <filename>

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

$ adb shell screenrecord /sdcard/demo.mp4

按下Ctrl-C停止屏幕录制,否则录制将在三分钟或--time-limit设置的时间限制到达时自动停止。

要开始记录设备屏幕,请运行screenrecord命令记录视频。然后,运行pull命令将视频从设备下载到主机计算机。以下是一个示例记录会话:

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

屏幕录制工具可以按照您要求的任何支持的分辨率和比特率进行录制,同时保留设备显示的宽高比。该工具默认以本地显示分辨率和方向进行记录,最长记录时间为三分钟。
在使用屏幕录制工具时,您应该注意一些已知的限制:
某些设备可能无法以其本机显示分辨率进行录制。如果您在屏幕录制过程中遇到问题,请尝试使用较低的屏幕分辨率。 不支持录制期间屏幕旋转。如果屏幕在录制过程中旋转,则部分屏幕会在录制中被切掉。

0

有些人说,在Perl中有许多方法来完成一件事情。:-) 无论如何,这种方式可能会表现得更好(因为没有正则表达式),并且可能解决在MS Windows的Cygwin中(其Perl定义\n为CRLF)的问题:

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

0
我对@steveha的解决方案进行了改进:
创建一个名为“android-screenshot”的shell脚本,其内容如下:
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

0

从Android 4.4开始,有一个名为screenrecord的程序。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接