| Index: tools/telemetry/telemetry/core/platform/android_platform_backend.py
|
| diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
|
| index fa4683455c71938d1278c6b2468687ef36296a12..d753372599c73b6968ee517e4574581b6cdc37ca 100644
|
| --- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py
|
| +++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
|
| @@ -7,6 +7,7 @@ import os
|
| import subprocess
|
| import tempfile
|
|
|
| +from telemetry.core import bitmap
|
| from telemetry.core import exceptions
|
| from telemetry.core import platform
|
| from telemetry.core import util
|
| @@ -25,6 +26,7 @@ except Exception:
|
|
|
|
|
| _HOST_APPLICATIONS = [
|
| + 'avconv',
|
| 'ipfw',
|
| ]
|
|
|
| @@ -200,9 +202,58 @@ class AndroidPlatformBackend(
|
| self._video_recorder.wait()
|
| self._video_recorder = None
|
|
|
| - # TODO(tonyg/szym): Decode the mp4 and yield the (time, bitmap) tuples.
|
| - raise NotImplementedError("mp4 video saved to %s, but Telemetry doesn't "
|
| - "know how to decode it." % self._video_output)
|
| + for frame in self._FramesFromMp4(self._video_output):
|
| + yield frame
|
| +
|
| + def _FramesFromMp4(self, mp4_file):
|
| + if not self.CanLaunchApplication('avconv'):
|
| + self.InstallApplication('avconv')
|
| +
|
| + def GetDimensions(video):
|
| + proc = subprocess.Popen(['avconv', '-i', video], stderr=subprocess.PIPE)
|
| + for line in proc.stderr.readlines():
|
| + if 'Video:' in line:
|
| + dimensions = line.split(',')[2]
|
| + dimensions = map(int, dimensions.split()[0].split('x'))
|
| + break
|
| + proc.wait()
|
| + assert dimensions, 'Failed to determine video dimensions'
|
| + return dimensions
|
| +
|
| + def GetFrameTimestampMs(stderr):
|
| + """Returns the frame timestamp in integer milliseconds from the dump log.
|
| +
|
| + The expected line format is:
|
| + ' dts=1.715 pts=1.715\n'
|
| +
|
| + We have to be careful to only read a single timestamp per call to avoid
|
| + deadlock because avconv interleaves its writes to stdout and stderr.
|
| + """
|
| + while True:
|
| + line = ''
|
| + next_char = ''
|
| + while next_char != '\n':
|
| + next_char = stderr.read(1)
|
| + line += next_char
|
| + if 'pts=' in line:
|
| + return int(1000 * float(line.split('=')[-1]))
|
| +
|
| + dimensions = GetDimensions(mp4_file)
|
| + frame_length = dimensions[0] * dimensions[1] * 3
|
| + frame_data = bytearray(frame_length)
|
| +
|
| + # Use rawvideo so that we don't need any external library to parse frames.
|
| + proc = subprocess.Popen(['avconv', '-i', mp4_file, '-vcodec',
|
| + 'rawvideo', '-pix_fmt', 'rgb24', '-dump',
|
| + '-loglevel', 'debug', '-f', 'rawvideo', '-'],
|
| + stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
| + while True:
|
| + num_read = proc.stdout.readinto(frame_data)
|
| + if not num_read:
|
| + raise StopIteration
|
| + assert num_read == len(frame_data), 'Unexpected frame size: %d' % num_read
|
| + yield (GetFrameTimestampMs(proc.stderr),
|
| + bitmap.Bitmap(3, dimensions[0], dimensions[1], frame_data))
|
|
|
| def _GetFileContents(self, fname):
|
| if not self._can_access_protected_file_contents:
|
|
|