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 "encode_heif_helper.h"
17 
18 namespace OHOS::VDI::HEIF {
19 using namespace OHOS::HDI::Codec::Image::V2_0;
20 using namespace std;
21 
22 
AllocOutputBuffer(SharedBuffer & output)23 bool HeifEncodeHelper::AllocOutputBuffer(SharedBuffer& output)
24 {
25     static constexpr size_t EXTERNAL_BUFFER_SIZE = 18 * 1024 * 1024;
26     int fd = AshmemCreate("ForHeifEditOut", EXTERNAL_BUFFER_SIZE);
27     bool flag = true;
28     if (fd >= 0) {
29         output.fd = fd;
30         output.capacity = static_cast<uint32_t>(AshmemGetSize(fd));
31     } else {
32         flag = false;
33         output.fd = -1;
34         output.capacity = 0;
35         HDF_LOGE("failed to create output buffer");
36     }
37     output.filledLen = 0;
38     return flag;
39 }
40 
41 
Reset()42 void HeifEncodeHelper::Reset()
43 {
44     inputImgs_.clear();
45     inputMetas_.clear();
46     refs_.clear();
47 }
48 
FillRefItem(ItemRef item,uint8_t * data,size_t size)49 ItemRef HeifEncodeHelper::FillRefItem(ItemRef item, uint8_t *data, size_t size)
50 {
51     uint8_t *dataEnd = data + size - 1;
52     if (dataEnd < (data + sizeof(uint8_t))) {
53         return item;
54     }
55     enum ValueOption : uint8_t {
56         OPTION_0 = 0,
57         OPTION_1,
58         OPTION_2,
59         OPTION_3,
60         OPTION_BUTT
61     };
62     switch ((*data) % OPTION_BUTT) {
63         case OPTION_0:
64             item.type = DIMG;
65             break;
66         case OPTION_1:
67             item.type = THMB;
68             break;
69         case OPTION_2:
70             item.type = AUXL;
71             break;
72         case OPTION_3:
73             item.type = CDSC;
74             break;
75     }
76     data += sizeof(uint8_t);
77 
78     if (dataEnd < data + sizeof(item.from)) {
79         return item;
80     }
81     item.from = ToUint32(data);
82     data += sizeof(item.from);
83 
84     if (dataEnd < data + sizeof(uint8_t)) {
85         return item;
86     }
87     uint8_t vecSize = (*data) % 2 + 1;
88     data += sizeof(vecSize);
89     if (dataEnd < (data + vecSize * sizeof(item.from))) {
90         return item;
91     } else {
92         while (vecSize--) {
93             item.to.emplace_back(ToUint32(data));
94             data += sizeof(item.from);
95         }
96     }
97     return item;
98 }
99 
FillImageItem(ImgType type,ImageItem & item,uint8_t * data,size_t size)100 bool HeifEncodeHelper::FillImageItem(ImgType type, ImageItem& item, uint8_t *data, size_t size)
101 {
102     uint8_t *dataEnd = data + size - 1;
103     item.itemName = "";
104     if (dataEnd < data + sizeof(item.id)) {
105         return false;
106     }
107     item.id = ToUint32(data);
108     data += sizeof(item.id);
109 
110     item.pixelBuffer = bufferHelper_.CreateImgBuffer(data, size);
111     IF_TRUE_RETURN_VAL((type != T_MAP && item.pixelBuffer == nullptr), false);
112     item.isPrimary = (type == PRIMARY_IMG);
113     item.isHidden = (type != PRIMARY_IMG);
114     item.compressType = (type == T_MAP ? "none" : "hevc");
115 
116     if (dataEnd < (data + sizeof(item.quality))) {
117         return false;
118     }
119     item.quality = ToUint32(data);
120     data += sizeof(item.quality);
121 
122     item.liteProperties = {};
123     if (dataEnd < (data + sizeof(uint8_t))) {
124         return false;
125     }
126     uint8_t liteProSize = *data;
127     data += sizeof(liteProSize);
128 
129     if (dataEnd < data + liteProSize) {
130         return false;
131     }
132 
133     HDF_LOGI("Fill Image LiteProperties");
134     while (liteProSize--) {
135         item.liteProperties.push_back(*data);
136         data += sizeof(uint8_t);
137     }
138 
139     item.sharedProperties = {
140         .fd = -1,
141         .filledLen = 0,
142         .capacity = 0
143     };
144 
145     if (dataEnd < (data + sizeof(uint8_t))) {
146         return false;
147     }
148     uint8_t decision = (*data) % 2;
149     data += sizeof(decision);
150     if (decision) {
151         HDF_LOGI("Fill Image SharedProperties");
152         item.sharedProperties = bufferHelper_.CreateSharedBuffer(data, size);
153     }
154     return true;
155 }
156 
AssembleParamForOtherImg(uint32_t primaryImgId,uint8_t * data,size_t size)157 bool HeifEncodeHelper::AssembleParamForOtherImg(uint32_t primaryImgId, uint8_t *data, size_t size)
158 {
159     uint8_t *dataEnd = data + size - 1;
160     if (dataEnd < data + sizeof(uint8_t)) {
161         return false;
162     }
163     uint8_t decision = (*data) % 2;
164     data += sizeof(uint8_t);
165 
166     if (decision == 1) {
167         ImageItem itemAuxlImg;
168         HDF_LOGI("Fill itemAuxlImg");
169         if (!FillImageItem(AUXILIARY_IMG, itemAuxlImg, data, size)) {
170             HDF_LOGE("%{public}s: Fill itemAuxlImg failed\n", __func__);
171             return false;
172         }
173         HDF_LOGI("Fill itemAuxlImg Succesfully");
174         inputImgs_.emplace_back(itemAuxlImg);
175         ItemRef refAuxl = {
176             .type = AUXL,
177             .auxType = "",
178             .from = itemAuxlImg.id,
179             .to = {primaryImgId}
180         };
181         ItemRef newRefAulx = FillRefItem(refAuxl, data, size);
182         refs_.emplace_back(newRefAulx);
183     } else {
184         ImageItem itemThmbImg;
185         HDF_LOGI("Fill itemThmbImg");
186         if (!FillImageItem(THUMBNAIL_IMG, itemThmbImg, data, size)) {
187             HDF_LOGE("%{public}s: Fill itemThmbImg failed\n", __func__);
188             return false;
189         }
190         HDF_LOGI("Fill itemThmbImg Succesfully");
191         inputImgs_.emplace_back(itemThmbImg);
192 
193         ItemRef refThmb = {
194             .type = THMB,
195             .auxType = "",
196             .from = itemThmbImg.id,
197             .to = {primaryImgId}
198         };
199         ItemRef newRefThmb = FillRefItem(refThmb, data, size);
200         refs_.emplace_back(newRefThmb);
201     }
202     return true;
203 }
204 
AssembleParamForTmap(uint8_t * data,size_t size)205 bool HeifEncodeHelper::AssembleParamForTmap(uint8_t *data, size_t size)
206 {
207     ImageItem itemTmap;
208     ImageItem itemPrimaryImg;
209     ImageItem itemGainMap;
210     HDF_LOGI("AssembleParamForTmap: Fill ImageItem");
211     if (!FillImageItem(T_MAP, itemTmap, data, size)) {
212         HDF_LOGE("%{public}s: Fill itemTmap failed\n", __func__);
213         return false;
214     }
215 
216     if (!FillImageItem(PRIMARY_IMG, itemPrimaryImg, data, size)) {
217         HDF_LOGE("%{public}s: Fill itemPrimaryImg failed\n", __func__);
218         return false;
219     }
220 
221     if (!FillImageItem(GAIN_MAP, itemGainMap, data, size)) {
222         HDF_LOGE("%{public}s: Fill itemGainMap failed\n", __func__);
223         return false;
224     }
225     inputImgs_.emplace_back(itemTmap);
226     inputImgs_.emplace_back(itemPrimaryImg);
227     inputImgs_.emplace_back(itemGainMap);
228 
229     ItemRef refTMap = {
230         .type = DIMG,
231         .auxType = "",
232         .from = itemTmap.id,
233         .to = {itemPrimaryImg.id, itemGainMap.id}
234     };
235 
236     HDF_LOGI("AssembleParamForTmap: Fill RefItem");
237     ItemRef newRefTMap = FillRefItem(refTMap, data, size);
238     refs_.emplace_back(newRefTMap);
239 
240     HDF_LOGI("AssembleParamForTmap: Fill OtherImg");
241     if (AssembleParamForOtherImg(itemPrimaryImg.id, data, size)) {
242         HDF_LOGI("AssembleParamForTmap: Fill MetaData");
243         return AssembleParamForMetaData(itemPrimaryImg.id, data, size);
244     }
245     return false;
246 }
247 
AssembleParamForPrimaryImg(uint8_t * data,size_t size)248 bool HeifEncodeHelper::AssembleParamForPrimaryImg(uint8_t *data, size_t size)
249 {
250     ImageItem itemPrimaryImg;
251     HDF_LOGI("AssembleParamForPrimaryImg: Fill ImageItem");
252     if (!FillImageItem(PRIMARY_IMG, itemPrimaryImg, data, size)) {
253         HDF_LOGE("%{public}s: Fill itemPrimaryImg failed\n", __func__);
254         return false;
255     }
256     inputImgs_.emplace_back(itemPrimaryImg);
257     HDF_LOGI("AssembleParamForPrimaryImg: Fill OtherImg");
258     if (AssembleParamForOtherImg(itemPrimaryImg.id, data, size)) {
259         HDF_LOGI("AssembleParamForPrimaryImg: Fill MetaData");
260         return AssembleParamForMetaData(itemPrimaryImg.id, data, size);
261     }
262     return true;
263 }
264 
FillMetaItem(MetaType type,MetaItem & item,uint8_t * data,size_t size)265 bool HeifEncodeHelper::FillMetaItem(MetaType type, MetaItem& item, uint8_t *data, size_t size)
266 {
267     uint8_t *dataEnd = data + size - 1;
268     item.itemName = "";
269     if (dataEnd < data + sizeof(item.id)) {
270         return false;
271     }
272     item.id = ToUint32(data);
273     data += sizeof(item.id);
274     item.properties = {};
275 
276     if (type == USER_DATA) {
277         static constexpr char USER_DATA_LABEL[] = "userdata";
278         item.itemName = USER_DATA_LABEL;
279 
280         if (dataEnd < data + sizeof(uint8_t)) {
281             return false;
282         }
283         uint8_t propertiesSize = *data;
284         data += sizeof(propertiesSize);
285 
286         if (dataEnd < data + propertiesSize) {
287             return false;
288         }
289 
290         while (propertiesSize--) {
291             item.properties.emplace_back(*data);
292             data += sizeof(uint8_t);
293         }
294     } else if (type == EXIF_DATA) {
295         static constexpr char EXIF_LABEL[] = "exif";
296         item.itemName = EXIF_LABEL;
297     }
298     item.data = bufferHelper_.CreateSharedBuffer(data, size);
299     return (item.data.fd >= 0);
300 }
301 
AssembleParamForMetaData(uint32_t primaryImgId,uint8_t * data,size_t size)302 bool HeifEncodeHelper::AssembleParamForMetaData(uint32_t primaryImgId, uint8_t *data, size_t size)
303 {
304     HDF_LOGI("AssembleParamForMetaData");
305     uint8_t* dataEnd = data + size - 1;
306     if (dataEnd < data + sizeof(uint8_t)) {
307         return false;
308     }
309     uint8_t decision = (*data) % 2;
310     data += sizeof(decision);
311     if (decision) {
312         HDF_LOGI("add exif");
313         MetaItem metaExifData;
314         HDF_LOGI("Fill Meta Item");
315         IF_TRUE_RETURN_VAL(!FillMetaItem(EXIF_DATA, metaExifData, data, size), false);
316         inputMetas_.emplace_back(metaExifData);
317         ItemRef refItem1 = {
318             .type = CDSC,
319             .auxType = "",
320             .from = metaExifData.id,
321             .to = {primaryImgId}
322         } ;
323         ItemRef newRefIt1 = FillRefItem(refItem1, data, size);
324         refs_.emplace_back(newRefIt1);
325         HDF_LOGI("Fill EXIF Data Succesfully");
326     } else {
327         HDF_LOGI("add userData");
328         MetaItem metaUserData;
329         HDF_LOGI("Fill Meta Item");
330         IF_TRUE_RETURN_VAL(!FillMetaItem(USER_DATA, metaUserData, data, size), false);
331         inputMetas_.emplace_back(metaUserData);
332         ItemRef refItem2 = {
333             .type = CDSC,
334             .auxType = "",
335             .from = metaUserData.id,
336             .to = {primaryImgId}
337         } ;
338         ItemRef newRefIt2 = FillRefItem(refItem2, data, size);
339         refs_.emplace_back(newRefIt2);
340         HDF_LOGI("Fill USER Data Succesfully");
341     }
342     return true;
343 }
344 
345 }
346