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 "auxiliary_generator.h"
17 #include "abs_image_decoder.h"
18 #include "fragment_metadata.h"
19 #include "hdr_type.h"
20 #include "image_log.h"
21 #include "image_utils.h"
22 #include "image_mime_type.h"
23 #include "image_source.h"
24 #include "jpeg_mpf_parser.h"
25 #include "metadata.h"
26 #include "pixel_map.h"
27 #include "pixel_yuv.h"
28 #ifdef EXT_PIXEL
29 #include "pixel_yuv_ext.h"
30 #endif
31 #include "securec.h"
32 #include "surface_buffer.h"
33
34 namespace OHOS {
35 namespace Media {
36 using namespace ImagePlugin;
37
38 static constexpr uint32_t FIRST_FRAME = 0;
39 static constexpr int32_t DEFAULT_SCALE_DENOMINATOR = 1;
40 static constexpr int32_t DEPTH_SCALE_DENOMINATOR = 4;
41 static constexpr int32_t LINEAR_SCALE_DENOMINATOR = 4;
42
IsSizeVailed(const Size &size)43 static inline bool IsSizeVailed(const Size &size)
44 {
45 return (size.width != 0 && size.height != 0);
46 }
47
GetAuxiliaryPictureDenominator(AuxiliaryPictureType type)48 static int32_t GetAuxiliaryPictureDenominator(AuxiliaryPictureType type)
49 {
50 int32_t denominator = DEFAULT_SCALE_DENOMINATOR;
51 switch (type) {
52 case AuxiliaryPictureType::DEPTH_MAP:
53 denominator = DEPTH_SCALE_DENOMINATOR;
54 break;
55 case AuxiliaryPictureType::LINEAR_MAP:
56 denominator = LINEAR_SCALE_DENOMINATOR;
57 break;
58 default:
59 break;
60 }
61 return denominator;
62 }
63
SetAuxiliaryDecodeOption(std::unique_ptr<AbsImageDecoder> &decoder, PlImageInfo &plInfo, AuxiliaryPictureType type)64 static uint32_t SetAuxiliaryDecodeOption(std::unique_ptr<AbsImageDecoder> &decoder, PlImageInfo &plInfo,
65 AuxiliaryPictureType type)
66 {
67 Size size;
68 uint32_t errorCode = decoder->GetImageSize(FIRST_FRAME, size);
69 if (errorCode != SUCCESS || !IsSizeVailed(size)) {
70 return ERR_IMAGE_DATA_ABNORMAL;
71 }
72 PixelDecodeOptions plOptions;
73 plOptions.desiredSize = size;
74 bool useF16Format = (type == AuxiliaryPictureType::LINEAR_MAP || type == AuxiliaryPictureType::DEPTH_MAP);
75 plOptions.desiredPixelFormat = useF16Format ? PixelFormat::RGBA_F16 : PixelFormat::RGBA_8888;
76 errorCode = decoder->SetDecodeOptions(FIRST_FRAME, plOptions, plInfo);
77 return errorCode;
78 }
79
FreeContextBuffer(const Media::CustomFreePixelMap &func, AllocatorType allocType, PlImageBuffer &buffer)80 static void FreeContextBuffer(const Media::CustomFreePixelMap &func, AllocatorType allocType, PlImageBuffer &buffer)
81 {
82 if (func != nullptr) {
83 func(buffer.buffer, buffer.context, buffer.bufferSize);
84 return;
85 }
86
87 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
88 if (allocType == AllocatorType::SHARE_MEM_ALLOC) {
89 int *fd = static_cast<int *>(buffer.context);
90 if (buffer.buffer != nullptr) {
91 ::munmap(buffer.buffer, buffer.bufferSize);
92 }
93 if (fd != nullptr) {
94 ::close(*fd);
95 }
96 return;
97 } else if (allocType == AllocatorType::DMA_ALLOC) {
98 if (buffer.buffer != nullptr) {
99 ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer *>(buffer.context));
100 buffer.context = nullptr;
101 }
102 } else if (allocType == AllocatorType::HEAP_ALLOC) {
103 if (buffer.buffer != nullptr) {
104 free(buffer.buffer);
105 buffer.buffer = nullptr;
106 }
107 }
108 #else
109 if (buffer.buffer != nullptr) {
110 free(buffer.buffer);
111 buffer.buffer = nullptr;
112 }
113 #endif
114 }
115
MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType, ColorSpace colorSpace, const std::string &encodedFormat)116 static ImageInfo MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType,
117 ColorSpace colorSpace, const std::string &encodedFormat)
118 {
119 ImageInfo info;
120 info.size.width = size.width;
121 info.size.height = size.height;
122 info.pixelFormat = format;
123 info.alphaType = alphaType;
124 info.colorSpace = colorSpace;
125 info.encodedFormat = encodedFormat;
126 return info;
127 }
128
MakeAuxiliaryPictureInfo(AuxiliaryPictureType type, const Size &size, uint32_t rowStride, PixelFormat format, ColorSpace colorSpace)129 static AuxiliaryPictureInfo MakeAuxiliaryPictureInfo(AuxiliaryPictureType type,
130 const Size &size, uint32_t rowStride, PixelFormat format, ColorSpace colorSpace)
131 {
132 AuxiliaryPictureInfo info;
133 info.auxiliaryPictureType = type;
134 info.size.width = size.width;
135 info.size.height = size.height;
136 info.rowStride = rowStride;
137 info.pixelFormat = format;
138 info.colorSpace = colorSpace;
139 return info;
140 }
141
CreatePixelMapByContext(DecodeContext &context, std::unique_ptr<AbsImageDecoder> &decoder, const std::string &encodedFormat, uint32_t &errorCode)142 static std::shared_ptr<PixelMap> CreatePixelMapByContext(DecodeContext &context,
143 std::unique_ptr<AbsImageDecoder> &decoder, const std::string &encodedFormat, uint32_t &errorCode)
144 {
145 std::shared_ptr<PixelMap> pixelMap;
146 if (ImageSource::IsYuvFormat(context.pixelFormat)) {
147 #ifdef EXT_PIXEL
148 pixelMap = std::make_shared<PixelYuvExt>();
149 #else
150 pixelMap = std::make_shared<PixelYuv>();
151 #endif
152 } else {
153 pixelMap = std::make_shared<PixelMap>();
154 }
155 if (pixelMap == nullptr) {
156 errorCode = ERR_IMAGE_ADD_PIXEL_MAP_FAILED;
157 return nullptr;
158 }
159
160 ImageInfo imageinfo = MakeImageInfo(context.outInfo.size, context.pixelFormat,
161 context.info.alphaType, context.colorSpace, encodedFormat);
162 pixelMap->SetImageInfo(imageinfo, true);
163
164 PixelMapAddrInfos addrInfos;
165 ImageSource::ContextToAddrInfos(context, addrInfos);
166 pixelMap->SetPixelsAddr(addrInfos.addr, addrInfos.context, addrInfos.size, addrInfos.type, addrInfos.func);
167
168 #ifdef IMAGE_COLORSPACE_FLAG
169 if (context.hdrType > ImageHdrType::SDR) {
170 pixelMap->InnerSetColorSpace(ColorManager::ColorSpace(context.grColorSpaceName));
171 } else if (decoder->IsSupportICCProfile()) {
172 pixelMap->InnerSetColorSpace(decoder->getGrColorSpace());
173 }
174 #endif
175 return pixelMap;
176 }
177
DecodeHdrMetadata(ImageHdrType hdrType, std::unique_ptr<AbsImageDecoder> &extDecoder, std::unique_ptr<AuxiliaryPicture> &auxPicture)178 static uint32_t DecodeHdrMetadata(ImageHdrType hdrType, std::unique_ptr<AbsImageDecoder> &extDecoder,
179 std::unique_ptr<AuxiliaryPicture> &auxPicture)
180 {
181 std::shared_ptr<HdrMetadata> hdrMetadata = std::make_shared<HdrMetadata>(extDecoder->GetHdrMetadata(hdrType));
182 std::shared_ptr<PixelMap> pixelMap = auxPicture->GetContentPixel();
183 if (pixelMap == nullptr) {
184 IMAGE_LOGE("Get invalid content pixel map for hdr metadata");
185 return ERR_IMAGE_GET_DATA_ABNORMAL;
186 }
187 pixelMap->SetHdrMetadata(hdrMetadata);
188 pixelMap->SetHdrType(hdrType);
189 return SUCCESS;
190 }
191
DecodeHeifFragmentMetadata(std::unique_ptr<AbsImageDecoder> &extDecoder, std::unique_ptr<AuxiliaryPicture> &auxPicture)192 static uint32_t DecodeHeifFragmentMetadata(std::unique_ptr<AbsImageDecoder> &extDecoder,
193 std::unique_ptr<AuxiliaryPicture> &auxPicture)
194 {
195 Rect fragmentRect;
196 if (!extDecoder->GetHeifFragmentMetadata(fragmentRect)) {
197 IMAGE_LOGE("Heif parsing fragment metadata failed");
198 return ERR_IMAGE_GET_DATA_ABNORMAL;
199 }
200 std::shared_ptr<ImageMetadata> fragmentMetadata = std::make_shared<FragmentMetadata>();
201 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_X, std::to_string(fragmentRect.left));
202 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_Y, std::to_string(fragmentRect.top));
203 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_WIDTH, std::to_string(fragmentRect.width));
204 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_HEIGHT, std::to_string(fragmentRect.height));
205 auxPicture->SetMetadata(MetadataType::FRAGMENT, fragmentMetadata);
206 return SUCCESS;
207 }
208
DecodeJpegFragmentMetadata(std::unique_ptr<InputDataStream> &auxStream, std::unique_ptr<AuxiliaryPicture> &auxPicture)209 static uint32_t DecodeJpegFragmentMetadata(std::unique_ptr<InputDataStream> &auxStream,
210 std::unique_ptr<AuxiliaryPicture> &auxPicture)
211 {
212 uint8_t *data = auxStream->GetDataPtr();
213 uint32_t size = auxStream->GetStreamSize();
214 Rect fragmentRect;
215 if (!JpegMpfParser::ParsingFragmentMetadata(data, size, fragmentRect)) {
216 IMAGE_LOGE("Jpeg parsing fragment metadata failed");
217 return ERR_IMAGE_GET_DATA_ABNORMAL;
218 }
219 std::shared_ptr<ImageMetadata> fragmentMetadata = std::make_shared<FragmentMetadata>();
220 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_X, std::to_string(fragmentRect.left));
221 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_Y, std::to_string(fragmentRect.top));
222 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_WIDTH, std::to_string(fragmentRect.width));
223 fragmentMetadata->SetValue(FRAGMENT_METADATA_KEY_HEIGHT, std::to_string(fragmentRect.height));
224 auxPicture->SetMetadata(MetadataType::FRAGMENT, fragmentMetadata);
225 return SUCCESS;
226 }
227
AllocSurfaceBuffer(Size &size, int32_t format, uint32_t &errorCode)228 static sptr<SurfaceBuffer> AllocSurfaceBuffer(Size &size, int32_t format, uint32_t &errorCode)
229 {
230 IMAGE_LOGD("SurfaceBuffer alloc width: %{public}d, height: %{public}d, format: %{public}d",
231 size.width, size.height, format);
232 sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
233 BufferRequestConfig requestConfig = {
234 .width = size.width,
235 .height = size.height,
236 .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
237 .format = format,
238 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE,
239 .timeout = 0,
240 };
241 GSError ret = sb->Alloc(requestConfig);
242 if (ret != GSERROR_OK) {
243 IMAGE_LOGE("SurfaceBuffer alloc failed, %{public}s", GSErrorStr(ret).c_str());
244 errorCode = ERR_DMA_NOT_EXIST;
245 return nullptr;
246 }
247 void *nativeBuffer = sb.GetRefPtr();
248 if (ImageUtils::SurfaceBuffer_Reference(nativeBuffer) != OHOS::GSERROR_OK) {
249 IMAGE_LOGE("Native buffer reference failed");
250 errorCode = ERR_SURFACEBUFFER_REFERENCE_FAILED;
251 return nullptr;
252 }
253 errorCode = SUCCESS;
254 return sb;
255 }
256
CopyToSurfaceBuffer(std::unique_ptr<InputDataStream> &stream, sptr<SurfaceBuffer> &surfaceBuffer)257 static uint32_t CopyToSurfaceBuffer(std::unique_ptr<InputDataStream> &stream, sptr<SurfaceBuffer> &surfaceBuffer)
258 {
259 uint8_t *src = stream->GetDataPtr();
260 uint32_t srcSize = stream->GetStreamSize();
261 uint8_t *dst = static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
262 uint32_t dstSize = surfaceBuffer->GetSize();
263 if (src == nullptr || dst == nullptr || srcSize == 0 || dstSize == 0) {
264 IMAGE_LOGE("%{public}s: invalid input data", __func__);
265 return ERR_IMAGE_INVALID_PARAMETER;
266 }
267 IMAGE_LOGD("SurfaceBuffer size: %{public}u, stream size: %{public}u", dstSize, srcSize);
268 if (memcpy_s(dst, dstSize, src, srcSize) != EOK) {
269 IMAGE_LOGE("%{public}s: memcpy failed", __func__);
270 ImageUtils::SurfaceBuffer_Unreference(surfaceBuffer.GetRefPtr());
271 return ERR_MEMORY_COPY_FAILED;
272 }
273 return SUCCESS;
274 }
275
SetUncodedAuxilaryPictureInfo(std::unique_ptr<AuxiliaryPicture> &auxPicture)276 static void SetUncodedAuxilaryPictureInfo(std::unique_ptr<AuxiliaryPicture> &auxPicture)
277 {
278 if (auxPicture == nullptr || auxPicture->GetContentPixel() == nullptr) {
279 IMAGE_LOGE("%{public}s auxPicture or auxPixelMap is nullptr", __func__);
280 return;
281 }
282 auto auxPixelMap = auxPicture->GetContentPixel();
283 ImageInfo imageInfo;
284 auxPixelMap->GetImageInfo(imageInfo);
285 auto auxInfo = MakeAuxiliaryPictureInfo(auxPicture->GetType(), imageInfo.size, auxPixelMap->GetRowStride(),
286 imageInfo.pixelFormat, imageInfo.colorSpace);
287 auxPicture->SetAuxiliaryPictureInfo(auxInfo);
288 }
289
GenerateAuxiliaryPicture(ImageHdrType hdrType, AuxiliaryPictureType type, const std::string &format, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)290 static std::unique_ptr<AuxiliaryPicture> GenerateAuxiliaryPicture(ImageHdrType hdrType, AuxiliaryPictureType type,
291 const std::string &format, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)
292 {
293 IMAGE_LOGI("Generate by decoder, type: %{public}d, format: %{public}s", static_cast<int>(type), format.c_str());
294 DecodeContext context;
295 context.allocatorType = AllocatorType::DMA_ALLOC;
296 errorCode = SetAuxiliaryDecodeOption(extDecoder, context.info, type);
297 if (errorCode != SUCCESS) {
298 IMAGE_LOGE("Set auxiliary decode option failed! errorCode: %{public}u", errorCode);
299 return nullptr;
300 }
301 if (format == IMAGE_HEIF_FORMAT) {
302 #ifdef HEIF_HW_DECODE_ENABLE
303 if (type == AuxiliaryPictureType::LINEAR_MAP || type == AuxiliaryPictureType::DEPTH_MAP) {
304 context.pixelFormat = PixelFormat::RGBA_F16;
305 context.info.pixelFormat = PixelFormat::RGBA_F16;
306 }
307 if (!extDecoder->DecodeHeifAuxiliaryMap(context, type)) {
308 errorCode = ERR_IMAGE_DECODE_FAILED;
309 }
310 #else
311 errorCode = ERR_IMAGE_HW_DECODE_UNSUPPORT;
312 #endif
313 } else if (format == IMAGE_JPEG_FORMAT) {
314 errorCode = extDecoder->Decode(FIRST_FRAME, context);
315 context.hdrType = hdrType;
316 } else {
317 errorCode = ERR_MEDIA_DATA_UNSUPPORT;
318 }
319 if (errorCode != SUCCESS) {
320 IMAGE_LOGE("Decode failed! Format: %{public}s, errorCode: %{public}u", format.c_str(), errorCode);
321 FreeContextBuffer(context.freeFunc, context.allocatorType, context.pixelsBuffer);
322 return nullptr;
323 }
324
325 std::string encodedFormat = ImageUtils::IsAuxiliaryPictureEncoded(type) ? format : "";
326 std::shared_ptr<PixelMap> pixelMap = CreatePixelMapByContext(context, extDecoder, encodedFormat, errorCode);
327 auto auxPicture = AuxiliaryPicture::Create(pixelMap, type, context.outInfo.size);
328 auxPicture->SetAuxiliaryPictureInfo(
329 MakeAuxiliaryPictureInfo(type, context.outInfo.size, pixelMap->GetRowStride(),
330 context.pixelFormat, context.outInfo.colorSpace));
331 return auxPicture;
332 }
333
GenerateHeifAuxiliaryPicture(ImageHdrType hdrType, AuxiliaryPictureType type, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)334 std::shared_ptr<AuxiliaryPicture> AuxiliaryGenerator::GenerateHeifAuxiliaryPicture(ImageHdrType hdrType,
335 AuxiliaryPictureType type, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)
336 {
337 IMAGE_LOGI("Generate heif auxiliary picture, type: %{public}d", static_cast<int>(type));
338 if (!ImageUtils::IsAuxiliaryPictureTypeSupported(type) || extDecoder == nullptr) {
339 errorCode = ERR_IMAGE_INVALID_PARAMETER;
340 return nullptr;
341 }
342
343 auto auxPicture = GenerateAuxiliaryPicture(hdrType, type, IMAGE_HEIF_FORMAT, extDecoder, errorCode);
344 if (errorCode != SUCCESS) {
345 IMAGE_LOGE("Generate heif auxiliary picture failed! errorCode: %{public}u", errorCode);
346 return nullptr;
347 }
348 if (type == AuxiliaryPictureType::GAINMAP) {
349 errorCode = DecodeHdrMetadata(hdrType, extDecoder, auxPicture);
350 } else if (type == AuxiliaryPictureType::FRAGMENT_MAP) {
351 errorCode = DecodeHeifFragmentMetadata(extDecoder, auxPicture);
352 }
353 if (errorCode != SUCCESS) {
354 IMAGE_LOGE("Decode heif metadata failed! errorCode: %{public}u", errorCode);
355 return nullptr;
356 }
357 return std::move(auxPicture);
358 }
359
GenerateJpegAuxiliaryPicture( const MainPictureInfo &mainInfo, AuxiliaryPictureType type, std::unique_ptr<InputDataStream> &auxStream, std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)360 std::shared_ptr<AuxiliaryPicture> AuxiliaryGenerator::GenerateJpegAuxiliaryPicture(
361 const MainPictureInfo &mainInfo, AuxiliaryPictureType type, std::unique_ptr<InputDataStream> &auxStream,
362 std::unique_ptr<AbsImageDecoder> &extDecoder, uint32_t &errorCode)
363 {
364 IMAGE_LOGI("Generate jpeg auxiliary picture, type: %{public}d", static_cast<int>(type));
365 if (!ImageUtils::IsAuxiliaryPictureTypeSupported(type) || auxStream == nullptr || extDecoder == nullptr) {
366 errorCode = ERR_IMAGE_INVALID_PARAMETER;
367 return nullptr;
368 }
369
370 if (ImageUtils::IsAuxiliaryPictureEncoded(type)) {
371 auto auxPicture = GenerateAuxiliaryPicture(mainInfo.hdrType, type, IMAGE_JPEG_FORMAT, extDecoder, errorCode);
372 if (errorCode != SUCCESS) {
373 IMAGE_LOGE("Generate jpeg auxiliary picture failed! errorCode: %{public}u", errorCode);
374 return nullptr;
375 }
376 if (type == AuxiliaryPictureType::GAINMAP) {
377 errorCode = DecodeHdrMetadata(mainInfo.hdrType, extDecoder, auxPicture);
378 } else if (type == AuxiliaryPictureType::FRAGMENT_MAP) {
379 errorCode = DecodeJpegFragmentMetadata(auxStream, auxPicture);
380 }
381 if (errorCode != SUCCESS) {
382 IMAGE_LOGE("Decode jpeg metadata failed! errorCode: %{public}u", errorCode);
383 return nullptr;
384 }
385 return auxPicture;
386 }
387
388 int32_t denominator = GetAuxiliaryPictureDenominator(type);
389 denominator = (denominator == 0) ? DEFAULT_SCALE_DENOMINATOR : denominator;
390 Size size = {mainInfo.imageInfo.size.width / denominator, mainInfo.imageInfo.size.height / denominator};
391 sptr<SurfaceBuffer> surfaceBuffer = AllocSurfaceBuffer(size, GRAPHIC_PIXEL_FMT_RGBA16_FLOAT, errorCode);
392 if (errorCode != SUCCESS || surfaceBuffer == nullptr) {
393 IMAGE_LOGE("Alloc surface buffer failed! errorCode: %{public}u", errorCode);
394 return nullptr;
395 }
396 errorCode = CopyToSurfaceBuffer(auxStream, surfaceBuffer);
397 if (errorCode != SUCCESS) {
398 IMAGE_LOGE("Convert stream to surface buffer failed! errorCode: %{public}u", errorCode);
399 return nullptr;
400 }
401 auto auxPicture = AuxiliaryPicture::Create(surfaceBuffer, type, size);
402 SetUncodedAuxilaryPictureInfo(auxPicture);
403 return auxPicture;
404 }
405
406 } // namespace Media
407 } // namespace OHOS
408