1 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import os 6 import tempfile 7 import time 8 9 import android_commands 10 import cmd_helper 11 12 13 def _GetTimestamp(): 14 return time.strftime('%Y-%m-%d-%H%M%S', time.localtime()) 15 16 17 def _EnsureHostDirectory(host_file): 18 host_dir = os.path.dirname(os.path.abspath(host_file)) 19 if not os.path.exists(host_dir): 20 os.makedirs(host_dir) 21 22 23 def TakeScreenshot(adb, host_file): 24 """Saves a screenshot image to |host_file| on the host. 25 26 Args: 27 adb: AndroidCommands instance. 28 host_file: Path to the image file to store on the host. 29 """ 30 host_file = os.path.abspath(host_file or 31 'screenshot-%s.png' % _GetTimestamp()) 32 _EnsureHostDirectory(host_file) 33 device_file = '%s/screenshot.png' % adb.GetExternalStorage() 34 adb.RunShellCommand('/system/bin/screencap -p %s' % device_file) 35 adb.PullFileFromDevice(device_file, host_file) 36 adb.RunShellCommand('rm -f "%s"' % device_file) 37 return host_file 38 39 40 class VideoRecorder(object): 41 """Records a screen capture video from an Android Device (KitKat or newer). 42 43 Args: 44 adb: AndroidCommands instance. 45 host_file: Path to the video file to store on the host. 46 megabits_per_second: Video bitrate in megabits per second. Allowed range 47 from 0.1 to 100 mbps. 48 size: Video frame size tuple (width, height) or None to use the device 49 default. 50 rotate: If True, the video will be rotated 90 degrees. 51 """ 52 def __init__(self, adb, host_file, megabits_per_second=4, size=None, 53 rotate=False): 54 self._adb = adb 55 self._device_file = '%s/screen-recording.mp4' % adb.GetExternalStorage() 56 self._host_file = host_file or 'screen-recording-%s.mp4' % _GetTimestamp() 57 self._host_file = os.path.abspath(self._host_file) 58 self._recorder = None 59 self._recorder_pids = None 60 self._recorder_stdout = None 61 self._is_started = False 62 63 self._args = ['adb'] 64 if self._adb.GetDevice(): 65 self._args += ['-s', self._adb.GetDevice()] 66 self._args += ['shell', 'screenrecord', '--verbose'] 67 self._args += ['--bit-rate', str(megabits_per_second * 1000 * 1000)] 68 if size: 69 self._args += ['--size', '%dx%d' % size] 70 if rotate: 71 self._args += ['--rotate'] 72 self._args += [self._device_file] 73 74 def Start(self): 75 """Start recording video.""" 76 _EnsureHostDirectory(self._host_file) 77 self._recorder_stdout = tempfile.mkstemp()[1] 78 self._recorder = cmd_helper.Popen( 79 self._args, stdout=open(self._recorder_stdout, 'w')) 80 self._recorder_pids = self._adb.ExtractPid('screenrecord') 81 if not self._recorder_pids: 82 raise RuntimeError('Recording failed. Is your device running Android ' 83 'KitKat or later?') 84 85 def IsStarted(self): 86 if not self._is_started: 87 for line in open(self._recorder_stdout): 88 self._is_started = line.startswith('Content area is ') 89 if self._is_started: 90 break 91 return self._is_started 92 93 def Stop(self): 94 """Stop recording video.""" 95 os.remove(self._recorder_stdout) 96 self._is_started = False 97 if not self._recorder or not self._recorder_pids: 98 return 99 self._adb.RunShellCommand('kill -SIGINT ' + ' '.join(self._recorder_pids)) 100 self._recorder.wait() 101 102 def Pull(self): 103 """Pull resulting video file from the device. 104 105 Returns: 106 Output video file name on the host. 107 """ 108 self._adb.PullFileFromDevice(self._device_file, self._host_file) 109 self._adb.RunShellCommand('rm -f "%s"' % self._device_file) 110 return self._host_file 111