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 18namespace OHOS::VDI::HEIF { 19using namespace OHOS::HDI::Codec::Image::V2_0; 20using namespace std; 21 22void 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 53bool 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 72void HeifEncoderHelper::Reset() 73{ 74 inputImgs_.clear(); 75 inputMetas_.clear(); 76 refs_.clear(); 77} 78 79bool 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 130bool 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 159bool 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 200bool 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 238bool 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 265bool 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 288bool 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 299bool 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 320bool 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