1*89a0ef05SAndroid Build Coastguard Worker /*
2*89a0ef05SAndroid Build Coastguard Worker * Copyright 2023 The Android Open Source Project
3*89a0ef05SAndroid Build Coastguard Worker *
4*89a0ef05SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*89a0ef05SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*89a0ef05SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*89a0ef05SAndroid Build Coastguard Worker *
8*89a0ef05SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*89a0ef05SAndroid Build Coastguard Worker *
10*89a0ef05SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*89a0ef05SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*89a0ef05SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*89a0ef05SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*89a0ef05SAndroid Build Coastguard Worker * limitations under the License.
15*89a0ef05SAndroid Build Coastguard Worker */
16*89a0ef05SAndroid Build Coastguard Worker
17*89a0ef05SAndroid Build Coastguard Worker #include "ultrahdr/multipictureformat.h"
18*89a0ef05SAndroid Build Coastguard Worker
19*89a0ef05SAndroid Build Coastguard Worker namespace ultrahdr {
calculateMpfSize()20*89a0ef05SAndroid Build Coastguard Worker size_t calculateMpfSize() {
21*89a0ef05SAndroid Build Coastguard Worker return sizeof(kMpfSig) + // Signature
22*89a0ef05SAndroid Build Coastguard Worker kMpEndianSize + // Endianness
23*89a0ef05SAndroid Build Coastguard Worker sizeof(uint32_t) + // Index IFD Offset
24*89a0ef05SAndroid Build Coastguard Worker sizeof(uint16_t) + // Tag count
25*89a0ef05SAndroid Build Coastguard Worker kTagSerializedCount * kTagSize + // 3 tags at 12 bytes each
26*89a0ef05SAndroid Build Coastguard Worker sizeof(uint32_t) + // Attribute IFD offset
27*89a0ef05SAndroid Build Coastguard Worker kNumPictures * kMPEntrySize; // MP Entries for each image
28*89a0ef05SAndroid Build Coastguard Worker }
29*89a0ef05SAndroid Build Coastguard Worker
generateMpf(size_t primary_image_size,size_t primary_image_offset,size_t secondary_image_size,size_t secondary_image_offset)30*89a0ef05SAndroid Build Coastguard Worker std::shared_ptr<DataStruct> generateMpf(size_t primary_image_size, size_t primary_image_offset,
31*89a0ef05SAndroid Build Coastguard Worker size_t secondary_image_size,
32*89a0ef05SAndroid Build Coastguard Worker size_t secondary_image_offset) {
33*89a0ef05SAndroid Build Coastguard Worker size_t mpf_size = calculateMpfSize();
34*89a0ef05SAndroid Build Coastguard Worker std::shared_ptr<DataStruct> dataStruct = std::make_shared<DataStruct>(mpf_size);
35*89a0ef05SAndroid Build Coastguard Worker
36*89a0ef05SAndroid Build Coastguard Worker dataStruct->write(static_cast<const void*>(kMpfSig), sizeof(kMpfSig));
37*89a0ef05SAndroid Build Coastguard Worker #if USE_BIG_ENDIAN_IN_MPF
38*89a0ef05SAndroid Build Coastguard Worker dataStruct->write(static_cast<const void*>(kMpBigEndian), kMpEndianSize);
39*89a0ef05SAndroid Build Coastguard Worker #else
40*89a0ef05SAndroid Build Coastguard Worker dataStruct->write(static_cast<const void*>(kMpLittleEndian), kMpEndianSize);
41*89a0ef05SAndroid Build Coastguard Worker #endif
42*89a0ef05SAndroid Build Coastguard Worker
43*89a0ef05SAndroid Build Coastguard Worker // Set the Index IFD offset be the position after the endianness value and this offset.
44*89a0ef05SAndroid Build Coastguard Worker constexpr uint32_t indexIfdOffset = static_cast<uint16_t>(kMpEndianSize + sizeof(kMpfSig));
45*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(indexIfdOffset));
46*89a0ef05SAndroid Build Coastguard Worker
47*89a0ef05SAndroid Build Coastguard Worker // We will write 3 tags (version, number of images, MP entries).
48*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kTagSerializedCount));
49*89a0ef05SAndroid Build Coastguard Worker
50*89a0ef05SAndroid Build Coastguard Worker // Write the version tag.
51*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kVersionTag));
52*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kVersionType));
53*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kVersionCount));
54*89a0ef05SAndroid Build Coastguard Worker dataStruct->write(kVersionExpected, kVersionSize);
55*89a0ef05SAndroid Build Coastguard Worker
56*89a0ef05SAndroid Build Coastguard Worker // Write the number of images.
57*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kNumberOfImagesTag));
58*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kNumberOfImagesType));
59*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kNumberOfImagesCount));
60*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kNumPictures));
61*89a0ef05SAndroid Build Coastguard Worker
62*89a0ef05SAndroid Build Coastguard Worker // Write the MP entries.
63*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kMPEntryTag));
64*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(Endian_SwapBE16(kMPEntryType));
65*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kMPEntrySize * kNumPictures));
66*89a0ef05SAndroid Build Coastguard Worker const uint32_t mpEntryOffset =
67*89a0ef05SAndroid Build Coastguard Worker static_cast<uint32_t>(dataStruct->getBytesWritten() - // The bytes written so far
68*89a0ef05SAndroid Build Coastguard Worker sizeof(kMpfSig) + // Excluding the MPF signature
69*89a0ef05SAndroid Build Coastguard Worker sizeof(uint32_t) + // The 4 bytes for this offset
70*89a0ef05SAndroid Build Coastguard Worker sizeof(uint32_t)); // The 4 bytes for the attribute IFD offset.
71*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(mpEntryOffset));
72*89a0ef05SAndroid Build Coastguard Worker
73*89a0ef05SAndroid Build Coastguard Worker // Write the attribute IFD offset (zero because we don't write it).
74*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(0);
75*89a0ef05SAndroid Build Coastguard Worker
76*89a0ef05SAndroid Build Coastguard Worker // Write the MP entries for primary image
77*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kMPEntryAttributeFormatJpeg | kMPEntryAttributeTypePrimary));
78*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(primary_image_size));
79*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(primary_image_offset));
80*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(0);
81*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(0);
82*89a0ef05SAndroid Build Coastguard Worker
83*89a0ef05SAndroid Build Coastguard Worker // Write the MP entries for secondary image
84*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(kMPEntryAttributeFormatJpeg));
85*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(secondary_image_size));
86*89a0ef05SAndroid Build Coastguard Worker dataStruct->write32(Endian_SwapBE32(secondary_image_offset));
87*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(0);
88*89a0ef05SAndroid Build Coastguard Worker dataStruct->write16(0);
89*89a0ef05SAndroid Build Coastguard Worker
90*89a0ef05SAndroid Build Coastguard Worker return dataStruct;
91*89a0ef05SAndroid Build Coastguard Worker }
92*89a0ef05SAndroid Build Coastguard Worker
93*89a0ef05SAndroid Build Coastguard Worker } // namespace ultrahdr
94