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 #include "image_packer_impl.h"
16
17 #include "image_common.h"
18
19 namespace {
20 constexpr int32_t INVALID_FD = -1;
21 constexpr int32_t SIZE_256 = 256;
22 constexpr int32_t SIZE_512 = 512;
23 constexpr int32_t SIZE_1024 = 1024;
24 constexpr int32_t SIZE_1440 = 1440;
25 constexpr int32_t SIZE_1920 = 1920;
26 constexpr uint64_t FILE_SIZE_300K = 300 * 1024;
27 constexpr uint64_t FILE_SIZE_1M = 1 * 1024 * 1024;
28 constexpr uint64_t FILE_SIZE_4M = 4 * 1024 * 1024;
29 constexpr uint64_t FILE_SIZE_10M = 10 * 1024 * 1024;
30 } // namespace
31
32 namespace OHOS {
33 namespace Media {
34 const int32_t TYPE_IMAGE_SOURCE = 1;
35 const int32_t TYPE_PIXEL_MAP = 2;
36 const int32_t TYPE_PICTURE = 3;
37 const uint64_t DEFAULT_BUFFER_SIZE = 25 * 1024 * 1024; // 25M is the maximum default packedSize
38
ImagePackerImpl()39 ImagePackerImpl::ImagePackerImpl()
40 {
41 real_ = std::make_unique<ImagePacker>();
42 }
43
GetImagePacker()44 std::shared_ptr<ImagePacker> ImagePackerImpl::GetImagePacker()
45 {
46 if (real_ == nullptr) {
47 return nullptr;
48 }
49 std::shared_ptr<ImagePacker> res = real_;
50 return res;
51 }
52
53 struct ImagePackerContext {
54 std::shared_ptr<ImageSource> rImageSource;
55 std::shared_ptr<ImagePacker> rImagePacker;
56 std::shared_ptr<PixelMap> rPixelMap;
57 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
58 std::shared_ptr<Picture> rPicture;
59 #endif
60 int32_t packType = TYPE_IMAGE_SOURCE;
61 };
62
getDefaultBufferSize(int32_t width,int32_t height)63 static uint64_t getDefaultBufferSize(int32_t width, int32_t height)
64 {
65 if (width <= SIZE_256 && height <= SIZE_256) {
66 return FILE_SIZE_300K;
67 }
68 if (width <= SIZE_512 && height <= SIZE_512) {
69 return FILE_SIZE_1M;
70 }
71 if (width <= SIZE_1024 && height <= SIZE_1024) {
72 return FILE_SIZE_4M;
73 }
74 if (width <= SIZE_1440 && height <= SIZE_1920) {
75 return FILE_SIZE_10M;
76 }
77 return DEFAULT_BUFFER_SIZE;
78 }
79
getDefaultBufferSize(std::shared_ptr<ImagePackerContext> context)80 static uint64_t getDefaultBufferSize(std::shared_ptr<ImagePackerContext> context)
81 {
82 if (context == nullptr) {
83 return DEFAULT_BUFFER_SIZE;
84 }
85 ImageInfo imageInfo {};
86 if (context->packType == TYPE_IMAGE_SOURCE) {
87 if (context->rImageSource == nullptr) {
88 return DEFAULT_BUFFER_SIZE;
89 }
90 context->rImageSource->GetImageInfo(imageInfo);
91 } else if (context->packType == TYPE_PIXEL_MAP) {
92 if (context->rPixelMap == nullptr) {
93 return DEFAULT_BUFFER_SIZE;
94 }
95 context->rPixelMap->GetImageInfo(imageInfo);
96 }
97 if (imageInfo.size.width <= 0 || imageInfo.size.height <= 0) {
98 return DEFAULT_BUFFER_SIZE;
99 }
100 return getDefaultBufferSize(imageInfo.size.width, imageInfo.size.height);
101 }
102
103 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
SetPicture(std::shared_ptr<ImagePackerContext> context,uint32_t & addImageRet)104 bool SetPicture(std::shared_ptr<ImagePackerContext> context, uint32_t& addImageRet)
105 {
106 IMAGE_LOGD("ImagePacker set picture");
107 if (context->rPicture == nullptr) {
108 return false;
109 }
110 addImageRet = context->rImagePacker->AddPicture(*(context->rPicture));
111 return true;
112 }
113 #endif
114
CommonPackToDataExec(std::shared_ptr<ImagePackerContext> context)115 static uint32_t CommonPackToDataExec(std::shared_ptr<ImagePackerContext> context)
116 {
117 if (context->packType == TYPE_IMAGE_SOURCE) {
118 IMAGE_LOGI("ImagePacker set image source");
119 if (context->rImageSource == nullptr) {
120 IMAGE_LOGE("ImageSource is nullptr");
121 return COMMON_ERR_INVALID_PARAMETER;
122 }
123 return context->rImagePacker->AddImage(*(context->rImageSource));
124 } else if (context->packType == TYPE_PIXEL_MAP) {
125 IMAGE_LOGD("ImagePacker set pixelmap");
126 if (context->rPixelMap == nullptr) {
127 IMAGE_LOGE("Pixelmap is nullptr");
128 return COMMON_ERR_INVALID_PARAMETER;
129 }
130 return context->rImagePacker->AddImage(*(context->rPixelMap));
131 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
132 } else if (context->packType == TYPE_PICTURE) {
133 IMAGE_LOGD("ImagePacker set picture");
134 uint32_t addImageRet = SUCCESS;
135 if (!SetPicture(context, addImageRet)) {
136 IMAGE_LOGE("Picture is nullptr");
137 return IMAGE_BAD_PARAMETER;
138 }
139 return addImageRet;
140 #endif
141 }
142 return COMMON_ERR_INVALID_PARAMETER;
143 }
144
CommonPackToData(std::shared_ptr<ImagePackerContext> context,const PackOption & option,uint64_t bufferSize)145 static std::tuple<int32_t, uint8_t*, int64_t> CommonPackToData(
146 std::shared_ptr<ImagePackerContext> context, const PackOption& option, uint64_t bufferSize)
147 {
148 uint32_t innerEncodeErrorCode =
149 static_cast<uint32_t>(context->packType == TYPE_PICTURE ? IMAGE_ENCODE_FAILED : ERR_IMAGE_ENCODE_FAILED);
150 if (context->rImagePacker == nullptr) {
151 IMAGE_LOGE("Packing failed, real_ is nullptr");
152 return std::make_tuple(innerEncodeErrorCode, nullptr, 0);
153 }
154
155 IMAGE_LOGD("ImagePacker BufferSize %{public}" PRId64, bufferSize);
156 bufferSize = bufferSize <= 0 ? getDefaultBufferSize(context) : bufferSize;
157 if (bufferSize > INT32_MAX) {
158 IMAGE_LOGE("Packing failed, bufferSize cannot be more than INT32_MAX");
159 return std::make_tuple(innerEncodeErrorCode, nullptr, 0);
160 }
161
162 uint8_t* resultBuffer = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * bufferSize));
163 if (resultBuffer == nullptr) {
164 IMAGE_LOGE("ImagePacker buffer alloc error");
165 return std::make_tuple(innerEncodeErrorCode, nullptr, 0);
166 }
167
168 uint32_t packingRet = context->rImagePacker->StartPacking(resultBuffer, bufferSize, option);
169 if (packingRet != SUCCESS) {
170 IMAGE_LOGE("Packing start packing failed");
171 free(resultBuffer);
172 packingRet = packingRet == ERR_IMAGE_INVALID_PARAMETER ? COMMON_ERR_INVALID_PARAMETER : innerEncodeErrorCode;
173 return std::make_tuple(packingRet, nullptr, 0);
174 }
175
176 uint32_t addImageRet = CommonPackToDataExec(context);
177 if (addImageRet != SUCCESS) {
178 IMAGE_LOGE("Packing failed, AddImage failed, ret=%{public}u.", addImageRet);
179 free(resultBuffer);
180 return std::make_tuple(addImageRet, nullptr, 0);
181 }
182
183 int64_t packedSize = 0;
184 uint32_t finalPackRet = context->rImagePacker->FinalizePacking(packedSize);
185 if (finalPackRet == SUCCESS) {
186 return std::make_tuple(SUCCESS_CODE, resultBuffer, packedSize);
187 } else if (packedSize == static_cast<int64_t>(bufferSize)) {
188 IMAGE_LOGE("output buffer is not enough");
189 free(resultBuffer);
190 return context->packType == TYPE_PICTURE ? std::make_tuple(IMAGE_ENCODE_FAILED, nullptr, 0)
191 : std::make_tuple(ERR_IMAGE_TOO_LARGE, nullptr, 0);
192 } else {
193 IMAGE_LOGE("Packing failed, packedSize outside size.");
194 free(resultBuffer);
195 finalPackRet =
196 finalPackRet == ERR_IMAGE_INVALID_PARAMETER ? ERR_IMAGE_INVALID_PARAMETER : innerEncodeErrorCode;
197 return std::make_tuple(finalPackRet, nullptr, 0);
198 }
199 }
200
FinalizePacking(std::shared_ptr<ImagePackerContext> context)201 static uint32_t FinalizePacking(std::shared_ptr<ImagePackerContext> context)
202 {
203 int64_t packedSize = 0;
204 uint32_t finalPackRet = context->rImagePacker->FinalizePacking(packedSize);
205 if (finalPackRet == SUCCESS && packedSize > 0) {
206 return SUCCESS;
207 } else {
208 IMAGE_LOGE("Packing failed, packedSize outside size.");
209 if (context->packType != TYPE_PICTURE) {
210 return finalPackRet;
211 }
212 return finalPackRet == ERR_IMAGE_INVALID_PARAMETER ? ERR_IMAGE_INVALID_PARAMETER : IMAGE_ENCODE_FAILED;
213 }
214 }
215
CommonPackToFile(std::shared_ptr<ImagePackerContext> context,int fd,const PackOption & option)216 static uint32_t CommonPackToFile(std::shared_ptr<ImagePackerContext> context, int fd, const PackOption& option)
217 {
218 if (fd <= INVALID_FD) {
219 IMAGE_LOGE("ImagePacker invalid fd");
220 return ERR_IMAGE_INVALID_PARAMETER;
221 }
222 if (context->rImagePacker == nullptr) {
223 IMAGE_LOGE("Packing failed, real_ is nullptr");
224 return context->packType == TYPE_PICTURE ? ERR_IMAGE_INVALID_PARAMETER : ERR_IMAGE_INIT_ABNORMAL;
225 }
226
227 uint32_t packingRet = context->rImagePacker->StartPacking(fd, option);
228 if (packingRet != SUCCESS) {
229 IMAGE_LOGE("Packing failed, StartPacking failed, ret=%{public}u.", packingRet);
230 return packingRet;
231 }
232
233 uint32_t addImageRet = SUCCESS;
234 if (context->packType == TYPE_IMAGE_SOURCE) {
235 IMAGE_LOGD("ImagePacker set image source");
236 if (!context->rImageSource) {
237 IMAGE_LOGE("ImageSource is nullptr");
238 return ERR_IMAGE_INVALID_PARAMETER;
239 }
240 addImageRet = context->rImagePacker->AddImage(*(context->rImageSource));
241 } else if (context->packType == TYPE_PIXEL_MAP) {
242 IMAGE_LOGD("ImagePacker set pixelmap");
243 if (!context->rPixelMap) {
244 IMAGE_LOGE("Pixelmap is nullptr");
245 return ERR_IMAGE_INVALID_PARAMETER;
246 }
247 addImageRet = context->rImagePacker->AddImage(*(context->rPixelMap));
248 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
249 } else if (context->packType == TYPE_PICTURE) {
250 IMAGE_LOGD("ImagePacker set picture");
251 if (!SetPicture(context, addImageRet)) {
252 IMAGE_LOGE("Picture is nullptr");
253 return ERR_IMAGE_INVALID_PARAMETER;
254 }
255 #endif
256 }
257 if (addImageRet != SUCCESS) {
258 IMAGE_LOGE("Packing failed, AddImage failed, ret=%{public}u.", addImageRet);
259 return addImageRet;
260 }
261 return FinalizePacking(context);
262 }
263
Packing(PixelMap & source,const PackOption & option,uint64_t bufferSize)264 std::tuple<int32_t, uint8_t*, int64_t> ImagePackerImpl::Packing(
265 PixelMap& source, const PackOption& option, uint64_t bufferSize)
266 {
267 return CommonPacking<PixelMap>(source, option, bufferSize);
268 }
269
Packing(ImageSource & source,const PackOption & option,uint64_t bufferSize)270 std::tuple<int32_t, uint8_t*, int64_t> ImagePackerImpl::Packing(
271 ImageSource& source, const PackOption& option, uint64_t bufferSize)
272 {
273 return CommonPacking<ImageSource>(source, option, bufferSize);
274 }
275
PackToData(std::shared_ptr<PixelMap> source,const PackOption & option,uint64_t bufferSize)276 std::tuple<int32_t, uint8_t*, int64_t> ImagePackerImpl::PackToData(
277 std::shared_ptr<PixelMap> source, const PackOption& option, uint64_t bufferSize)
278 {
279 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
280 if (context == nullptr) {
281 return std::make_tuple(ERR_IMAGE_ENCODE_FAILED, nullptr, 0);
282 }
283 context->rPixelMap = source;
284 context->packType = TYPE_PIXEL_MAP;
285 context->rImagePacker = real_;
286 return CommonPackToData(context, option, bufferSize);
287 }
288
PackToData(std::shared_ptr<ImageSource> source,const PackOption & option,uint64_t bufferSize)289 std::tuple<int32_t, uint8_t*, int64_t> ImagePackerImpl::PackToData(
290 std::shared_ptr<ImageSource> source, const PackOption& option, uint64_t bufferSize)
291 {
292 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
293 if (context == nullptr) {
294 return std::make_tuple(ERR_IMAGE_ENCODE_FAILED, nullptr, 0);
295 }
296 context->rImageSource = source;
297 context->packType = TYPE_IMAGE_SOURCE;
298 context->rImagePacker = real_;
299 return CommonPackToData(context, option, bufferSize);
300 }
301
PackToData(std::shared_ptr<Picture> source,const PackOption & option,uint64_t bufferSize)302 std::tuple<int32_t, uint8_t*, int64_t> ImagePackerImpl::PackToData(
303 std::shared_ptr<Picture> source, const PackOption& option, uint64_t bufferSize)
304 {
305 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
306 if (context == nullptr) {
307 return std::make_tuple(IMAGE_ENCODE_FAILED, nullptr, 0);
308 }
309 context->rPicture = source;
310 context->packType = TYPE_PICTURE;
311 context->rImagePacker = real_;
312 return CommonPackToData(context, option, bufferSize);
313 }
314
PackToFile(std::shared_ptr<PixelMap> source,int fd,const PackOption & option)315 uint32_t ImagePackerImpl::PackToFile(std::shared_ptr<PixelMap> source, int fd, const PackOption& option)
316 {
317 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
318 if (context == nullptr) {
319 return ERR_IMAGE_ENCODE_FAILED;
320 }
321 context->rPixelMap = source;
322 context->packType = TYPE_PIXEL_MAP;
323 context->rImagePacker = real_;
324 return CommonPackToFile(context, fd, option);
325 }
326
PackToFile(std::shared_ptr<ImageSource> source,int fd,const PackOption & option)327 uint32_t ImagePackerImpl::PackToFile(std::shared_ptr<ImageSource> source, int fd, const PackOption& option)
328 {
329 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
330 if (context == nullptr) {
331 return ERR_IMAGE_ENCODE_FAILED;
332 }
333 context->rImageSource = source;
334 context->packType = TYPE_IMAGE_SOURCE;
335 context->rImagePacker = real_;
336 return CommonPackToFile(context, fd, option);
337 }
338
PackToFile(std::shared_ptr<Picture> source,int fd,const PackOption & option)339 uint32_t ImagePackerImpl::PackToFile(std::shared_ptr<Picture> source, int fd, const PackOption& option)
340 {
341 std::shared_ptr<ImagePackerContext> context = std::make_shared<ImagePackerContext>();
342 if (context == nullptr) {
343 return IMAGE_ENCODE_FAILED;
344 }
345 context->rPicture = source;
346 context->packType = TYPE_PICTURE;
347 context->rImagePacker = real_;
348 return CommonPackToFile(context, fd, option);
349 }
350 } // namespace Media
351 } // namespace OHOS
352