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