power_dashboard: Add library to send video fps

Add the library classes to log video fps and send to dashboard.
- power_status.VideoFpsLogger
- power_dashboard.VideoFpsLoggerDashboard

BUG=b:146021591
TEST=power_VideoCall.fast

Change-Id: I323b954fbce969f160fe2c77e463ee226e9d2872
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/1974489
Tested-by: Puthikorn Voravootivat <puthik@chromium.org>
Auto-Submit: Puthikorn Voravootivat <puthik@chromium.org>
Commit-Queue: Todd Broch <tbroch@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
diff --git a/client/cros/power/power_dashboard.py b/client/cros/power/power_dashboard.py
index 809a63c..9e21f77 100644
--- a/client/cros/power/power_dashboard.py
+++ b/client/cros/power/power_dashboard.py
@@ -457,7 +457,7 @@
 
 
 class TempLoggerDashboard(MeasurementLoggerDashboard):
-    """Dashboard class for power_status.PowerLogger.
+    """Dashboard class for power_status.TempLogger.
     """
 
     def __init__(self, logger, testname, resultsdir=None, uploadurl=None,
@@ -601,3 +601,16 @@
 
             # Run "cpuidle_C{:_>2s}E-SKL".format("1") to get "cpuidle_C.1E-SKL"
             self._padded_domains.append(formatter_str.format(number_strs[i]))
+
+
+class VideoFpsLoggerDashboard(MeasurementLoggerDashboard):
+    """Dashboard class for power_status.VideoFpsLogger."""
+
+    def __init__(self, logger, testname, resultsdir=None, uploadurl=None,
+                 note=''):
+        if uploadurl is None:
+            uploadurl = 'http://chrome-power.appspot.com/rapl'
+        super(VideoFpsLoggerDashboard, self).__init__(
+            logger, testname, resultsdir, uploadurl, note)
+        self._unit = 'fps'
+        self._type = 'fps'
diff --git a/client/cros/power/power_status.py b/client/cros/power/power_status.py
index 583376c..1f221e9 100644
--- a/client/cros/power/power_status.py
+++ b/client/cros/power/power_status.py
@@ -2143,6 +2143,42 @@
         return super(TempLogger, self).calc(mtype)
 
 
+class VideoFpsLogger(MeasurementLogger):
+    """Class to measure Video FPS."""
+
+    def __init__(self, tab, seconds_period=1.0, checkpoint_logger=None):
+        """Initialize a VideoFpsLogger.
+
+        Args:
+            tab: Chrome tab object
+        """
+        super(VideoFpsLogger, self).__init__([], seconds_period,
+                                             checkpoint_logger)
+        self._tab = tab
+        names = self._tab.EvaluateJavaScript(
+            'Array.from(document.getElementsByTagName("video")).map(v => v.id)')
+        self.domains =  [n or 'video_' + str(i) for i, n in enumerate(names)]
+        self._last = [0] * len(names)
+        self.refresh()
+
+    def refresh(self):
+        current = self._tab.EvaluateJavaScript(
+            'Array.from(document.getElementsByTagName("video")).map('
+            'v => v.webkitDecodedFrameCount)')
+        fps = [(b - a) / self.seconds_period
+               for a, b in zip(self._last , current)]
+        self._last = current
+        return fps
+
+    def save_results(self, resultsdir, fname_prefix=None):
+        if not fname_prefix:
+            fname_prefix = 'video_fps_results_%.0f' % time.time()
+        super(VideoFpsLogger, self).save_results(resultsdir, fname_prefix)
+
+    def calc(self, mtype='fps'):
+        return super(VideoFpsLogger, self).calc(mtype)
+
+
 class DiskStateLogger(threading.Thread):
     """Records the time percentages the disk stays in its different power modes.