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 signal 7 import tempfile 8 9 from pylib import cmd_helper 10 11 # TODO(jbudorick) Remove once telemetry gets switched over. 12 import pylib.android_commands 13 import pylib.device.device_utils 14 15 16 class VideoRecorder(object): 17 """Records a screen capture video from an Android Device (KitKat or newer). 18 19 Args: 20 device: DeviceUtils instance. 21 host_file: Path to the video file to store on the host. 22 megabits_per_second: Video bitrate in megabits per second. Allowed range 23 from 0.1 to 100 mbps. 24 size: Video frame size tuple (width, height) or None to use the device 25 default. 26 rotate: If True, the video will be rotated 90 degrees. 27 """ 28 def __init__(self, device, megabits_per_second=4, size=None, 29 rotate=False): 30 # TODO(jbudorick) Remove once telemetry gets switched over. 31 if isinstance(device, pylib.android_commands.AndroidCommands): 32 device = pylib.device.device_utils.DeviceUtils(device) 33 self._device = device 34 self._device_file = ( 35 '%s/screen-recording.mp4' % device.GetExternalStoragePath()) 36 self._recorder = None 37 self._recorder_stdout = None 38 self._is_started = False 39 40 self._args = ['adb'] 41 if str(self._device): 42 self._args += ['-s', str(self._device)] 43 self._args += ['shell', 'screenrecord', '--verbose'] 44 self._args += ['--bit-rate', str(megabits_per_second * 1000 * 1000)] 45 if size: 46 self._args += ['--size', '%dx%d' % size] 47 if rotate: 48 self._args += ['--rotate'] 49 self._args += [self._device_file] 50 51 def Start(self): 52 """Start recording video.""" 53 self._recorder_stdout = tempfile.mkstemp()[1] 54 self._recorder = cmd_helper.Popen( 55 self._args, stdout=open(self._recorder_stdout, 'w')) 56 if not self._device.GetPids('screenrecord'): 57 raise RuntimeError('Recording failed. Is your device running Android ' 58 'KitKat or later?') 59 60 def IsStarted(self): 61 if not self._is_started: 62 for line in open(self._recorder_stdout): 63 self._is_started = line.startswith('Content area is ') 64 if self._is_started: 65 break 66 return self._is_started 67 68 def Stop(self): 69 """Stop recording video.""" 70 os.remove(self._recorder_stdout) 71 self._is_started = False 72 if not self._recorder: 73 return 74 self._device.KillAll('screenrecord', signum=signal.SIGINT) 75 self._recorder.wait() 76 77 def Pull(self, host_file=None): 78 """Pull resulting video file from the device. 79 80 Args: 81 host_file: Path to the video file to store on the host. 82 Returns: 83 Output video file name on the host. 84 """ 85 host_file_name = host_file or ('screen-recording-%s.mp4' % 86 self._device.old_interface.GetTimestamp()) 87 host_file_name = os.path.abspath(host_file_name) 88 self._device.old_interface.EnsureHostDirectory(host_file_name) 89 self._device.PullFile(self._device_file, host_file_name) 90 self._device.RunShellCommand('rm -f "%s"' % self._device_file) 91 return host_file_name 92