Скриншот Nexus One от adb? - PullRequest
46 голосов
/ 11 мая 2010

Моя цель - набрать команду из одного слова и получить скриншот с укоренившегося Nexus One, подключенного через USB.

Пока что я могу получить кадровый буфер, который я считаю 32bit xRGB888 необработанным изображением, потянув его так:

adb pull /dev/graphics/fb0 fb0

Оттуда, однако, мне трудно преобразовать его в png. Я пытаюсь с ffmpeg, как это:

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb8888 -s 480x800 -i fb0 -f image2 -vcodec png image.png

Это создает прекрасное фиолетовое изображение с частями, которые смутно напоминают экран, но это ни в коем случае не чистый скриншот.

Ответы [ 14 ]

90 голосов
/ 03 августа 2012

Гораздо более простым решением для ICS является использование следующего из командной строки

adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png

Это сохранит файл screenshot.png в текущем каталоге.

Протестировано на Samsung Galaxy SII & SII под управлением 4.0.3.

13 голосов
/ 16 февраля 2012

На самом деле есть еще одна очень простая возможность получить скриншот с вашего устройства Android: напишите простой скрипт 1.script, например:

# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()

# Takes a screenshot
result = device.takeSnapshot()

# Writes the screenshot to a file
result.writeToFile('1.png','png')

и звоните monkeyrunner 1.script.

11 голосов
/ 19 июля 2010

Кажется, что кадровый буфер N1 использует кодировку RGB32 (32 бита на пиксель).

Вот мой скрипт с использованием ffmpeg:

adb pull /dev/graphics/fb0 fb0
dd bs=1920 count=800 if=fb0 of=fb0b
ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s 480x800 -i fb0b -f image2 -vcodec png fb0.png

Другой способ, полученный из метода ADP1, описанного здесь http://code.lardcave.net/entries/2009/07/27/132648/

adb pull /dev/graphics/fb0 fb0
dd bs=1920 count=800 if=fb0 of=fb0b
python rgb32torgb888.py <fb0b >fb0b.888
convert -depth 8 -size 480x800 RGB:fb0b.888 fb0.png

Python-скрипт 'rgb32torgb888.py':

import sys
while 1:
 colour = sys.stdin.read(4)
 if not colour:
  break
 sys.stdout.write(colour[2])
 sys.stdout.write(colour[1])
 sys.stdout.write(colour[0])
7 голосов
/ 11 мая 2010

Используя мой HTC Hero (и, следовательно, настраивая с 480x800 на 320x480), это работает, если я использую rgb565 вместо 8888:

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320x480 -i fb0 -f image2 -vcodec png image.png
6 голосов
/ 02 декабря 2013

Если у вас установлен dos2unix, то ниже

adb shell screencap -p | dos2unix > screen.png
2 голосов
/ 10 марта 2015

Теперь у нас есть однострочная команда, чтобы сделать скриншот. Команда выглядит следующим образом:

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

Введите вышеуказанную команду в своем терминале и нажмите ввод. Если вы хотите, чтобы скриншот хранился в каком-то определенном месте, укажите каталог (или) пути до screen.png.

Источник .

2 голосов
/ 11 мая 2010

Я считаю, что на сегодняшний день все фреймбуферы RGB 565, а не 888.

1 голос
/ 07 января 2014

Способ полностью автоматизировать этот процесс - создать скрипт, который добавляет текущую временную метку к имени файла. Таким образом, вам не нужно писать имя файла самостоятельно, все ваши скриншоты имеют другое имя, и ваши скриншоты отсортированы по времени.

Пример скрипта bash:

#! /bin/bash

filename=$(date +"_%Y-%m-%d-%H:%M")

/PATH_TO_ANDROID_SDK/platform-tools/adb -d shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screenshot$filename.png

Это создаст файл с именем, подобным screenshot_2014-01-07-10: 31.png

1 голос
/ 14 июля 2013

Это может быть связано с проблемой Чтение двоичных данных из stdout оболочки adb , где adb пытается выполнить преобразование LF в CRLF для вас (это, вероятно, просто версия adb для Windows). У меня лично были проблемы с преобразованием \ n в \ r \ r \ n, поэтому для преобразования этого кода хорошо использовать код по адресу [ 1 ] или использовать.

для меня это работает (в cygwin): adb shell 'cat /dev/graphics/fb0' | perl -pi -e 's/\r\r\n/\n/g' казалось, помогло

Кроме этого попробуйте сравнить ширину и высоту с размером файла. Размер файла должен делиться на Width * height, если это не так, тогда либо инструмент adb автоматически сделает все за вас, либо это более экзотический формат, чем rgb545 или rgb8888.

если это просто проблема цвета (т. Е. Все в результирующем изображении находится в правильном месте), вы можете рассмотреть возможность замены каналов Red & Blue, поскольку некоторые системы (в общем) используют порядок байтов BGRA вместо RGBA.

