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 "colorspace_helper.h"
17
18 #include <unordered_map>
19
20 #include "metadata_helper.h"
21 #include "colorspace_converter.h"
22 #include "metadata_generator.h"
23 #include "effect_log.h"
24
25 namespace OHOS {
26 namespace Media {
27 namespace Effect {
28 using namespace OHOS::ColorManager;
29 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
30
31 static const std::unordered_map<EffectColorSpace, ColorSpaceName> EFFECT_TO_COLORMANAGER_COLORSPACE_MAP = {
32 { EffectColorSpace::SRGB, ColorSpaceName::SRGB },
33 { EffectColorSpace::SRGB_LIMIT, ColorSpaceName::SRGB_LIMIT },
34 { EffectColorSpace::DISPLAY_P3, ColorSpaceName::DISPLAY_P3 },
35 { EffectColorSpace::DISPLAY_P3_LIMIT, ColorSpaceName::DISPLAY_P3_LIMIT },
36 { EffectColorSpace::BT2020_HLG, ColorSpaceName::BT2020_HLG },
37 { EffectColorSpace::BT2020_HLG_LIMIT, ColorSpaceName::BT2020_HLG_LIMIT },
38 { EffectColorSpace::BT2020_PQ, ColorSpaceName::BT2020_PQ },
39 { EffectColorSpace::BT2020_PQ_LIMIT, ColorSpaceName::BT2020_PQ_LIMIT },
40 { EffectColorSpace::ADOBE_RGB, ColorSpaceName::ADOBE_RGB },
41 };
42
43 static const std::unordered_map<EffectColorSpace, CM_ColorSpaceType> EFFECT_TO_GRAPHIC_COLORSPACE_MAP = {
44 { EffectColorSpace::SRGB, CM_ColorSpaceType::CM_SRGB_FULL },
45 { EffectColorSpace::SRGB_LIMIT, CM_ColorSpaceType::CM_SRGB_LIMIT },
46 { EffectColorSpace::DISPLAY_P3, CM_ColorSpaceType::CM_P3_FULL },
47 { EffectColorSpace::DISPLAY_P3_LIMIT, CM_ColorSpaceType::CM_P3_LIMIT },
48 { EffectColorSpace::BT2020_HLG, CM_ColorSpaceType::CM_BT2020_HLG_FULL },
49 { EffectColorSpace::BT2020_HLG_LIMIT, CM_ColorSpaceType::CM_BT2020_HLG_LIMIT },
50 { EffectColorSpace::BT2020_PQ, CM_ColorSpaceType::CM_BT2020_PQ_FULL },
51 { EffectColorSpace::BT2020_PQ_LIMIT, CM_ColorSpaceType::CM_BT2020_PQ_LIMIT },
52 { EffectColorSpace::ADOBE_RGB, CM_ColorSpaceType::CM_ADOBERGB_FULL },
53 };
54
55 static const std::unordered_map<EffectColorSpace, OH_NativeBuffer_ColorSpace> EFFECT_TO_NATIVE_BUFFER_COLORSPACE_MAP = {
56 { EffectColorSpace::SRGB, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_SRGB_FULL },
57 { EffectColorSpace::SRGB_LIMIT, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_SRGB_LIMIT },
58 { EffectColorSpace::DISPLAY_P3, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_P3_FULL },
59 { EffectColorSpace::DISPLAY_P3_LIMIT, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_P3_LIMIT },
60 { EffectColorSpace::BT2020_HLG, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_BT2020_HLG_FULL },
61 { EffectColorSpace::BT2020_HLG_LIMIT, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_BT2020_HLG_LIMIT },
62 { EffectColorSpace::BT2020_PQ, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_BT2020_PQ_FULL },
63 { EffectColorSpace::BT2020_PQ_LIMIT, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_BT2020_PQ_LIMIT },
64 { EffectColorSpace::ADOBE_RGB, OH_NativeBuffer_ColorSpace::OH_COLORSPACE_ADOBERGB_FULL },
65 };
66
IsHdrColorSpace(EffectColorSpace colorSpace)67 bool ColorSpaceHelper::IsHdrColorSpace(EffectColorSpace colorSpace)
68 {
69 return colorSpace == EffectColorSpace::BT2020_HLG || colorSpace == EffectColorSpace::BT2020_HLG_LIMIT ||
70 colorSpace == EffectColorSpace::BT2020_PQ || colorSpace == EffectColorSpace::BT2020_PQ_LIMIT;
71 }
72
ConvertToEffectColorSpace(ColorSpaceName colorSpaceName)73 EffectColorSpace ColorSpaceHelper::ConvertToEffectColorSpace(ColorSpaceName colorSpaceName)
74 {
75 EffectColorSpace colorSpaceType = EffectColorSpace::DEFAULT;
76
77 for (const auto &it : EFFECT_TO_COLORMANAGER_COLORSPACE_MAP) {
78 if (it.second == colorSpaceName) {
79 colorSpaceType = it.first;
80 break;
81 }
82 }
83
84 EFFECT_LOGD("ConvertToEffectColorSpace: colorSpaceName=%{public}d, effectColorSpaceType=%{public}d",
85 colorSpaceName, colorSpaceType);
86 return colorSpaceType;
87 }
88
ConvertToNativeBufferColorSpace(EffectColorSpace effectColorSpace)89 OH_NativeBuffer_ColorSpace ColorSpaceHelper::ConvertToNativeBufferColorSpace(EffectColorSpace effectColorSpace)
90 {
91 OH_NativeBuffer_ColorSpace nativeBufferColorSpace = OH_NativeBuffer_ColorSpace::OH_COLORSPACE_NONE;
92 auto it = EFFECT_TO_NATIVE_BUFFER_COLORSPACE_MAP.find(effectColorSpace);
93 if (it != EFFECT_TO_NATIVE_BUFFER_COLORSPACE_MAP.end()) {
94 nativeBufferColorSpace = it->second;
95 }
96
97 EFFECT_LOGD("ConvertToEffectColorSpace: colorSpaceType=%{public}d, effectColorSpaceType=%{public}d",
98 effectColorSpace, nativeBufferColorSpace);
99 return nativeBufferColorSpace;
100 }
101
ConvertToColorSpaceName(EffectColorSpace colorSpace)102 ColorSpaceName ColorSpaceHelper::ConvertToColorSpaceName(EffectColorSpace colorSpace)
103 {
104 ColorSpaceName colorSpaceName = ColorSpaceName::NONE;
105 auto it = EFFECT_TO_COLORMANAGER_COLORSPACE_MAP.find(colorSpace);
106 if (it != EFFECT_TO_COLORMANAGER_COLORSPACE_MAP.end()) {
107 colorSpaceName = it->second;
108 }
109
110 return colorSpaceName;
111 }
112
ConvertToEffectColorSpace(CM_ColorSpaceType type)113 EffectColorSpace ColorSpaceHelper::ConvertToEffectColorSpace(CM_ColorSpaceType type)
114 {
115 EffectColorSpace effectColorSpaceType = EffectColorSpace::DEFAULT;
116
117 for (const auto &it : EFFECT_TO_GRAPHIC_COLORSPACE_MAP) {
118 if (it.second == type) {
119 effectColorSpaceType = it.first;
120 break;
121 }
122 }
123
124 EFFECT_LOGD("ConvertToEffectColorSpace: colorSpaceType=%{public}d, effectColorSpaceType=%{public}d",
125 type, effectColorSpaceType);
126 return effectColorSpaceType;
127 }
128
ConvertToCMColorSpace(EffectColorSpace colorSpace)129 CM_ColorSpaceType ColorSpaceHelper::ConvertToCMColorSpace(EffectColorSpace colorSpace)
130 {
131 CM_ColorSpaceType cmColorSpaceType = CM_ColorSpaceType::CM_COLORSPACE_NONE;
132 auto it = EFFECT_TO_GRAPHIC_COLORSPACE_MAP.find(colorSpace);
133 if (it != EFFECT_TO_GRAPHIC_COLORSPACE_MAP.end()) {
134 cmColorSpaceType = it->second;
135 }
136
137 return cmColorSpaceType;
138 }
139
SetSurfaceBufferMetadataType(SurfaceBuffer * sb,const CM_HDR_Metadata_Type & type)140 ErrorCode ColorSpaceHelper::SetSurfaceBufferMetadataType(SurfaceBuffer *sb, const CM_HDR_Metadata_Type &type)
141 {
142 sptr<SurfaceBuffer> buffer = sb;
143 auto res = MetadataHelper::SetHDRMetadataType(buffer, type);
144 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_SET_METADATA_FAIL,
145 "SetSurfaceBufferMetadataType: SetHDRMetadataType fail! res=%{public}d", res);
146 return ErrorCode::SUCCESS;
147 }
148
GetSurfaceBufferMetadataType(SurfaceBuffer * sb,CM_HDR_Metadata_Type & type)149 ErrorCode ColorSpaceHelper::GetSurfaceBufferMetadataType(SurfaceBuffer *sb, CM_HDR_Metadata_Type &type)
150 {
151 sptr<SurfaceBuffer> buffer = sb;
152 auto res = MetadataHelper::GetHDRMetadataType(buffer, type);
153 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_GET_METADATA_FAIL,
154 "GetSurfaceBufferMetadataType: GetHDRMetadataType fail! res=%{public}d", res);
155 return ErrorCode::SUCCESS;
156 }
157
SetSurfaceBufferColorSpaceType(SurfaceBuffer * sb,const CM_ColorSpaceType & type)158 ErrorCode ColorSpaceHelper::SetSurfaceBufferColorSpaceType(SurfaceBuffer *sb, const CM_ColorSpaceType &type)
159 {
160 sptr<SurfaceBuffer> buffer = sb;
161 auto res = MetadataHelper::SetColorSpaceType(buffer, type);
162 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_SET_COLORSPACETYPE_FAIL,
163 "SetSurfaceBufferColorSpaceType: SetColorSpaceType fail! res=%{public}d", res);
164 return ErrorCode::SUCCESS;
165 }
166
GetSurfaceBufferColorSpaceType(SurfaceBuffer * sb,CM_ColorSpaceType & type)167 ErrorCode ColorSpaceHelper::GetSurfaceBufferColorSpaceType(SurfaceBuffer *sb, CM_ColorSpaceType &type)
168 {
169 sptr<SurfaceBuffer> buffer = sb;
170 auto res = MetadataHelper::GetColorSpaceType(buffer, type);
171 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_GET_COLORSPACETYPE_FAIL,
172 "GetSurfaceBufferColorSpaceType: GetColorSpaceType fail! res=%{public}d", res);
173 return ErrorCode::SUCCESS;
174 }
175
SetHDRDynamicMetadata(SurfaceBuffer * sb,const std::vector<uint8_t> & hdrDynamicMetadata)176 ErrorCode ColorSpaceHelper::SetHDRDynamicMetadata(SurfaceBuffer *sb, const std::vector<uint8_t> &hdrDynamicMetadata)
177 {
178 sptr<SurfaceBuffer> buffer = sb;
179 auto res = MetadataHelper::SetHDRDynamicMetadata(buffer, hdrDynamicMetadata);
180 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_SET_METADATA_FAIL,
181 "SetHDRDynamicMetadata: SetHDRDynamicMetadata fail! res=%{public}d", res);
182 return ErrorCode::SUCCESS;
183 }
184
SetHDRStaticMetadata(SurfaceBuffer * sb,const std::vector<uint8_t> & hdrStaticMetadata)185 ErrorCode ColorSpaceHelper::SetHDRStaticMetadata(SurfaceBuffer *sb, const std::vector<uint8_t> &hdrStaticMetadata)
186 {
187 sptr<SurfaceBuffer> buffer = sb;
188 auto res = MetadataHelper::SetHDRStaticMetadata(buffer, hdrStaticMetadata);
189 CHECK_AND_RETURN_RET_LOG(res == GSError::GSERROR_OK, ErrorCode::ERR_SET_METADATA_FAIL,
190 "SetHDRStaticMetadata: SetHDRStaticMetadata fail! res=%{public}d", res);
191 return ErrorCode::SUCCESS;
192 }
193
UpdateMetadata(EffectBuffer * input)194 ErrorCode ColorSpaceHelper::UpdateMetadata(EffectBuffer *input)
195 {
196 CHECK_AND_RETURN_RET_LOG(input != nullptr && input->bufferInfo_ != nullptr && input->extraInfo_ != nullptr,
197 ErrorCode::ERR_INPUT_NULL, "UpdateMetadata: inputBuffer is null");
198
199 return UpdateMetadata(input->extraInfo_->surfaceBuffer, input->bufferInfo_->colorSpace_);
200 }
201
UpdateMetadata(SurfaceBuffer * input,const EffectColorSpace & colorSpace)202 ErrorCode ColorSpaceHelper::UpdateMetadata(SurfaceBuffer *input, const EffectColorSpace &colorSpace)
203 {
204 EFFECT_LOGD("UpdateMetadata: colorSpace=%{public}d}", colorSpace);
205 if (input == nullptr || !ColorSpaceHelper::IsHdrColorSpace(colorSpace)) {
206 return ErrorCode::SUCCESS;
207 }
208
209 std::shared_ptr<MetadataGenerator> metadataGenerator = std::make_shared<MetadataGenerator>();
210 return metadataGenerator->ProcessImage(input);
211 }
212
ApplyColorSpaceIfNeed(std::shared_ptr<EffectBuffer> & srcBuffer,const std::shared_ptr<EffectContext> & context,EffectColorSpace & colorSpace)213 ErrorCode ApplyColorSpaceIfNeed(std::shared_ptr<EffectBuffer> &srcBuffer, const std::shared_ptr<EffectContext> &context,
214 EffectColorSpace &colorSpace)
215 {
216 if (!ColorSpaceManager::IsNeedConvertColorSpace(colorSpace)) {
217 return ErrorCode::SUCCESS;
218 }
219
220 EFFECT_LOGD("ColorSpaceHelper::ApplyColorSpace");
221 void *buffer = srcBuffer->buffer_;
222 std::shared_ptr<Memory> memory = context->memoryManager_->GetMemoryByAddr(buffer);
223 EffectColorSpace outputColorSpace = EffectColorSpace::DEFAULT;
224 ErrorCode res = context->colorSpaceManager_->ApplyColorSpace(srcBuffer.get(), colorSpace, outputColorSpace);
225 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res,
226 "ApplyColorSpaceIfNeed: ConvertColorSpace fail! res=%{public}d, colorSpace=%{public}d", res, colorSpace);
227
228 // update memoryManager memory
229 if (buffer != srcBuffer->buffer_) {
230 EFFECT_LOGD("ApplyColorSpaceIfNeed: update memory.");
231 context->memoryManager_->RemoveMemory(memory);
232
233 std::shared_ptr<Memory> updateMemory = std::make_shared<Memory>();
234 updateMemory->memoryData_ = std::make_shared<MemoryData>();
235 updateMemory->memoryData_->data = srcBuffer->buffer_;
236 updateMemory->memoryData_->memoryInfo.bufferInfo = *srcBuffer->bufferInfo_;
237 updateMemory->memoryData_->memoryInfo.extra = srcBuffer->extraInfo_->surfaceBuffer;
238 updateMemory->memoryData_->memoryInfo.bufferType = srcBuffer->extraInfo_->bufferType;
239 updateMemory->memDataType_ = MemDataType::INPUT;
240 updateMemory->isAllowModify_ = true;
241 context->memoryManager_->AddMemory(updateMemory);
242 }
243
244 colorSpace = outputColorSpace;
245 return ErrorCode::SUCCESS;
246 }
247
DecomposeHdrImageIfNeed(const EffectColorSpace & colorSpace,const EffectColorSpace & chosenColorSpace,std::shared_ptr<EffectBuffer> & buffer,const std::shared_ptr<EffectContext> & context)248 ErrorCode DecomposeHdrImageIfNeed(const EffectColorSpace &colorSpace, const EffectColorSpace &chosenColorSpace,
249 std::shared_ptr<EffectBuffer> &buffer, const std::shared_ptr<EffectContext> &context)
250 {
251 bool isNeedDecompose =
252 ColorSpaceHelper::IsHdrColorSpace(colorSpace) && !ColorSpaceHelper::IsHdrColorSpace(chosenColorSpace);
253 if (!isNeedDecompose) {
254 return ErrorCode::SUCCESS;
255 }
256
257 EFFECT_LOGI("ColorSpaceHelper::DecomposeHdrImage");
258 std::shared_ptr<Memory> oldMemory = context->memoryManager_->GetMemoryByAddr(buffer->buffer_);
259 std::shared_ptr<ColorSpaceConverter> converter = std::make_shared<ColorSpaceConverter>();
260 std::shared_ptr<EffectBuffer> sdrImage = nullptr;
261 ErrorCode res = converter->ProcessHdrImage(buffer.get(), sdrImage);
262 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "DecomposeHdrImageIfNeed: ProcessHdrImage fail! "
263 "res=%{public}d, colorSpace=%{public}d, chosenColorSpace=%{public}d", res, colorSpace, chosenColorSpace);
264 CHECK_AND_RETURN_RET_LOG(sdrImage != nullptr && sdrImage->extraInfo_ != nullptr, ErrorCode::ERR_INPUT_NULL,
265 "DecomposeHdrImageIfNeed: sdrImage is null or extraInfo of sdrImage is null!"
266 "sdrImage=%{public}d, sdrImage->extraInfo_=%{public}d", sdrImage == nullptr, sdrImage->extraInfo_ == nullptr);
267
268 context->memoryManager_->RemoveMemory(oldMemory);
269 std::shared_ptr<MemoryData> memoryData = converter->GetMemoryData(sdrImage->extraInfo_->surfaceBuffer);
270
271 SurfaceBuffer *sb = sdrImage->extraInfo_->surfaceBuffer;
272 ColorSpaceHelper::SetSurfaceBufferMetadataType(sb, CM_HDR_Metadata_Type::CM_METADATA_NONE);
273 ColorSpaceHelper::SetSurfaceBufferColorSpaceType(sb, CM_ColorSpaceType::CM_COLORSPACE_NONE);
274
275 std::shared_ptr<Memory> memory = std::make_shared<Memory>();
276 memory->memoryData_ = memoryData;
277 context->memoryManager_->AddMemory(memory);
278 *buffer = *sdrImage;
279
280 return ErrorCode::SUCCESS;
281 }
282
ConvertColorSpace(std::shared_ptr<EffectBuffer> & srcBuffer,std::shared_ptr<EffectContext> & context)283 ErrorCode ColorSpaceHelper::ConvertColorSpace(std::shared_ptr<EffectBuffer> &srcBuffer,
284 std::shared_ptr<EffectContext> &context)
285 {
286 EffectColorSpace colorSpace = srcBuffer->bufferInfo_->colorSpace_;
287 EFFECT_LOGD("ConvertColorSpace: colorSpace=%{public}d", colorSpace);
288
289 // If color space is none, it means that color space is not supported. But it still should return success,
290 // because the real color space maybe defined as ColorSpaceName::CUSTOM in ExtDecoder::getGrColorSpace or
291 // the color space is not exist when invoking InnerGetGrColorSpacePtr of pixelmap returned null ptr.
292 if (colorSpace == EffectColorSpace::DEFAULT) {
293 EFFECT_LOGI("ConvertColorSpace: colorspace is none! Do nothing!");
294 return ErrorCode::SUCCESS;
295 }
296
297 EFFECT_LOGD("ColorSpaceHelper::ConvertColorSpace colorSpace=%{public}d", colorSpace);
298 ErrorCode res = ApplyColorSpaceIfNeed(srcBuffer, context, colorSpace);
299 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "ConvertColorSpace: ConvertColorSpaceIfNeed fail! "
300 "res=%{public}d, colorSpace=%{public}d", res, colorSpace);
301
302 EffectColorSpace chosenColorSpace = EffectColorSpace::DEFAULT;
303 res = context->colorSpaceManager_->ChooseColorSpace(
304 context->filtersSupportedColorSpace_, colorSpace, chosenColorSpace);
305 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "ConvertColorSpace: ChooseColorSpace fail! "
306 "res=%{public}d, colorSpace=%{public}d", res, colorSpace);
307
308 EFFECT_LOGD("ConvertColorSpace: colorSpace=%{public}d, chosenColorSpace=%{public}d", colorSpace, chosenColorSpace);
309 res = DecomposeHdrImageIfNeed(colorSpace, chosenColorSpace, srcBuffer, context);
310 CHECK_AND_RETURN_RET_LOG(res == ErrorCode::SUCCESS, res, "ConvertColorSpace: DecomposeHdrImageIfNeed fail! "
311 "res=%{public}d, colorSpace=%{public}d, chosenColorSpace=%{public}d", res, colorSpace, chosenColorSpace);
312
313 return ErrorCode::SUCCESS;
314 }
315 } // namespace Effect
316 } // namespace Media
317 } // namespace OHOS