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 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 "codec_heif_helper.h"
17
18 namespace OHOS::VDI::HEIF {
19 using namespace OHOS::HDI::Codec::Image::V2_0;
20 using namespace std;
21
DoEncode()22 void HeifEncoderHelper::DoEncode()
23 {
24 HDF_LOGI("start heif encode");
25 Reset();
26 bool flag = false;
27 if (encodeOpt_.gainMapPath.length() > 0) {
28 HDF_LOGI("AssembleParamForTmap");
29 flag = AssembleParamForTmap();
30 } else {
31 HDF_LOGI("AssembleParamForPrimaryImg");
32 flag = AssembleParamForPrimaryImg();
33 }
34 IF_TRUE_RETURN(!flag);
35 HDF_LOGI("get ICodecImage");
36 sptr<ICodecImage> hdiHeifEncoder = ICodecImage::Get();
37 IF_TRUE_RETURN_WITH_MSG(hdiHeifEncoder == nullptr, "failed to get ICodecImage");
38 SharedBuffer output;
39 IF_TRUE_RETURN(!AllocOutputBuffer(output));
40 uint32_t filledLen = 0;
41 HDF_LOGI("DoHeifEncode");
42 int32_t ret = hdiHeifEncoder->DoHeifEncode(inputImgs_, inputMetas_, refs_, output, filledLen);
43 if (ret == HDF_SUCCESS) {
44 HDF_LOGI("heif encode succeed");
45 output.filledLen = filledLen;
46 bufferHelper_.DumpBuffer(encodeOpt_.outputPath, output);
47 } else {
48 HDF_LOGE("heif encode failed");
49 }
50 close(output.fd);
51 }
52
AllocOutputBuffer(SharedBuffer & output)53 bool HeifEncoderHelper::AllocOutputBuffer(SharedBuffer& output)
54 {
55 static constexpr size_t EXTERNAL_BUFFER_SIZE = 18 * 1024 * 1024;
56 int fd = AshmemCreate("ForHeifEditOut", EXTERNAL_BUFFER_SIZE);
57 bool flag = true;
58 if (fd >= 0) {
59 output.fd = fd;
60 output.capacity = static_cast<uint32_t>(AshmemGetSize(fd));
61 } else {
62 flag = false;
63 output.fd = -1;
64 output.capacity = 0;
65 HDF_LOGE("failed to create output buffer");
66 }
67 output.filledLen = 0;
68 return flag;
69 }
70
71
Reset()72 void HeifEncoderHelper::Reset()
73 {
74 inputImgs_.clear();
75 inputMetas_.clear();
76 refs_.clear();
77 }
78
AddPropOnlyForTmap(ByteWriter & bw)79 bool HeifEncoderHelper::AddPropOnlyForTmap(ByteWriter& bw)
80 {
81 MasteringDisplayColourVolume clrVol = {
82 .displayPrimariesRX = 1,
83 .displayPrimariesRY = 2,
84 .displayPrimariesGX = 3,
85 .displayPrimariesGY = 4,
86 .displayPrimariesBX = 5,
87 .displayPrimariesBY = 6,
88 .whitePointX = 0,
89 .whitePointY = 0,
90 .maxDisplayMasteringLuminance = 0,
91 .minDisplayMasteringLuminance = 0
92 };
93 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<MasteringDisplayColourVolume>(MASTER_DISPLAY_COLOR_VOLUME, clrVol), false,
94 "failed to add MASTER_DISPLAY_COLOR_VOLUME");
95 HDF_LOGI("add MASTER_DISPLAY_COLOR_VOLUME succeed");
96
97 ToneMapMetadata tmapMeta;
98 static constexpr uint8_t MULTI_CHANNEL = 3;
99 tmapMeta.channelCnt = MULTI_CHANNEL;
100 tmapMeta.useBaseColorSpace = true;
101 tmapMeta.baseHdrHeadroom = {12, 23};
102 tmapMeta.alternateHdrHeadroom = {36, 62};
103 tmapMeta.channels1 = {
104 .gainMapMin = {5, 21},
105 .gainMapMax = {5, 7},
106 .gamma = {2, 7},
107 .baseOffset = {1, 3},
108 .alternateOffset = {1, 7}
109 };
110 tmapMeta.channels2 = {
111 .gainMapMin = {5, 21},
112 .gainMapMax = {5, 7},
113 .gamma = {2, 7},
114 .baseOffset = {1, 3},
115 .alternateOffset = {1, 7}
116 };
117 tmapMeta.channels3 = {
118 .gainMapMin = {5, 21},
119 .gainMapMax = {5, 7},
120 .gamma = {2, 7},
121 .baseOffset = {1, 3},
122 .alternateOffset = {1, 7}
123 };
124 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<ToneMapMetadata>(TONE_MAP_METADATA, tmapMeta), false,
125 "failed to add TONE_MAP_METADATA");
126 HDF_LOGI("add TONE_MAP_METADATA succeed");
127 return true;
128 }
129
AddPropMirrorAndRotate(ByteWriter & bw)130 bool HeifEncoderHelper::AddPropMirrorAndRotate(ByteWriter& bw)
131 {
132 static map<ImageMirror, bool> mirrorMap = {
133 { ImageMirror::HORIZONTAL, false },
134 { ImageMirror::VERTICAL, true },
135 };
136 auto iterMirror = mirrorMap.find(encodeOpt_.mirrorInfo);
137 if (iterMirror != mirrorMap.end()) {
138 bool isMirrorVertical = iterMirror->second;
139 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<bool>(MIRROR_INFO, isMirrorVertical), false,
140 "failed to add MIRROR_INFO");
141 HDF_LOGI("add MIRROR_INFO succeed");
142 }
143
144 static map<ImageRotation, uint32_t> rotateMap = {
145 { ImageRotation::ANTI_CLOCKWISE_90, 90 },
146 { ImageRotation::ANTI_CLOCKWISE_180, 180 },
147 { ImageRotation::ANTI_CLOCKWISE_270, 270 },
148 };
149 auto iterRotate = rotateMap.find(encodeOpt_.rotateInfo);
150 if (iterRotate != rotateMap.end()) {
151 uint32_t rotateDegree = iterRotate->second;
152 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<uint32_t>(ROTATE_INFO, rotateDegree), false,
153 "failed to add ROTATE_INFO");
154 HDF_LOGI("add ROTATE_INFO succeed");
155 }
156 return true;
157 }
158
CreateImgParam(ImgType type,vector<uint8_t> & props)159 bool HeifEncoderHelper::CreateImgParam(ImgType type, vector<uint8_t>& props)
160 {
161 ByteWriter bw;
162
163 if (type != T_MAP) {
164 IF_TRUE_RETURN_VAL(!AddPropMirrorAndRotate(bw), false);
165 }
166
167 ColorType clrType = encodeOpt_.iccProfilePath.length() > 0 ? PROF : NCLX;
168 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<ColorType>(COLOR_TYPE, clrType), false, "failed to add COLOR_TYPE");
169 HDF_LOGI("add COLOR_TYPE succeed");
170
171 if (clrType == NCLX) {
172 ColourInfo clrInfo = {
173 .colourPrimaries = 2,
174 .transferCharacteristics = 2,
175 .matrixCoefficients = 2,
176 .fullRangeFlag = false
177 };
178 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<ColourInfo>(COLOR_INFO, clrInfo), false, "failed to add COLOR_INFO");
179 HDF_LOGI("add COLOR_INFO succeed");
180 }
181
182 if (type == T_MAP || type == PRIMARY_IMG) {
183 ContentLightLevel level = {
184 .maxContentLightLevel = 1,
185 .maxPicAverageLightLevel = 2
186 };
187 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<ContentLightLevel>(CONTENT_LIGHT_LEVEL, level), false,
188 "failed to add CONTENT_LIGHT_LEVEL");
189 HDF_LOGI("add CONTENT_LIGHT_LEVEL succeed");
190 }
191
192 if (type == T_MAP) {
193 IF_TRUE_RETURN_VAL(!AddPropOnlyForTmap(bw), false);
194 }
195
196 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.Finalize(props), false, "failed to write img prop");
197 return true;
198 }
199
FillImageItem(ImgType type,ImageItem & item)200 bool HeifEncoderHelper::FillImageItem(ImgType type, ImageItem& item)
201 {
202 map<ImgType, string> typeToFile = {
203 { PRIMARY_IMG, encodeOpt_.primaryImgPath },
204 { AUXILIARY_IMG, encodeOpt_.auxiliaryImgPath },
205 { THUMBNAIL_IMG, encodeOpt_.thumbnailImgPath },
206 { GAIN_MAP, encodeOpt_.gainMapPath },
207 { T_MAP, "" },
208 };
209 item.itemName = "";
210 item.id = GetNextId();
211 item.sharedProperties = {
212 .fd = -1,
213 .filledLen = 0,
214 .capacity = 0
215 };
216 item.pixelBuffer = bufferHelper_.CreateImgBuffer(typeToFile[type]);
217 IF_TRUE_RETURN_VAL((type != T_MAP && item.pixelBuffer == nullptr), false);
218 item.isPrimary = (type == PRIMARY_IMG);
219 item.isHidden = (type != PRIMARY_IMG);
220 item.compressType = (type == T_MAP ? "none" : "hevc");
221 static constexpr uint32_t ENCODE_QUALITY = 85;
222 item.quality = ENCODE_QUALITY;
223 IF_TRUE_RETURN_VAL(!CreateImgParam(type, item.liteProperties), false);
224 map<PropertyType, string> sharedProps;
225 if (encodeOpt_.iccProfilePath.length() > 0) {
226 HDF_LOGI("add ICC_PROFILE");
227 sharedProps[ICC_PROFILE] = encodeOpt_.iccProfilePath;
228 }
229 if (type == T_MAP && encodeOpt_.it35Path.length() > 0) {
230 HDF_LOGI("add IT35_INFO");
231 sharedProps[IT35_INFO] = encodeOpt_.it35Path;
232 }
233 IF_TRUE_RETURN_VAL(sharedProps.empty(), true);
234 item.sharedProperties = bufferHelper_.CreateSharedBuffer(sharedProps);
235 return (item.sharedProperties.fd >= 0);
236 }
237
AssembleParamForOtherImg(uint32_t primaryImgId)238 bool HeifEncoderHelper::AssembleParamForOtherImg(uint32_t primaryImgId)
239 {
240 if (encodeOpt_.auxiliaryImgPath.length() > 0) {
241 ImageItem itemAuxlImg;
242 IF_TRUE_RETURN_VAL(!FillImageItem(AUXILIARY_IMG, itemAuxlImg), false);
243 inputImgs_.emplace_back(itemAuxlImg);
244 refs_.emplace_back(ItemRef {
245 .type = AUXL,
246 .auxType = "",
247 .from = itemAuxlImg.id,
248 .to = {primaryImgId}
249 });
250 }
251 if (encodeOpt_.thumbnailImgPath.length() > 0) {
252 ImageItem itemThmbImg;
253 IF_TRUE_RETURN_VAL(!FillImageItem(THUMBNAIL_IMG, itemThmbImg), false);
254 inputImgs_.emplace_back(itemThmbImg);
255 refs_.emplace_back(ItemRef {
256 .type = THMB,
257 .auxType = "",
258 .from = itemThmbImg.id,
259 .to = {primaryImgId}
260 });
261 }
262 return true;
263 }
264
AssembleParamForTmap()265 bool HeifEncoderHelper::AssembleParamForTmap()
266 {
267 ImageItem itemTmap;
268 ImageItem itemPrimaryImg;
269 ImageItem itemGainMap;
270 IF_TRUE_RETURN_VAL(!FillImageItem(T_MAP, itemTmap), false);
271 IF_TRUE_RETURN_VAL(!FillImageItem(PRIMARY_IMG, itemPrimaryImg), false);
272 IF_TRUE_RETURN_VAL(!FillImageItem(GAIN_MAP, itemGainMap), false);
273 inputImgs_.emplace_back(itemTmap);
274 inputImgs_.emplace_back(itemPrimaryImg);
275 inputImgs_.emplace_back(itemGainMap);
276 refs_.emplace_back(ItemRef {
277 .type = DIMG,
278 .auxType = "",
279 .from = itemTmap.id,
280 .to = {itemPrimaryImg.id, itemGainMap.id}
281 });
282 if (AssembleParamForOtherImg(itemPrimaryImg.id)) {
283 return AssembleParamForMetaData(itemPrimaryImg.id);
284 }
285 return false;
286 }
287
AssembleParamForPrimaryImg()288 bool HeifEncoderHelper::AssembleParamForPrimaryImg()
289 {
290 ImageItem itemPrimaryImg;
291 IF_TRUE_RETURN_VAL(!FillImageItem(PRIMARY_IMG, itemPrimaryImg), false);
292 inputImgs_.emplace_back(itemPrimaryImg);
293 if (AssembleParamForOtherImg(itemPrimaryImg.id)) {
294 return AssembleParamForMetaData(itemPrimaryImg.id);
295 }
296 return false;
297 }
298
FillMetaItem(const string & metaFile,MetaType type,MetaItem & item)299 bool HeifEncoderHelper::FillMetaItem(const string& metaFile, MetaType type, MetaItem& item)
300 {
301 item.itemName = "";
302 item.id = GetNextId();
303 item.properties = {};
304 if (type == USER_DATA) {
305 static constexpr char USER_DATA_LABEL[] = "userdata";
306 item.itemName = USER_DATA_LABEL;
307 bool useCompress = true;
308 ByteWriter bw;
309 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.AddData<bool>(USER_DATA_DO_COMPRESS, useCompress), false,
310 "failed to add USER_DATA_DO_COMPRESS");
311 IF_TRUE_RETURN_VAL_WITH_MSG(!bw.Finalize(item.properties), false, "failed to write USER_DATA_DO_COMPRESS");
312 } else if (type == EXIF_DATA) {
313 static constexpr char EXIF_LABEL[] = "exif";
314 item.itemName = EXIF_LABEL;
315 }
316 item.data = bufferHelper_.CreateSharedBuffer(metaFile);
317 return (item.data.fd >= 0);
318 }
319
AssembleParamForMetaData(uint32_t primaryImgId)320 bool HeifEncoderHelper::AssembleParamForMetaData(uint32_t primaryImgId)
321 {
322 HDF_LOGI("AssembleParamForMetaData");
323 if (encodeOpt_.exifDataPath.length() > 0) {
324 HDF_LOGI("add exif: %{public}s", encodeOpt_.exifDataPath.c_str());
325 MetaItem metaExifData;
326 IF_TRUE_RETURN_VAL(!FillMetaItem(encodeOpt_.exifDataPath, EXIF_DATA, metaExifData), false);
327 inputMetas_.emplace_back(metaExifData);
328 refs_.emplace_back(ItemRef {
329 .type = CDSC,
330 .auxType = "",
331 .from = metaExifData.id,
332 .to = {primaryImgId}
333 });
334 }
335 if (encodeOpt_.userDataPath.length() > 0) {
336 HDF_LOGI("add userData: %{public}s", encodeOpt_.userDataPath.c_str());
337 MetaItem metaUserData;
338 IF_TRUE_RETURN_VAL(!FillMetaItem(encodeOpt_.userDataPath, USER_DATA, metaUserData), false);
339 inputMetas_.emplace_back(metaUserData);
340 refs_.emplace_back(ItemRef {
341 .type = CDSC,
342 .auxType = "",
343 .from = metaUserData.id,
344 .to = {primaryImgId}
345 });
346 }
347 return true;
348 }
349 }
350