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