0001 .. SPDX-License-Identifier: GPL-2.0
0002
0003 Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
0004 =======================================================================
0005
0006 Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
0007
0008 Terminology
0009 -----------
0010
0011 sensor scales: horizontal and vertical scales, configured by the sensor driver
0012 host scales: -"- host driver
0013 combined scales: sensor_scale * host_scale
0014
0015
0016 Generic scaling / cropping scheme
0017 ---------------------------------
0018
0019 .. code-block:: none
0020
0021 -1--
0022 |
0023 -2-- -\
0024 | --\
0025 | --\
0026 +-5-- . -- -3-- -\
0027 | `... -\
0028 | `... -4-- . - -7..
0029 | `.
0030 | `. .6--
0031 |
0032 | . .6'-
0033 | .´
0034 | ... -4'- .´
0035 | ...´ - -7'.
0036 +-5'- .´ -/
0037 | -- -3'- -/
0038 | --/
0039 | --/
0040 -2'- -/
0041 |
0042 |
0043 -1'-
0044
0045 In the above chart minuses and slashes represent "real" data amounts, points and
0046 accents represent "useful" data, basically, CEU scaled and cropped output,
0047 mapped back onto the client's source plane.
0048
0049 Such a configuration can be produced by user requests:
0050
0051 S_CROP(left / top = (5) - (1), width / height = (5') - (5))
0052 S_FMT(width / height = (6') - (6))
0053
0054 Here:
0055
0056 (1) to (1') - whole max width or height
0057 (1) to (2) - sensor cropped left or top
0058 (2) to (2') - sensor cropped width or height
0059 (3) to (3') - sensor scale
0060 (3) to (4) - CEU cropped left or top
0061 (4) to (4') - CEU cropped width or height
0062 (5) to (5') - reverse sensor scale applied to CEU cropped width or height
0063 (2) to (5) - reverse sensor scale applied to CEU cropped left or top
0064 (6) to (6') - CEU scale - user window
0065
0066
0067 S_FMT
0068 -----
0069
0070 Do not touch input rectangle - it is already optimal.
0071
0072 1. Calculate current sensor scales:
0073
0074 scale_s = ((2') - (2)) / ((3') - (3))
0075
0076 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
0077 current sensor scales onto input window - this is user S_CROP:
0078
0079 width_u = (5') - (5) = ((4') - (4)) * scale_s
0080
0081 3. Calculate new combined scales from "effective" input window to requested user
0082 window:
0083
0084 scale_comb = width_u / ((6') - (6))
0085
0086 4. Calculate sensor output window by applying combined scales to real input
0087 window:
0088
0089 width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb
0090
0091 5. Apply iterative sensor S_FMT for sensor output window.
0092
0093 subdev->video_ops->s_fmt(.width = width_s_out)
0094
0095 6. Retrieve sensor output window (g_fmt)
0096
0097 7. Calculate new sensor scales:
0098
0099 scale_s_new = ((3')_new - (3)_new) / ((2') - (2))
0100
0101 8. Calculate new CEU crop - apply sensor scales to previously calculated
0102 "effective" crop:
0103
0104 width_ceu = (4')_new - (4)_new = width_u / scale_s_new
0105 left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new
0106
0107 9. Use CEU cropping to crop to the new window:
0108
0109 ceu_crop(.width = width_ceu, .left = left_ceu)
0110
0111 10. Use CEU scaling to scale to the requested user window:
0112
0113 scale_ceu = width_ceu / width
0114
0115
0116 S_CROP
0117 ------
0118
0119 The :ref:`V4L2 crop API <crop-scale>` says:
0120
0121 "...specification does not define an origin or units. However by convention
0122 drivers should horizontally count unscaled samples relative to 0H."
0123
0124 We choose to follow the advise and interpret cropping units as client input
0125 pixels.
0126
0127 Cropping is performed in the following 6 steps:
0128
0129 1. Request exactly user rectangle from the sensor.
0130
0131 2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
0132 to 2 : 2', target crop 5 : 5', current output format 6' - 6.
0133
0134 3. In the previous step the sensor has tried to preserve its output frame as
0135 good as possible, but it could have changed. Retrieve it again.
0136
0137 4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
0138 intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
0139
0140 5. Calculate and apply host scale = (6' - 6) / (4' - 4)
0141
0142 6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)