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