Documentation/driver-api/media/drivers/sh_mobile_ceu_camera.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver

sh_mobile_ceu_camera의 sensor·host combined scale, S_FMT 10단계와 S_CROP 6단계 좌표 변환을 설명하는 전문 번역입니다.

Source pathDocumentation/driver-api/media/drivers/sh_mobile_ceu_camera.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

sh_mobile_ceu_camera.rst:1-142

이 문서의 핵심은 사용자 crop rectangle을 한 장치의 고정 좌표로 취급하지 않고, sensor crop·sensor scale·CEU crop·CEU scale 사이에서 일관되게 변환하는 것입니다. Sensor format 협상 결과가 요청과 달라질 수 있으므로 `S_FMT`와 `S_CROP` 모두 실제 sensor output을 다시 읽어 후속 계산에 사용합니다.

원문의 `(1)`부터 `(7')` 좌표는 수평 width·left와 수직 height·top에 공통으로 적용됩니다. 구현을 검토할 때는 source plane의 `(5):(5')`, sensor input의 `(2):(2')`, CEU input의 `(4):(4')`, 최종 user window의 `(6):(6')`를 구분해야 반대 방향의 배율이나 offset을 잘못 적용하지 않습니다.

문서 구성
원문 줄내용검토 초점
1-14Sensor·host·combined scale 용어`sensor_scale * host_scale`
15-65일반 좌표 그림과 구간 정의Source plane 역사상과 `(1)…(7')`
66-115`S_FMT` 10단계실제 sensor output을 반영한 CEU crop 재계산
116-142`S_CROP` 6단계Client input pixel 단위와 host 변환

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
4 =======================================================================
5
6 Author: Guennadi Liakhovetski <[email protected]>
7
8 Terminology
9 -----------
10
11 sensor scales: horizontal and vertical scales, configured by the sensor driver
12 host scales: -"- host driver
13 combined scales: sensor_scale * host_scale
14
15
16 Generic scaling / cropping scheme
17 ---------------------------------
18
19 .. code-block:: none
20
21 -1--
22 |
23 -2-- -\
24 | --\
25 | --\
26 +-5-- . -- -3-- -\
27 | `... -\
28 | `... -4-- . - -7..
29 | `.
30 | `. .6--
31 |
32 | . .6'-
33 | .´
34 | ... -4'- .´
35 | ...´ - -7'.
36 +-5'- .´ -/
37 | -- -3'- -/
38 | --/
39 | --/
40 -2'- -/
41 |
42 |
43 -1'-
44
45 In the above chart minuses and slashes represent "real" data amounts, points and
46 accents represent "useful" data, basically, CEU scaled and cropped output,
47 mapped back onto the client's source plane.
48
49 Such a configuration can be produced by user requests:
50
51 S_CROP(left / top = (5) - (1), width / height = (5') - (5))
52 S_FMT(width / height = (6') - (6))
53
54 Here:
55
56 (1) to (1') - whole max width or height
57 (1) to (2) - sensor cropped left or top
58 (2) to (2') - sensor cropped width or height
59 (3) to (3') - sensor scale
60 (3) to (4) - CEU cropped left or top
61 (4) to (4') - CEU cropped width or height
62 (5) to (5') - reverse sensor scale applied to CEU cropped width or height
63 (2) to (5) - reverse sensor scale applied to CEU cropped left or top
64 (6) to (6') - CEU scale - user window
65
66
67 S_FMT
68 -----
69
70 Do not touch input rectangle - it is already optimal.
71
72 1. Calculate current sensor scales:
73
74 scale_s = ((2') - (2)) / ((3') - (3))
75
76 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
77 current sensor scales onto input window - this is user S_CROP:
78
79 width_u = (5') - (5) = ((4') - (4)) * scale_s
80
81 3. Calculate new combined scales from "effective" input window to requested user
82 window:
83
84 scale_comb = width_u / ((6') - (6))
85
86 4. Calculate sensor output window by applying combined scales to real input
87 window:
88
89 width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb
90
91 5. Apply iterative sensor S_FMT for sensor output window.
92
93 subdev->video_ops->s_fmt(.width = width_s_out)
94
95 6. Retrieve sensor output window (g_fmt)
96
97 7. Calculate new sensor scales:
98
99 scale_s_new = ((3')_new - (3)_new) / ((2') - (2))
100
101 8. Calculate new CEU crop - apply sensor scales to previously calculated
102 "effective" crop:
103
104 width_ceu = (4')_new - (4)_new = width_u / scale_s_new
105 left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new
106
107 9. Use CEU cropping to crop to the new window:
108
109 ceu_crop(.width = width_ceu, .left = left_ceu)
110
111 10. Use CEU scaling to scale to the requested user window:
112
113 scale_ceu = width_ceu / width
114
115
116 S_CROP
117 ------
118
119 The :ref:`V4L2 crop API <crop-scale>` says:
120
121 "...specification does not define an origin or units. However by convention
122 drivers should horizontally count unscaled samples relative to 0H."
123
124 We choose to follow the advise and interpret cropping units as client input
125 pixels.
126
127 Cropping is performed in the following 6 steps:
128
129 1. Request exactly user rectangle from the sensor.
130
131 2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
132 to 2 : 2', target crop 5 : 5', current output format 6' - 6.
133
134 3. In the previous step the sensor has tried to preserve its output frame as
135 good as possible, but it could have changed. Retrieve it again.
136
137 4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
138 intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
139
140 5. Calculate and apply host scale = (6' - 6) / (4' - 4)
141
142 6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)
143

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 범위와 용어

1-14

이 `GPL-2.0` 문서는 Guennadi Liakhovetski가 작성했으며, `sh_mobile_ceu_camera` driver에서 사용하는 cropping 및 scaling 알고리즘을 설명합니다.

`sensor scales`는 sensor driver가 설정한 수평·수직 배율이고, `host scales`는 host driver가 설정한 수평·수직 배율입니다. `combined scales`는 두 단계를 연속 적용한 전체 배율이며 `sensor_scale * host_scale`로 계산합니다.

Scaling 용어
용어설정 주체의미
`sensor scales`Sensor driverSensor가 입력 영상을 줄이거나 늘리는 수평·수직 배율
`host scales`Host driverCEU host가 sensor 출력을 다시 변환하는 수평·수직 배율
`combined scales`Sensor + host`sensor_scale * host_scale`로 얻는 전체 배율

.. SPDX-License-Identifier: GPL-2.0

Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
=======================================================================

Author: Guennadi Liakhovetski <[email protected]>

Terminology
-----------

sensor scales: horizontal and vertical scales, configured by the sensor driver
host scales: -"- host driver
combined scales: sensor_scale * host_scale

일반적인 scaling·cropping 좌표 체계

15-65

원문의 ASCII 그림에서 빼기표와 사선은 실제 데이터의 양을 나타내고, 점과 악센트는 유효한 데이터의 양을 나타냅니다. 유효 데이터는 기본적으로 CEU가 scaling하고 cropping한 출력을 client의 source plane에 역으로 사상한 영역입니다.

사용자는 `S_CROP(left / top = (5) - (1), width / height = (5') - (5))`로 source plane의 crop rectangle을 요청하고, `S_FMT(width / height = (6') - (6))`로 최종 user window의 크기를 요청합니다.

좌표 `(1)`부터 `(1')`까지는 전체 최대 width 또는 height입니다. `(1)`부터 `(2)`까지는 sensor가 잘라낸 left 또는 top이고, `(2)`부터 `(2')`까지는 sensor crop의 width 또는 height입니다. 이 실제 입력 영역은 sensor scaling을 거쳐 `(3)`부터 `(3')`까지가 됩니다.

Sensor 출력에서 `(3)`부터 `(4)`까지는 CEU가 잘라낸 left 또는 top이고, `(4)`부터 `(4')`까지는 CEU crop의 width 또는 height입니다. 이를 sensor 배율의 역으로 source plane에 사상하면 `(2)`부터 `(5)`까지가 CEU crop offset, `(5)`부터 `(5')`까지가 CEU crop 크기에 대응합니다.

마지막으로 `(6)`부터 `(6')`까지는 CEU scaling 뒤 사용자가 받는 window입니다. 그림의 `(7)`과 `(7')`은 새 combined scale을 실제 sensor 입력 window에 적용해 얻는 sensor output window의 경계입니다.

원문 좌표 그림의 처리 경로
전체 입력 `(1):(1')`Sensor crop `(2):(2')`Sensor scale `(3):(3')`
CEU crop `(4):(4')`CEU scaleUser window `(6):(6')`
CEU crop을 source plane에 역사상User crop `(5):(5')`
Combined scale 적용Sensor output `(7):(7')`

ASCII 도식을 같은 의미의 처리 단계와 좌표 구간으로 재구성했습니다.

좌표 구간 대응
구간의미좌표계
`(1)` → `(1')`전체 최대 width 또는 heightClient source plane
`(1)` → `(2)`Sensor가 crop한 left 또는 topClient source plane
`(2)` → `(2')`Sensor가 crop한 width 또는 heightSensor input
`(3)` → `(3')`Sensor scale 뒤의 windowSensor output / CEU input
`(3)` → `(4)`CEU가 crop한 left 또는 topCEU input
`(4)` → `(4')`CEU가 crop한 width 또는 heightCEU input
`(5)` → `(5')`CEU crop 크기에 reverse sensor scale 적용Client source plane
`(2)` → `(5)`CEU crop offset에 reverse sensor scale 적용Client source plane
`(6)` → `(6')`CEU scale 뒤의 user windowClient output
`(7)` → `(7')`Combined scale로 계산한 sensor output windowSensor output


Generic scaling / cropping scheme
---------------------------------

.. code-block:: none

        -1--
        |
        -2-- -\
        |      --\
        |         --\
        +-5-- .      -- -3-- -\
        |      `...            -\
        |          `... -4-- .   - -7..
        |                     `.
        |                       `. .6--
        |
        |                        . .6'-
        |                      .´
        |           ... -4'- .´
        |       ...´             - -7'.
        +-5'- .´               -/
        |            -- -3'- -/
        |         --/
        |      --/
        -2'- -/
        |
        |
        -1'-

In the above chart minuses and slashes represent "real" data amounts, points and
accents represent "useful" data, basically, CEU scaled and cropped output,
mapped back onto the client's source plane.

Such a configuration can be produced by user requests:

S_CROP(left / top = (5) - (1), width / height = (5') - (5))
S_FMT(width / height = (6') - (6))

Here:

(1) to (1') - whole max width or height
(1) to (2)  - sensor cropped left or top
(2) to (2') - sensor cropped width or height
(3) to (3') - sensor scale
(3) to (4)  - CEU cropped left or top
(4) to (4') - CEU cropped width or height
(5) to (5') - reverse sensor scale applied to CEU cropped width or height
(2) to (5)  - reverse sensor scale applied to CEU cropped left or top
(6) to (6') - CEU scale - user window

S_FMT 알고리즘

66-115

`S_FMT`는 이미 최적인 input rectangle을 건드리지 않습니다. 대신 현재 sensor 배율과 기존 `S_CROP`의 유효 입력 영역을 바탕으로 새 sensor output, CEU crop, CEU scale을 차례로 계산합니다.

1단계에서는 현재 sensor 배율 `scale_s = ((2') - (2)) / ((3') - (3))`를 계산합니다. 2단계에서는 현재 sensor 배율로 CEU crop을 input window에 역사상해 사용자의 `S_CROP`인 유효 input crop을 구합니다. 식은 `width_u = (5') - (5) = ((4') - (4)) * scale_s`입니다.

3단계에서는 유효 input window에서 요청한 user window까지의 새 combined scale을 `scale_comb = width_u / ((6') - (6))`으로 계산합니다. 4단계에서는 이 combined scale을 실제 input window에 적용해 sensor output을 `width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb`으로 계산합니다.

5단계에서는 sensor output window에 대해 `subdev->video_ops->s_fmt(.width = width_s_out)`를 반복 적용합니다. 6단계에서는 `g_fmt`로 sensor output window를 다시 가져옵니다. Sensor가 요청값을 그대로 수용하지 않을 수 있으므로 실제 결과를 기준으로 다음 계산을 계속해야 합니다.

7단계에서는 새 sensor 배율을 `scale_s_new = ((3')_new - (3)_new) / ((2') - (2))`로 계산합니다. 8단계에서는 앞서 구한 유효 crop에 이 배율을 적용해 새 CEU crop의 크기 `width_ceu = (4')_new - (4)_new = width_u / scale_s_new`와 offset `left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new`를 구합니다.

9단계에서는 `ceu_crop(.width = width_ceu, .left = left_ceu)`로 새 window를 crop합니다. 10단계에서는 요청한 user window에 맞도록 CEU 배율 `scale_ceu = width_ceu / width`를 적용합니다. 같은 계산은 수평의 width·left와 수직의 height·top에 각각 대응합니다.

S_FMT 핵심 수식
수식역할
`scale_s``((2') - (2)) / ((3') - (3))`현재 sensor scale
`width_u``(5') - (5) = ((4') - (4)) * scale_s`Source plane의 유효 input crop
`scale_comb``width_u / ((6') - (6))`유효 입력에서 user window까지의 combined scale
`width_s_out``((7') - (7)) = ((2') - (2)) / scale_comb`요청할 sensor output width
`scale_s_new``((3')_new - (3)_new) / ((2') - (2))`실제 S_FMT 결과의 새 sensor scale
`width_ceu``(4')_new - (4)_new = width_u / scale_s_new`새 CEU crop width
`left_ceu``(4)_new - (3)_new = ((5) - (2)) / scale_s_new`새 CEU crop left
`scale_ceu``width_ceu / width`최종 user width에 맞추는 CEU scale

S_FMT 10단계
1. `scale_s` 계산2. `width_u` 계산3. `scale_comb` 계산4. `width_s_out` 계산
5. Sensor `S_FMT` 반복 적용6. `g_fmt`로 실제 output 조회
7. `scale_s_new` 계산8. `width_ceu`·`left_ceu` 계산
9. `ceu_crop` 적용10. `scale_ceu` 적용요청한 `(6):(6')` 출력

Input rectangle을 유지하면서 sensor와 CEU의 실제 결과를 반영합니다.


S_FMT
-----

Do not touch input rectangle - it is already optimal.

1. Calculate current sensor scales:

        scale_s = ((2') - (2)) / ((3') - (3))

2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
current sensor scales onto input window - this is user S_CROP:

        width_u = (5') - (5) = ((4') - (4)) * scale_s

3. Calculate new combined scales from "effective" input window to requested user
window:

        scale_comb = width_u / ((6') - (6))

4. Calculate sensor output window by applying combined scales to real input
window:

        width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb

5. Apply iterative sensor S_FMT for sensor output window.

        subdev->video_ops->s_fmt(.width = width_s_out)

6. Retrieve sensor output window (g_fmt)

7. Calculate new sensor scales:

        scale_s_new = ((3')_new - (3)_new) / ((2') - (2))

8. Calculate new CEU crop - apply sensor scales to previously calculated
"effective" crop:

        width_ceu = (4')_new - (4)_new = width_u / scale_s_new
        left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new

9. Use CEU cropping to crop to the new window:

        ceu_crop(.width = width_ceu, .left = left_ceu)

10. Use CEU scaling to scale to the requested user window:

        scale_ceu = width_ceu / width

S_CROP 알고리즘

116-142

`V4L2 crop API <crop-scale>`는 crop의 origin이나 unit을 규정하지 않지만, 관례상 driver가 수평 방향의 unscaled sample을 `0H`를 기준으로 세도록 권고합니다. 이 driver는 그 조언을 따라 cropping unit을 client input pixel로 해석합니다.

Cropping은 6단계로 수행합니다. 1단계에서 sensor에 사용자가 지정한 rectangle을 정확히 요청합니다. 2단계에서 결과가 더 작으면 더 큰 rectangle을 얻을 때까지 반복합니다. 그 결과 sensor crop은 `(2):(2')`, 목표 crop은 `(5):(5')`, 현재 output format은 `(6') - (6)`이 됩니다.

3단계에서는 이전 협상에서 sensor가 output frame을 최대한 보존하려 했더라도 값이 달라졌을 수 있으므로 output을 다시 조회합니다. 4단계에서 sensor는 `(3):(3')`로 scale했고 sensor scale은 `(2' - 2) / (3' - 3)`입니다. 따라서 중간 window는 `4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)`로 계산합니다.

5단계에서는 host scale `(6' - 6) / (4' - 4)`를 계산해 적용합니다. 6단계에서는 host crop offset `6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)`를 계산해 적용합니다. 이 절차는 client input pixel로 표현된 목표 crop을 sensor와 host가 실제로 제공하는 window에 맞춰 나눠 적용합니다.

S_CROP 좌표와 수식
항목표현의미
Sensor crop`(2):(2')`반복 협상으로 얻은 실제 sensor rectangle
Target crop`(5):(5')`Client input pixel 단위의 사용자 요청
Current output`(6') - (6)`현재 출력 format 크기
Sensor scale`(2' - 2) / (3' - 3)`Sensor input과 output의 비율
Intermediate window`4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)`Host가 crop·scale할 중간 크기
Host scale`(6' - 6) / (4' - 4)`중간 window에서 output까지의 비율
Host crop`6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)`Output 좌표계의 crop offset

S_CROP 6단계
1. 정확한 user rectangle 요청2. 더 큰 sensor rectangle까지 반복
3. Sensor output 재조회4. Sensor scale과 intermediate window 계산
5. Host scale 계산·적용6. Host crop 계산·적용
Client input pixel cropSensor + CEU 처리현재 output format

Sensor 협상 결과를 다시 읽은 뒤 host crop과 scale을 계산합니다.

S_CROP
------

The :ref:`V4L2 crop API <crop-scale>` says:

"...specification does not define an origin or units. However by convention
drivers should horizontally count unscaled samples relative to 0H."

We choose to follow the advise and interpret cropping units as client input
pixels.

Cropping is performed in the following 6 steps:

1. Request exactly user rectangle from the sensor.

2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
   to 2 : 2', target crop 5 : 5', current output format 6' - 6.

3. In the previous step the sensor has tried to preserve its output frame as
   good as possible, but it could have changed. Retrieve it again.

4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
   intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)

5. Calculate and apply host scale = (6' - 6) / (4' - 4)

6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)