1 голос
/ 02 октября 2012

Немного сложный / чрезмерный, но он обрабатывает сценарии как screencap, так и кадрового буфера (а также вычисляет разрешение тоже).

#!/bin/bash
#
# adb-screenshot - simple script to take screenshots of android devices
#
# Requires: 'ffmpeg' and 'adb' to be somewhere in the PATH
#
# Author: Kevin C. Krinke <kevin@krinke.ca>
# License: Public Domain

# globals / constants
NAME=$(basename $0)
TGT=~/Desktop/${NAME}.png
SRC=/sdcard/${NAME}.png
TMP=/tmp/${NAME}.$$
RAW=/tmp/${NAME}.raw
FFMPEG=$(which ffmpeg)
ADB=$(which adb)
DD=$(which dd)
USB_DEVICE=""

# remove transitory files if exist
function cleanup () {
    [ -f "${RAW}" ] && rm -f "${RAW}"
    [ -f "${TMP}" ] && rm -f "${TMP}"
    [ -z "$1" ] && die "aborting process now."
    exit 0
}

# exit with an error
function die () {
    echo "Critical Error: $@"
    exit 1
}

# catch all signals and cleanup / dump
trap cleanup \
    SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGEMT SIGFPE \
    SIGKILL SIGBUS SIGSEGV SIGSYS SIGPIPE SIGALRM SIGTERM SIGURG \
    SIGSTOP SIGTSTP SIGCONT SIGCHLD SIGTTIN SIGTTOU SIGIO SIGXCPU \
    SIGXFSZ SIGVTALRM SIGPROF SIGWINCH SIGINFO SIGUSR1 SIGUSR2

# adb is absolutely required
[ -x "${ADB}" ] || die "ADB is missing!"

# cheap getopt
while [ $# -gt 0 ]
do
    case "$1" in
        "-h"|"--help")
            echo "usage: $(basename $0) [-h|--help] [-s SERIAL] [/path/to/output.png]"
            exit 1
            ;;
        "-s")
            [ -z "$2" ] && die "Missing argument for option \"-s\", try \"${NAME} --help\""
            HAS_DEVICE=$(${ADB} devices | grep "$2" )
            [ -z "${HAS_DEVICE}" ] && die "No device found with serial $2"
            USB_DEVICE="$2"
            ;;
        *)
            [ -n "$1" -a -d "$(dirname $1)" ] && TGT="$1"
            ;;
    esac
    shift
done

# prep target with fire
[ -f "${TGT}" ] && rm -f "${TGT}"

# tweak ADB command line
if [ -n "${USB_DEVICE}" ]
then
    ADB="$(which adb) -s ${USB_DEVICE}"
fi

# calculate resolution
DISPLAY_RAW=$(${ADB} shell dumpsys window)
HRES=$(echo "${DISPLAY_RAW}" | grep SurfaceWidth  | head -1 | perl -pe 's/^.*\bSurfaceWidth\:\s*(\d+)px\b.*$/$1/')
VRES=$(echo "${DISPLAY_RAW}" | grep SurfaceHeight | head -1 | perl -pe 's/^.*\bSurfaceHeight\:\s*(\d+)px\b.*$/$1/')
RES=${HRES}x${VRES}

# check for screencap binary
HAS_SCREENCAP=$(${ADB} shell "[ -x /system/bin/screencap ] && echo 1 || echo 0" | perl -pe 's/\D+//g')
if [ "$HAS_SCREENCAP" == "1" ]
then # use screencap to get the image easy-peasy
    echo -n "Getting ${RES} screencap... "
    ( ${ADB} shell /system/bin/screencap ${SRC} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to execute screencap"
    ( ${ADB} pull ${SRC} ${TMP} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to pull png image"
    ( ${ADB} shell rm ${SRC} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to remove png image"
    mv ${TMP} ${TGT}
    echo "wrote: ${TGT}"
else # fetch a framebuffer snapshot
    # ffmpeg is only needed if device is pre-ICS
    [ -x "${FFMPEG}" ] || die "FFMPEG is missing!"
    [ -x "${DD}" ] || die "DD is missing!"
    echo -n "Getting ${RES} framebuffer... "
    ( ${ADB} pull /dev/graphics/fb0 ${RAW} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to pull raw image data"
    # calculate dd parameters
    COUNT=$((HRES*4))
    BLOCKSIZE=$((VRES))
    ( ${DD} bs=${BLOCKSIZE} count=${COUNT} if=${RAW} of=${TMP} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to realign raw image data"
    ( ${FFMPEG} -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s ${RES} -i ${TMP} -f image2 -vcodec png ${TGT} 2>&1 ) > /dev/null
    [ "$?" != "0" ] && die "Failed to encode PNG image"
    echo "wrote: ${TGT}"
fi

# exit app normal
cleanup 1
...