web-dev-qa-db-fra.com

Capture d'écran du Nexus One d'AdB?

Mon objectif est de pouvoir taper une commande à un mot et obtenir une capture d'écran d'un Nexus One rooté connecté par USB.

Jusqu'à présent, je peux obtenir le framebuffer qui je crois est un 32bit xRGB888 image brute en la tirant comme ceci:

adb pull /dev/graphics/fb0 fb0

À partir de là cependant, j'ai du mal à le convertir en png. J'essaie avec ffmpeg comme ceci:

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

Cela crée une belle image violette qui a des parties qui ressemblent vaguement à l'écran, mais ce n'est en aucun cas une capture d'écran nette.

46
Marcus

Une solution beaucoup plus simple pour ICS consiste à utiliser ce qui suit à partir de la ligne de commande

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

Cela enregistrera le fichier screenshot.png dans le répertoire courant.

Testé sur un Samsung Galaxy SII et SII exécutant 4.0.3.

90
Ben Clayton

En fait, il existe une autre possibilité très simple de saisir une capture d'écran de votre appareil Android: écrire un script simple 1.script comme ça:

# 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')

et appelez monkeyrunner 1.script.

13
Andrey Starodubtsev

Il semble que le tampon de trame de N1 utilise le codage RGB32 (32 bits par pixel).

Voici mon script utilisant 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

Une autre façon dérivée de la méthode ADP1 décrite ici 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

Script 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])
11
Olivier

En utilisant mon HTC Hero (et donc en ajustant de 480x800 à 320x480), cela fonctionne si j'utilise rgb565 au lieu de 8888:

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 320x480 -i fb0 -f image2 -vcodec png image.png
7
Cowan

Si vous avez installé dos2unix, alors ce qui suit

adb Shell screencap -p | dos2unix > screen.png
6
user3058757

Je crois que tous les tampons d'image à ce jour sont RVB 565, pas 888.

2
Yann Ramin

Nous avons maintenant une commande sur une seule ligne pour faire une capture d'écran. La commande comme suit:

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

Tapez la commande ci-dessus dans votre terminal et appuyez sur Entrée. Si vous souhaitez que la capture d'écran soit stockée dans un emplacement spécifique, indiquez le répertoire chemin (ou) avant screen.png.

Source .

2
parthiban

Un peu élaboré/excessif, mais il gère à la fois les scénarios de capture d'écran et de framebuffer (ainsi que la résolution de la résolution).

#!/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 <[email protected]>
# 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
1
Kevin C. Krinke

Sur le MyTouch Slide 3G, je me suis retrouvé avec les canaux rouges et bleus échangés dans mes captures d'écran. Voici l'incantation ffmpeg correcte pour toute autre personne dans cette situation: (la partie notable: - pix_fmt bgr32)

ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt bgr32 -s 320x480 -i fb0 -f image2 -vcodec png image.png

Merci à Patola pour le script Shell pratique! Au moins pour mon téléphone, aucune mogrification n'est nécessaire pour s'orienter correctement en mode portrait (320x480), et donc la fin de son script devient:

# assuming 'down' is towards the keyboard or usb jack 
# in landscape and protrait modes respectively
(( ${PORTRAIT} )) || mogrify -rotate 270 "${outputfile}"

/bin/rm -f fb0.$$ fb0b.$$
1
Andy

rgb565 au lieu de 8888 fonctionne également sur l'émulateur

1
Andry

Cela peut être lié au problème Lecture des données binaires depuis la sortie standard d'Adb Shell où adb tente de faire LF en conversion CRLF pour vous (c'est probablement juste la version Windows d'Adb Personnellement, j’ai eu des problèmes avec sa conversion\n en\r\r\n, donc pour le convertir, il est bon d’utiliser le code à [ 1 ] ou d’utiliser.

pour moi le faire fonctionner avec (dans cygwin): adb Shell 'cat /dev/graphics/fb0' | Perl -pi -e 's/\r\r\n/\n/g' semblait aider

à part cela, essayez de comparer la largeur et la hauteur à la taille du fichier. La taille du fichier doit être divisible par Width * height si ce n'est pas le cas, alors l'outil adb fait automatiquement les choses pour vous ou c'est un format plus exotique que rgb545 ou rgb8888.

si c'est juste un problème de couleur (c'est-à-dire que tout dans l'image du résultat est au bon endroit), vous voudrez peut-être envisager d'échanger les canaux rouge et bleu car certains systèmes (en général) utilisent l'ordre des octets BGRA au lieu de RGBA.

1
ProgramQii

Un moyen d'automatiser complètement ce processus consiste à créer un script qui ajoute l'horodatage actuel au nom de fichier. De cette façon, vous n'avez pas à écrire le nom du fichier vous-même, toutes vos captures d'écran ont un nom différent et vos captures d'écran sont triées par heure.

Exemple de script 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

Cela va créer un fichier nommé comme screenshot_2014-01-07-10: 31.png

1
Raphaël Titol

J'espère que mon script pourrait être utile. Je l'utilise sur mon onglet galaxie et cela fonctionne parfaitement, mais il vous est possible de changer la résolution par défaut. Il nécessite cependant le shell "zsh":

#!/bin/zsh

# These settings are for the galaxy tab.
HRES=600
VRES=1024

usage() {
  echo "Usage: $0 [ -p ] outputfile.png"
  echo "-- takes screenshot off your Galaxy Tab Android phone."
  echo " -p: portrait mode"
  echo " -r X:Y: specify resolution, e.g. -r 480:640 specifies that your cellphone has 480x640 resolution."
  exit 1
}

PORTRAIT=0 # false by default

umask 022

[[ ! -w . ]] && {
  echo "*** Error: current directory not writeable."
  usage
}

[[ ! -x $(which mogrify) ]] && {
  echo "*** Error: ImageMagick (mogrify) is not in the PATH!"
  usage
}

while getopts "pr:" myvar
do
  [[ "$myvar" == "p" ]] && PORTRAIT=1
  [[ "$myvar" == "r" ]] && {
    testhres="${OPTARG%%:*}" # remove longest-matching :* from end
    testvres="${OPTARG##*:}" # remove longest-matchung *: from beginning
    if [[ $testhres == <0-> && $testvres == <0-> ]] # Interval: from 0 to infinite. Any value would be: <->
    then
      HRES=$testhres
      VRES=$testvres
    else
      echo "Error! One of these values - '${testhres}' or '${testvres}' - is not numeric!"
      usage
    fi
  }
done
shift $((OPTIND-1))

[[ $# < 1 ]] && usage

outputfile="${1}"

blocksize=$((HRES*4))
count=$((VRES))

adb pull /dev/graphics/fb0 fb0.$$
/bin/dd bs=$blocksize count=$count if=fb0.$$ of=fb0b.$$
/usr/bin/ffmpeg -vframes 1 -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s ${VRES}x${HRES} -i fb0b.$$ -f image2 -vcodec png "${outputfile}"

if (( ${PORTRAIT} ))
then
  mogrify -rotate 270 "${outputfile}"
else
  mogrify -flip -flop "${outputfile}"
fi

/bin/rm -f fb0.$$ fb0b.$$
1
Patola

Je pense que rgb32torgb888.py devrait être

 sys.stdout.write(colour[0])
 sys.stdout.write(colour[1])
 sys.stdout.write(colour[2])
1
clsung