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 "format_helper.h"
17
18 #include "effect_log.h"
19
20 namespace {
21 const float YUV_BYTES_PER_PIXEL = 1.5f;
22 const int32_t RGBA_BYTES_PER_PIXEL = 4;
23 const int32_t P10_BYTES_PER_LUMA = 2;
24 const int32_t R = 0;
25 const int32_t G = 1;
26 const int32_t B = 2;
27 const int32_t A = 3;
28 const int32_t UV_SPLIT_FACTOR = 2;
29 }
30
31 namespace OHOS {
32 namespace Media {
33 namespace Effect {
34
35 void ConvertRGBAToNV12(FormatConverterInfo &src, FormatConverterInfo &dst);
36 void ConvertRGBAToNV21(FormatConverterInfo &src, FormatConverterInfo &dst);
37 void ConvertNV12ToRGBA(FormatConverterInfo &src, FormatConverterInfo &dst);
38 void ConvertNV21ToRGBA(FormatConverterInfo &src, FormatConverterInfo &dst);
39
40 using FormatConverterFunc = std::function<void(FormatConverterInfo &src, FormatConverterInfo &dst)>;
41
42 struct FormatConverter {
43 IEffectFormat srcFormat;
44 IEffectFormat dstFormat;
45 FormatConverterFunc converterFunc;
46 };
47
48 static const std::vector<FormatConverter> FORMAT_CONVERTER = {
49 FormatConverter{ IEffectFormat::RGBA8888, IEffectFormat::YUVNV12, ConvertRGBAToNV12 },
50 FormatConverter{ IEffectFormat::RGBA8888, IEffectFormat::YUVNV21, ConvertRGBAToNV21 },
51 FormatConverter{ IEffectFormat::YUVNV12, IEffectFormat::RGBA8888, ConvertNV12ToRGBA },
52 FormatConverter{ IEffectFormat::YUVNV21, IEffectFormat::RGBA8888, ConvertNV21ToRGBA },
53 };
54
55 static const std::unordered_set<IEffectFormat> SUPPORTED_FORMATS = {
56 IEffectFormat::RGBA8888,
57 IEffectFormat::YUVNV12,
58 IEffectFormat::YUVNV21,
59 IEffectFormat::RGBA_1010102,
60 IEffectFormat::YCRCB_P010,
61 IEffectFormat::YCBCR_P010,
62 };
63
CalculateDataRowCount(uint32_t height,IEffectFormat format)64 uint32_t FormatHelper::CalculateDataRowCount(uint32_t height, IEffectFormat format)
65 {
66 switch (format) {
67 case IEffectFormat::RGBA8888:
68 case IEffectFormat::RGBA_1010102:
69 return height;
70 case IEffectFormat::YUVNV12:
71 case IEffectFormat::YUVNV21:
72 case IEffectFormat::YCBCR_P010:
73 case IEffectFormat::YCRCB_P010:
74 return static_cast<uint32_t>(height * YUV_BYTES_PER_PIXEL);
75 default:
76 return height;
77 }
78 }
79
CalculateRowStride(uint32_t width,IEffectFormat format)80 uint32_t FormatHelper::CalculateRowStride(uint32_t width, IEffectFormat format)
81 {
82 switch (format) {
83 case IEffectFormat::RGBA8888:
84 case IEffectFormat::RGBA_1010102:
85 return width * RGBA_BYTES_PER_PIXEL;
86 case IEffectFormat::YUVNV12:
87 case IEffectFormat::YUVNV21:
88 return width;
89 case IEffectFormat::YCRCB_P010:
90 case IEffectFormat::YCBCR_P010:
91 return width * P10_BYTES_PER_LUMA;
92 default:
93 return width;
94 }
95 }
96
CalculateSize(uint32_t width,uint32_t height,IEffectFormat format)97 uint32_t FormatHelper::CalculateSize(uint32_t width, uint32_t height, IEffectFormat format)
98 {
99 return CalculateDataRowCount(height, format) * CalculateRowStride(width, format);
100 }
101
GetAllSupportedFormats()102 std::unordered_set<IEffectFormat> FormatHelper::GetAllSupportedFormats()
103 {
104 return SUPPORTED_FORMATS;
105 }
106
IsSupportConvert(IEffectFormat srcFormat,IEffectFormat dstFormat)107 bool FormatHelper::IsSupportConvert(IEffectFormat srcFormat, IEffectFormat dstFormat)
108 {
109 return std::any_of(FORMAT_CONVERTER.begin(), FORMAT_CONVERTER.end(), [=](const FormatConverter &converter) {
110 return converter.srcFormat == srcFormat && converter.dstFormat == dstFormat;
111 });
112 }
113
GetFormatConverterFunc(IEffectFormat srcFormat,IEffectFormat dstFormat)114 FormatConverterFunc GetFormatConverterFunc(IEffectFormat srcFormat, IEffectFormat dstFormat)
115 {
116 for (const auto &converter : FORMAT_CONVERTER) {
117 if (converter.srcFormat == srcFormat && converter.dstFormat == dstFormat) {
118 return converter.converterFunc;
119 }
120 }
121
122 return nullptr;
123 }
124
CheckConverterInfo(FormatConverterInfo & src,FormatConverterInfo & dst)125 ErrorCode CheckConverterInfo(FormatConverterInfo &src, FormatConverterInfo &dst)
126 {
127 CHECK_AND_RETURN_RET_LOG(src.buffer != nullptr && dst.buffer != nullptr, ErrorCode::ERR_PARAM_INVALID,
128 "CheckConverterInfo: invalid buffer!");
129
130 BufferInfo &srcBuffInfo = src.bufferInfo;
131 BufferInfo &dstBuffInfo = dst.bufferInfo;
132 if (srcBuffInfo.width_ != dstBuffInfo.width_ || srcBuffInfo.height_ != dstBuffInfo.height_) {
133 EFFECT_LOGW("CheckConverterInfo: diff size! srcW=%{public}d, srcH=%{public}d, dstW=%{public}d, dstH=%{public}d",
134 srcBuffInfo.width_, srcBuffInfo.height_, dstBuffInfo.width_, dstBuffInfo.height_);
135 }
136
137 EFFECT_LOGD("CheckConverterInfo: src{w=%{public}d h=%{public}d format=%{public}d len=%{public}d stride=%{public}d},"
138 " dts={w=%{public}d h=%{public}d format=%{public}d len=%{public}d stride=%{public}d}",
139 srcBuffInfo.width_, srcBuffInfo.height_, srcBuffInfo.formatType_, srcBuffInfo.len_, srcBuffInfo.rowStride_,
140 dstBuffInfo.width_, dstBuffInfo.height_, dstBuffInfo.formatType_, dstBuffInfo.len_, dstBuffInfo.rowStride_);
141
142 uint32_t minSrcRowStride = FormatHelper::CalculateRowStride(srcBuffInfo.width_, srcBuffInfo.formatType_);
143 uint32_t minDstRowStride = FormatHelper::CalculateRowStride(dstBuffInfo.width_, dstBuffInfo.formatType_);
144 uint32_t minSrcLen = FormatHelper::CalculateSize(srcBuffInfo.width_, srcBuffInfo.height_, srcBuffInfo.formatType_);
145 uint32_t minDstLen = FormatHelper::CalculateSize(dstBuffInfo.width_, dstBuffInfo.height_, dstBuffInfo.formatType_);
146 CHECK_AND_RETURN_RET_LOG(minSrcRowStride <= srcBuffInfo.rowStride_ && minDstRowStride <= dstBuffInfo.rowStride_ &&
147 minSrcLen <= srcBuffInfo.len_ && minDstLen <= dstBuffInfo.len_, ErrorCode::ERR_PARAM_INVALID,
148 "CheckConverterInfo: invalid size! src{%{public}d %{public}d %{public}d %{public}d %{public}d}, "
149 "dst{%{public}d %{public}d %{public}d %{public}d %{public}d}",
150 srcBuffInfo.width_, srcBuffInfo.height_, srcBuffInfo.formatType_, srcBuffInfo.len_, srcBuffInfo.rowStride_,
151 dstBuffInfo.width_, dstBuffInfo.height_, dstBuffInfo.formatType_, dstBuffInfo.len_, dstBuffInfo.rowStride_);
152
153 return ErrorCode::SUCCESS;
154 }
155
ConvertFormat(FormatConverterInfo & src,FormatConverterInfo & dst)156 ErrorCode FormatHelper::ConvertFormat(FormatConverterInfo &src, FormatConverterInfo &dst)
157 {
158 IEffectFormat srcFormat = src.bufferInfo.formatType_;
159 IEffectFormat dstFormat = dst.bufferInfo.formatType_;
160
161 auto func = GetFormatConverterFunc(srcFormat, dstFormat);
162 CHECK_AND_RETURN_RET_LOG(func != nullptr, ErrorCode::ERR_NOT_SUPPORT_CONVERT_FORMAT,
163 "ConvertFormat: format not support convert! srcFormat=%{public}d, dstFormat=%{public}d", srcFormat, dstFormat);
164
165 ErrorCode res = CheckConverterInfo(src, dst);
166 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "ConvertFormat: invalid para! res=%{public}d", res);
167
168 func(src, dst);
169 return ErrorCode::SUCCESS;
170 }
171
ConvertRGBAToNV12(FormatConverterInfo & src,FormatConverterInfo & dst)172 void ConvertRGBAToNV12(FormatConverterInfo &src, FormatConverterInfo &dst)
173 {
174 EFFECT_LOGW("ConvertRGBAToNV12: ConvertRGBAToNV12 will loss alpha information!");
175 BufferInfo &srcBuffInfo = src.bufferInfo;
176 BufferInfo &dstBuffInfo = dst.bufferInfo;
177 uint32_t width = std::min(srcBuffInfo.width_, dstBuffInfo.width_);
178 uint32_t height = std::min(srcBuffInfo.height_, dstBuffInfo.height_);
179 uint32_t srcRowStride = srcBuffInfo.rowStride_;
180 uint32_t dstRowStride = dstBuffInfo.rowStride_;
181
182 uint8_t *srcRGBA = static_cast<uint8_t *>(src.buffer);
183 uint8_t *dstNV12 = static_cast<uint8_t *>(dst.buffer);
184 uint8_t *dstNV12UV = dstNV12 + dstBuffInfo.height_ * dstRowStride;
185
186 #pragma omp parallel for default(none) shared(height, width, srcRGBA, dstNV12, dstNV12UV, srcRowStride, dstRowStride)
187 for (uint32_t i = 0; i < height; i++) {
188 for (uint32_t j = 0; j < width; j++) {
189 uint32_t y_index = i * dstRowStride + j;
190 uint32_t nv_index = i / UV_SPLIT_FACTOR * dstRowStride + j - j % UV_SPLIT_FACTOR;
191 uint32_t srcIndex = i * srcRowStride + j * RGBA_BYTES_PER_PIXEL;
192 uint8_t r = srcRGBA[srcIndex + R];
193 uint8_t g = srcRGBA[srcIndex + G];
194 uint8_t b = srcRGBA[srcIndex + B];
195
196 dstNV12[y_index] = FormatHelper::RGBToY(r, g, b);
197 dstNV12UV[nv_index] = FormatHelper::RGBToU(r, g, b);
198 dstNV12UV[nv_index + 1] = FormatHelper::RGBToV(r, g, b);
199 }
200 }
201 }
202
ConvertRGBAToNV21(FormatConverterInfo & src,FormatConverterInfo & dst)203 void ConvertRGBAToNV21(FormatConverterInfo &src, FormatConverterInfo &dst)
204 {
205 EFFECT_LOGW("ConvertRGBAToNV21: ConvertRGBAToNV21 will loss alpha information!");
206 BufferInfo &srcBuffInfo = src.bufferInfo;
207 BufferInfo &dstBuffInfo = dst.bufferInfo;
208 uint32_t width = std::min(srcBuffInfo.width_, dstBuffInfo.width_);
209 uint32_t height = std::min(srcBuffInfo.height_, dstBuffInfo.height_);
210 uint32_t srcRowStride = srcBuffInfo.rowStride_;
211 uint32_t dstRowStride = dstBuffInfo.rowStride_;
212
213 uint8_t *srcRGBA = static_cast<uint8_t *>(src.buffer);
214 uint8_t *dstNV21 = static_cast<uint8_t *>(dst.buffer);
215 uint8_t *dstNV21UV = dstNV21 + dstBuffInfo.height_ * dstRowStride;
216
217 #pragma omp parallel for default(none) shared(height, width, srcRGBA, dstNV12, dstNV12UV, srcRowStride, dstRowStride)
218 for (uint32_t i = 0; i < height; i++) {
219 for (uint32_t j = 0; j < width; j++) {
220 uint32_t y_index = i * dstRowStride + j;
221 uint32_t nv_index = i / UV_SPLIT_FACTOR * dstRowStride + j - j % UV_SPLIT_FACTOR;
222 uint32_t srcIndex = i * srcRowStride + j * RGBA_BYTES_PER_PIXEL;
223 uint8_t r = srcRGBA[srcIndex + R];
224 uint8_t g = srcRGBA[srcIndex + G];
225 uint8_t b = srcRGBA[srcIndex + B];
226
227 dstNV21[y_index] = FormatHelper::RGBToY(r, g, b);
228 dstNV21UV[nv_index] = FormatHelper::RGBToV(r, g, b);
229 dstNV21UV[nv_index + 1] = FormatHelper::RGBToU(r, g, b);
230 }
231 }
232 }
233
ConvertNV12ToRGBA(FormatConverterInfo & src,FormatConverterInfo & dst)234 void ConvertNV12ToRGBA(FormatConverterInfo &src, FormatConverterInfo &dst)
235 {
236 BufferInfo &srcBuffInfo = src.bufferInfo;
237 BufferInfo &dstBuffInfo = dst.bufferInfo;
238 uint32_t width = std::min(srcBuffInfo.width_, dstBuffInfo.width_);
239 uint32_t height = std::min(srcBuffInfo.height_, dstBuffInfo.height_);
240 uint32_t srcRowStride = srcBuffInfo.rowStride_;
241 uint32_t dstRowStride = dstBuffInfo.rowStride_;
242
243 uint8_t *srcNV12 = static_cast<uint8_t *>(src.buffer);
244 uint8_t *srcNV12UV = srcNV12 + srcBuffInfo.height_ * srcRowStride;
245 uint8_t *dstRGBA = static_cast<uint8_t *>(dst.buffer);
246
247 #pragma omp parallel for default(none) shared(height, width, srcNV12, srcNV12UV, dstRGBA, srcRowStride, dstRowStride)
248 for (uint32_t i = 0; i < height; i++) {
249 for (uint32_t j = 0; j < width; j++) {
250 uint32_t y_index = i * srcRowStride + j;
251 uint32_t nv_index = i / UV_SPLIT_FACTOR * srcRowStride + j - j % UV_SPLIT_FACTOR;
252 uint32_t dstIndex = i * dstRowStride + j *RGBA_BYTES_PER_PIXEL;
253 uint8_t y = srcNV12[y_index];
254 uint8_t u = srcNV12UV[nv_index];
255 uint8_t v = srcNV12UV[nv_index + 1];
256
257 dstRGBA[dstIndex + R] = FormatHelper::YuvToR(y, u, v);
258 dstRGBA[dstIndex + G] = FormatHelper::YuvToG(y, u, v);
259 dstRGBA[dstIndex + B] = FormatHelper::YuvToB(y, u, v);
260 dstRGBA[dstIndex + A] = UNSIGHED_CHAR_MAX;
261 }
262 }
263 }
264
ConvertNV21ToRGBA(FormatConverterInfo & src,FormatConverterInfo & dst)265 void ConvertNV21ToRGBA(FormatConverterInfo &src, FormatConverterInfo &dst)
266 {
267 BufferInfo &srcBuffInfo = src.bufferInfo;
268 BufferInfo &dstBuffInfo = dst.bufferInfo;
269 uint32_t width = std::min(srcBuffInfo.width_, dstBuffInfo.width_);
270 uint32_t height = std::min(srcBuffInfo.height_, dstBuffInfo.height_);
271 uint32_t srcRowStride = srcBuffInfo.rowStride_;
272 uint32_t dstRowStride = dstBuffInfo.rowStride_;
273
274 CHECK_AND_RETURN_LOG(src.buffer != nullptr && dst.buffer != nullptr,
275 "ConvertNV21ToRGBA: src buffer or dst buffer is null!");
276 uint8_t *srcNV21 = static_cast<uint8_t *>(src.buffer);
277 uint8_t *srcNV21UV = srcNV21 + srcBuffInfo.height_ * srcRowStride;
278 uint8_t *dstRGBA = static_cast<uint8_t *>(dst.buffer);
279
280 #pragma omp parallel for default(none) shared(height, width, srcNV21, srcNV21UV, dstRGBA, srcRowStride, dstRowStride)
281 for (uint32_t i = 0; i < height; i++) {
282 for (uint32_t j = 0; j < width; j++) {
283 uint32_t y_index = i * srcRowStride + j;
284 uint32_t nv_index = i / UV_SPLIT_FACTOR * srcRowStride + j - j % UV_SPLIT_FACTOR;
285 uint32_t dstIndex = i * dstRowStride + j *RGBA_BYTES_PER_PIXEL;
286 uint8_t y = srcNV21[y_index];
287 uint8_t v = srcNV21UV[nv_index];
288 uint8_t u = srcNV21UV[nv_index + 1];
289
290 dstRGBA[dstIndex + R] = FormatHelper::YuvToR(y, u, v);
291 dstRGBA[dstIndex + G] = FormatHelper::YuvToG(y, u, v);
292 dstRGBA[dstIndex + B] = FormatHelper::YuvToB(y, u, v);
293 dstRGBA[dstIndex + A] = UNSIGHED_CHAR_MAX;
294 }
295 }
296 }
297 } // namespace Effect
298 } // namespace Media
299 } // namespace OHOS