• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "webp_decoder.h"
17 
18 #include "image_utils.h"
19 #include "media_errors.h"
20 #include "multimedia_templates.h"
21 #include "securec.h"
22 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
23 #include "surface_buffer.h"
24 #endif
25 
26 namespace OHOS {
27 namespace ImagePlugin {
28 using namespace OHOS::HiviewDFX;
29 using namespace MultimediaPlugin;
30 using namespace Media;
31 using namespace MultiMedia;
32 
33 namespace {
34 constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "WebpDecoder" };
35 constexpr int32_t WEBP_IMAGE_NUM = 1;
36 constexpr int32_t EXTERNAL_MEMORY = 1;
37 constexpr size_t DECODE_VP8CHUNK_MIN_SIZE = 4096;
38 } // namespace
39 
WebpDecoder()40 WebpDecoder::WebpDecoder()
41 {}
42 
~WebpDecoder()43 WebpDecoder::~WebpDecoder()
44 {
45     Reset();
46 }
47 
SetSource(InputDataStream & sourceStream)48 void WebpDecoder::SetSource(InputDataStream &sourceStream)
49 {
50     stream_ = &sourceStream;
51     state_ = WebpDecodingState::SOURCE_INITED;
52 }
53 
GetImageSize(uint32_t index,PlSize & size)54 uint32_t WebpDecoder::GetImageSize(uint32_t index, PlSize &size)
55 {
56     if (index >= WEBP_IMAGE_NUM) {
57         HiLog::Error(LABEL, "image size:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM);
58         return ERR_IMAGE_INVALID_PARAMETER;
59     }
60     if (state_ < WebpDecodingState::SOURCE_INITED) {
61         HiLog::Error(LABEL, "get image size failed for state %{public}d.", state_);
62         return ERR_MEDIA_INVALID_OPERATION;
63     }
64     if (state_ >= WebpDecodingState::BASE_INFO_PARSED) {
65         size = webpSize_;
66         return SUCCESS;
67     }
68 
69     uint32_t ret = DecodeHeader();
70     if (ret != SUCCESS) {
71         HiLog::Debug(LABEL, "decode header error on get image ret:%{public}u.", ret);
72         return ret;
73     }
74     size = webpSize_;
75     return SUCCESS;
76 }
77 
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)78 uint32_t WebpDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
79 {
80     if (index >= WEBP_IMAGE_NUM) {
81         HiLog::Error(LABEL, "set option:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM);
82         return ERR_IMAGE_INVALID_PARAMETER;
83     }
84     if (state_ < WebpDecodingState::SOURCE_INITED) {
85         HiLog::Error(LABEL, "set decode option failed for state %{public}d.", state_);
86         return ERR_MEDIA_INVALID_OPERATION;
87     }
88     if (state_ >= WebpDecodingState::IMAGE_DECODING) {
89         FinishOldDecompress();
90         state_ = WebpDecodingState::SOURCE_INITED;
91     }
92     if (state_ < WebpDecodingState::BASE_INFO_PARSED) {
93         uint32_t ret = DecodeHeader();
94         if (ret != SUCCESS) {
95             HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret);
96             state_ = WebpDecodingState::BASE_INFO_PARSING;
97             return ret;
98         }
99         state_ = WebpDecodingState::BASE_INFO_PARSED;
100     }
101 
102     bool hasAlpha = true;
103     if (opts.desiredPixelFormat == PlPixelFormat::RGB_565) {
104         hasAlpha = false;
105         info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
106     } else {
107         info.alphaType = opts.desireAlphaType;
108     }
109     webpMode_ = GetWebpDecodeMode(opts.desiredPixelFormat,
110                                   hasAlpha && (opts.desireAlphaType == PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL));
111     info.size = webpSize_;
112     info.pixelFormat = outputFormat_;
113     opts_ = opts;
114 
115     state_ = WebpDecodingState::IMAGE_DECODING;
116     return SUCCESS;
117 }
118 
Decode(uint32_t index,DecodeContext & context)119 uint32_t WebpDecoder::Decode(uint32_t index, DecodeContext &context)
120 {
121 #if defined(A_PLATFORM) || defined(IOS_PLATFORM)
122     context.allocatorType = Media::AllocatorType::HEAP_ALLOC;
123 #endif
124     if (index >= WEBP_IMAGE_NUM) {
125         HiLog::Error(LABEL, "decode:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM);
126         return ERR_IMAGE_INVALID_PARAMETER;
127     }
128     if (state_ < WebpDecodingState::IMAGE_DECODING) {
129         HiLog::Error(LABEL, "set decode option failed for state %{public}d.", state_);
130         return ERR_MEDIA_INVALID_OPERATION;
131     }
132     if (state_ > WebpDecodingState::IMAGE_DECODING) {
133         FinishOldDecompress();
134         uint32_t ret = DecodeHeader();
135         if (ret != SUCCESS) {
136             HiLog::Error(LABEL, "decode header error on set decode options:%{public}u.", ret);
137             state_ = WebpDecodingState::BASE_INFO_PARSING;
138             return ret;
139         }
140         bool hasAlpha = true;
141         if (opts_.desiredPixelFormat == PlPixelFormat::RGB_565) {
142             hasAlpha = false;
143         }
144         webpMode_ =
145             GetWebpDecodeMode(opts_.desiredPixelFormat,
146                               hasAlpha && opts_.desireAlphaType == PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL);
147         state_ = WebpDecodingState::IMAGE_DECODING;
148     }
149 
150     return DoCommonDecode(context);
151 }
152 
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)153 uint32_t WebpDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
154 {
155     context.totalProcessProgress = 0;
156     if (index >= WEBP_IMAGE_NUM) {
157         HiLog::Error(LABEL, "incremental:invalid index, index:%{public}u, range:%{public}u.", index, WEBP_IMAGE_NUM);
158         return ERR_IMAGE_INVALID_PARAMETER;
159     }
160 
161     if (state_ != WebpDecodingState::IMAGE_DECODING) {
162         HiLog::Error(LABEL, "incremental decode failed for state %{public}d.", state_);
163         return ERR_MEDIA_INVALID_OPERATION;
164     }
165 
166     if (!IsDataEnough()) {
167         HiLog::Debug(LABEL, "increment data not enough, need next data.");
168         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
169     }
170     return DoIncrementalDecode(context);
171 }
172 
DecodeHeader()173 uint32_t WebpDecoder::DecodeHeader()
174 {
175     uint32_t ret = ReadIncrementalHead();
176     if (ret != SUCCESS) {
177         if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) {
178             state_ = WebpDecodingState::BASE_INFO_PARSING;
179         } else {
180             state_ = WebpDecodingState::SOURCE_INITED;
181             HiLog::Error(LABEL, "decode image head, ret:%{public}u.", ret);
182         }
183         return ret;
184     }
185     state_ = WebpDecodingState::BASE_INFO_PARSED;
186     return SUCCESS;
187 }
188 
ReadIncrementalHead()189 uint32_t WebpDecoder::ReadIncrementalHead()
190 {
191     size_t stremSize = stream_->GetStreamSize();
192     if (stremSize >= DECODE_VP8CHUNK_MIN_SIZE || stream_->IsStreamCompleted()) {
193         stream_->Seek(0);
194         if (!stream_->Read(stream_->GetStreamSize(), dataBuffer_)) {
195             HiLog::Error(LABEL, "read data fail.");
196             return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
197         }
198         if (dataBuffer_.inputStreamBuffer == nullptr || dataBuffer_.dataSize == 0) {
199             HiLog::Error(LABEL, "inputStreamBuffer is null or data size is %{public}u.", dataBuffer_.dataSize);
200             return ERR_IMAGE_GET_DATA_ABNORMAL;
201         }
202 
203         int32_t width = 0;
204         int32_t height = 0;
205         int32_t ret = WebPGetInfo(dataBuffer_.inputStreamBuffer, dataBuffer_.bufferSize, &width, &height);
206         if (ret == 0 || (width == 0 && height == 0)) {
207             // may be incomplete data
208             HiLog::Error(LABEL, "get width and height fail.");
209             return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
210         }
211 
212         if (width < 0 || height < 0) {
213             HiLog::Error(LABEL, "width and height invalid, width:%{public}d, height:%{public}d.", width, height);
214             return ERR_IMAGE_INVALID_PARAMETER;
215         }
216         webpSize_.width = static_cast<uint32_t>(width);
217         webpSize_.height = static_cast<uint32_t>(height);
218         incrementSize_ = stremSize;
219         lastDecodeSize_ = stremSize;
220         return SUCCESS;
221     }
222 
223     return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
224 }
225 
IsDataEnough()226 bool WebpDecoder::IsDataEnough()
227 {
228     size_t streamSize = stream_->GetStreamSize();
229     if (incrementSize_ < DECODE_VP8CHUNK_MIN_SIZE && !stream_->IsStreamCompleted()) {
230         incrementSize_ += streamSize - lastDecodeSize_;
231         lastDecodeSize_ = streamSize;
232         return false;
233     }
234     incrementSize_ = streamSize - lastDecodeSize_;
235     lastDecodeSize_ = streamSize;
236     return true;
237 }
238 
GetWebpDecodeMode(const PlPixelFormat & pixelFormat,bool premul)239 WEBP_CSP_MODE WebpDecoder::GetWebpDecodeMode(const PlPixelFormat &pixelFormat, bool premul)
240 {
241     WEBP_CSP_MODE webpMode = MODE_RGBA;
242     outputFormat_ = pixelFormat;
243     switch (pixelFormat) {
244         case PlPixelFormat::BGRA_8888:
245             webpMode = premul ? MODE_bgrA : MODE_BGRA;
246             break;
247         case PlPixelFormat::RGBA_8888:
248             webpMode = premul ? MODE_rgbA : MODE_RGBA;
249             break;
250         case PlPixelFormat::RGB_565:
251             bytesPerPixel_ = 2;  // RGB_565 2 bytes each pixel
252             webpMode = MODE_RGB_565;
253             break;
254         case PlPixelFormat::UNKNOWN:
255         default:
256             outputFormat_ = PlPixelFormat::RGBA_8888;
257             webpMode = premul ? MODE_rgbA : MODE_RGBA;
258             break;
259     }
260     return webpMode;
261 }
262 
FinishOldDecompress()263 void WebpDecoder::FinishOldDecompress()
264 {
265     if (state_ < WebpDecodingState::IMAGE_DECODING) {
266         return;
267     }
268     Reset();
269 }
270 
DoCommonDecode(DecodeContext & context)271 uint32_t WebpDecoder::DoCommonDecode(DecodeContext &context)
272 {
273     WebPDecoderConfig config;
274     if (!PreDecodeProc(context, config, false)) {
275         HiLog::Error(LABEL, "prepare common decode failed.");
276         state_ = WebpDecodingState::IMAGE_ERROR;
277         return ERR_IMAGE_MALLOC_ABNORMAL;
278     }
279 
280     TAutoCallProc<WebPDecBuffer, WebPFreeDecBuffer> webpOutput(&config.output);
281     TAutoCallProc<WebPIDecoder, WebPIDelete> idec(WebPINewDecoder(&config.output));
282     if (idec == nullptr) {
283         HiLog::Error(LABEL, "common decode:idec is null.");
284         state_ = WebpDecodingState::IMAGE_ERROR;
285         return ERR_IMAGE_DECODE_FAILED;
286     }
287 
288     VP8StatusCode status = WebPIUpdate(idec, dataBuffer_.inputStreamBuffer, static_cast<size_t>(dataBuffer_.dataSize));
289     if (status == VP8_STATUS_OK) {
290         state_ = WebpDecodingState::IMAGE_DECODED;
291         return SUCCESS;
292     }
293     if (status == VP8_STATUS_SUSPENDED && opts_.allowPartialImage) {
294         state_ = WebpDecodingState::IMAGE_PARTIAL;
295         context.ifPartialOutput = true;
296         HiLog::Error(LABEL, "this is partial image data to decode.");
297         return SUCCESS;
298     }
299 
300     HiLog::Error(LABEL, "decode image data failed, status:%{public}d.", status);
301     state_ = WebpDecodingState::IMAGE_ERROR;
302     return ERR_IMAGE_DECODE_FAILED;
303 }
304 
DoIncrementalDecode(ProgDecodeContext & context)305 uint32_t WebpDecoder::DoIncrementalDecode(ProgDecodeContext &context)
306 {
307     WebPDecoderConfig config;
308     if (!PreDecodeProc(context.decodeContext, config, true)) {
309         HiLog::Error(LABEL, "prepare increment decode failed.");
310         return ERR_IMAGE_MALLOC_ABNORMAL;
311     }
312 
313     TAutoCallProc<WebPDecBuffer, WebPFreeDecBuffer> webpOutput(&config.output);
314     TAutoCallProc<WebPIDecoder, WebPIDelete> idec(WebPINewDecoder(&config.output));
315     if (idec == nullptr) {
316         HiLog::Error(LABEL, "incremental code:idec is null.");
317         return ERR_IMAGE_DECODE_FAILED;
318     }
319 
320     dataBuffer_ = { nullptr, 0, 0 };
321     stream_->Seek(0);
322     if (!stream_->Read(stream_->GetStreamSize(), dataBuffer_)) {
323         HiLog::Error(LABEL, "incremental:read data failed.");
324         return ERR_IMAGE_DECODE_FAILED;
325     }
326     if (dataBuffer_.inputStreamBuffer == nullptr || dataBuffer_.dataSize == 0) {
327         HiLog::Error(LABEL, "incremental:data is null.");
328         return ERR_IMAGE_DECODE_FAILED;
329     }
330 
331     VP8StatusCode status = WebPIUpdate(idec, dataBuffer_.inputStreamBuffer, static_cast<size_t>(dataBuffer_.dataSize));
332     if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
333         HiLog::Error(LABEL, "incremental:webp status exception,status:%{public}d.", status);
334         return ERR_IMAGE_DECODE_FAILED;
335     }
336     if (status == VP8_STATUS_SUSPENDED) {
337         int32_t curHeight = 0;
338         if (WebPIDecGetRGB(idec, &curHeight, nullptr, nullptr, nullptr) == nullptr) {
339             HiLog::Debug(LABEL, "refresh image failed, current height:%{public}d.", curHeight);
340         }
341         if (curHeight > 0 && webpSize_.height != 0) {
342             context.totalProcessProgress =
343                 static_cast<uint32_t>(curHeight) * ProgDecodeContext::FULL_PROGRESS / webpSize_.height;
344         }
345         return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
346     }
347     if (status == VP8_STATUS_OK) {
348         context.totalProcessProgress = context.FULL_PROGRESS;
349         state_ = WebpDecodingState::IMAGE_DECODED;
350     }
351     return SUCCESS;
352 }
353 
InitWebpOutput(const DecodeContext & context,WebPDecBuffer & output)354 void WebpDecoder::InitWebpOutput(const DecodeContext &context, WebPDecBuffer &output)
355 {
356     output.is_external_memory = EXTERNAL_MEMORY;  // external allocated space
357     output.u.RGBA.rgba = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
358     output.u.RGBA.stride = webpSize_.width * bytesPerPixel_;
359     output.u.RGBA.size = context.pixelsBuffer.bufferSize;
360     output.colorspace = webpMode_;
361 }
362 
PreDecodeProc(DecodeContext & context,WebPDecoderConfig & config,bool isIncremental)363 bool WebpDecoder::PreDecodeProc(DecodeContext &context, WebPDecoderConfig &config, bool isIncremental)
364 {
365     if (WebPInitDecoderConfig(&config) == 0) {
366         HiLog::Error(LABEL, "init config failed.");
367         return false;
368     }
369     if (!AllocOutputBuffer(context, isIncremental)) {
370         HiLog::Error(LABEL, "get pixels memory failed.");
371         return false;
372     }
373 
374     InitWebpOutput(context, config.output);
375     return true;
376 }
377 
Reset()378 void WebpDecoder::Reset()
379 {
380     stream_->Seek(0);
381     dataBuffer_ = { nullptr, 0, 0 };
382     webpSize_ = { 0, 0 };
383 }
384 
SharedMemoryCreate(DecodeContext & context,const uint32_t & byteCount)385 static bool SharedMemoryCreate(DecodeContext &context, const uint32_t &byteCount)
386 {
387 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
388     HiLog::Error(LABEL, "Unsupport dma mem alloc");
389     return false;
390 #else
391     uint32_t id = context.pixelmapUniqueId_;
392     std::string name = "WEBP RawData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(id);
393     int fd = AshmemCreate(name.c_str(), byteCount);
394     if (fd < 0) {
395         return false;
396     }
397     int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
398     if (result < 0) {
399         ::close(fd);
400         return false;
401     }
402     void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
403     if (ptr == MAP_FAILED) {
404         ::close(fd);
405         return false;
406     }
407     context.pixelsBuffer.buffer = ptr;
408     void *fdBuffer = new int32_t();
409     if (fdBuffer == nullptr) {
410         HiLog::Error(LABEL, "malloc fdBuffer fail");
411         ::munmap(ptr, byteCount);
412         ::close(fd);
413         context.pixelsBuffer.buffer = nullptr;
414         return false;
415     }
416     *static_cast<int32_t *>(fdBuffer) = fd;
417     context.pixelsBuffer.context = fdBuffer;
418     context.pixelsBuffer.bufferSize = byteCount;
419     context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
420     context.freeFunc = nullptr;
421     return true;
422 #endif
423 }
424 
HeapMemoryCreate(DecodeContext & context,const uint32_t & byteCount)425 static bool HeapMemoryCreate(DecodeContext &context, const uint32_t &byteCount)
426 {
427     if (byteCount == 0 || byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
428         HiLog::Error(LABEL, "Invalid value of byteCount");
429         return false;
430     }
431     void *outputBuffer = malloc(byteCount);
432     if (outputBuffer == nullptr) {
433         HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.",
434             static_cast<unsigned long long>(byteCount));
435         return false;
436     }
437 #ifdef _WIN32
438     errno_t backRet = memset_s(outputBuffer, 0, byteCount);
439     if (backRet != EOK) {
440         HiLog::Error(LABEL, "memset buffer failed.", backRet);
441         free(outputBuffer);
442         outputBuffer = nullptr;
443         return false;
444     }
445 #else
446     if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
447         HiLog::Error(LABEL, "memset buffer failed.");
448         free(outputBuffer);
449         outputBuffer = nullptr;
450         return false;
451     }
452 #endif
453     context.pixelsBuffer.buffer = outputBuffer;
454     context.pixelsBuffer.bufferSize = byteCount;
455     context.pixelsBuffer.context = nullptr;
456     context.allocatorType = AllocatorType::HEAP_ALLOC;
457     context.freeFunc = nullptr;
458     return true;
459 }
460 
DmaMemoryCreate(DecodeContext & context,const uint32_t & byteCount,const PlSize & webpSize)461 static bool DmaMemoryCreate(DecodeContext &context, const uint32_t &byteCount, const PlSize &webpSize)
462 {
463 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
464     HiLog::Error(LABEL, "Unsupport dma mem alloc");
465     return false;
466 #else
467     sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
468     BufferRequestConfig requestConfig = {
469         .width = webpSize.width,
470         .height = webpSize.height,
471         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
472         .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
473         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
474         .timeout = 0,
475         .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
476         .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
477     };
478     GSError ret = sb->Alloc(requestConfig);
479     if (ret != GSERROR_OK) {
480         HiLog::Error(LABEL, "SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
481         return false;
482     }
483     void* nativeBuffer = sb.GetRefPtr();
484     int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
485     if (err != OHOS::GSERROR_OK) {
486         HiLog::Error(LABEL, "NativeBufferReference failed");
487         return false;
488     }
489 
490     context.pixelsBuffer.buffer = sb->GetVirAddr();
491     context.pixelsBuffer.context = nativeBuffer;
492     context.pixelsBuffer.bufferSize = byteCount;
493     context.allocatorType = AllocatorType::DMA_ALLOC;
494     context.freeFunc = nullptr;
495     return true;
496 #endif
497 }
498 
AllocOutputBuffer(DecodeContext & context,bool isIncremental)499 bool WebpDecoder::AllocOutputBuffer(DecodeContext &context, bool isIncremental)
500 {
501     if (isIncremental) {
502         if (context.pixelsBuffer.buffer != nullptr && context.allocatorType == AllocatorType::HEAP_ALLOC) {
503             free(context.pixelsBuffer.buffer);
504             context.pixelsBuffer.buffer = nullptr;
505         }
506     }
507     if (context.pixelsBuffer.buffer == nullptr) {
508         uint64_t byteCount = static_cast<uint64_t>(webpSize_.width * webpSize_.height * bytesPerPixel_);
509         if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
510             return SharedMemoryCreate(context, byteCount);
511         } else if (context.allocatorType == Media::AllocatorType::HEAP_ALLOC) {
512             return HeapMemoryCreate(context, byteCount);
513         } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
514             return DmaMemoryCreate(context, byteCount, webpSize_);
515         }
516         // Current Defalut alloc function
517         return SharedMemoryCreate(context, byteCount);
518     }
519     return true;
520 }
521 } // namespace ImagePlugin
522 } // namespace OHOS
523