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