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 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