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 "bmp_decoder.h"
17 #include "image_utils.h"
18 #include "media_errors.h"
19 #include "securec.h"
20 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
21 #include "surface_buffer.h"
22 #endif
23
24 namespace OHOS {
25 namespace ImagePlugin {
26 using namespace OHOS::HiviewDFX;
27 using namespace Media;
28 using namespace std;
29 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "BmpDecoder" };
30 namespace {
31 constexpr uint32_t BMP_IMAGE_NUM = 1;
32 }
33
SetSource(InputDataStream & sourceStream)34 void BmpDecoder::SetSource(InputDataStream &sourceStream)
35 {
36 stream_ = &sourceStream;
37 state_ = BmpDecodingState::SOURCE_INITED;
38 }
39
Reset()40 void BmpDecoder::Reset()
41 {
42 if (stream_ != nullptr) {
43 stream_->Seek(0);
44 }
45 codec_.release();
46 info_.reset();
47 desireColor_ = kUnknown_SkColorType;
48 }
49
GetImageSize(uint32_t index,PlSize & size)50 uint32_t BmpDecoder::GetImageSize(uint32_t index, PlSize &size)
51 {
52 if (index >= BMP_IMAGE_NUM) {
53 HiLog::Error(LABEL, "GetImageSize failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM);
54 return ERR_IMAGE_INVALID_PARAMETER;
55 }
56 if (state_ < BmpDecodingState::SOURCE_INITED) {
57 HiLog::Error(LABEL, "GetImageSize failed, invalid state:%{public}d", state_);
58 return ERR_MEDIA_INVALID_OPERATION;
59 }
60 if (state_ >= BmpDecodingState::BASE_INFO_PARSED) {
61 size.width = info_.width();
62 size.height = info_.height();
63 return SUCCESS;
64 }
65 if (!DecodeHeader()) {
66 HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_);
67 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
68 }
69 size.width = info_.width();
70 size.height = info_.height();
71 state_ = BmpDecodingState::BASE_INFO_PARSED;
72 return SUCCESS;
73 }
74
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)75 uint32_t BmpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
76 {
77 if (index >= BMP_IMAGE_NUM) {
78 HiLog::Error(LABEL, "SetDecodeOptions failed, invalid index:%{public}u, range:%{public}u", index,
79 BMP_IMAGE_NUM);
80 return ERR_IMAGE_INVALID_PARAMETER;
81 }
82 if (state_ < BmpDecodingState::SOURCE_INITED) {
83 HiLog::Error(LABEL, "SetDecodeOptions failed, invalid state %{public}d", state_);
84 return ERR_MEDIA_INVALID_OPERATION;
85 }
86 if (state_ >= BmpDecodingState::IMAGE_DECODING) {
87 Reset();
88 state_ = BmpDecodingState::SOURCE_INITED;
89 }
90 if (state_ < BmpDecodingState::BASE_INFO_PARSED) {
91 if (!DecodeHeader()) {
92 HiLog::Error(LABEL, "GetImageSize failed, decode header failed, state=%{public}d", state_);
93 return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
94 }
95 state_ = BmpDecodingState::BASE_INFO_PARSED;
96 }
97 PlPixelFormat desiredFormat = opts.desiredPixelFormat;
98 desireColor_ = ConvertToColorType(desiredFormat, info.pixelFormat);
99 info.size.width = info_.width();
100 info.size.height = info_.height();
101 info.alphaType = ConvertToAlphaType(info_.alphaType());
102 state_ = BmpDecodingState::IMAGE_DECODING;
103 return SUCCESS;
104 }
105
SetShareMemBuffer(uint64_t byteCount,DecodeContext & context)106 uint32_t BmpDecoder::SetShareMemBuffer(uint64_t byteCount, DecodeContext &context)
107 {
108 #if !defined(_WIN32) && !defined(_APPLE) && !defined(A_PLATFORM) && !defined(IOS_PLATFORM)
109 uint32_t id = context.pixelmapUniqueId_;
110 std::string name = "BMP RawData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(id);
111 int fd = AshmemCreate(name.c_str(), byteCount);
112 if (fd < 0) {
113 return ERR_SHAMEM_DATA_ABNORMAL;
114 }
115 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
116 if (result < 0) {
117 ::close(fd);
118 return ERR_SHAMEM_DATA_ABNORMAL;
119 }
120 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
121 if (ptr == MAP_FAILED) {
122 ::close(fd);
123 return ERR_SHAMEM_DATA_ABNORMAL;
124 }
125 context.pixelsBuffer.buffer = ptr;
126 void *fdBuffer = new int32_t();
127 if (fdBuffer == nullptr) {
128 ::munmap(ptr, byteCount);
129 ::close(fd);
130 context.pixelsBuffer.buffer = nullptr;
131 return ERR_SHAMEM_DATA_ABNORMAL;
132 }
133 *static_cast<int32_t *>(fdBuffer) = fd;
134 context.pixelsBuffer.context = fdBuffer;
135 context.pixelsBuffer.bufferSize = byteCount;
136 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
137 context.freeFunc = nullptr;
138 #endif
139 return SUCCESS;
140 }
141
DmaMemAlloc(uint64_t count,DecodeContext & context,SkImageInfo & dstInfo)142 static uint32_t DmaMemAlloc(uint64_t count, DecodeContext &context, SkImageInfo &dstInfo)
143 {
144 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
145 HiLog::Error(LABEL, "Unsupport dma mem alloc");
146 return ERR_IMAGE_DATA_UNSUPPORT;
147 #else
148 sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
149 BufferRequestConfig requestConfig = {
150 .width = dstInfo.width(),
151 .height = dstInfo.height(),
152 .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
153 .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
154 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
155 .timeout = 0,
156 .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
157 .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
158 };
159 GSError ret = sb->Alloc(requestConfig);
160 if (ret != GSERROR_OK) {
161 HiLog::Error(LABEL, "SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
162 return ERR_DMA_NOT_EXIST;
163 }
164 void* nativeBuffer = sb.GetRefPtr();
165 int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
166 if (err != OHOS::GSERROR_OK) {
167 HiLog::Error(LABEL, "NativeBufferReference failed");
168 return ERR_DMA_DATA_ABNORMAL;
169 }
170 context.pixelsBuffer.buffer = static_cast<uint8_t*>(sb->GetVirAddr());
171 context.pixelsBuffer.bufferSize = count;
172 context.pixelsBuffer.context = nativeBuffer;
173 context.allocatorType = AllocatorType::DMA_ALLOC;
174 context.freeFunc = nullptr;
175 return SUCCESS;
176 #endif
177 }
178
SetBuffer(uint64_t byteCount,DecodeContext & context)179 uint32_t SetBuffer(uint64_t byteCount, DecodeContext &context)
180 {
181 #if !defined(_WIN32) && !defined(_APPLE) && !defined(A_PLATFORM) && !defined(IOS_PLATFORM)
182 if (byteCount <= 0) {
183 HiLog::Error(LABEL, "Decode failed, byteCount is invalid value");
184 return ERR_MEDIA_INVALID_VALUE;
185 }
186 void *outputBuffer = malloc(byteCount);
187 if (outputBuffer == nullptr) {
188 HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error",
189 static_cast<unsigned long long>(byteCount));
190 return ERR_IMAGE_MALLOC_ABNORMAL;
191 }
192 #ifdef _WIN32
193 if (memset_s(outputBuffer, 0, byteCount) != EOK) {
194 HiLog::Error(LABEL, "Decode failed, memset buffer failed", backRet);
195 free(outputBuffer);
196 outputBuffer = nullptr;
197 return ERR_IMAGE_DECODE_FAILED;
198 }
199 #else
200 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
201 HiLog::Error(LABEL, "Decode failed, memset buffer failed");
202 free(outputBuffer);
203 outputBuffer = nullptr;
204 return ERR_IMAGE_DECODE_FAILED;
205 }
206 #endif
207 context.pixelsBuffer.buffer = outputBuffer;
208 context.pixelsBuffer.bufferSize = byteCount;
209 context.pixelsBuffer.context = nullptr;
210 context.allocatorType = AllocatorType::HEAP_ALLOC;
211 context.freeFunc = nullptr;
212 context.freeFunc = nullptr;
213 #endif
214 return SUCCESS;
215 }
216
SetBufferForPlatform(uint64_t byteCount,DecodeContext & context)217 uint32_t SetBufferForPlatform(uint64_t byteCount, DecodeContext &context)
218 {
219 if (byteCount <= 0) {
220 HiLog::Error(LABEL, "Decode failed, byteCount is invalid value");
221 return ERR_MEDIA_INVALID_VALUE;
222 }
223 void *outputBuffer = malloc(byteCount);
224 if (outputBuffer == nullptr) {
225 HiLog::Error(LABEL, "Decode failed, alloc output buffer size:[%{public}llu] error",
226 static_cast<unsigned long long>(byteCount));
227 return ERR_IMAGE_MALLOC_ABNORMAL;
228 }
229 #ifdef _WIN32
230 if (memset_s(outputBuffer, 0, byteCount) != EOK) {
231 HiLog::Error(LABEL, "Decode failed, memset buffer failed", backRet);
232 free(outputBuffer);
233 outputBuffer = nullptr;
234 return ERR_IMAGE_DECODE_FAILED;
235 }
236 #else
237 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
238 HiLog::Error(LABEL, "Decode failed, memset buffer failed");
239 free(outputBuffer);
240 outputBuffer = nullptr;
241 return ERR_IMAGE_DECODE_FAILED;
242 }
243 #endif
244 context.pixelsBuffer.buffer = outputBuffer;
245 context.pixelsBuffer.bufferSize = byteCount;
246 context.pixelsBuffer.context = nullptr;
247 context.allocatorType = AllocatorType::HEAP_ALLOC;
248 context.freeFunc = nullptr;
249 return SUCCESS;
250 }
251
SetContextPixelsBuffer(uint64_t byteCount,DecodeContext & context,SkImageInfo & dstInfo)252 uint32_t BmpDecoder::SetContextPixelsBuffer(uint64_t byteCount, DecodeContext &context, SkImageInfo &dstInfo)
253 {
254 #if !defined(_WIN32) && !defined(_APPLE) && !defined(A_PLATFORM) && !defined(IOS_PLATFORM)
255 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
256 uint32_t res = SetShareMemBuffer(byteCount, context);
257 if (res != SUCCESS) {
258 return res;
259 }
260 } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
261 uint32_t res = DmaMemAlloc(byteCount, context, dstInfo);
262 if (res != SUCCESS) {
263 return res;
264 }
265 } else {
266 uint32_t res = SetBuffer(byteCount, context);
267 if (res != SUCCESS) {
268 return res;
269 }
270 }
271 #else
272 uint32_t res = SetBufferForPlatform(byteCount, context);
273 if (res != SUCCESS) {
274 return res;
275 }
276 #endif
277 return SUCCESS;
278 }
279
Decode(uint32_t index,DecodeContext & context)280 uint32_t BmpDecoder::Decode(uint32_t index, DecodeContext &context)
281 {
282 if (index >= BMP_IMAGE_NUM) {
283 HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}u", index, BMP_IMAGE_NUM);
284 return ERR_IMAGE_INVALID_PARAMETER;
285 }
286 if (codec_ == nullptr) {
287 HiLog::Error(LABEL, "Decode failed, codec is null");
288 return ERR_IMAGE_DECODE_FAILED;
289 }
290 if (state_ != BmpDecodingState::IMAGE_DECODING) {
291 HiLog::Error(LABEL, "Decode failed, invalid state %{public}d", state_);
292 return ERR_MEDIA_INVALID_OPERATION;
293 }
294
295 SkImageInfo dstInfo = info_.makeColorType(desireColor_);
296 if (ImageUtils::CheckMulOverflow(dstInfo.width(), dstInfo.height(), dstInfo.bytesPerPixel())) {
297 HiLog::Error(LABEL, "Decode failed, width:%{public}d, height:%{public}d is too large",
298 dstInfo.width(), dstInfo.height());
299 return ERR_IMAGE_DECODE_FAILED;
300 }
301 if (context.pixelsBuffer.buffer == nullptr) {
302 uint64_t byteCount = static_cast<uint64_t>(dstInfo.height()) * dstInfo.width() * dstInfo.bytesPerPixel();
303 uint32_t res = SetContextPixelsBuffer(byteCount, context, dstInfo);
304 if (res != SUCCESS) {
305 return res;
306 }
307 }
308 uint8_t *dstBuffer = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
309 size_t rowBytes = dstInfo.width() * dstInfo.bytesPerPixel();
310 SkCodec::Result ret = codec_->getPixels(dstInfo, dstBuffer, rowBytes);
311 if (ret != SkCodec::kSuccess) {
312 HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret);
313 state_ = BmpDecodingState::IMAGE_ERROR;
314 return ERR_IMAGE_DECODE_ABNORMAL;
315 }
316 state_ = BmpDecodingState::IMAGE_DECODED;
317 return SUCCESS;
318 }
319
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)320 uint32_t BmpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
321 {
322 // currently not support increment decode
323 return ERR_IMAGE_DATA_UNSUPPORT;
324 }
325
DecodeHeader()326 bool BmpDecoder::DecodeHeader()
327 {
328 codec_ = SkCodec::MakeFromStream(make_unique<BmpStream>(stream_));
329 if (codec_ == nullptr) {
330 HiLog::Error(LABEL, "create codec from stream failed");
331 return false;
332 }
333 info_ = codec_->getInfo();
334 return true;
335 }
336
ConvertToAlphaType(SkAlphaType alphaType)337 PlAlphaType BmpDecoder::ConvertToAlphaType(SkAlphaType alphaType)
338 {
339 switch (alphaType) {
340 case kOpaque_SkAlphaType:
341 return PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
342 case kPremul_SkAlphaType:
343 return PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL;
344 case kUnpremul_SkAlphaType:
345 return PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
346 default:
347 HiLog::Error(LABEL, "known alpha type:%{public}d", alphaType);
348 break;
349 }
350 return PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
351 }
352
ConvertToColorType(PlPixelFormat format,PlPixelFormat & outputFormat)353 SkColorType BmpDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat)
354 {
355 switch (format) {
356 case PlPixelFormat::UNKNOWN:
357 case PlPixelFormat::RGBA_8888: {
358 outputFormat = PlPixelFormat::RGBA_8888;
359 return kRGBA_8888_SkColorType;
360 }
361 case PlPixelFormat::BGRA_8888: {
362 outputFormat = PlPixelFormat::BGRA_8888;
363 return kBGRA_8888_SkColorType;
364 }
365 case PlPixelFormat::ALPHA_8: {
366 SkColorType colorType = info_.colorType();
367 if (colorType == kAlpha_8_SkColorType || (colorType == kGray_8_SkColorType && info_.isOpaque())) {
368 outputFormat = PlPixelFormat::ALPHA_8;
369 return kAlpha_8_SkColorType;
370 }
371 break;
372 }
373 case PlPixelFormat::RGB_565: {
374 if (info_.isOpaque()) {
375 outputFormat = PlPixelFormat::RGB_565;
376 return kRGB_565_SkColorType;
377 }
378 break;
379 }
380 default: {
381 break;
382 }
383 }
384 HiLog::Debug(LABEL, "unsupported convert to format:%{public}d, set default RGBA", format);
385 outputFormat = PlPixelFormat::RGBA_8888;
386 return kRGBA_8888_SkColorType;
387 }
388 } // namespace ImagePlugin
389 } // namespace OHOS
390