1 /*
2  * Copyright (C) 2022 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 "image_packer.h"
17 
18 #include "buffer_packer_stream.h"
19 #include "file_packer_stream.h"
20 #include "image/abs_image_encoder.h"
21 #include "image_log.h"
22 #include "image_mime_type.h"
23 #include "image_trace.h"
24 #include "image_utils.h"
25 #include "media_errors.h"
26 #include "ostream_packer_stream.h"
27 #include "plugin_server.h"
28 #include "string_ex.h"
29 #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
30 #include "include/jpeg_encoder.h"
31 #endif
32 #ifdef HEIF_HW_ENCODE_ENABLE
33 #include "v3_0/codec_types.h"
34 #include "v3_0/icodec_component_manager.h"
35 #endif
36 
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
39 
40 #undef LOG_TAG
41 #define LOG_TAG "ImagePacker"
42 
43 namespace OHOS {
44 namespace Media {
45 using namespace ImagePlugin;
46 using namespace MultimediaPlugin;
47 static constexpr uint8_t QUALITY_MAX = 100;
48 const static std::string EXTENDED_ENCODER = "image/jpeg,image/png,image/webp";
49 static constexpr size_t SIZE_ZERO = 0;
50 
51 PluginServer &ImagePacker::pluginServer_ = ImageUtils::GetPluginServer();
52 
53 #ifdef HEIF_HW_ENCODE_ENABLE
IsEncodeSecureMode(const std::string &name)54 static bool IsEncodeSecureMode(const std::string &name)
55 {
56     std::string prefix = ".secure";
57     if (name.length() <= prefix.length()) {
58         return false;
59     }
60     return name.rfind(prefix) == (name.length() - prefix.length());
61 }
62 #endif
63 
IsSupportHeifEncode()64 static bool IsSupportHeifEncode()
65 {
66 #ifdef HEIF_HW_ENCODE_ENABLE
67     sptr<HDI::Codec::V3_0::ICodecComponentManager> manager =
68             HDI::Codec::V3_0::ICodecComponentManager::Get(false);
69     if (manager == nullptr) {
70         return false;
71     }
72     int32_t compCnt = 0;
73     int32_t ret = manager->GetComponentNum(compCnt);
74     if (ret != HDF_SUCCESS || compCnt <= 0) {
75         return false;
76     }
77     std::vector<HDI::Codec::V3_0::CodecCompCapability> capList(compCnt);
78     ret = manager->GetComponentCapabilityList(capList, compCnt);
79     if (ret != HDF_SUCCESS || capList.empty()) {
80         return false;
81     }
82     for (const auto& cap : capList) {
83         if (cap.role == HDI::Codec::V3_0::MEDIA_ROLETYPE_VIDEO_HEVC &&
84             cap.type == HDI::Codec::V3_0::VIDEO_ENCODER && !IsEncodeSecureMode(cap.compName)) {
85             return true;
86         }
87     }
88 #endif
89     return false;
90 }
91 
GetSupportedFormats(std::set<std::string> &formats)92 uint32_t ImagePacker::GetSupportedFormats(std::set<std::string> &formats)
93 {
94     formats.clear();
95     std::vector<ClassInfo> classInfos;
96     uint32_t ret =
97         pluginServer_.PluginServerGetClassInfo<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, classInfos);
98     if (ret != SUCCESS) {
99         IMAGE_LOGE("get class info from plugin server failed, ret:%{public}u.", ret);
100         return ret;
101     }
102     for (auto &info : classInfos) {
103         std::map<std::string, AttrData> &capbility = info.capabilities;
104         auto iter = capbility.find(IMAGE_ENCODE_FORMAT);
105         if (iter == capbility.end()) {
106             continue;
107         }
108         AttrData &attr = iter->second;
109         std::string format;
110         if (attr.GetValue(format) != SUCCESS) {
111             IMAGE_LOGE("attr data get format failed.");
112             continue;
113         }
114         std::vector<std::string> splitedVector;
115         SplitStr(format, ",", splitedVector);
116         for (std::string item : splitedVector) {
117             formats.insert(item);
118         }
119     }
120     static bool isSupportHeif = IsSupportHeifEncode();
121     if (isSupportHeif) {
122         formats.insert(IMAGE_HEIF_FORMAT);
123     }
124     return SUCCESS;
125 }
126 
StartPackingImpl(const PackOption &option)127 uint32_t ImagePacker::StartPackingImpl(const PackOption &option)
128 {
129     if (packerStream_ == nullptr || packerStream_.get() == nullptr) {
130         IMAGE_LOGE("make buffer packer stream failed.");
131         return ERR_IMAGE_DATA_ABNORMAL;
132     }
133     if (!GetEncoderPlugin(option)) {
134         IMAGE_LOGE("StartPackingImpl get encoder plugin failed.");
135         return ERR_IMAGE_MISMATCHED_FORMAT;
136     }
137     encodeToSdr_ = ((option.desiredDynamicRange == EncodeDynamicRange::SDR) ||
138         (option.format != IMAGE_JPEG_FORMAT && option.format != IMAGE_HEIF_FORMAT));
139     PlEncodeOptions plOpts;
140     CopyOptionsToPlugin(option, plOpts);
141     return DoEncodingFunc([this, &plOpts](ImagePlugin::AbsImageEncoder* encoder) {
142         return encoder->StartEncode(*packerStream_.get(), plOpts);
143     });
144 }
145 
StartPacking(uint8_t *outputData, uint32_t maxSize, const PackOption &option)146 uint32_t ImagePacker::StartPacking(uint8_t *outputData, uint32_t maxSize, const PackOption &option)
147 {
148     ImageTrace imageTrace("ImagePacker::StartPacking by outputData");
149     if (!IsPackOptionValid(option)) {
150         IMAGE_LOGE("array startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
151             option.quality);
152         return ERR_IMAGE_INVALID_PARAMETER;
153     }
154 
155     if (outputData == nullptr) {
156         IMAGE_LOGE("output buffer is null.");
157         return ERR_IMAGE_INVALID_PARAMETER;
158     }
159     BufferPackerStream *stream = new (std::nothrow) BufferPackerStream(outputData, maxSize);
160     if (stream == nullptr) {
161         IMAGE_LOGE("make buffer packer stream failed.");
162         return ERR_IMAGE_DATA_ABNORMAL;
163     }
164     FreeOldPackerStream();
165     packerStream_ = std::unique_ptr<BufferPackerStream>(stream);
166     return StartPackingImpl(option);
167 }
168 
StartPacking(const std::string &filePath, const PackOption &option)169 uint32_t ImagePacker::StartPacking(const std::string &filePath, const PackOption &option)
170 {
171     ImageTrace imageTrace("ImagePacker::StartPacking by filePath");
172     if (!IsPackOptionValid(option)) {
173         IMAGE_LOGE("filepath startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
174             option.quality);
175         return ERR_IMAGE_INVALID_PARAMETER;
176     }
177     FilePackerStream *stream = new (std::nothrow) FilePackerStream(filePath);
178     if (stream == nullptr) {
179         IMAGE_LOGE("make file packer stream failed.");
180         return ERR_IMAGE_DATA_ABNORMAL;
181     }
182     FreeOldPackerStream();
183     packerStream_ = std::unique_ptr<FilePackerStream>(stream);
184     return StartPackingImpl(option);
185 }
186 
StartPacking(const int &fd, const PackOption &option)187 uint32_t ImagePacker::StartPacking(const int &fd, const PackOption &option)
188 {
189     ImageTrace imageTrace("ImagePacker::StartPacking by fd");
190     if (!IsPackOptionValid(option)) {
191         IMAGE_LOGE("fd startPacking option invalid %{public}s, %{public}u.", option.format.c_str(), option.quality);
192         return ERR_IMAGE_INVALID_PARAMETER;
193     }
194     FilePackerStream *stream = new (std::nothrow) FilePackerStream(fd);
195     if (stream == nullptr) {
196         IMAGE_LOGE("make file packer stream failed.");
197         return ERR_IMAGE_DATA_ABNORMAL;
198     }
199     FreeOldPackerStream();
200     packerStream_ = std::unique_ptr<FilePackerStream>(stream);
201     return StartPackingImpl(option);
202 }
203 
StartPacking(std::ostream &outputStream, const PackOption &option)204 uint32_t ImagePacker::StartPacking(std::ostream &outputStream, const PackOption &option)
205 {
206     ImageTrace imageTrace("ImagePacker::StartPacking by outputStream");
207     if (!IsPackOptionValid(option)) {
208         IMAGE_LOGE("outputStream startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
209             option.quality);
210         return ERR_IMAGE_INVALID_PARAMETER;
211     }
212     OstreamPackerStream *stream = new (std::nothrow) OstreamPackerStream(outputStream);
213     if (stream == nullptr) {
214         IMAGE_LOGE("make ostream packer stream failed.");
215         return ERR_IMAGE_DATA_ABNORMAL;
216     }
217     FreeOldPackerStream();
218     packerStream_ = std::unique_ptr<OstreamPackerStream>(stream);
219     return StartPackingImpl(option);
220 }
221 
222 // JNI adapter method, this method be called by jni and the outputStream be created by jni, here we manage the lifecycle
223 // of the outputStream
StartPackingAdapter(PackerStream &outputStream, const PackOption &option)224 uint32_t ImagePacker::StartPackingAdapter(PackerStream &outputStream, const PackOption &option)
225 {
226     FreeOldPackerStream();
227     packerStream_ = std::unique_ptr<PackerStream>(&outputStream);
228 
229     if (!IsPackOptionValid(option)) {
230         IMAGE_LOGE("packer stream option invalid %{public}s, %{public}u.", option.format.c_str(), option.quality);
231         return ERR_IMAGE_INVALID_PARAMETER;
232     }
233     return StartPackingImpl(option);
234 }
235 
AddImage(PixelMap &pixelMap)236 uint32_t ImagePacker::AddImage(PixelMap &pixelMap)
237 {
238     ImageUtils::DumpPixelMapBeforeEncode(pixelMap);
239     ImageTrace imageTrace("ImagePacker::AddImage by pixelMap");
240 
241     return DoEncodingFunc([this, &pixelMap](ImagePlugin::AbsImageEncoder* encoder) {
242         return encoder->AddImage(pixelMap);
243     });
244 }
245 
AddImage(ImageSource &source)246 uint32_t ImagePacker::AddImage(ImageSource &source)
247 {
248     ImageTrace imageTrace("ImagePacker::AddImage by imageSource");
249     DecodeOptions decodeOpts;
250     decodeOpts.desiredDynamicRange = encodeToSdr_ ? DecodeDynamicRange::SDR : DecodeDynamicRange::AUTO;
251     uint32_t ret = SUCCESS;
252     if (pixelMap_ != nullptr) {
253         pixelMap_.reset();  // release old inner pixelmap
254     }
255     pixelMap_ = source.CreatePixelMap(decodeOpts, ret);
256     if (ret != SUCCESS) {
257         IMAGE_LOGE("image source create pixel map failed.");
258         return ret;
259     }
260 
261     if (pixelMap_ == nullptr || pixelMap_.get() == nullptr) {
262         IMAGE_LOGE("create the pixel map unique_ptr fail.");
263         return ERR_IMAGE_MALLOC_ABNORMAL;
264     }
265 
266     return AddImage(*pixelMap_.get());
267 }
268 
AddImage(ImageSource &source, uint32_t index)269 uint32_t ImagePacker::AddImage(ImageSource &source, uint32_t index)
270 {
271     ImageTrace imageTrace("ImagePacker::AddImage by imageSource and index %{public}u", index);
272     DecodeOptions decodeOpts;
273     decodeOpts.desiredDynamicRange = encodeToSdr_ ? DecodeDynamicRange::SDR : DecodeDynamicRange::AUTO;
274     uint32_t ret = SUCCESS;
275     if (pixelMap_ != nullptr) {
276         pixelMap_.reset();  // release old inner pixelmap
277     }
278     pixelMap_ = source.CreatePixelMap(index, decodeOpts, ret);
279     if (ret != SUCCESS) {
280         IMAGE_LOGE("image source create pixel map failed.");
281         return ret;
282     }
283     if (pixelMap_ == nullptr || pixelMap_.get() == nullptr) {
284         IMAGE_LOGE("create the pixel map unique_ptr fail.");
285         return ERR_IMAGE_MALLOC_ABNORMAL;
286     }
287 
288     return AddImage(*pixelMap_.get());
289 }
290 
291 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
AddPicture(Picture &picture)292 uint32_t ImagePacker::AddPicture(Picture &picture)
293 {
294     return DoEncodingFunc([this, &picture](ImagePlugin::AbsImageEncoder* encoder) {
295         return encoder->AddPicture(picture);
296     });
297 }
298 #endif
299 
300 uint32_t ImagePacker::FinalizePacking()
301 {
302     return DoEncodingFunc([](ImagePlugin::AbsImageEncoder* encoder) {
303         auto res = encoder->FinalizeEncode();
304         if (res != SUCCESS) {
305             IMAGE_LOGE("FinalizePacking failed %{public}d.", res);
306         }
307         return res;
308         }, false);
309 }
310 
311 uint32_t ImagePacker::FinalizePacking(int64_t &packedSize)
312 {
313     uint32_t ret = FinalizePacking();
314     if (packerStream_ != nullptr) {
315         packerStream_->Flush();
316     }
317     packedSize = (packerStream_ != nullptr) ? packerStream_->BytesWritten() : 0;
318     return ret;
319 }
320 
321 static ImagePlugin::AbsImageEncoder* GetEncoder(PluginServer &pluginServer, std::string format)
322 {
323     std::map<std::string, AttrData> capabilities;
324     capabilities.insert(std::map<std::string, AttrData>::value_type(IMAGE_ENCODE_FORMAT, AttrData(format)));
325     return pluginServer.CreateObject<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, capabilities);
326 }
327 
328 bool ImagePacker::GetEncoderPlugin(const PackOption &option)
329 {
330     encoders_.clear();
331     IMAGE_LOGD("GetEncoderPlugin current encoder plugin size %{public}zu.", encoders_.size());
332     auto encoder = GetEncoder(pluginServer_, EXTENDED_ENCODER);
333     if (encoder != nullptr) {
334         encoders_.emplace_back(std::unique_ptr<ImagePlugin::AbsImageEncoder>(encoder));
335     } else {
336         IMAGE_LOGE("GetEncoderPlugin get ext_encoder plugin failed.");
337     }
338     encoder = GetEncoder(pluginServer_, option.format);
339     if (encoder != nullptr) {
340         encoders_.emplace_back(std::unique_ptr<ImagePlugin::AbsImageEncoder>(encoder));
341     } else {
342         IMAGE_LOGD("GetEncoderPlugin get %{public}s plugin failed, use ext_encoder plugin",
343             option.format.c_str());
344     }
345     return encoders_.size() != SIZE_ZERO;
346 }
347 
348 void ImagePacker::CopyOptionsToPlugin(const PackOption &opts, PlEncodeOptions &plOpts)
349 {
350     plOpts.delayTimes = opts.delayTimes;
351     plOpts.loop = opts.loop;
352     plOpts.numberHint = opts.numberHint;
353     plOpts.quality = opts.quality;
354     plOpts.format = opts.format;
355     plOpts.disposalTypes = opts.disposalTypes;
356     plOpts.needsPackProperties = opts.needsPackProperties;
357     plOpts.desiredDynamicRange = opts.desiredDynamicRange;
358     plOpts.isEditScene = opts.isEditScene;
359 }
360 
361 void ImagePacker::FreeOldPackerStream()
362 {
363     if (packerStream_ != nullptr) {
364         packerStream_.reset();
365     }
366 }
367 
368 bool ImagePacker::IsPackOptionValid(const PackOption &option)
369 {
370     return !(option.quality > QUALITY_MAX || option.format.empty());
371 }
372 
373 uint32_t ImagePacker::DoEncodingFunc(std::function<uint32_t(ImagePlugin::AbsImageEncoder*)> func, bool forAll)
374 {
375     if (encoders_.size() == SIZE_ZERO) {
376         IMAGE_LOGE("DoEncodingFunc encoders is empty.");
377         return ERR_IMAGE_DECODE_ABNORMAL;
378     }
379     std::vector<uint32_t> rets;
380     rets.resize(SIZE_ZERO);
381     bool isSuccessOnce = false;
382     for (size_t i = SIZE_ZERO; i < encoders_.size(); i++) {
383         if (!forAll && isSuccessOnce) {
384             IMAGE_LOGD("DoEncodingFunc encoding successed, reset other encoder.");
385             encoders_.at(i).reset();
386             continue;
387         }
388         auto iterRes = func(encoders_.at(i).get());
389         rets.emplace_back(iterRes);
390         if (iterRes == SUCCESS) {
391             isSuccessOnce = true;
392         }
393         if (!forAll && !isSuccessOnce) {
394             IMAGE_LOGD("DoEncodingFunc failed.");
395         }
396     }
397     if (isSuccessOnce) {
398         return SUCCESS;
399     }
400     return (rets.size() == SIZE_ZERO)?ERR_IMAGE_DECODE_ABNORMAL:rets.front();
401 }
402 
403 // class reference need explicit constructor and destructor, otherwise unique_ptr<T> use unnormal
404 ImagePacker::ImagePacker()
405 {}
406 
407 ImagePacker::~ImagePacker()
408 {}
409 } // namespace Media
410 } // namespace OHOS
411