Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4039)

Unified Diff: build/android/devil/android/tools/video_recorder.py

Issue 1522313002: [Android] Move screenshot and video_recorder into devil. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix video_recorder timing Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/android/devil/android/tools/script_common_test.py ('k') | build/android/pylib/screenshot.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/devil/android/tools/video_recorder.py
diff --git a/build/android/devil/android/tools/video_recorder.py b/build/android/devil/android/tools/video_recorder.py
new file mode 100755
index 0000000000000000000000000000000000000000..685b682ea866c952f3d563ff389d9a0059324438
--- /dev/null
+++ b/build/android/devil/android/tools/video_recorder.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Captures a video from an Android device."""
+
+import argparse
+import logging
+import os
+import threading
+import time
+import sys
+
+if __name__ == '__main__':
+ sys.path.append(os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)))
+from devil.android import device_signal
+from devil.android import device_utils
+from devil.android.tools import script_common
+from devil.utils import cmd_helper
+from devil.utils import reraiser_thread
+from devil.utils import timeout_retry
+
+
+class VideoRecorder(object):
+ """Records a screen capture video from an Android Device (KitKat or newer)."""
+
+ def __init__(self, device, megabits_per_second=4, size=None,
+ rotate=False):
+ """Creates a VideoRecorder instance.
+
+ Args:
+ device: DeviceUtils instance.
+ host_file: Path to the video file to store on the host.
+ megabits_per_second: Video bitrate in megabits per second. Allowed range
+ from 0.1 to 100 mbps.
+ size: Video frame size tuple (width, height) or None to use the device
+ default.
+ rotate: If True, the video will be rotated 90 degrees.
+ """
+ self._bit_rate = megabits_per_second * 1000 * 1000
+ self._device = device
+ self._device_file = (
+ '%s/screen-recording.mp4' % device.GetExternalStoragePath())
+ self._recorder_thread = None
+ self._rotate = rotate
+ self._size = size
+ self._started = threading.Event()
+
+ def __enter__(self):
+ self.Start()
+
+ def Start(self, timeout=None):
+ """Start recording video."""
+ def screenrecord_started():
+ return bool(self._device.GetPids('screenrecord'))
+
+ if screenrecord_started():
+ raise Exception("Can't run multiple concurrent video captures.")
+
+ self._started.clear()
+ self._recorder_thread = reraiser_thread.ReraiserThread(self._Record)
+ self._recorder_thread.start()
+ timeout_retry.WaitFor(
+ screenrecord_started, wait_period=1, max_tries=timeout)
+ self._started.wait(timeout)
+
+ def _Record(self):
+ cmd = ['screenrecord', '--verbose', '--bit-rate', str(self._bit_rate)]
+ if self._rotate:
+ cmd += ['--rotate']
+ if self._size:
+ cmd += ['--size', '%dx%d' % self._size]
+ cmd += [self._device_file]
+ for line in self._device.adb.IterShell(
+ ' '.join(cmd_helper.SingleQuote(i) for i in cmd), None):
+ if line.startswith('Content area is '):
+ self._started.set()
+
+ def __exit__(self, _exc_type, _exc_value, _traceback):
+ self.Stop()
+
+ def Stop(self):
+ """Stop recording video."""
+ if not self._device.KillAll('screenrecord', signum=device_signal.SIGINT,
+ quiet=True):
+ logging.warning('Nothing to kill: screenrecord was not running')
+ self._recorder_thread.join()
+
+ def Pull(self, host_file=None):
+ """Pull resulting video file from the device.
+
+ Args:
+ host_file: Path to the video file to store on the host.
+ Returns:
+ Output video file name on the host.
+ """
+ # TODO(jbudorick): Merge filename generation with the logic for doing so in
+ # DeviceUtils.
+ host_file_name = (
+ host_file
+ or 'screen-recording-%s-%s.mp4' % (
+ str(self._device),
+ time.strftime('%Y%m%dT%H%M%S', time.localtime())))
+ host_file_name = os.path.abspath(host_file_name)
+ self._device.PullFile(self._device_file, host_file_name)
+ self._device.RunShellCommand('rm -f "%s"' % self._device_file)
+ return host_file_name
+
+
+def main():
+ # Parse options.
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('-d', '--device', dest='devices', action='append',
+ help='Serial number of Android device to use.')
+ parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
+ parser.add_argument('-f', '--file', metavar='FILE',
+ help='Save result to file instead of generating a '
+ 'timestamped file name.')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='Verbose logging.')
+ parser.add_argument('-b', '--bitrate', default=4, type=float,
+ help='Bitrate in megabits/s, from 0.1 to 100 mbps, '
+ '%default mbps by default.')
+ parser.add_argument('-r', '--rotate', action='store_true',
+ help='Rotate video by 90 degrees.')
+ parser.add_argument('-s', '--size', metavar='WIDTHxHEIGHT',
+ help='Frame size to use instead of the device '
+ 'screen size.')
+ parser.add_argument('host_file', nargs='?',
+ help='File to which the video capture will be written.')
+
+ args = parser.parse_args()
+
+ host_file = args.host_file or args.file
+
+ if args.verbose:
+ logging.getLogger().setLevel(logging.DEBUG)
+
+ size = (tuple(int(i) for i in args.size.split('x'))
+ if args.size
+ else None)
+
+ def record_video(device, stop_recording):
+ recorder = VideoRecorder(
+ device, megabits_per_second=args.bitrate, size=size, rotate=args.rotate)
+ with recorder:
+ stop_recording.wait()
+
+ f = None
+ if host_file:
+ root, ext = os.path.splitext(host_file)
+ f = '%s_%s%s' % (root, str(device), ext)
+ f = recorder.Pull(f)
+ print 'Video written to %s' % os.path.abspath(f)
+
+ parallel_devices = device_utils.DeviceUtils.parallel(
+ script_common.GetDevices(args.devices, args.blacklist_file),
+ async=True)
+ stop_recording = threading.Event()
+ running_recording = parallel_devices.pMap(record_video, stop_recording)
+ print 'Recording. Press Enter to stop.',
+ sys.stdout.flush()
+ raw_input()
+ stop_recording.set()
+
+ running_recording.pGet(None)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
« no previous file with comments | « build/android/devil/android/tools/script_common_test.py ('k') | build/android/pylib/screenshot.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698