1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
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 */
15
16 #include "post_proc_slr.h"
17
18 #include <cstdint>
19 #include <memory>
20 #include <unistd.h>
21 #include <vector>
22 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
23 #include "ffrt.h"
24 #endif
25 #include "image_log.h"
26 #include "image_trace.h"
27 #include "image_utils.h"
28
29 namespace OHOS {
30 namespace Media {
31 using namespace std;
32
33 constexpr float PI = 3.14159265;
34 constexpr float EPSILON = 1e-6;
35 constexpr int FFRT_THREAD_LIMIT = 8;
36
GetSLRFactor(float x,int a)37 float GetSLRFactor(float x, int a)
38 {
39 if (a <= 0) {
40 return 1.0f;
41 }
42 if (std::fabs(x) < EPSILON) {
43 return 1.0f;
44 }
45 if (x > a || x < -a) {
46 return 0.0f;
47 }
48
49 x *= PI;
50 return a * std::sin(x) * std::sin(x / a) / (x * x);
51 }
52
GetWeights(float coeff,int n)53 SLRWeightMat SLRProc::GetWeights(float coeff, int n)
54 {
55 if (std::fabs(coeff) < EPSILON || coeff < .0f || n <= 0) {
56 return nullptr;
57 }
58 float tao = 1.0f / coeff;
59 int a = std::max(2, static_cast<int>(std::floor(tao))); // 2 max SLR box size
60 SLRWeightMat weights = std::make_shared<SLRWeightVec>(n, std::vector<float>(2 * a, 0));
61 float beta = 1.0f;
62 if (coeff > 0.8999f && coeff < 1.0f) { // 0.8999f adjust low pass filter
63 beta = 1.2f; // 1.2f adjust low pass filter
64 } else if (coeff < 0.9f && coeff > 0.8f) { // 0.9f adjust low pass filter
65 beta = 1.1f; // 1.1f adjust low pass filter
66 }
67 float scale = coeff > 1.0f ? 1.0f : coeff;
68
69 for (int i = 0; i < n; i++) {
70 float etaf = (i + 0.5) / coeff - 0.5;
71 int eta = std::floor(etaf);
72 for (int k = eta - a + 1; k < eta + a + 1; k++) {
73 float factor = GetSLRFactor(scale / beta * (etaf - k), a);
74 (*weights)[i][k - eta + a - 1] = factor;
75 }
76 }
77 std::vector<float> rowSum(n, 0);
78 for (int i = 0; i < n; i++) {
79 for (int j = 0; j < 2 * a; j++) { // 2 max SLR box size
80 rowSum[i] += (*weights)[i][j];
81 }
82 if (std::fabs(rowSum[i]) < EPSILON) {
83 rowSum[i] = 1.0f; // 1.0f default weight
84 }
85 for (int j = 0; j < 2 * a; j++) { // 2 max SLR box size
86 (*weights)[i][j] /= rowSum[i];
87 }
88 }
89 return weights;
90 }
91
SLRCheck(const SLRMat & src,const SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)92 bool SLRCheck(const SLRMat &src, const SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
93 {
94 if (x == nullptr || y == nullptr) {
95 return false;
96 }
97 if (src.size_.width == 0 || src.size_.height == 0) {
98 return false;
99 }
100 if (dst.size_.width == 0 || dst.size_.height == 0) {
101 return false;
102 }
103 return true;
104 }
105
SLRCast(float v)106 inline uint32_t SLRCast(float v)
107 {
108 v = std::clamp(v, 0.0f, 255.0f); // 255.0f rgba max value
109 uint32_t uv = static_cast<uint32_t>(v);
110 return uv;
111 }
112
113 struct SLRSliceKey {
SLRSliceKeyOHOS::Media::SLRSliceKey114 SLRSliceKey(int v1, int v2) : x(v1), y(v2) {}
115 int x;
116 int y;
117 };
118
SLRBoxCheck(const SLRSliceKey & key,const SLRMat & src,const SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)119 bool SLRBoxCheck(const SLRSliceKey &key, const SLRMat &src, const SLRMat &dst, const SLRWeightMat &x,
120 const SLRWeightMat &y)
121 {
122 if (key.x < 0 || key.y < 0) {
123 IMAGE_LOGE("SLRBoxCheck Key error:%{public}d, %{public}d", key.x, key.y);
124 return false;
125 }
126 uint32_t* srcArr = static_cast<uint32_t*>(src.data_);
127 if (srcArr == nullptr) {
128 IMAGE_LOGE("SLRBoxCheck srcArr null");
129 return false;
130 }
131 uint32_t* dstArr = static_cast<uint32_t*>(dst.data_);
132 if (dstArr == nullptr) {
133 IMAGE_LOGE("SLRBoxCheck dstArr null");
134 return false;
135 }
136 int srcM = src.size_.height, srcN = src.size_.width;
137 int dstM = dst.size_.height, dstN = dst.size_.width;
138 float coeffX = static_cast<float>(dstM) / srcM;
139 float coeffY = static_cast<float>(dstN) / srcN;
140 float taoX = 1 / coeffX;
141 float taoY = 1 / coeffY;
142 int aX = std::max(2, static_cast<int>(std::floor(taoX)));
143 int aY = std::max(2, static_cast<int>(std::floor(taoY))); // 2 default size
144 if (static_cast<int>((*x).size()) < key.y || static_cast<int>((*x)[0].size()) < 2 * aY) { // 2 max slr box size
145 IMAGE_LOGE("SLRBoxCheck h_y error:%{public}zu, %{public}d", (*x).size(), aY);
146 return false;
147 }
148 if (static_cast<int>((*y).size()) < key.x || static_cast<int>((*y)[0].size()) < 2 * aX) { // 2 max slr box size
149 IMAGE_LOGE("SLRBoxCheck h_x error:%{public}zu, %{public}d", (*y).size(), aX);
150 return false;
151 }
152 int dstIndex = key.x * dst.rowStride_ + key.y;
153 int maxDstSize = dstM * dstN;
154 if (dstIndex >= maxDstSize) {
155 IMAGE_LOGE("SLRBoxCheck dst index error:%{public}d, %{public}d", dstIndex, maxDstSize);
156 return false;
157 }
158 return true;
159 }
160
SLRBox(const SLRSliceKey & key,const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)161 void SLRBox(const SLRSliceKey &key, const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
162 {
163 if (!SLRBoxCheck(key, src, dst, x, y)) {
164 return;
165 }
166 uint32_t* srcArr = static_cast<uint32_t*>(src.data_);
167 uint32_t* dstArr = static_cast<uint32_t*>(dst.data_);
168 int srcM = src.size_.height, srcN = src.size_.width, dstM = dst.size_.height, dstN = dst.size_.width;
169 float coeffX = static_cast<float>(dstM) / srcM, coeffY = static_cast<float>(dstN) / srcN;
170 float taoX = 1 / coeffX, taoY = 1 / coeffY;
171 int aX = std::max(2, static_cast<int>(std::floor(taoX)));
172 int aY = std::max(2, static_cast<int>(std::floor(taoY))); // 2 default size
173 int etaI = static_cast<int>((key.x + 0.5) * taoX - 0.5); // 0.5 middle index
174 int etaJ = static_cast<int>((key.y + 0.5) * taoY - 0.5); // 0.5 middle index
175 int rStart = etaI - aX + 1, rEnd = etaI + aX;
176 int cStart = etaJ - aY + 1, cEnd = etaJ + aY;
177 float rgba[4]{ .0f, .0f, .0f, .0f };
178 int maxSrcSize = srcM * srcN;
179 for (int r = rStart; r <= rEnd; ++r) {
180 int nR = min(max(0, r), srcM - 1);
181 for (int c = cStart; c <= cEnd; ++c) {
182 int nC = min(max(0, c), srcN - 1);
183 auto w = (*x)[key.y][c - cStart];
184 w *= (*y)[key.x][r - rStart];
185 int srcIndex = nR * src.rowStride_ + nC;
186 if (srcIndex < 0 || srcIndex >= maxSrcSize) {
187 IMAGE_LOGE("SLRBox src index error:%{public}d, %{public}d", srcIndex, maxSrcSize);
188 return;
189 }
190 uint32_t color = *(srcArr + srcIndex);
191 rgba[0] += ((color >> 24) & 0xFF) * w; // 24 rgba r
192 rgba[1] += ((color >> 16) & 0xFF) * w; // 16 rgba g
193 rgba[2] += ((color >> 8) & 0xFF) * w; // 2 8 rgba b
194 rgba[3] += (color & 0xFF) * w; // 3 rgba a
195 }
196 }
197 uint32_t r = SLRCast(rgba[0]), g = SLRCast(rgba[1]), b = SLRCast(rgba[2]), a = SLRCast(rgba[3]); // 2 3 rgba
198 dstArr[key.x * dst.rowStride_ + key.y] = (r << 24) | (g << 16) | (b << 8) | a; // 24 16 8 rgba
199 }
200
Serial(const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)201 void SLRProc::Serial(const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
202 {
203 if (!SLRCheck(src, dst, x, y)) {
204 IMAGE_LOGE("SLRProc::Serial param error");
205 return;
206 }
207
208 int m = dst.size_.height, n = dst.size_.width;
209 for (int i = 0; i < m; i++) {
210 for (int j = 0; j < n; j++) {
211 SLRSliceKey key(i, j);
212 SLRBox(key, src, dst, x, y);
213 }
214 }
215 }
216
SLRSubtask(const SLRSliceKey & key,const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)217 inline void SLRSubtask(const SLRSliceKey &key, const SLRMat &src, SLRMat &dst,
218 const SLRWeightMat &x, const SLRWeightMat &y)
219 {
220 int start = key.x;
221 int end = key.y;
222 int n = dst.size_.width;
223 for (int i = start; i < end; i++) {
224 for (int j = 0; j < n; j++) {
225 SLRSliceKey boxKey(i, j);
226 SLRBox(boxKey, src, dst, x, y);
227 }
228 }
229 }
230
Parallel(const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)231 void SLRProc::Parallel(const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
232 {
233 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
234 if (!SLRCheck(src, dst, x, y)) {
235 IMAGE_LOGE("SLRProc::Parallel param error");
236 return;
237 }
238 const int maxThread = 16; // 16 max thread size
239 int m = dst.size_.height, n = dst.size_.width;
240 int step = m / maxThread;
241 int stepMod = (m % maxThread == 0) ? 1 : 0;
242 std::vector<ffrt::dependence> ffrtHandles;
243 std::vector<ffrt::dependence> ffrtHandles1;
244 for (int k = 0; k < maxThread - stepMod; k++) {
245 int start = k * step;
246 int end = (k + 1) * step;
247 auto func = [&src, &dst, &x, &y, start, end, n] {
248 SLRSliceKey key(start, end);
249 SLRSubtask(key, src, dst, x, y);
250 };
251 auto handler = ffrt::submit_h(func, {}, {}, ffrt::task_attr().qos(5)); // 5 max ffrt qos value
252 if (ffrtHandles.size() < FFRT_THREAD_LIMIT) {
253 ffrtHandles.emplace_back(handler);
254 } else {
255 ffrtHandles1.emplace_back(handler);
256 }
257 }
258
259 for (int i = (maxThread - stepMod) * step; i < m; i++) {
260 for (int j = 0; j < n; j++) {
261 SLRSliceKey key(i, j);
262 SLRBox(key, src, dst, x, y);
263 }
264 }
265
266 ffrt::wait(ffrtHandles);
267 ffrt::wait(ffrtHandles1);
268 #else
269 SLRProc::Serial(src, dst, x, y);
270 #endif
271 }
272 } // namespace Media
273 } // namespace OHOS