• 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 "heif_decoder.h"
17 #include "media_errors.h"
18 #include "securec.h"
19 
20 namespace OHOS {
21 namespace ImagePlugin {
22 using namespace OHOS::HiviewDFX;
23 using namespace MultimediaPlugin;
24 using namespace Media;
25 
26 constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "HeifDecoder" };
27 constexpr uint32_t HEIF_IMAGE_NUM = 1;
28 
SetSource(InputDataStream & sourceStream)29 void HeifDecoder::SetSource(InputDataStream &sourceStream)
30 {
31     heifDecoderInterface_ = HeifDecoderWrapper::CreateHeifDecoderInterface(sourceStream);
32 }
33 
Reset()34 void HeifDecoder::Reset()
35 {
36     heifDecoderInterface_ = nullptr;
37     heifSize_.width = 0;
38     heifSize_.height = 0;
39     bytesPerPixel_ = 0;
40 }
41 
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)42 uint32_t HeifDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
43 {
44     uint32_t ret = GetImageSize(index, info.size);
45     if (ret != SUCCESS) {
46         HiLog::Error(LABEL, "get image size failed, ret=%{public}u", ret);
47         return ret;
48     }
49     heifSize_ = info.size;
50 
51     if (heifDecoderInterface_->ConversionSupported(opts.desiredPixelFormat, bytesPerPixel_)) {
52         info.pixelFormat = opts.desiredPixelFormat;
53         if (info.pixelFormat == PlPixelFormat::UNKNOWN) {
54             info.pixelFormat = PlPixelFormat::BGRA_8888;
55         }
56     } else {
57         return ERR_IMAGE_COLOR_CONVERT;
58     }
59     heifDecoderInterface_->SetAllowPartial(opts.allowPartialImage);
60     bool hasAlpha = (info.pixelFormat == PlPixelFormat::RGB_565 || info.pixelFormat == PlPixelFormat::RGB_888 ||
61                      info.pixelFormat == PlPixelFormat::ALPHA_8);
62     if (hasAlpha) {
63         info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
64     } else {
65         info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
66     }
67     return SUCCESS;
68 }
Decode(uint32_t index,DecodeContext & context)69 uint32_t HeifDecoder::Decode(uint32_t index, DecodeContext &context)
70 {
71     if (heifDecoderInterface_ == nullptr) {
72         HiLog::Error(LABEL, "create heif interface object failed!");
73         return ERR_IMAGE_INIT_ABNORMAL;
74     }
75 
76     if (index >= HEIF_IMAGE_NUM) {
77         HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}d.", index, HEIF_IMAGE_NUM);
78         return ERR_IMAGE_INVALID_PARAMETER;
79     }
80 
81     if (!AllocHeapBuffer(context)) {
82         HiLog::Error(LABEL, "get pixels memory fail.");
83         return ERR_IMAGE_MALLOC_ABNORMAL;
84     }
85     return heifDecoderInterface_->OnGetPixels(heifSize_, heifSize_.width * bytesPerPixel_, context);
86 }
87 
GetImageSize(uint32_t index,PlSize & size)88 uint32_t HeifDecoder::GetImageSize(uint32_t index, PlSize &size)
89 {
90     if (index >= HEIF_IMAGE_NUM) {
91         HiLog::Error(LABEL, "decode image out of range, index:%{public}u, range:%{public}d.", index, HEIF_IMAGE_NUM);
92         return ERR_IMAGE_INVALID_PARAMETER;
93     }
94 
95     if (heifDecoderInterface_ == nullptr) {
96         HiLog::Error(LABEL, "create heif interface object failed!");
97         return ERR_IMAGE_INIT_ABNORMAL;
98     }
99 
100     heifDecoderInterface_->GetHeifSize(size);
101     if (size.width == 0 || size.height == 0) {
102         HiLog::Error(LABEL, "get width and height fail, height:%{public}u, width:%{public}u.", size.height,
103                      size.height);
104         return ERR_IMAGE_GET_DATA_ABNORMAL;
105     }
106     return SUCCESS;
107 }
108 
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)109 uint32_t HeifDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
110 {
111     // currently not support increment decode
112     return ERR_IMAGE_DATA_UNSUPPORT;
113 }
GetTopLevelImageNum(uint32_t & num)114 uint32_t HeifDecoder::GetTopLevelImageNum(uint32_t &num)
115 {
116     // currently only supports single frame
117     num = HEIF_IMAGE_NUM;
118     return SUCCESS;
119 }
120 
AllocHeapBuffer(DecodeContext & context)121 bool HeifDecoder::AllocHeapBuffer(DecodeContext &context)
122 {
123     if (context.pixelsBuffer.buffer == nullptr) {
124         if (!IsHeifImageParaValid(heifSize_, bytesPerPixel_)) {
125             HiLog::Error(LABEL, "check heif image para fail");
126             return false;
127         }
128         uint64_t byteCount = static_cast<uint64_t>(heifSize_.width) * heifSize_.height * bytesPerPixel_;
129         if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
130             int fd = AshmemCreate("HEIF RawData", byteCount);
131             if (fd < 0) {
132                 return false;
133             }
134             int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
135             if (result < 0) {
136                 ::close(fd);
137                 return false;
138             }
139             void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
140             if (ptr == MAP_FAILED) {
141                 ::close(fd);
142                 return false;
143             }
144             context.pixelsBuffer.buffer = ptr;
145             void *fdBuffer = new int32_t();
146             if (fdBuffer == nullptr) {
147                 HiLog::Error(LABEL, "new fdBuffer fail");
148                 ::munmap(ptr, byteCount);
149                 ::close(fd);
150                 context.pixelsBuffer.buffer = nullptr;
151                 return false;
152             }
153             *static_cast<int32_t *>(fdBuffer) = fd;
154             context.pixelsBuffer.context = fdBuffer;
155             context.pixelsBuffer.bufferSize = byteCount;
156             context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
157             context.freeFunc = nullptr;
158         } else {
159             void *outputBuffer = malloc(byteCount);
160             if (outputBuffer == nullptr) {
161                 HiLog::Error(LABEL, "alloc output buffer size:[%{public}llu] error.",
162                              static_cast<unsigned long long>(byteCount));
163                 return false;
164             }
165             if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
166                 HiLog::Error(LABEL, "memset buffer failed.");
167                 free(outputBuffer);
168                 outputBuffer = nullptr;
169                 return false;
170             }
171             context.pixelsBuffer.buffer = outputBuffer;
172             context.pixelsBuffer.bufferSize = byteCount;
173             context.pixelsBuffer.context = nullptr;
174             context.allocatorType = AllocatorType::HEAP_ALLOC;
175             context.freeFunc = nullptr;
176         }
177     }
178     return true;
179 }
180 
IsHeifImageParaValid(PlSize heifSize,uint32_t bytesPerPixel)181 bool HeifDecoder::IsHeifImageParaValid(PlSize heifSize, uint32_t bytesPerPixel)
182 {
183     if (heifSize.width == 0 || heifSize.height == 0 || bytesPerPixel == 0) {
184         HiLog::Error(LABEL, "heif image para is 0");
185         return false;
186     }
187     uint64_t area = static_cast<uint64_t>(heifSize.width) * heifSize.height;
188     if ((area / heifSize.width) != heifSize.height) {
189         HiLog::Error(LABEL, "compute width*height overflow!");
190         return false;
191     }
192     uint64_t size = area * bytesPerPixel;
193     if ((size / bytesPerPixel) != area) {
194         HiLog::Error(LABEL, "compute area*bytesPerPixel overflow!");
195         return false;
196     }
197     if (size > UINT32_MAX) {
198         HiLog::Error(LABEL, "size is too large!");
199         return false;
200     }
201     return true;
202 }
203 } // namespace ImagePlugin
204 } // namespace OHOS