1 /*
2 * Copyright (C) 2025 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_processor.h"
17
18 #include <v1_0/cm_color_space.h>
19 #include <v1_0/buffer_handle_meta_key_type.h>
20 #include <hdr_type.h>
21 #include "effect_log.h"
22 #include "v1_0/cm_color_space.h"
23 #include "colorspace_helper.h"
24 #include "format_helper.h"
25 #include "common_utils.h"
26 #include "pixel_map.h"
27 #include "metadata_helper.h"
28 #ifdef VPE_ENABLE
29 #include "colorspace_converter.h"
30 #endif
31
32 namespace OHOS {
33 namespace Media {
34 namespace Effect {
35 using namespace OHOS::ColorManager;
36 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
37 using namespace OHOS::Media::VideoProcessingEngine;
38
ColorSpaceProcessor()39 ColorSpaceProcessor::ColorSpaceProcessor()
40 {
41 #ifdef VPE_ENABLE
42 converter = ColorSpaceConverter::Create();
43 #endif
44 }
45
~ColorSpaceProcessor()46 ColorSpaceProcessor::~ColorSpaceProcessor()
47 {
48 }
49
AllocSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> & memoryDataArray,MemoryInfo & allocMemInfo,CM_HDR_Metadata_Type type,CM_ColorSpaceType colorSpace)50 SurfaceBuffer *AllocSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> &memoryDataArray, MemoryInfo &allocMemInfo,
51 CM_HDR_Metadata_Type type, CM_ColorSpaceType colorSpace)
52 {
53 BufferInfo &bufferInfo = allocMemInfo.bufferInfo;
54 EFFECT_LOGD("AllocSurfaceBuffer: Alloc surface buffer memory! w=%{public}d, h=%{public}d, format=%{public}d",
55 bufferInfo.width_, bufferInfo.height_, bufferInfo.formatType_);
56
57 std::unique_ptr<AbsMemory> absMemory = EffectMemory::CreateMemory(BufferType::DMA_BUFFER);
58 CHECK_AND_RETURN_RET_LOG(absMemory != nullptr, nullptr, "AllocSurfaceBuffer: absMemory is null!");
59 std::shared_ptr<MemoryData> memoryData = absMemory->Alloc(allocMemInfo);
60 CHECK_AND_RETURN_RET_LOG(memoryData != nullptr, nullptr, "AllocSurfaceBuffer: memoryData is null!");
61
62 void *surfaceBuffer = memoryData->memoryInfo.extra;
63 CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, nullptr, "AllocSurfaceBuffer: extra info is null!");
64
65 auto *sb = static_cast<SurfaceBuffer *>(surfaceBuffer);
66 ColorSpaceHelper::SetSurfaceBufferMetadataType(sb, type);
67 ColorSpaceHelper::SetSurfaceBufferColorSpaceType(sb, colorSpace);
68 memoryDataArray.emplace_back(memoryData);
69 return sb;
70 }
71
AllocSdrSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> & memoryDataArray,const EffectBuffer * inputHdr,CM_HDR_Metadata_Type type,CM_ColorSpaceType colorSpaceType,EffectColorSpace effectColorSpace)72 sptr<SurfaceBuffer> AllocSdrSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> &memoryDataArray,
73 const EffectBuffer *inputHdr, CM_HDR_Metadata_Type type, CM_ColorSpaceType colorSpaceType,
74 EffectColorSpace effectColorSpace)
75 {
76 MemoryInfo allocMemInfo;
77 BufferInfo &bufferInfo = allocMemInfo.bufferInfo;
78 bufferInfo = *inputHdr->bufferInfo_;
79 bufferInfo.formatType_ = IEffectFormat::RGBA8888;
80 bufferInfo.colorSpace_ = effectColorSpace;
81 SurfaceBuffer *sb = AllocSurfaceBuffer(memoryDataArray, allocMemInfo, type, colorSpaceType);
82 CHECK_AND_RETURN_RET_LOG(sb != nullptr, nullptr,
83 "AllocSdrSurfaceBuffer: alloc fail! w=%{public}d, h=%{public}d, format=%{public}d",
84 bufferInfo.width_, bufferInfo.height_, bufferInfo.formatType_);
85
86 return sb;
87 }
88
AllocGainmapSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> & memoryDataArray,const EffectBuffer * inputHdr,CM_HDR_Metadata_Type type,CM_ColorSpaceType colorSpaceType,EffectColorSpace effectColorSpace)89 sptr<SurfaceBuffer> AllocGainmapSurfaceBuffer(std::vector<std::shared_ptr<MemoryData>> &memoryDataArray,
90 const EffectBuffer *inputHdr, CM_HDR_Metadata_Type type, CM_ColorSpaceType colorSpaceType,
91 EffectColorSpace effectColorSpace)
92 {
93 MemoryInfo allocMemInfo;
94 BufferInfo &bufferInfo = allocMemInfo.bufferInfo;
95 bufferInfo = *inputHdr->bufferInfo_;
96 uint32_t half = 2;
97 bufferInfo.width_ = bufferInfo.width_ / half;
98 bufferInfo.height_ = bufferInfo.height_ / half;
99 bufferInfo.formatType_ = IEffectFormat::RGBA8888;
100 bufferInfo.colorSpace_ = effectColorSpace;
101 SurfaceBuffer *sb = AllocSurfaceBuffer(memoryDataArray, allocMemInfo, type, colorSpaceType);
102 CHECK_AND_RETURN_RET_LOG(sb != nullptr, nullptr,
103 "AllocGainmapSurfaceBuffer: alloc fail! w=%{public}d, h=%{public}d, format=%{public}d",
104 bufferInfo.width_, bufferInfo.height_, bufferInfo.formatType_);
105
106 return sb;
107 }
108
PrintColorSpaceInfo(const sptr<SurfaceBuffer> & surfaceBuffer,const std::string & tag)109 void PrintColorSpaceInfo(const sptr<SurfaceBuffer> &surfaceBuffer, const std::string &tag)
110 {
111 if (surfaceBuffer == nullptr) {
112 return;
113 }
114
115 CM_HDR_Metadata_Type metadataType = CM_HDR_Metadata_Type::CM_METADATA_NONE;
116 ColorSpaceHelper::GetSurfaceBufferMetadataType(surfaceBuffer, metadataType);
117 CM_ColorSpaceType colorSpaceType = CM_ColorSpaceType::CM_COLORSPACE_NONE;
118 ColorSpaceHelper::GetSurfaceBufferColorSpaceType(surfaceBuffer, colorSpaceType);
119
120 EFFECT_LOGD("%{public}s: metadataType=%{public}d, colorSpaceType=%{public}d, format=%{public}d",
121 tag.c_str(), metadataType, colorSpaceType, surfaceBuffer->GetFormat());
122 }
123
ComposeHdrImage(const EffectBuffer * inputSdr,const SurfaceBuffer * inputGainmap,EffectBuffer * outputHdr)124 ErrorCode ColorSpaceProcessor::ComposeHdrImage(const EffectBuffer *inputSdr, const SurfaceBuffer *inputGainmap,
125 EffectBuffer *outputHdr)
126 {
127 #ifdef VPE_ENABLE
128 CHECK_AND_RETURN_RET_LOG(converter != nullptr, ErrorCode::ERR_INVALID_VPE_INSTANCE,
129 "DecomposeHdrImageInner: invalid vpe instance!");
130 CHECK_AND_RETURN_RET_LOG(inputSdr != nullptr && inputGainmap != nullptr && outputHdr != nullptr,
131 ErrorCode::ERR_INPUT_NULL, "ComposeHdrImageInner: inputSdr or inputGainmap or outputHdr is null!");
132
133 sptr<SurfaceBuffer> sdrSb = inputSdr->bufferInfo_->surfaceBuffer_;
134 sptr<SurfaceBuffer> gainmapSb = const_cast<SurfaceBuffer *>(inputGainmap);
135 sptr<SurfaceBuffer> hdrSb = outputHdr->bufferInfo_->surfaceBuffer_;
136 CHECK_AND_RETURN_RET_LOG(sdrSb != nullptr && gainmapSb != nullptr && hdrSb != nullptr,
137 ErrorCode::ERR_INVALID_SURFACE_BUFFER, "ComposeHdrImageInner: invalid surface buffer! sdrSb=%{public}d,"
138 "gainmapSb=%{public}d, hdrSb=%{public}d", sdrSb == nullptr, gainmapSb == nullptr, hdrSb == nullptr);
139
140 PrintColorSpaceInfo(sdrSb, "ComposeHdrImageInner:SdrSurfaceBuffer");
141 PrintColorSpaceInfo(gainmapSb, "ComposeHdrImageInner:GainmapSurfaceBuffer");
142 PrintColorSpaceInfo(hdrSb, "ComposeHdrImageInner:HdrSurfaceBuffer");
143
144 ColorSpaceConverterParameter parameter;
145 parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
146 converter->SetParameter(parameter);
147
148 int32_t res = converter->ComposeImage(sdrSb, gainmapSb, hdrSb, false);
149 CHECK_AND_RETURN_RET_LOG(res == 0, ErrorCode::ERR_VPE_COMPOSE_IMAGE_FAIL,
150 "ComposeHdrImageInner: ColorSpaceConverterComposeImage fail! res=%{public}d", res);
151 #endif
152 return ErrorCode::SUCCESS;
153 }
154
DecomposeHdrImage(const EffectBuffer * inputHdr,std::shared_ptr<EffectBuffer> & outputSdr,SurfaceBuffer ** outputGainmap)155 ErrorCode ColorSpaceProcessor::DecomposeHdrImage(const EffectBuffer *inputHdr, std::shared_ptr<EffectBuffer> &outputSdr,
156 SurfaceBuffer **outputGainmap)
157 {
158 #ifdef VPE_ENABLE
159 CHECK_AND_RETURN_RET_LOG(converter != nullptr, ErrorCode::ERR_INVALID_VPE_INSTANCE,
160 "DecomposeHdrImageInner: invalid vpe instance!");
161 CHECK_AND_RETURN_RET_LOG(inputHdr != nullptr && outputGainmap != nullptr,
162 ErrorCode::ERR_INPUT_NULL, "DecomposeHdrImageInner: inputHdr or outputGainmap is null!");
163
164 sptr<SurfaceBuffer> hdrSb = inputHdr->bufferInfo_->surfaceBuffer_;
165 sptr<SurfaceBuffer> sdrSb = AllocSdrSurfaceBuffer(memoryDataArray_, inputHdr, CM_IMAGE_HDR_VIVID_DUAL, CM_P3_FULL,
166 EffectColorSpace::DISPLAY_P3);
167 sptr<SurfaceBuffer> gainmapSb = AllocGainmapSurfaceBuffer(memoryDataArray_, inputHdr, CM_METADATA_NONE, CM_P3_FULL,
168 EffectColorSpace::DISPLAY_P3);
169 CHECK_AND_RETURN_RET_LOG(hdrSb != nullptr && sdrSb != nullptr && gainmapSb != nullptr,
170 ErrorCode::ERR_INVALID_SURFACE_BUFFER, "DecomposeHdrImageInner: invalid surface buffer! hdrSb=%{public}d,"
171 "sdrSb=%{public}d, gainmapSb=%{public}d", hdrSb == nullptr, sdrSb == nullptr, gainmapSb == nullptr);
172
173 ColorSpaceHelper::SetHDRDynamicMetadata(hdrSb, std::vector<uint8_t>(0));
174 ColorSpaceHelper::SetHDRStaticMetadata(hdrSb, std::vector<uint8_t>(0));
175
176 PrintColorSpaceInfo(hdrSb, "DecomposeHdrImageInner:HdrSurfaceBuffer");
177 PrintColorSpaceInfo(sdrSb, "DecomposeHdrImageInner:SdrSurfaceBuffer");
178 PrintColorSpaceInfo(gainmapSb, "DecomposeHdrImageInner:GainmapSurfaceBuffer");
179
180 ColorSpaceConverterParameter parameter;
181 parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
182 converter->SetParameter(parameter);
183
184 int32_t res = converter->DecomposeImage(hdrSb, sdrSb, gainmapSb);
185 CHECK_AND_RETURN_RET_LOG(res == 0, ErrorCode::ERR_VPE_DECOMPOSE_IMAGE_FAIL,
186 "DecomposeHdrImageInner: ColorSpaceConverterDecomposeImage fail! res=%{public}d", res);
187
188 // update effectBuffer
189 std::shared_ptr<EffectBuffer> buffer = nullptr;
190 ErrorCode errorCode = CommonUtils::ParseSurfaceData(sdrSb, buffer, inputHdr->extraInfo_->dataType);
191 CHECK_AND_RETURN_RET_LOG(errorCode == ErrorCode::SUCCESS, errorCode,
192 "DecomposeHdrImageInner: ParseSurfaceData fail! errorCode=%{public}d", errorCode);
193 CHECK_AND_RETURN_RET_LOG(buffer != nullptr && buffer->extraInfo_ != nullptr, ErrorCode::ERR_INPUT_NULL,
194 "DecomposeHdrImageInner: buffer is null or extraInfo of buffer is null!"
195 "buffer=%{public}d, buffer->extraInfo_=%{public}d", buffer == nullptr, buffer->extraInfo_ == nullptr);
196 *buffer->extraInfo_ = *inputHdr->extraInfo_;
197 buffer->bufferInfo_->surfaceBuffer_ = sdrSb;
198 buffer->extraInfo_->bufferType = BufferType::DMA_BUFFER;
199
200 outputSdr = buffer;
201 *outputGainmap = gainmapSb;
202 #endif
203 return ErrorCode::SUCCESS;
204 }
205
ProcessHdrImage(const EffectBuffer * inputHdr,std::shared_ptr<EffectBuffer> & outputSdr)206 ErrorCode ColorSpaceProcessor::ProcessHdrImage(const EffectBuffer *inputHdr, std::shared_ptr<EffectBuffer> &outputSdr)
207 {
208 #ifdef VPE_ENABLE
209 CHECK_AND_RETURN_RET_LOG(converter != nullptr, ErrorCode::ERR_INVALID_VPE_INSTANCE,
210 "DecomposeHdrImageInner: invalid vpe instance!");
211 CHECK_AND_RETURN_RET_LOG(inputHdr != nullptr, ErrorCode::ERR_INPUT_NULL,
212 "ProcessHdrImageInner: inputHdr is null!");
213
214 sptr<SurfaceBuffer> sdrSb = AllocSdrSurfaceBuffer(memoryDataArray_, inputHdr, CM_IMAGE_HDR_VIVID_DUAL, CM_P3_FULL,
215 EffectColorSpace::DISPLAY_P3);
216 sptr<SurfaceBuffer> hdrSb = inputHdr->bufferInfo_->surfaceBuffer_;
217 CHECK_AND_RETURN_RET_LOG(sdrSb != nullptr && hdrSb != nullptr, ErrorCode::ERR_INVALID_SURFACE_BUFFER,
218 "ProcessHdrImageInner: invalid surface buffer! sdrSb=%{public}d, hdrSb=%{public}d",
219 sdrSb == nullptr, hdrSb == nullptr);
220
221 PrintColorSpaceInfo(hdrSb, "ProcessHdrImageInner:HdrSurfaceBuffer");
222 PrintColorSpaceInfo(sdrSb, "ProcessHdrImageInner:SdrSurfaceBuffer");
223
224 ColorSpaceHelper::SetHDRDynamicMetadata(hdrSb, std::vector<uint8_t>(0));
225 ColorSpaceHelper::SetHDRStaticMetadata(hdrSb, std::vector<uint8_t>(0));
226
227 ColorSpaceConverterParameter parameter;
228 parameter.renderIntent = RenderIntent::RENDER_INTENT_ABSOLUTE_COLORIMETRIC;
229 converter->SetParameter(parameter);
230
231 int32_t res = converter->Process(hdrSb, sdrSb);
232 CHECK_AND_RETURN_RET_LOG(res == 0, ErrorCode::ERR_VPE_PROCESS_IMAGE_FAIL,
233 "ProcessHdrImageInner: ColorSpaceConverterProcessImage fail! res=%{public}d", res);
234
235 // update effectBuffer
236 std::shared_ptr<EffectBuffer> buffer;
237 ErrorCode errorCode = CommonUtils::ParseSurfaceData(sdrSb, buffer, inputHdr->extraInfo_->dataType);
238 CHECK_AND_RETURN_RET_LOG(errorCode == ErrorCode::SUCCESS, errorCode,
239 "ProcessHdrImageInner: ParseSurfaceData fail! errorCode=%{public}d", errorCode);
240 *buffer->extraInfo_ = *inputHdr->extraInfo_;
241 buffer->bufferInfo_->surfaceBuffer_ = sdrSb;
242 buffer->extraInfo_->bufferType = BufferType::DMA_BUFFER;
243
244 outputSdr = buffer;
245 #endif
246 return ErrorCode::SUCCESS;
247 }
248
GetMemoryData(SurfaceBuffer * sb)249 std::shared_ptr<MemoryData> ColorSpaceProcessor::GetMemoryData(SurfaceBuffer *sb)
250 {
251 CHECK_AND_RETURN_RET_LOG(sb != nullptr, nullptr, "GetMemoryData: sb is null!");
252
253 void *pSurfaceBuffer = static_cast<void *>(sb);
254 for (const auto &memoryData : memoryDataArray_) {
255 if (memoryData->memoryInfo.extra == pSurfaceBuffer) {
256 return memoryData;
257 }
258 }
259
260 return nullptr;
261 }
262
CreatePixelMap(EffectBuffer * effectBuffer)263 PixelMap *CreatePixelMap(EffectBuffer *effectBuffer)
264 {
265 std::shared_ptr<BufferInfo> &bufferInfo = effectBuffer->bufferInfo_;
266 InitializationOptions options = {
267 .size = {
268 .width = static_cast<int32_t>(bufferInfo->width_),
269 .height = static_cast<int32_t>(bufferInfo->height_),
270 },
271 .srcPixelFormat = CommonUtils::SwitchToPixelFormat(bufferInfo->formatType_),
272 .pixelFormat = CommonUtils::SwitchToPixelFormat(bufferInfo->formatType_),
273 };
274 std::unique_ptr<PixelMap> pixelMap = PixelMap::Create(static_cast<uint32_t *>(effectBuffer->buffer_),
275 bufferInfo->len_, 0, static_cast<int32_t>(bufferInfo->rowStride_), options, true);
276 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, nullptr, "CreatePixelMap: create fail!");
277 CHECK_AND_RETURN_RET_LOG(pixelMap->GetPixelFormat() == options.pixelFormat, nullptr,
278 "CreatePixelMap: pixelFormat error! pixelFormat=%{public}d, optionPixelFormat=%{public}d",
279 pixelMap->GetPixelFormat(), options.pixelFormat);
280
281 const std::shared_ptr<ExtraInfo> &extraInfo = effectBuffer->extraInfo_;
282 extraInfo->innerPixelMap = std::move(pixelMap);
283 return extraInfo->innerPixelMap.get();
284 }
285
GetPixelMap(EffectBuffer * effectBuffer)286 PixelMap *GetPixelMap(EffectBuffer *effectBuffer)
287 {
288 std::shared_ptr<ExtraInfo> &extraInfo = effectBuffer->extraInfo_;
289 std::shared_ptr<BufferInfo> &bufferInfo = effectBuffer->bufferInfo_;
290 switch (extraInfo->dataType) {
291 case DataType::PIXEL_MAP:
292 return bufferInfo->pixelMap_;
293 case DataType::URI:
294 case DataType::PATH:
295 case DataType::PICTURE:
296 return extraInfo->picture == nullptr ? nullptr : extraInfo->picture->GetMainPixel().get();
297 case DataType::SURFACE:
298 case DataType::SURFACE_BUFFER:
299 return CreatePixelMap(effectBuffer);
300 default:
301 EFFECT_LOGE("Data type not support! dataType=%{public}d", extraInfo->dataType);
302 return nullptr;
303 }
304 }
305
ApplyColorSpace(EffectBuffer * effectBuffer,EffectColorSpace targetColorSpace)306 ErrorCode ColorSpaceProcessor::ApplyColorSpace(EffectBuffer *effectBuffer, EffectColorSpace targetColorSpace)
307 {
308 CHECK_AND_RETURN_RET_LOG(effectBuffer != nullptr && effectBuffer->bufferInfo_ != nullptr &&
309 effectBuffer->buffer_ != nullptr && effectBuffer->extraInfo_ != nullptr,
310 ErrorCode::ERR_INPUT_NULL, "ApplyColorSpace: effectBuffer is null!");
311
312 ColorSpaceName colorSpaceName = ColorSpaceHelper::ConvertToColorSpaceName(targetColorSpace);
313 CHECK_AND_RETURN_RET_LOG(colorSpaceName != ColorSpaceName::NONE, ErrorCode::ERR_INVALID_COLORSPACE,
314 "ApplyColorSpace: invalid color space! targetColorSpace=%{public}d", targetColorSpace);
315
316 PixelMap *pixelMap = GetPixelMap(effectBuffer);
317 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, ErrorCode::ERR_CREATE_PIXELMAP_FAIL,
318 "ApplyColorSpace create pixelmap fail!");
319
320 OHOS::ColorManager::ColorSpace grColorSpace(colorSpaceName);
321 uint32_t res = pixelMap->ApplyColorSpace(grColorSpace);
322 CHECK_AND_RETURN_RET_LOG(res == 0, ErrorCode::ERR_APPLYCOLORSPACE_FAIL, "ApplyColorSpace: pixelMap "
323 "ApplyColorSpace fail! res=%{public}d, colorSpaceName=%{public}d", res, colorSpaceName);
324
325 // update effectBuffer
326 std::shared_ptr<EffectBuffer> buffer;
327 ErrorCode errorCode = CommonUtils::LockPixelMap(pixelMap, buffer);
328 CHECK_AND_RETURN_RET_LOG(errorCode == ErrorCode::SUCCESS, errorCode, "ApplyColorSpace: pixelMap parse fail!"
329 "res=%{public}d, colorSpaceName=%{public}d", res, colorSpaceName);
330
331 effectBuffer->bufferInfo_ = buffer->bufferInfo_;
332 effectBuffer->buffer_ = buffer->buffer_;
333 effectBuffer->bufferInfo_->surfaceBuffer_ = buffer->bufferInfo_->surfaceBuffer_;
334
335 return ErrorCode::SUCCESS;
336 }
337 } // namespace Effect
338 } // namespace Media
339 } // namespace OHOS