• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "heif_parser.h"
17 #include "box/item_property_aux_box.h"
18 #include "box/item_property_basic_box.h"
19 #include "box/item_property_display_box.h"
20 #include "box/item_property_transform_box.h"
21 #include "securec.h"
22 
23 #include <algorithm>
24 #include <limits>
25 #include <cstring>
26 #include <set>
27 
28 namespace OHOS {
29 namespace ImagePlugin {
30 
31 const auto EXIF_ID = "Exif\0\0";
32 const auto HEIF_AUXTTYPE_ID_FRAGMENT_MAP = "urn:com:huawei:photo:5:0:0:aux:fragmentmap";
33 const std::set<std::string> INFE_ITEM_TYPE = {
34     "hvc1", "grid", "tmap", "iden", "mime", "iovl"
35 };
36 
37 HeifParser::HeifParser() = default;
38 
39 HeifParser::~HeifParser() = default;
40 
MakeFromMemory(const void * data,size_t size,bool isNeedCopy,std::shared_ptr<HeifParser> * out)41 heif_error HeifParser::MakeFromMemory(const void *data, size_t size, bool isNeedCopy, std::shared_ptr<HeifParser> *out)
42 {
43     if (data == nullptr) {
44         return heif_error_no_data;
45     }
46     auto input_stream = std::make_shared<HeifBufferInputStream>((const uint8_t *) data, size, isNeedCopy);
47     return MakeFromStream(input_stream, out);
48 }
49 
MakeFromStream(const std::shared_ptr<HeifInputStream> & stream,std::shared_ptr<HeifParser> * out)50 heif_error HeifParser::MakeFromStream(const std::shared_ptr<HeifInputStream> &stream, std::shared_ptr<HeifParser> *out)
51 {
52     if (stream == nullptr) {
53         return heif_error_no_data;
54     }
55     std::shared_ptr<HeifParser> file = std::make_shared<HeifParser>(stream);
56 
57     auto maxSize = static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
58     HeifStreamReader reader(stream, 0, maxSize);
59 
60     heif_error errorBox = file->AssembleBoxes(reader);
61     if (errorBox != heif_error_ok) {
62         return errorBox;
63     }
64 
65     heif_error errorImage = file->AssembleImages();
66     if (errorImage != heif_error_ok) {
67         return errorImage;
68     }
69 
70     *out = std::move(file);
71     return errorBox;
72 }
73 
Write(HeifStreamWriter & writer)74 void HeifParser::Write(HeifStreamWriter &writer)
75 {
76     CheckExtentData();
77     for (auto &box: topBoxes_) {
78         box->InferAllFullBoxVersion();
79         box->Write(writer);
80     }
81 
82     ilocBox_->WriteMdatBox(writer);
83 }
84 
GetPrimaryItemId() const85 heif_item_id HeifParser::GetPrimaryItemId() const
86 {
87     return pitmBox_->GetItemId();
88 }
89 
GetAllItemId(std::vector<heif_item_id> & itemIdList) const90 void HeifParser::GetAllItemId(std::vector<heif_item_id> &itemIdList) const
91 {
92     for (const auto &infeBox: infeBoxes_) {
93         itemIdList.push_back(infeBox.second->GetItemId());
94     }
95 }
96 
AssembleBoxes(HeifStreamReader & reader)97 heif_error HeifParser::AssembleBoxes(HeifStreamReader &reader)
98 {
99     while (true) {
100         std::shared_ptr<HeifBox> box;
101         uint32_t recursionCount = 0;
102         heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
103         if (reader.IsAtEnd() || error == heif_error_eof) {
104             break;
105         }
106         if (error != heif_error_ok) {
107             return error;
108         }
109         topBoxes_.push_back(box);
110         if (box->GetBoxType() == BOX_TYPE_META) {
111             metaBox_ = std::dynamic_pointer_cast<HeifMetaBox>(box);
112         }
113         if (box->GetBoxType() == BOX_TYPE_MOOV) {
114             moovBox_ = std::dynamic_pointer_cast<HeifMoovBox>(box);
115         }
116         if (box->GetBoxType() == BOX_TYPE_FTYP) {
117             ftypBox_ = std::dynamic_pointer_cast<HeifFtypBox>(box);
118         }
119     }
120 
121     if (moovBox_) {
122         return AssembleMovieBoxes();
123     }
124 
125     if (!ftypBox_) {
126         return heif_error_no_ftyp;
127     }
128 
129     if (!metaBox_) {
130         return heif_error_no_meta;
131     }
132 
133     hdlrBox_ = metaBox_->GetChild<HeifHdlrBox>(BOX_TYPE_HDLR);
134     if (!hdlrBox_ || (hdlrBox_ && hdlrBox_->GetHandlerType() != HANDLER_TYPE_PICT)) {
135         return heif_error_invalid_handler;
136     }
137 
138     pitmBox_ = metaBox_->GetChild<HeifPtimBox>(BOX_TYPE_PITM);
139     if (!pitmBox_) {
140         return heif_error_no_pitm;
141     }
142 
143     iinfBox_ = metaBox_->GetChild<HeifIinfBox>(BOX_TYPE_IINF);
144     if (!iinfBox_) {
145         return heif_error_no_iinf;
146     }
147     std::vector<std::shared_ptr<HeifInfeBox>> infes = iinfBox_->GetChildren<HeifInfeBox>(BOX_TYPE_INFE);
148     for (auto &infe: infes) {
149         infeBoxes_.insert(std::make_pair(infe->GetItemId(), infe));
150     }
151 
152     irefBox_ = metaBox_->GetChild<HeifIrefBox>(BOX_TYPE_IREF);
153 
154     iprpBox_ = metaBox_->GetChild<HeifIprpBox>(BOX_TYPE_IPRP);
155     if (!iprpBox_) {
156         return heif_error_no_iprp;
157     }
158 
159     ipcoBox_ = iprpBox_->GetChild<HeifIpcoBox>(BOX_TYPE_IPCO);
160     if (!ipcoBox_) {
161         return heif_error_no_ipco;
162     }
163 
164     std::vector<std::shared_ptr<HeifIpmaBox>> ipmas = iprpBox_->GetChildren<HeifIpmaBox>(BOX_TYPE_IPMA);
165     if (ipmas.empty()) {
166         return heif_error_no_ipma;
167     }
168     ipmaBox_ = std::make_shared<HeifIpmaBox>();
169     for (auto &ipma : ipmas) {
170         ipmaBox_->MergeImpaBoxes(*ipma);
171     }
172     idatBox_ = metaBox_->GetChild<HeifIdatBox>(BOX_TYPE_IDAT);
173 
174     ilocBox_ = metaBox_->GetChild<HeifIlocBox>(BOX_TYPE_ILOC);
175     if (!ilocBox_) {
176         return heif_error_no_iloc;
177     }
178     return heif_error_ok;
179 }
180 
HasItemId(heif_item_id itemId) const181 bool HeifParser::HasItemId(heif_item_id itemId) const
182 {
183     return infeBoxes_.find(itemId) != infeBoxes_.end();
184 }
185 
GetItemType(heif_item_id itemId) const186 std::string HeifParser::GetItemType(heif_item_id itemId) const
187 {
188     auto infe_box = GetInfeBox(itemId);
189     if (!infe_box) {
190         return "";
191     }
192     return infe_box->GetItemType();
193 }
194 
GetItemContentType(heif_item_id itemId) const195 std::string HeifParser::GetItemContentType(heif_item_id itemId) const
196 {
197     auto infe_box = GetInfeBox(itemId);
198     if (!infe_box) {
199         return "";
200     }
201     return infe_box->GetContentType();
202 }
203 
GetItemUriType(heif_item_id itemId) const204 std::string HeifParser::GetItemUriType(heif_item_id itemId) const
205 {
206     auto infe_box = GetInfeBox(itemId);
207     if (!infe_box) {
208         return "";
209     }
210     return infe_box->GetItemUriType();
211 }
212 
213 
GetAllProperties(heif_item_id itemId,std::vector<std::shared_ptr<HeifBox>> & properties) const214 heif_error HeifParser::GetAllProperties(heif_item_id itemId, std::vector<std::shared_ptr<HeifBox>> &properties) const
215 {
216     if (!ipcoBox_) {
217         return heif_error_no_ipco;
218     }
219     if (!ipmaBox_) {
220         return heif_error_no_ipma;
221     }
222     return ipcoBox_->GetProperties(itemId, ipmaBox_, properties);
223 }
224 
GetGridLength(heif_item_id itemId,size_t & length)225 heif_error HeifParser::GetGridLength(heif_item_id itemId, size_t &length)
226 {
227     if (!HasItemId(itemId)) {
228         return heif_error_item_not_found;
229     }
230     auto items = ilocBox_->GetItems();
231     const HeifIlocBox::Item *ilocItem = nullptr;
232     auto iter = std::find_if(items.begin(), items.end(), [&itemId](const auto &item) {
233         return item.itemId == itemId;
234     });
235     if (iter != items.end()) {
236         ilocItem = &*iter;
237     } else {
238         return heif_error_item_data_not_found;
239     }
240     return ilocBox_->GetIlocDataLength(*ilocItem, length);
241 }
242 
GetItemData(heif_item_id itemId,std::vector<uint8_t> * out,heif_header_option option) const243 heif_error HeifParser::GetItemData(heif_item_id itemId, std::vector<uint8_t> *out, heif_header_option option) const
244 {
245     if (!HasItemId(itemId)) {
246         return heif_error_item_not_found;
247     }
248 
249     auto infe_box = GetInfeBox(itemId);
250     if (!infe_box) {
251         return heif_error_item_not_found;
252     }
253 
254     std::string item_type = infe_box->GetItemType();
255     auto items = ilocBox_->GetItems();
256     const HeifIlocBox::Item *ilocItem = nullptr;
257     for (const auto &item: items) {
258         if (item.itemId == itemId) {
259             ilocItem = &item;
260             break;
261         }
262     }
263     if (!ilocItem) {
264         return heif_error_item_data_not_found;
265     }
266 
267     heif_error error;
268     if (item_type == "hvc1") {
269         auto hvcc = GetProperty<HeifHvccBox>(itemId);
270         if (!hvcc) {
271             return heif_error_no_hvcc;
272         }
273         if (option != heif_no_header && !hvcc->GetHeaders(out)) {
274             return heif_error_item_data_not_found;
275         }
276         if (option != heif_only_header) {
277             error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
278         } else {
279             error = heif_error_ok;
280         }
281     } else {
282         error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
283     }
284 
285     return error;
286 }
287 
GetTileImages(heif_item_id gridItemId,std::vector<std::shared_ptr<HeifImage>> & out)288 void HeifParser::GetTileImages(heif_item_id gridItemId, std::vector<std::shared_ptr<HeifImage>> &out)
289 {
290     auto infe = GetInfeBox(gridItemId);
291     if (!infe || infe->GetItemType() != "grid") {
292         return;
293     }
294     if (!irefBox_) {
295         return;
296     }
297     auto toItemIds = irefBox_->GetReferences(gridItemId, BOX_TYPE_DIMG);
298     for (heif_item_id toItemId: toItemIds) {
299         auto tileImage = GetImage(toItemId);
300         if (tileImage) {
301             out.push_back(tileImage);
302         }
303     }
304 }
305 
GetIovlImages(heif_item_id itemId,std::vector<std::shared_ptr<HeifImage>> & out)306 void HeifParser::GetIovlImages(heif_item_id itemId, std::vector<std::shared_ptr<HeifImage>> &out)
307 {
308     auto infe = GetInfeBox(itemId);
309     if (!infe || infe->GetItemType() != "iovl") {
310         return;
311     }
312     if (!irefBox_) {
313         return;
314     }
315     auto toItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
316     for (heif_item_id toItemId: toItemIds) {
317         auto tileImage = GetImage(toItemId);
318         if (tileImage) {
319             out.push_back(tileImage);
320         }
321     }
322 }
323 
GetIdenImage(heif_item_id itemId,std::shared_ptr<HeifImage> & out)324 void HeifParser::GetIdenImage(heif_item_id itemId, std::shared_ptr<HeifImage> &out)
325 {
326     auto infe = GetInfeBox(itemId);
327     if (!infe || infe->GetItemType() != "iden") {
328         return;
329     }
330     if (!irefBox_) {
331         return;
332     }
333     auto toItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
334     for (heif_item_id toItemId: toItemIds) {
335         auto idenImage = GetImage(toItemId);
336         if (idenImage) {
337             out = idenImage;
338             return;
339         }
340     }
341 }
342 
GetInfeBox(heif_item_id itemId) const343 std::shared_ptr<HeifInfeBox> HeifParser::GetInfeBox(heif_item_id itemId) const
344 {
345     auto iter = infeBoxes_.find(itemId);
346     if (iter == infeBoxes_.end()) {
347         return nullptr;
348     }
349     return iter->second;
350 }
351 
AssembleImages()352 heif_error HeifParser::AssembleImages()
353 {
354     images_.clear();
355     primaryImage_.reset();
356 
357     if (moovBox_) {
358         auto image = std::make_shared<HeifImage>(0);
359         image->SetPrimaryImage(true);
360         image->SetMovieImage(true);
361         primaryImage_ = image;
362         ExtractMovieImageProperties(image);
363     }
364     std::vector<heif_item_id> allItemIds;
365     GetAllItemId(allItemIds);
366 
367     for (heif_item_id itemId: allItemIds) {
368         // extract Image Item
369         auto infe = GetInfeBox(itemId);
370         if (!infe) {
371             continue;
372         }
373         const std::string& itemType = infe->GetItemType();
374         if (INFE_ITEM_TYPE.find(itemType) == INFE_ITEM_TYPE.end()) {
375             continue;
376         }
377         auto image = std::make_shared<HeifImage>(itemId);
378         if (itemType == "tmap") {
379             tmapImage_ = image;
380             ExtractImageProperties(tmapImage_);
381             continue;
382         }
383         images_.insert(std::make_pair(itemId, image));
384         if (!infe->IsHidden() && itemId == GetPrimaryItemId()) {
385             image->SetPrimaryImage(true);
386             primaryImage_ = image;
387         }
388 
389         ExtractImageProperties(image);
390     }
391 
392     if (!primaryImage_) {
393         return heif_error_primary_item_not_found;
394     }
395 
396     ExtractGainmap(allItemIds);
397     ExtractDerivedImageProperties();
398     ExtractNonMasterImages();
399     ExtractMetadata(allItemIds);
400     return heif_error_ok;
401 }
402 
ExtractIT35Metadata(const heif_item_id & metadataItemId)403 void HeifParser::ExtractIT35Metadata(const heif_item_id& metadataItemId)
404 {
405     if (GetItemType(metadataItemId) != "it35") {
406         return;
407     }
408     std::vector<uint8_t> extendInfo;
409     heif_error err = GetItemData(metadataItemId, &(extendInfo));
410     if (err != heif_error_ok || extendInfo.empty()) {
411         return;
412     }
413     primaryImage_->SetUWAInfo(extendInfo);
414 }
415 
ExtractISOMetadata(const heif_item_id & itemId)416 void HeifParser::ExtractISOMetadata(const heif_item_id& itemId)
417 {
418     if (GetItemType(itemId) != "tmap") {
419         return;
420     }
421     std::vector<uint8_t> extendInfo;
422     heif_error err = GetItemData(itemId, &extendInfo);
423     if (err != heif_error_ok || extendInfo.empty()) {
424         return ;
425     }
426     primaryImage_->SetISOMetadata(extendInfo);
427 }
428 
ExtractFragmentMetadata(const heif_item_id & itemId)429 void HeifParser::ExtractFragmentMetadata(const heif_item_id& itemId)
430 {
431     HeifFragmentMetadata extendInfo;
432     auto ispe = GetProperty<HeifIspeBox>(itemId);
433     if (ispe) {
434         extendInfo.width = ispe->GetWidth();
435         extendInfo.height = ispe->GetHeight();
436     }
437     auto rloc = GetProperty<HeifRlocBox>(itemId);
438     if (rloc) {
439         extendInfo.horizontalOffset = rloc->GetX();
440         extendInfo.verticalOffset = rloc->GetY();
441     }
442     primaryImage_->SetFragmentMetadata(extendInfo);
443 }
444 
ExtractDisplayData(std::shared_ptr<HeifImage> & image,heif_item_id & itemId)445 void HeifParser::ExtractDisplayData(std::shared_ptr<HeifImage>& image, heif_item_id& itemId)
446 {
447     auto mdcv = GetProperty<HeifMdcvBox>(itemId);
448     auto clli = GetProperty<HeifClliBox>(itemId);
449     if (mdcv == nullptr && clli == nullptr) {
450         return;
451     }
452     DisplayColourVolume displayColourVolume{};
453     ContentLightLevelInfo lightInfo{};
454     uint32_t displaySize = sizeof(DisplayColourVolume);
455     std::vector<uint8_t> displayVec(displaySize);
456     if (mdcv) {
457         displayColourVolume = mdcv->GetColourVolume();
458         if (memcpy_s(displayVec.data(), displaySize, &displayColourVolume, displaySize) != EOK) {
459             displayVec.resize(0);
460         }
461     }
462 
463     uint32_t lightInfoSize = sizeof(ContentLightLevelInfo);
464     std::vector<uint8_t> lightInfoVec(lightInfoSize);
465     if (clli) {
466         lightInfo = clli->GetLightLevel();
467         if (memcpy_s(lightInfoVec.data(), lightInfoSize, &lightInfo, lightInfoSize) != EOK) {
468             lightInfoVec.resize(0);
469         }
470     }
471 
472     image->SetStaticMetadata(displayVec, lightInfoVec);
473 }
474 
ExtractGainmap(const std::vector<heif_item_id> & allItemIds)475 void HeifParser::ExtractGainmap(const std::vector<heif_item_id>& allItemIds)
476 {
477     for (heif_item_id itemId: allItemIds) {
478         // extract Image Item
479         auto infe = GetInfeBox(itemId);
480         if (!infe) {
481             continue;
482         }
483         const std::string& itemType = infe->GetItemType();
484         if (itemType == "it35") {
485             ExtractIT35Metadata(itemId);
486         }
487         if (itemType == "tmap") {
488             ExtractISOMetadata(itemId);
489             ExtractGainmapImage(itemId);
490         }
491     }
492 }
493 
ExtractMovieImageProperties(std::shared_ptr<HeifImage> & image)494 void HeifParser::ExtractMovieImageProperties(std::shared_ptr<HeifImage> &image)
495 {
496     if (stsdBox_) {
497         uint32_t width = 0;
498         uint32_t height = 0;
499         stsdBox_->GetSampleEntryWidthHeight(0, width, height);
500         image->SetOriginalSize(width, height);
501     }
502 }
503 
ExtractImageProperties(std::shared_ptr<HeifImage> & image)504 void HeifParser::ExtractImageProperties(std::shared_ptr<HeifImage> &image)
505 {
506     heif_item_id itemId = image->GetItemId();
507 
508     auto ispe = GetProperty<HeifIspeBox>(itemId);
509     if (ispe) {
510         uint32_t width = ispe->GetWidth();
511         uint32_t height = ispe->GetHeight();
512         image->SetOriginalSize(width, height);
513     }
514 
515     auto irot = GetProperty<HeifIrotBox>(itemId);
516     if (irot) {
517         image->SetRotateDegrees(irot->GetRotDegree());
518     }
519 
520     auto imir = GetProperty<HeifImirBox>(itemId);
521     if (imir) {
522         image->SetMirrorDirection(imir->GetDirection());
523     }
524 
525     auto colr = GetProperty<HeifColrBox>(itemId);
526     if (colr) {
527         auto profile = colr->GetColorProfile();
528         image->SetColorProfile(profile);
529     }
530 
531     auto pixi = GetProperty<HeifPixiBox>(itemId);
532     if (pixi && pixi->GetChannelNum() == 1) {
533         image->SetDefaultColorFormat(HeifColorFormat::MONOCHROME);
534         image->SetDefaultPixelFormat(HeifPixelFormat::MONOCHROME);
535     } else {
536         image->SetDefaultColorFormat(HeifColorFormat::YCBCR);
537         image->SetDefaultPixelFormat(HeifPixelFormat::UNDEFINED);
538     }
539 
540     auto hvcc = GetProperty<HeifHvccBox>(itemId);
541     if (hvcc) {
542         auto hvccConfig = hvcc->GetConfig();
543         image->SetLumaBitNum(hvccConfig.bitDepthLuma);
544         image->SetChromaBitNum(hvccConfig.bitDepthChroma);
545         image->SetDefaultPixelFormat((HeifPixelFormat) hvccConfig.chromaFormat);
546 
547         auto nalArrays = hvcc->GetNalArrays();
548         hvcc->ParserHvccColorRangeFlag(nalArrays);
549         auto spsConfig = hvcc->GetSpsConfig();
550         image->SetColorRangeFlag(static_cast<int>(spsConfig.videoRangeFlag));
551     }
552     ExtractDisplayData(image, itemId);
553 }
554 
ExtractDerivedImageProperties()555 void HeifParser::ExtractDerivedImageProperties()
556 {
557     for (auto &pair: images_) {
558         heif_item_id itemId = pair.first;
559         auto infe = GetInfeBox(itemId);
560         if (!infe || (infe->GetItemType() != "grid" && infe->GetItemType() != "iden")) {
561             continue;
562         }
563         auto &image = pair.second;
564         if (!irefBox_) {
565             return;
566         }
567         auto tileItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
568         if (tileItemIds.empty()) {
569             continue;
570         }
571         auto tileImage = GetImage(tileItemIds[0]);
572         if (tileImage == nullptr) {
573             continue;
574         }
575         if (image->GetLumaBitNum() < 0) {
576             image->SetLumaBitNum(tileImage->GetLumaBitNum());
577         }
578         if (image->GetChromaBitNum() < 0) {
579             image->SetChromaBitNum(tileImage->GetChromaBitNum());
580         }
581         if (image->GetDefaultPixelFormat() == HeifPixelFormat::UNDEFINED) {
582             image->SetDefaultPixelFormat(tileImage->GetDefaultPixelFormat());
583         }
584         if (image->GetDefaultColorFormat() == HeifColorFormat::UNDEDEFINED) {
585             image->SetDefaultColorFormat(tileImage->GetDefaultColorFormat());
586         }
587     }
588 }
589 
ExtractThumbnailImage(std::shared_ptr<HeifImage> & thumbnailImage,const HeifIrefBox::Reference & ref)590 void HeifParser::ExtractThumbnailImage(std::shared_ptr<HeifImage> &thumbnailImage, const HeifIrefBox::Reference &ref)
591 {
592     std::vector<heif_item_id> toItemIds = ref.toItemIds;
593     if (toItemIds.empty()) {
594         return;
595     }
596     heif_item_id masterItemId = toItemIds[0];
597     if (masterItemId == thumbnailImage->GetItemId()) {
598         return;
599     }
600     auto masterImage = GetImage(masterItemId);
601     if (!masterImage) {
602         return;
603     }
604 
605     thumbnailImage->SetThumbnailImage(masterItemId);
606     masterImage->AddThumbnailImage(thumbnailImage);
607 }
608 
ExtractAuxImage(std::shared_ptr<HeifImage> & auxImage,const HeifIrefBox::Reference & ref)609 void HeifParser::ExtractAuxImage(std::shared_ptr<HeifImage> &auxImage, const HeifIrefBox::Reference &ref)
610 {
611     std::vector<heif_item_id> toItemIds = ref.toItemIds;
612     if (toItemIds.empty()) {
613         return;
614     }
615     heif_item_id masterItemId = toItemIds[0];
616     heif_item_id auxItemId = auxImage->GetItemId();
617     if (masterItemId == auxItemId) {
618         return;
619     }
620     auto masterImage = GetImage(masterItemId);
621     if (!masterImage) {
622         return;
623     }
624     std::shared_ptr<HeifAuxcBox> auxc = GetProperty<HeifAuxcBox>(auxItemId);
625     if (!auxc) {
626         return;
627     }
628 
629     if (auxc->GetAuxType() == HEIF_AUXTTYPE_ID_FRAGMENT_MAP) {
630         ExtractFragmentMetadata(auxItemId);
631     }
632     auxImage->SetAuxImage(masterItemId, auxc->GetAuxType());
633     masterImage->AddAuxImage(auxImage);
634 }
635 
ExtractGainmapImage(const heif_item_id & tmapId)636 void HeifParser::ExtractGainmapImage(const heif_item_id& tmapId)
637 {
638     if (!irefBox_) {
639         return;
640     }
641     std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(tmapId);
642     for (const HeifIrefBox::Reference &ref : references) {
643         uint32_t type = ref.box.GetBoxType();
644         if (type != BOX_TYPE_DIMG) {
645             continue;
646         }
647         heif_item_id fromItemId = ref.fromItemId;
648         auto fromItemInfeBox = GetInfeBox(fromItemId);
649         if (fromItemInfeBox == nullptr) {
650             continue;
651         }
652         if (fromItemInfeBox->GetItemType() != "tmap") {
653             return;
654         }
655         std::vector<heif_item_id> toItemIds = ref.toItemIds;
656         const size_t tmapToItemSize = 2;
657         if (toItemIds.size() != tmapToItemSize) {
658             return;
659         }
660         const uint8_t baseIndex = 0;
661         const uint8_t gainmapIndex = 1;
662         heif_item_id baseId = toItemIds[baseIndex];
663         if (baseId != primaryImage_->GetItemId()) {
664             return;
665         }
666         heif_item_id gainmapId = toItemIds[gainmapIndex];
667         auto gainmapImage = GetImage(gainmapId);
668         if (gainmapImage == nullptr) {
669             return;
670         }
671         gainmapImage->SetGainmapMasterImage(baseId);
672         gainmapImage->SetTmapBoxId(tmapId);
673         primaryImage_->AddGainmapImage(gainmapImage);
674         primaryImage_->SetTmapBoxId(tmapId);
675     }
676 }
677 
ExtractNonMasterImages()678 void HeifParser::ExtractNonMasterImages()
679 {
680     if (!irefBox_) {
681         return;
682     }
683     for (auto &pair: images_) {
684         auto &image = pair.second;
685         std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(image->GetItemId());
686         for (const HeifIrefBox::Reference &ref: references) {
687             uint32_t type = ref.box.GetBoxType();
688             if (type == BOX_TYPE_THMB) {
689                 ExtractThumbnailImage(image, ref);
690             } else if (type == BOX_TYPE_AUXL) {
691                 ExtractAuxImage(image, ref);
692             }
693         }
694     }
695 }
696 
ExtractMetadata(const std::vector<heif_item_id> & allItemIds)697 void HeifParser::ExtractMetadata(const std::vector<heif_item_id> &allItemIds)
698 {
699     if (!irefBox_) {
700         return;
701     }
702 
703     for (heif_item_id metadataItemId: allItemIds) {
704         std::vector<heif_item_id> toItemIds = irefBox_->GetReferences(metadataItemId, BOX_TYPE_CDSC);
705         if (toItemIds.empty()) {
706             continue;
707         }
708         heif_item_id masterImageId = toItemIds[0];
709         if (masterImageId == metadataItemId) {
710             continue;
711         }
712         auto masterImage = GetImage(masterImageId);
713         if (!masterImage) {
714             continue;
715         }
716 
717         std::shared_ptr<HeifMetadata> metadata = std::make_shared<HeifMetadata>();
718         metadata->itemId = metadataItemId;
719         metadata->itemType = GetItemType(metadataItemId);
720         metadata->contentType = GetItemContentType(metadataItemId);
721         metadata->itemUriType = GetItemUriType(metadataItemId);
722         heif_error err = GetItemData(metadataItemId, &(metadata->mData));
723         if (err != heif_error_ok) {
724             metadata.reset();
725             continue;
726         }
727         masterImage->AddMetadata(metadata);
728     }
729 }
730 
GetImage(heif_item_id itemId)731 std::shared_ptr<HeifImage> HeifParser::GetImage(heif_item_id itemId)
732 {
733     auto iter = images_.find(itemId);
734     if (iter == images_.end()) {
735         return nullptr;
736     }
737     return iter->second;
738 }
739 
GetPrimaryImage()740 std::shared_ptr<HeifImage> HeifParser::GetPrimaryImage()
741 {
742     return primaryImage_;
743 }
744 
GetGainmapImage()745 std::shared_ptr<HeifImage> HeifParser::GetGainmapImage()
746 {
747     return primaryImage_ != nullptr ? primaryImage_->GetGainmapImage() : nullptr;
748 }
749 
GetAuxiliaryMapImage(const std::string type)750 std::shared_ptr<HeifImage> HeifParser::GetAuxiliaryMapImage(const std::string type)
751 {
752     auto auxImages = primaryImage_->GetAuxImages();
753     for (auto image : auxImages) {
754         if (image->GetAuxImageType() == type) {
755             return image;
756         }
757     }
758     return nullptr;
759 }
760 
GetTmapImage()761 std::shared_ptr<HeifImage> HeifParser::GetTmapImage()
762 {
763     return tmapImage_;
764 }
765 
GetNextItemId() const766 heif_item_id HeifParser::GetNextItemId() const
767 {
768     heif_item_id max_id = 0;
769     for (const auto& infe: infeBoxes_) {
770         max_id = std::max(max_id, infe.second->GetItemId());
771     }
772     return max_id + 1;
773 }
774 
AddItem(const char * itemType,bool hidden)775 std::shared_ptr<HeifInfeBox> HeifParser::AddItem(const char *itemType, bool hidden)
776 {
777     heif_item_id newItemId = GetNextItemId();
778     auto newInfe = std::make_shared<HeifInfeBox>(newItemId, itemType, false);
779     newInfe->SetHidden(hidden);
780     infeBoxes_[newItemId] = newInfe;
781     if (iinfBox_ == nullptr) {
782         return nullptr;
783     }
784     iinfBox_->AddChild(newInfe);
785     return newInfe;
786 }
787 
AddIspeProperty(heif_item_id itemId,uint32_t width,uint32_t height)788 void HeifParser::AddIspeProperty(heif_item_id itemId, uint32_t width, uint32_t height)
789 {
790     auto ispe = std::make_shared<HeifIspeBox>();
791     ispe->SetDimension(width, height);
792     AddProperty(itemId, ispe, false);
793 }
794 
AddProperty(heif_item_id itemId,const std::shared_ptr<HeifBox> & property,bool essential)795 heif_property_id HeifParser::AddProperty(heif_item_id itemId, const std::shared_ptr<HeifBox>& property, bool essential)
796 {
797     int index = ipcoBox_->AddChild(property);
798     ipmaBox_->AddProperty(itemId, PropertyAssociation{essential, uint16_t(index + 1)});
799     return index + 1;
800 }
801 
AddPixiProperty(heif_item_id itemId,uint8_t c1,uint8_t c2,uint8_t c3)802 void HeifParser::AddPixiProperty(heif_item_id itemId, uint8_t c1, uint8_t c2, uint8_t c3)
803 {
804     auto pixi = std::make_shared<HeifPixiBox>();
805     pixi->AddBitNum(c1);
806     pixi->AddBitNum(c2);
807     pixi->AddBitNum(c3);
808     AddProperty(itemId, pixi, false);
809 }
810 
811 
AddHvccProperty(heif_item_id itemId)812 void HeifParser::AddHvccProperty(heif_item_id itemId)
813 {
814     auto hvcC = std::make_shared<HeifHvccBox>();
815     AddProperty(itemId, hvcC, true);
816 }
817 
AppendHvccNalData(heif_item_id itemId,const std::vector<uint8_t> & data)818 heif_error HeifParser::AppendHvccNalData(heif_item_id itemId, const std::vector<uint8_t> &data)
819 {
820     auto hvcc = GetProperty<HeifHvccBox>(itemId);
821     if (!hvcc) {
822         return heif_error_no_hvcc;
823     }
824     hvcc->AppendNalData(data);
825     return heif_error_ok;
826 }
827 
SetHvccConfig(heif_item_id itemId,const HvccConfig & config)828 heif_error HeifParser::SetHvccConfig(heif_item_id itemId, const HvccConfig &config)
829 {
830     auto hvcc = GetProperty<HeifHvccBox>(itemId);
831     if (!hvcc) {
832         return heif_error_no_hvcc;
833     }
834     hvcc->SetConfig(config);
835     return heif_error_ok;
836 }
837 
AppendIlocData(heif_item_id itemId,const std::vector<uint8_t> & data,uint8_t construction_method)838 void HeifParser::AppendIlocData(heif_item_id itemId, const std::vector<uint8_t> &data, uint8_t construction_method)
839 {
840     if (!ilocBox_) {
841         return;
842     }
843     ilocBox_->AppendData(itemId, data, construction_method);
844 }
845 
SetPrimaryItemId(heif_item_id itemId)846 void HeifParser::SetPrimaryItemId(heif_item_id itemId)
847 {
848     if (!pitmBox_) {
849         return;
850     }
851     pitmBox_->SetItemId(itemId);
852 }
853 
AddReference(heif_item_id fromItemId,uint32_t type,const std::vector<heif_item_id> & toItemIds)854 void HeifParser::AddReference(heif_item_id fromItemId, uint32_t type, const std::vector<heif_item_id> &toItemIds)
855 {
856     if (!irefBox_) {
857         irefBox_ = std::make_shared<HeifIrefBox>();
858         metaBox_->AddChild(irefBox_);
859     }
860     irefBox_->AddReferences(fromItemId, type, toItemIds);
861 }
862 
SetAuxcProperty(heif_item_id itemId,const std::string & type)863 void HeifParser::SetAuxcProperty(heif_item_id itemId, const std::string &type)
864 {
865     auto auxC = std::make_shared<HeifAuxcBox>();
866     auxC->SetAuxType(type);
867     AddProperty(itemId, auxC, true);
868 }
869 
SetColorProfile(heif_item_id itemId,const std::shared_ptr<const HeifColorProfile> & profile)870 void HeifParser::SetColorProfile(heif_item_id itemId, const std::shared_ptr<const HeifColorProfile> &profile)
871 {
872     auto colr = std::make_shared<HeifColrBox>();
873     colr->SetColorProfile(profile);
874     AddProperty(itemId, colr, false);
875 }
876 
CheckExtentData()877 void HeifParser::CheckExtentData()
878 {
879     const std::vector<HeifIlocBox::Item>& items = ilocBox_->GetItems();
880     for (const HeifIlocBox::Item& item: items) {
881         ilocBox_->ReadToExtentData(const_cast<HeifIlocBox::Item &>(item), inputStream_, idatBox_);
882     }
883 }
884 
SetPrimaryImage(const std::shared_ptr<HeifImage> & image)885 void HeifParser::SetPrimaryImage(const std::shared_ptr<HeifImage> &image)
886 {
887     if (primaryImage_) {
888         if (primaryImage_->GetItemId() == image->GetItemId()) {
889             return;
890         }
891         primaryImage_->SetPrimaryImage(false);
892     }
893     primaryImage_ = image;
894     image->SetPrimaryImage(true);
895     SetPrimaryItemId(image->GetItemId());
896 }
897 
GetExifHeaderOffset(const uint8_t * data,uint32_t size)898 uint32_t HeifParser::GetExifHeaderOffset(const uint8_t *data, uint32_t size)
899 {
900     uint32_t offset = 0;
901     const int endianSize = 4;
902     while (offset + endianSize < static_cast<unsigned int>(size)) {
903         if (!memcmp(data + offset, "MM\0*", endianSize) || !memcmp(data + offset, "II*\0", endianSize)) {
904             return offset;
905         }
906         offset++;
907     }
908     return offset;
909 }
910 
SetExifMetadata(const std::shared_ptr<HeifImage> & image,const uint8_t * data,uint32_t size)911 heif_error HeifParser::SetExifMetadata(const std::shared_ptr<HeifImage> &image, const uint8_t *data, uint32_t size)
912 {
913     uint32_t offset = GetExifHeaderOffset(data, size);
914     if (offset >= size) {
915         return heif_invalid_exif_data;
916     }
917 
918     std::vector<uint8_t> content;
919     content.resize(size + UINT32_BYTES_NUM);
920     std::string offsetFourcc = code_to_fourcc(offset);
921     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
922         content[index] = (uint8_t)offsetFourcc[index];
923     }
924     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != EOK) {
925         return heif_invalid_exif_data;
926     }
927     return SetMetadata(image, content, "Exif", nullptr);
928 }
929 
UpdateExifMetadata(const std::shared_ptr<HeifImage> & master_image,const uint8_t * data,uint32_t size,heif_item_id itemId)930 heif_error HeifParser::UpdateExifMetadata(const std::shared_ptr<HeifImage> &master_image, const uint8_t *data,
931                                           uint32_t size, heif_item_id itemId)
932 {
933     uint32_t offset = GetExifHeaderOffset(data, size);
934     if (offset >= static_cast<unsigned int>(size)) {
935         return heif_invalid_exif_data;
936     }
937 
938     std::vector<uint8_t> content;
939     content.resize(size + UINT32_BYTES_NUM);
940     std::string offsetFourcc = code_to_fourcc(offset);
941     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
942         content[index] = (uint8_t)offsetFourcc[index];
943     }
944 
945     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != 0) {
946         return heif_invalid_exif_data;
947     }
948 
949     uint8_t construction_method = GetConstructMethod(itemId);
950 
951     return ilocBox_->UpdateData(itemId, content, construction_method);
952 }
953 
SetMetadata(const std::shared_ptr<HeifImage> & image,const std::vector<uint8_t> & data,const char * item_type,const char * content_type)954 heif_error HeifParser::SetMetadata(const std::shared_ptr<HeifImage> &image, const std::vector<uint8_t> &data,
955                                    const char *item_type, const char *content_type)
956 {
957     auto metadataInfe = AddItem(item_type, true);
958     if (content_type != nullptr) {
959         metadataInfe->SetContentType(content_type);
960     }
961 
962     heif_item_id metadataItemId = metadataInfe->GetItemId();
963     heif_item_id imageItemId = image->GetItemId();
964     AddReference(metadataItemId, BOX_TYPE_CDSC, {imageItemId});
965 
966     // store metadata in mdat
967     AppendIlocData(metadataItemId, data, 0);
968     return heif_error_ok;
969 }
970 
GetConstructMethod(const heif_item_id & id)971 uint8_t HeifParser::GetConstructMethod(const heif_item_id &id)
972 {
973     auto items = ilocBox_->GetItems();
974     for (const auto &item: items) {
975         if (item.itemId == id) {
976             return item.constructionMethod;
977         }
978     }
979 
980     // CONSTRUCTION_METHOD_FILE_OFFSET 0
981     return 0;
982 }
983 
SetTiffOffset()984 void HeifParser::SetTiffOffset()
985 {
986     if (tiffOffset_ != 0) {
987         return;
988     }
989     if (GetPrimaryImage() == nullptr) {
990         return;
991     }
992     auto metadataList = GetPrimaryImage()->GetAllMetadata();
993     heif_item_id exifId = 0;
994     for (auto metadata : metadataList) {
995         if (metadata && metadata->itemType == EXIF_ID) {
996             exifId = metadata->itemId;
997             break;
998         }
999     }
1000     if (exifId == 0) {
1001         return;
1002     }
1003 
1004     if (!HasItemId(exifId)) {
1005         return;
1006     }
1007 
1008     auto items = ilocBox_->GetItems();
1009     const HeifIlocBox::Item *ilocItem = nullptr;
1010     for (const auto &item: items) {
1011         if (item.itemId == exifId) {
1012             ilocItem = &item;
1013             break;
1014         }
1015     }
1016     if (!ilocItem) {
1017         return;
1018     }
1019 
1020     tiffOffset_ = ilocItem->baseOffset;
1021     if (!ilocItem->extents.empty()) {
1022         tiffOffset_ += ilocItem->extents[0].offset;
1023     }
1024 }
1025 
AssembleMovieBoxes()1026 heif_error HeifParser::AssembleMovieBoxes()
1027 {
1028     mvhdBox_ = moovBox_->GetChild<HeifMvhdBox>(BOX_TYPE_MVHD);
1029     if (!mvhdBox_) {
1030         return heif_error_no_mvhd;
1031     }
1032 
1033     trakBox_ = moovBox_->GetChild<HeifTrakBox>(BOX_TYPE_TRAK);
1034     if (!trakBox_) {
1035         return heif_error_no_trak;
1036     }
1037 
1038     tkhdBox_ = trakBox_->GetChild<HeifTkhdBox>(BOX_TYPE_TKHD);
1039     if (!tkhdBox_) {
1040         return heif_error_no_tkhd;
1041     }
1042 
1043     mdiaBox_ = trakBox_->GetChild<HeifMdiaBox>(BOX_TYPE_MDIA);
1044     if (!mdiaBox_) {
1045         return heif_error_no_mdia;
1046     }
1047 
1048     mdhdBox_ = mdiaBox_->GetChild<HeifMdhdBox>(BOX_TYPE_MDHD);
1049     if (!mdhdBox_) {
1050         return heif_error_no_mdhd;
1051     }
1052 
1053     hdlrBox_ = mdiaBox_->GetChild<HeifHdlrBox>(BOX_TYPE_HDLR);
1054     if (!hdlrBox_) {
1055         return heif_error_no_hdlr;
1056     }
1057 
1058     minfBox_ = mdiaBox_->GetChild<HeifMinfBox>(BOX_TYPE_MINF);
1059     if (!minfBox_) {
1060         return heif_error_no_minf;
1061     }
1062 
1063     vmhdBox_ = minfBox_->GetChild<HeifVmhdBox>(BOX_TYPE_VMHD);
1064     if (!vmhdBox_) {
1065         return heif_error_no_vmhd;
1066     }
1067 
1068     dinfBox_ = minfBox_->GetChild<HeifDinfBox>(BOX_TYPE_DINF);
1069     if (!dinfBox_) {
1070         return heif_error_no_dinf;
1071     }
1072 
1073     stblBox_ = minfBox_->GetChild<HeifStblBox>(BOX_TYPE_STBL);
1074     if (!stblBox_) {
1075         return heif_error_no_stbl;
1076     }
1077 
1078     drefBox_ = dinfBox_->GetChild<HeifDrefBox>(BOX_TYPE_DREF);
1079     if (!drefBox_) {
1080         return heif_error_no_dref;
1081     }
1082 
1083     stsdBox_ = stblBox_->GetChild<HeifStsdBox>(BOX_TYPE_STSD);
1084     if (!stsdBox_) {
1085         return heif_error_no_stsd;
1086     }
1087 
1088     sttsBox_ = stblBox_->GetChild<HeifSttsBox>(BOX_TYPE_STTS);
1089     if (!sttsBox_) {
1090         return heif_error_no_stts;
1091     }
1092 
1093     stscBox_ = stblBox_->GetChild<HeifStscBox>(BOX_TYPE_STSC);
1094     if (!stscBox_) {
1095         return heif_error_no_stsc;
1096     }
1097 
1098     stcoBox_ = stblBox_->GetChild<HeifStcoBox>(BOX_TYPE_STCO);
1099     if (!stcoBox_) {
1100         return heif_error_no_stco;
1101     }
1102 
1103     stszBox_ = stblBox_->GetChild<HeifStszBox>(BOX_TYPE_STSZ);
1104     if (!stszBox_) {
1105         return heif_error_no_stsz;
1106     }
1107     return heif_error_ok;
1108 }
1109 
GetMovieFrameData(uint32_t index,std::vector<uint8_t> * dest,heif_header_option option) const1110 heif_error HeifParser::GetMovieFrameData(uint32_t index, std::vector<uint8_t> *dest, heif_header_option option) const
1111 {
1112     if (!stsdBox_) {
1113         return heif_error_no_stsd;
1114     }
1115     auto hvcc = std::dynamic_pointer_cast<HeifHvccBox>(stsdBox_->GetHvccBox(0));
1116     if (!hvcc) {
1117         return heif_error_no_hvcc;
1118     }
1119     if (option != heif_no_header && !hvcc->GetHeaders(dest)) {
1120         return heif_error_item_data_not_found;
1121     }
1122     auto res = heif_error_ok;
1123     if (option != heif_only_header) {
1124         res = GetSampleData(index, dest);
1125     }
1126     return heif_error_ok;
1127 }
1128 
GetSampleData(uint32_t index,std::vector<uint8_t> * dest) const1129 heif_error HeifParser::GetSampleData(uint32_t index, std::vector<uint8_t> *dest) const
1130 {
1131     uint32_t chunkOffset = 0;
1132     uint32_t sampleSize = 0;
1133     if (!stcoBox_) {
1134         return heif_error_no_stco;
1135     }
1136     heif_error res = stcoBox_->GetChunkOffset(index, chunkOffset);
1137     if (res != heif_error_ok) {
1138         return res;
1139     }
1140     if (!stszBox_) {
1141         return heif_error_no_stsz;
1142     }
1143     res = stszBox_->GetSampleSize(index, sampleSize);
1144     if (res != heif_error_ok) {
1145         return res;
1146     }
1147     std::vector<uint8_t> firstFrameData(sampleSize);
1148     inputStream_->Seek(chunkOffset);
1149     size_t oldSize = dest->size();
1150     dest->resize(static_cast<size_t>(sampleSize) + oldSize);
1151 
1152     inputStream_->Read(reinterpret_cast<char*>(dest->data()) + oldSize, static_cast<size_t>(sampleSize));
1153     return heif_error_ok;
1154 }
1155 } // namespace ImagePlugin
1156 } // namespace OHOS
1157