• 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 #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