1 /*
2 * Copyright (C) 2021 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
27 namespace OHOS {
28 namespace Media {
29 using namespace OHOS::HiviewDFX;
30 using namespace ImagePlugin;
31 using namespace MultimediaPlugin;
32 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_IMAGE, "ImagePacker" };
33 static constexpr uint8_t QUALITY_MAX = 100;
34
35 PluginServer &ImagePacker::pluginServer_ = ImageUtils::GetPluginServer();
36
GetSupportedFormats(std::set<std::string> & formats)37 uint32_t ImagePacker::GetSupportedFormats(std::set<std::string> &formats)
38 {
39 formats.clear();
40 std::vector<ClassInfo> classInfos;
41 uint32_t ret =
42 pluginServer_.PluginServerGetClassInfo<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, classInfos);
43 if (ret != SUCCESS) {
44 HiLog::Error(LABEL, "get class info from plugin server,ret:%{public}u.", ret);
45 return ret;
46 }
47 for (auto &info : classInfos) {
48 std::map<std::string, AttrData> &capbility = info.capabilities;
49 auto iter = capbility.find(IMAGE_ENCODE_FORMAT);
50 if (iter == capbility.end()) {
51 continue;
52 }
53 AttrData &attr = iter->second;
54 std::string format;
55 if (attr.GetValue(format) != SUCCESS) {
56 HiLog::Error(LABEL, "attr data get format failed.");
57 continue;
58 }
59 formats.insert(format);
60 }
61 return SUCCESS;
62 }
63
StartPackingImpl(const PackOption & option)64 uint32_t ImagePacker::StartPackingImpl(const PackOption &option)
65 {
66 if (!GetEncoderPlugin(option)) {
67 HiLog::Error(LABEL, "StartPackingImpl get encoder plugin failed.");
68 return ERR_IMAGE_MISMATCHED_FORMAT;
69 }
70 PlEncodeOptions plOpts;
71 CopyOptionsToPlugin(option, plOpts);
72 return encoder_->StartEncode(*packerStream_.get(), plOpts);
73 }
74
StartPacking(uint8_t * outputData,uint32_t maxSize,const PackOption & option)75 uint32_t ImagePacker::StartPacking(uint8_t *outputData, uint32_t maxSize, const PackOption &option)
76 {
77 if (!IsPackOptionValid(option)) {
78 HiLog::Error(LABEL, "array startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
79 option.quality);
80 return ERR_IMAGE_INVALID_PARAMETER;
81 }
82
83 if (outputData == nullptr) {
84 HiLog::Error(LABEL, "output buffer is null.");
85 return ERR_IMAGE_INVALID_PARAMETER;
86 }
87 BufferPackerStream *stream = new (std::nothrow) BufferPackerStream(outputData, maxSize);
88 if (stream == nullptr) {
89 HiLog::Error(LABEL, "make buffer packer stream failed.");
90 return ERR_IMAGE_DATA_ABNORMAL;
91 }
92 FreeOldPackerStream();
93 packerStream_ = std::unique_ptr<BufferPackerStream>(stream);
94 return StartPackingImpl(option);
95 }
96
StartPacking(const std::string & filePath,const PackOption & option)97 uint32_t ImagePacker::StartPacking(const std::string &filePath, const PackOption &option)
98 {
99 if (!IsPackOptionValid(option)) {
100 HiLog::Error(LABEL, "filepath startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
101 option.quality);
102 return ERR_IMAGE_INVALID_PARAMETER;
103 }
104 FilePackerStream *stream = new (std::nothrow) FilePackerStream(filePath);
105 if (stream == nullptr) {
106 HiLog::Error(LABEL, "make file packer stream failed.");
107 return ERR_IMAGE_DATA_ABNORMAL;
108 }
109 FreeOldPackerStream();
110 packerStream_ = std::unique_ptr<FilePackerStream>(stream);
111 return StartPackingImpl(option);
112 }
113
StartPacking(const int & fd,const PackOption & option)114 uint32_t ImagePacker::StartPacking(const int &fd, const PackOption &option)
115 {
116 if (!IsPackOptionValid(option)) {
117 HiLog::Error(LABEL, "fd startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
118 option.quality);
119 return ERR_IMAGE_INVALID_PARAMETER;
120 }
121 FilePackerStream *stream = new (std::nothrow) FilePackerStream(fd);
122 if (stream == nullptr) {
123 HiLog::Error(LABEL, "make file packer stream failed.");
124 return ERR_IMAGE_DATA_ABNORMAL;
125 }
126 FreeOldPackerStream();
127 packerStream_ = std::unique_ptr<FilePackerStream>(stream);
128 return StartPackingImpl(option);
129 }
130
StartPacking(std::ostream & outputStream,const PackOption & option)131 uint32_t ImagePacker::StartPacking(std::ostream &outputStream, const PackOption &option)
132 {
133 if (!IsPackOptionValid(option)) {
134 HiLog::Error(LABEL, "outputStream startPacking option invalid %{public}s, %{public}u.", option.format.c_str(),
135 option.quality);
136 return ERR_IMAGE_INVALID_PARAMETER;
137 }
138 OstreamPackerStream *stream = new (std::nothrow) OstreamPackerStream(outputStream);
139 if (stream == nullptr) {
140 HiLog::Error(LABEL, "make ostream packer stream failed.");
141 return ERR_IMAGE_DATA_ABNORMAL;
142 }
143 FreeOldPackerStream();
144 packerStream_ = std::unique_ptr<OstreamPackerStream>(stream);
145 return StartPackingImpl(option);
146 }
147
148 // JNI adapter method, this method be called by jni and the outputStream be created by jni, here we manage the lifecycle
149 // of the outputStream
StartPackingAdapter(PackerStream & outputStream,const PackOption & option)150 uint32_t ImagePacker::StartPackingAdapter(PackerStream &outputStream, const PackOption &option)
151 {
152 FreeOldPackerStream();
153 packerStream_ = std::unique_ptr<PackerStream>(&outputStream);
154
155 if (!IsPackOptionValid(option)) {
156 HiLog::Error(LABEL, "packer stream option invalid %{public}s, %{public}u.", option.format.c_str(),
157 option.quality);
158 return ERR_IMAGE_INVALID_PARAMETER;
159 }
160 return StartPackingImpl(option);
161 }
162
AddImage(PixelMap & pixelMap)163 uint32_t ImagePacker::AddImage(PixelMap &pixelMap)
164 {
165 if (encoder_ == nullptr) {
166 HiLog::Error(LABEL, "AddImage get encoder plugin failed.");
167 return ERR_IMAGE_MISMATCHED_FORMAT;
168 }
169 return encoder_->AddImage(pixelMap);
170 }
171
AddImage(ImageSource & source)172 uint32_t ImagePacker::AddImage(ImageSource &source)
173 {
174 DecodeOptions opts;
175 uint32_t ret = SUCCESS;
176 if (pixelMap_ != nullptr) {
177 pixelMap_.reset(); // release old inner pixelmap
178 }
179 pixelMap_ = source.CreatePixelMap(opts, ret);
180 if (ret != SUCCESS) {
181 HiLog::Error(LABEL, "image source create pixel map failed.");
182 return ret;
183 }
184 return AddImage(*pixelMap_.get());
185 }
186
AddImage(ImageSource & source,uint32_t index)187 uint32_t ImagePacker::AddImage(ImageSource &source, uint32_t index)
188 {
189 DecodeOptions opts;
190 uint32_t ret = SUCCESS;
191 if (pixelMap_ != nullptr) {
192 pixelMap_.reset(); // release old inner pixelmap
193 }
194 pixelMap_ = source.CreatePixelMap(index, opts, ret);
195 if (ret != SUCCESS) {
196 HiLog::Error(LABEL, "image source create pixel map failed.");
197 return ret;
198 }
199 return AddImage(*pixelMap_.get());
200 }
201
FinalizePacking()202 uint32_t ImagePacker::FinalizePacking()
203 {
204 if (encoder_ == nullptr) {
205 HiLog::Error(LABEL, "FinalizePacking get encoder plugin failed.");
206 return ERR_IMAGE_MISMATCHED_FORMAT;
207 }
208 return encoder_->FinalizeEncode();
209 }
210
FinalizePacking(int64_t & packedSize)211 uint32_t ImagePacker::FinalizePacking(int64_t &packedSize)
212 {
213 uint32_t ret = FinalizePacking();
214 packedSize = (packerStream_ != nullptr) ? packerStream_->BytesWritten() : 0;
215 return ret;
216 }
217
GetEncoderPlugin(const PackOption & option)218 bool ImagePacker::GetEncoderPlugin(const PackOption &option)
219 {
220 std::map<std::string, AttrData> capabilities;
221 capabilities.insert(std::map<std::string, AttrData>::value_type(IMAGE_ENCODE_FORMAT, AttrData(option.format)));
222 if (encoder_ != nullptr) {
223 encoder_.reset();
224 }
225 encoder_ = std::unique_ptr<ImagePlugin::AbsImageEncoder>(
226 pluginServer_.CreateObject<AbsImageEncoder>(AbsImageEncoder::SERVICE_DEFAULT, capabilities));
227 return (encoder_ != nullptr);
228 }
229
CopyOptionsToPlugin(const PackOption & opts,PlEncodeOptions & plOpts)230 void ImagePacker::CopyOptionsToPlugin(const PackOption &opts, PlEncodeOptions &plOpts)
231 {
232 plOpts.numberHint = opts.numberHint;
233 plOpts.quality = opts.quality;
234 }
235
FreeOldPackerStream()236 void ImagePacker::FreeOldPackerStream()
237 {
238 if (packerStream_ != nullptr) {
239 packerStream_.reset();
240 }
241 }
242
IsPackOptionValid(const PackOption & option)243 bool ImagePacker::IsPackOptionValid(const PackOption &option)
244 {
245 if (option.quality > QUALITY_MAX || option.format.empty()) {
246 return false;
247 }
248 return true;
249 }
250
251 // class reference need explicit constructor and destructor, otherwise unique_ptr<T> use unnormal
ImagePacker()252 ImagePacker::ImagePacker()
253 {}
254
~ImagePacker()255 ImagePacker::~ImagePacker()
256 {}
257 } // namespace Media
258 } // namespace OHOS