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