1# Copyright 2020 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Utility functions for scene change test."""
15
16
17import logging
18import unittest
19
20_DARK_SCENE_THRESH = 0.2
21_FPS = 30  # Frames Per Second
22_FRAME_SHIFT_SMALL = 5  # Num of frames to shift if scene or brightness change.
23_FRAME_SHIFT_LARGE = 30  # Num of frames to shift if no change in capture.
24SCENE_CHANGE_FAIL_CODE = -1001
25SCENE_CHANGE_PASS_CODE = 1001
26
27
28def calc_timing_adjustment(converged, scene_change_flag,
29                           bright_change_flag, bright_final):
30  """Calculate timing adjustment based on converged frame and flags.
31
32  Args:
33    converged: Boolean on whether 3A converged or not.
34    scene_change_flag: Boolean for if afSceneChanged triggered.
35    bright_change_flag: Boolean for if image brightness changes.
36    bright_final: Float for average value of center patch of final frame.
37  Returns:
38    scene_change_timing_shift: Timing shift in frames.
39
40  Does timing adjustment based on input values from captured frames.
41    Truth table for 3A frame, Change flag, Bright flag, Last frame brightness
42      3, C, B, L
43      1, 1, 1, X --> PASS: 3A settled, scene and brightness change
44      1, 1, 0, X --> FAIL: 3A settled, scene change, but no brightness change
45      1, 0, 1, X --> shift FRAME_SHIFT_SMALL earlier
46      1, 0, 0, 1 --> shift FRAME_SHIFT_LARGE earlier
47      1, 0, 0, 0 --> shift FRAME_SHIFT_LARGE later
48      0, X, 1, X --> shift FRAME_SHIFT_SMALL later
49      0, X, 0, X --> FAIL: Check results of scene2/test_continuous_picture.
50    Note: these values have been found empirically for 4 different phone
51          models and 8 cameras. It is possible they may need to be tweaked as
52          more phone models become available.
53  """
54  if converged:  # 3A converges
55    if scene_change_flag:
56      if bright_change_flag:  # scene_change_flag & brightness change --> PASS
57        logging.debug('Scene & brightness change: PASS.')
58        return SCENE_CHANGE_PASS_CODE
59      else:  # scene_change_flag & no brightness change --> FAIL
60        scene_change_frame_shift = SCENE_CHANGE_FAIL_CODE
61        logging.error('Scene change, but no brightness change.')
62    else:  # No scene change flag: shift timing
63      if bright_change_flag:
64        scene_change_frame_shift = -1 * _FRAME_SHIFT_SMALL
65        logging.debug('No scene change flag, but brightness change.')
66      else:
67        logging.debug('No scene change flag, no brightness change.')
68        if bright_final < _DARK_SCENE_THRESH:
69          scene_change_frame_shift = _FRAME_SHIFT_LARGE
70          logging.debug('Scene dark entire capture.')
71        else:
72          scene_change_frame_shift = -1 * _FRAME_SHIFT_LARGE
73          logging.debug('Scene light entire capture.')
74  else:  # 3A does not converge.
75    if bright_change_flag:
76      scene_change_frame_shift = _FRAME_SHIFT_SMALL
77      logging.debug('3A does not converge, but brightness changes.')
78    else:
79      scene_change_frame_shift = SCENE_CHANGE_FAIL_CODE
80      logging.error('3A does not converge, and brightness does not change.')
81  if scene_change_frame_shift >= 0:
82    logging.debug('Shift +%d frames.', scene_change_frame_shift)
83  else:
84    logging.debug('Shift %d frames.', scene_change_frame_shift)
85  return scene_change_frame_shift
86
87
88class ItsSessionUtilsTests(unittest.TestCase):
89  """Unit tests for this module."""
90
91  def test_calc_timing_adjustment_shift(self):
92    results = {}
93    expected_results = {'1111': SCENE_CHANGE_PASS_CODE,
94                        '1110': SCENE_CHANGE_PASS_CODE,
95                        '1101': SCENE_CHANGE_FAIL_CODE,
96                        '1100': SCENE_CHANGE_FAIL_CODE,
97                        '1011': -1*_FRAME_SHIFT_SMALL,
98                        '1010': -1*_FRAME_SHIFT_SMALL,
99                        '1001': -1*_FRAME_SHIFT_LARGE,
100                        '1000': _FRAME_SHIFT_LARGE,
101                        '0111': _FRAME_SHIFT_SMALL,
102                        '0110': _FRAME_SHIFT_SMALL,
103                        '0101': SCENE_CHANGE_FAIL_CODE,
104                        '0100': SCENE_CHANGE_FAIL_CODE,
105                        '0011': _FRAME_SHIFT_SMALL,
106                        '0010': _FRAME_SHIFT_SMALL,
107                        '0001': SCENE_CHANGE_FAIL_CODE,
108                        '0000': SCENE_CHANGE_FAIL_CODE,
109                        }
110    converged_list = [1, 0]
111    scene_change_flag_list = [1, 0]
112    bright_change_flag_list = [1, 0]
113    bright_final_list = [1, 0]
114    for converged in converged_list:
115      for scene_flag in scene_change_flag_list:
116        for bright_flag in bright_change_flag_list:
117          for bright_final in bright_final_list:
118            key = f'{converged}{scene_flag}{bright_flag}{bright_final}'
119            results[key] = calc_timing_adjustment(converged, scene_flag,
120                                                  bright_flag, bright_final)
121    self.assertEqual(results, expected_results)
122
123
124if __name__ == '__main__':
125  unittest.main()
126