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_utils.h"
22 #include "log_tags.h"
23 #include "media_errors.h"
24 #include "ostream_packer_stream.h"
25 #include "plugin_server.h"
26 #if defined(A_PLATFORM) || defined(IOS_PLATFORM)
27 #include "include/jpeg_encoder.h"
28 #endif
29
30 namespace OHOS {
31 namespace Media {
32 using namespace OHOS::HiviewDFX;
33 using namespace ImagePlugin;
34 using namespace MultimediaPlugin;
35 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImagePacker" };
36 static constexpr uint8_t QUALITY_MAX = 100;
37 const static std::string EXTENDED_ENCODER = "image/extended";
38 static constexpr size_t SIZE_ZERO = 0;
39
40 PluginServer &ImagePacker::pluginServer_ = ImageUtils::GetPluginServer();
41
GetSupportedFormats(std::set<std::string> & formats)42 uint32_t ImagePacker::GetSupportedFormats(std::set<std::string> &formats)
43 {
44 formats.clear();
45 std::vector<ClassInfo> classInfos;
46 uint32_t ret =
47 pluginServer_.PluginServerGetClassInfo<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, classInfos);
48 if (ret != SUCCESS) {
49 HiLog::Error(LABEL, "get class info from plugin server,ret:%{public}u.", ret);
50 return ret;
51 }
52 for (auto &info : classInfos) {
53 std::map<std::string, AttrData> &capbility = info.capabilities;
54 auto iter = capbility.find(IMAGE_ENCODE_FORMAT);
55 if (iter == capbility.end()) {
56 continue;
57 }
58 AttrData &attr = iter->second;
59 std::string format;
60 if (attr.GetValue(format) != SUCCESS) {
61 HiLog::Error(LABEL, "attr data get format failed.");
62 continue;
63 }
64 formats.insert(format);
65 }
66 return SUCCESS;
67 }
68
StartPackingImpl(const PackOption & option)69 uint32_t ImagePacker::StartPackingImpl(const PackOption &option)
70 {
71 if (packerStream_ == nullptr || packerStream_.get() == nullptr) {
72 HiLog::Error(LABEL, "make buffer packer stream failed.");
73 return ERR_IMAGE_DATA_ABNORMAL;
74 }
75 if (!GetEncoderPlugin(option)) {
76 HiLog::Error(LABEL, "StartPackingImpl get encoder plugin failed.");
77 return ERR_IMAGE_MISMATCHED_FORMAT;
78 }
79 PlEncodeOptions plOpts;
80 CopyOptionsToPlugin(option, plOpts);
81 return DoEncodingFunc([this, &plOpts](ImagePlugin::AbsImageEncoder* encoder) {
82 return encoder->StartEncode(*packerStream_.get(), plOpts);
83 });
84 }
85
StartPacking(uint8_t * outputData,uint32_t maxSize,const PackOption & option)86 uint32_t ImagePacker::StartPacking(uint8_t *outputData, uint32_t maxSize, const PackOption &option)
87 {
88 if (!IsPackOptionValid(option)) {
89 HiLog::Error(LABEL, "array startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
90 option.quality);
91 return ERR_IMAGE_INVALID_PARAMETER;
92 }
93
94 if (outputData == nullptr) {
95 HiLog::Error(LABEL, "output buffer is null.");
96 return ERR_IMAGE_INVALID_PARAMETER;
97 }
98 BufferPackerStream *stream = new (std::nothrow) BufferPackerStream(outputData, maxSize);
99 if (stream == nullptr) {
100 HiLog::Error(LABEL, "make buffer packer stream failed.");
101 return ERR_IMAGE_DATA_ABNORMAL;
102 }
103 FreeOldPackerStream();
104 packerStream_ = std::unique_ptr<BufferPackerStream>(stream);
105 return StartPackingImpl(option);
106 }
107
StartPacking(const std::string & filePath,const PackOption & option)108 uint32_t ImagePacker::StartPacking(const std::string &filePath, const PackOption &option)
109 {
110 if (!IsPackOptionValid(option)) {
111 HiLog::Error(LABEL, "filepath startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
112 option.quality);
113 return ERR_IMAGE_INVALID_PARAMETER;
114 }
115 FilePackerStream *stream = new (std::nothrow) FilePackerStream(filePath);
116 if (stream == nullptr) {
117 HiLog::Error(LABEL, "make file packer stream failed.");
118 return ERR_IMAGE_DATA_ABNORMAL;
119 }
120 FreeOldPackerStream();
121 packerStream_ = std::unique_ptr<FilePackerStream>(stream);
122 return StartPackingImpl(option);
123 }
124
StartPacking(const int & fd,const PackOption & option)125 uint32_t ImagePacker::StartPacking(const int &fd, const PackOption &option)
126 {
127 if (!IsPackOptionValid(option)) {
128 HiLog::Error(LABEL, "fd startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
129 option.quality);
130 return ERR_IMAGE_INVALID_PARAMETER;
131 }
132 FilePackerStream *stream = new (std::nothrow) FilePackerStream(fd);
133 if (stream == nullptr) {
134 HiLog::Error(LABEL, "make file packer stream failed.");
135 return ERR_IMAGE_DATA_ABNORMAL;
136 }
137 FreeOldPackerStream();
138 packerStream_ = std::unique_ptr<FilePackerStream>(stream);
139 return StartPackingImpl(option);
140 }
141
StartPacking(std::ostream & outputStream,const PackOption & option)142 uint32_t ImagePacker::StartPacking(std::ostream &outputStream, const PackOption &option)
143 {
144 if (!IsPackOptionValid(option)) {
145 HiLog::Error(LABEL, "outputStream startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
146 option.quality);
147 return ERR_IMAGE_INVALID_PARAMETER;
148 }
149 OstreamPackerStream *stream = new (std::nothrow) OstreamPackerStream(outputStream);
150 if (stream == nullptr) {
151 HiLog::Error(LABEL, "make ostream packer stream failed.");
152 return ERR_IMAGE_DATA_ABNORMAL;
153 }
154 FreeOldPackerStream();
155 packerStream_ = std::unique_ptr<OstreamPackerStream>(stream);
156 return StartPackingImpl(option);
157 }
158
159 // JNI adapter method, this method be called by jni and the outputStream be created by jni, here we manage the lifecycle
160 // of the outputStream
StartPackingAdapter(PackerStream & outputStream,const PackOption & option)161 uint32_t ImagePacker::StartPackingAdapter(PackerStream &outputStream, const PackOption &option)
162 {
163 FreeOldPackerStream();
164 packerStream_ = std::unique_ptr<PackerStream>(&outputStream);
165
166 if (!IsPackOptionValid(option)) {
167 HiLog::Error(LABEL, "packer stream option invalid %{public}s, %{public}u.", option.format.c_str(),
168 option.quality);
169 return ERR_IMAGE_INVALID_PARAMETER;
170 }
171 return StartPackingImpl(option);
172 }
173
AddImage(PixelMap & pixelMap)174 uint32_t ImagePacker::AddImage(PixelMap &pixelMap)
175 {
176 return DoEncodingFunc([this, &pixelMap](ImagePlugin::AbsImageEncoder* encoder) {
177 return encoder->AddImage(pixelMap);
178 });
179 }
180
AddImage(ImageSource & source)181 uint32_t ImagePacker::AddImage(ImageSource &source)
182 {
183 DecodeOptions opts;
184 uint32_t ret = SUCCESS;
185 if (pixelMap_ != nullptr) {
186 pixelMap_.reset(); // release old inner pixelmap
187 }
188 pixelMap_ = source.CreatePixelMap(opts, ret);
189 if (ret != SUCCESS) {
190 HiLog::Error(LABEL, "image source create pixel map failed.");
191 return ret;
192 }
193 if (pixelMap_ == nullptr || pixelMap_.get() == nullptr) {
194 HiLog::Error(LABEL, "create the pixel map unique_ptr fail.");
195 return ERR_IMAGE_MALLOC_ABNORMAL;
196 }
197 return AddImage(*pixelMap_.get());
198 }
199
AddImage(ImageSource & source,uint32_t index)200 uint32_t ImagePacker::AddImage(ImageSource &source, uint32_t index)
201 {
202 DecodeOptions opts;
203 uint32_t ret = SUCCESS;
204 if (pixelMap_ != nullptr) {
205 pixelMap_.reset(); // release old inner pixelmap
206 }
207 pixelMap_ = source.CreatePixelMap(index, opts, ret);
208 if (ret != SUCCESS) {
209 HiLog::Error(LABEL, "image source create pixel map failed.");
210 return ret;
211 }
212 if (pixelMap_ == nullptr || pixelMap_.get() == nullptr) {
213 HiLog::Error(LABEL, "create the pixel map unique_ptr fail.");
214 return ERR_IMAGE_MALLOC_ABNORMAL;
215 }
216 return AddImage(*pixelMap_.get());
217 }
218
FinalizePacking()219 uint32_t ImagePacker::FinalizePacking()
220 {
221 return DoEncodingFunc([](ImagePlugin::AbsImageEncoder* encoder) {
222 auto res = encoder->FinalizeEncode();
223 if (res != SUCCESS) {
224 HiLog::Error(LABEL, "FinalizePacking failed %{public}d.", res);
225 }
226 return res;
227 }, false);
228 }
229
FinalizePacking(int64_t & packedSize)230 uint32_t ImagePacker::FinalizePacking(int64_t &packedSize)
231 {
232 uint32_t ret = FinalizePacking();
233 packedSize = (packerStream_ != nullptr) ? packerStream_->BytesWritten() : 0;
234 return ret;
235 }
236
GetEncoder(PluginServer & pluginServer,std::string format)237 static ImagePlugin::AbsImageEncoder* GetEncoder(PluginServer &pluginServer, std::string format)
238 {
239 std::map<std::string, AttrData> capabilities;
240 capabilities.insert(std::map<std::string, AttrData>::value_type(IMAGE_ENCODE_FORMAT, AttrData(format)));
241 return pluginServer.CreateObject<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, capabilities);
242 }
243
GetEncoderPlugin(const PackOption & option)244 bool ImagePacker::GetEncoderPlugin(const PackOption &option)
245 {
246 encoders_.clear();
247 HiLog::Debug(LABEL, "GetEncoderPlugin current encoder plugin size %{public}zu.", encoders_.size());
248 auto encoder = GetEncoder(pluginServer_, EXTENDED_ENCODER);
249 if (encoder != nullptr) {
250 encoders_.emplace_back(std::unique_ptr<ImagePlugin::AbsImageEncoder>(encoder));
251 } else {
252 HiLog::Error(LABEL, "GetEncoderPlugin get exencoder plugin failed.");
253 }
254 encoder = GetEncoder(pluginServer_, option.format);
255 if (encoder != nullptr) {
256 encoders_.emplace_back(std::unique_ptr<ImagePlugin::AbsImageEncoder>(encoder));
257 } else {
258 HiLog::Error(LABEL, "GetEncoderPlugin get %{publci}s plugin failed.", option.format.c_str());
259 }
260 return encoders_.size() != SIZE_ZERO;
261 }
262
CopyOptionsToPlugin(const PackOption & opts,PlEncodeOptions & plOpts)263 void ImagePacker::CopyOptionsToPlugin(const PackOption &opts, PlEncodeOptions &plOpts)
264 {
265 plOpts.numberHint = opts.numberHint;
266 plOpts.quality = opts.quality;
267 plOpts.format = opts.format;
268 }
269
FreeOldPackerStream()270 void ImagePacker::FreeOldPackerStream()
271 {
272 if (packerStream_ != nullptr) {
273 packerStream_.reset();
274 }
275 }
276
IsPackOptionValid(const PackOption & option)277 bool ImagePacker::IsPackOptionValid(const PackOption &option)
278 {
279 return !(option.quality > QUALITY_MAX || option.format.empty());
280 }
281
DoEncodingFunc(std::function<uint32_t (ImagePlugin::AbsImageEncoder *)> func,bool forAll)282 uint32_t ImagePacker::DoEncodingFunc(std::function<uint32_t(ImagePlugin::AbsImageEncoder*)> func, bool forAll)
283 {
284 if (encoders_.size() == SIZE_ZERO) {
285 HiLog::Error(LABEL, "DoEncodingFunc encoders is empty.");
286 return ERR_IMAGE_DECODE_ABNORMAL;
287 }
288 std::vector<uint32_t> rets;
289 rets.resize(SIZE_ZERO);
290 bool isSuccessOnce = false;
291 for (size_t i = SIZE_ZERO; i < encoders_.size(); i++) {
292 if (!forAll && isSuccessOnce) {
293 HiLog::Debug(LABEL, "DoEncodingFunc encoding successed, reset other encoder.");
294 encoders_.at(i).reset();
295 continue;
296 }
297 auto iterRes = func(encoders_.at(i).get());
298 rets.emplace_back(iterRes);
299 if (iterRes == SUCCESS) {
300 isSuccessOnce = true;
301 }
302 if (!forAll && !isSuccessOnce) {
303 HiLog::Debug(LABEL, "DoEncodingFunc failed.");
304 }
305 }
306 if (isSuccessOnce) {
307 return SUCCESS;
308 }
309 return (rets.size() == SIZE_ZERO)?ERR_IMAGE_DECODE_ABNORMAL:rets.front();
310 }
311
312 // class reference need explicit constructor and destructor, otherwise unique_ptr<T> use unnormal
ImagePacker()313 ImagePacker::ImagePacker()
314 {}
315
~ImagePacker()316 ImagePacker::~ImagePacker()
317 {}
318 } // namespace Media
319 } // namespace OHOS
320