Home | History | Annotate | Download | only in pylib
      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