Merge "Add FrameDropRate post-processing tool"
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index f9e3276..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-subdir-makefiles)
diff --git a/camera/__init__.py b/camera/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/__init__.py
diff --git a/camera/app/__init__.py b/camera/app/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/app/__init__.py
diff --git a/camera/app/stress_test/FrameDropRate.py b/camera/app/stress_test/FrameDropRate.py
new file mode 100755
index 0000000..687b8ce
--- /dev/null
+++ b/camera/app/stress_test/FrameDropRate.py
@@ -0,0 +1,116 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import re
+import subprocess
+import sys
+
+_VIDEO_EXTS = ['.mp4', '.mov', '.avi', '.MOV']
+
+def Analyze(dir_path, ffmpeg_binary_path, fps=30.0):
+ """Script for frame-drop detection and statistics calculation.
+
+ The script would scan through all video files in the folder and print out the
+ number of frame drops for each video, and the effective frame rate for all
+ videos.
+
+ Args:
+ dir_path: string, the path of a dir which contains the media files.
+ ffmpeg_binary_path: string, the path of ffmpeg binary.
+ fps: float, frames per second.
+
+ Returns:
+ A string containing a report
+ """
+ # Change the fps to match the source videos (all videos in the folder should
+ # have identical target FPS
+ if not ffmpeg_binary_path:
+ print "ffmpeg_binary_path not set"
+ return ""
+
+ videos = [f for f in os.listdir(dir_path)
+ if os.path.splitext(f)[1] in _VIDEO_EXTS]
+
+ thres_30fps = 45.0
+ thres = thres_30fps * 30.0 / fps
+
+ frame_cnt_all = 0.0
+ frame_drop_cnt_all = 0.0
+ report_all = 'Scan ' + dir_path
+ for v in videos:
+ full_path = os.path.join(dir_path, v)
+ command = [ffmpeg_binary_path, '-i', full_path, '-an', '-vf', 'showinfo', '-f',
+ 'null', '-']
+ ret = subprocess.Popen(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[1]
+ rets = ret.split('\n')
+ idx = 0
+ time_prev = 0
+ framedrop_cnt = 0.0
+ total_frame_cnt = 0
+ dropped_frames = []
+
+ report = ''
+
+ for r in rets:
+ head = r.find('[Parsed_showinfo_0')
+ if head >= 0:
+ r = r[head:]
+ else:
+ continue
+ tokens = re.findall(r'\S+', r.replace(':', ' '))
+ if not tokens:
+ continue
+
+ if tokens[0] != '[Parsed_showinfo_0' or tokens[3] != 'n':
+ continue
+
+ idx = int(tokens[4])
+ time = float(tokens[8])
+ diff = 1000 * (time - time_prev)
+ if diff > thres:
+ print 'Curr(s)/Prev(s)/Delta(ms) ', time, time_prev, diff
+ dropped_frames.append([idx, diff])
+ framedrop_cnt += (diff / (1000.0 / fps) - 1)
+
+ time_prev = time
+ total_frame_cnt += 1
+ # Add the dropped frame into the total frame count
+ # (which is the ideal number of total frames)
+ total_frame_cnt += framedrop_cnt
+ framedrop_rate = 100.0 * framedrop_cnt / total_frame_cnt
+ report = report + '\n' + v + (' total {t:5f} frames. Frame drops: {v} '
+ '({p:4.2f}%)\n').format(t=total_frame_cnt,
+ v=framedrop_cnt,
+ p=framedrop_rate)
+ for frame in dropped_frames:
+ report += ' {v:5d}: {t:5.1f}\n'.format(v=frame[0], t=frame[1])
+
+ frame_cnt_all += total_frame_cnt
+ frame_drop_cnt_all += framedrop_cnt
+ report_all += report
+ framedrop_rate = 100.0 * frame_drop_cnt_all / frame_cnt_all
+ effective_framerate = fps * (1.0 - float(frame_drop_cnt_all) / frame_cnt_all)
+ report_all += ('\nTotal framedrop: {a}/{b} ({c:4.2f}%). Effective framerate: '
+ '{d}').format(a=frame_drop_cnt_all,
+ b=frame_cnt_all,
+ c=framedrop_rate,
+ d=effective_framerate)
+
+ return report_all
diff --git a/camera/app/stress_test/__init__.py b/camera/app/stress_test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/app/stress_test/__init__.py