1 /*
2 * Copyright (c) 2024 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 "hardware/imagecodec/image_decoder.h"
17 #include "hardware/imagecodec/image_codec_log.h"
18 #include <cassert>
19 #include "codec_omx_ext.h" // drivers/peripheral/codec/interfaces/include/codec_omx_ext.h
20 #include "OMX_VideoExt.h" // third_party/openmax/api/1.1.2/OMX_VideoExt.h
21 #include "surface_buffer.h" // foundation/graphic/graphic_surface/interfaces/inner_api/surface/surface_buffer.h
22
23 namespace OHOS::ImagePlugin {
24 using namespace std;
25
ImageDecoder()26 ImageDecoder::ImageDecoder()
27 : ImageCodec(static_cast<OMX_VIDEO_CODINGTYPE>(CODEC_OMX_VIDEO_CodingHEVC), false)
28 {}
29
OnConfigure(const Format & format)30 int32_t ImageDecoder::OnConfigure(const Format &format)
31 {
32 configFormat_ = make_shared<Format>(format);
33
34 (void)format.GetValue(ImageCodecDescriptionKey::ENABLE_HEIF_GRID, enableHeifGrid_);
35
36 UseBufferType useBufferTypes;
37 InitOMXParamExt(useBufferTypes);
38 useBufferTypes.portIndex = OMX_DirOutput;
39 useBufferTypes.bufferType = CODEC_BUFFER_TYPE_HANDLE;
40 if (!SetParameter(OMX_IndexParamUseBufferType, useBufferTypes)) {
41 HLOGE("component don't support CODEC_BUFFER_TYPE_HANDLE");
42 return IC_ERR_INVALID_VAL;
43 }
44
45 (void)SetProcessName(format);
46 (void)SetFrameRateAdaptiveMode(format);
47 return SetupPort(format);
48 }
49
SetupPort(const Format & format)50 int32_t ImageDecoder::SetupPort(const Format &format)
51 {
52 uint32_t width;
53 if (!format.GetValue(ImageCodecDescriptionKey::WIDTH, width) || width <= 0) {
54 HLOGE("format should contain width");
55 return IC_ERR_INVALID_VAL;
56 }
57 uint32_t height;
58 if (!format.GetValue(ImageCodecDescriptionKey::HEIGHT, height) || height <= 0) {
59 HLOGE("format should contain height");
60 return IC_ERR_INVALID_VAL;
61 }
62 HLOGI("user set width %{public}u, height %{public}u", width, height);
63 if (!GetPixelFmtFromUser(format)) {
64 return IC_ERR_INVALID_VAL;
65 }
66 uint32_t inputBufferCnt = 0;
67 (void)format.GetValue(ImageCodecDescriptionKey::INPUT_BUFFER_COUNT, inputBufferCnt);
68 uint32_t outputBufferCnt = 0;
69 (void)format.GetValue(ImageCodecDescriptionKey::OUTPUT_BUFFER_COUNT, outputBufferCnt);
70
71 optional<double> frameRate = GetFrameRateFromUser(format);
72 if (!frameRate.has_value()) {
73 HLOGI("user don't set valid frame rate, use default 30.0");
74 frameRate = 30.0; // default frame rate 30.0
75 }
76
77 PortInfo inputPortInfo {width, height, codingType_, std::nullopt, frameRate.value()};
78 int32_t maxInputSize = 0;
79 (void)format.GetValue(ImageCodecDescriptionKey::MAX_INPUT_SIZE, maxInputSize);
80 if (maxInputSize > 0) {
81 inputPortInfo.inputBufSize = static_cast<uint32_t>(maxInputSize);
82 }
83 if (inputBufferCnt > 0) {
84 inputPortInfo.bufferCnt = inputBufferCnt;
85 }
86 int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
87 if (ret != IC_ERR_OK) {
88 return ret;
89 }
90
91 PortInfo outputPortInfo = {width, height, OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
92 if (outputBufferCnt > 0) {
93 outputPortInfo.bufferCnt = outputBufferCnt;
94 }
95 ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
96 if (ret != IC_ERR_OK) {
97 return ret;
98 }
99
100 return IC_ERR_OK;
101 }
102
UpdateConfiguredFmt(OMX_COLOR_FORMATTYPE portFmt)103 bool ImageDecoder::UpdateConfiguredFmt(OMX_COLOR_FORMATTYPE portFmt)
104 {
105 auto graphicFmt = static_cast<GraphicPixelFormat>(portFmt);
106 if (graphicFmt != configuredFmt_.graphicFmt) {
107 optional<PixelFmt> fmt = TypeConverter::GraphicFmtToFmt(graphicFmt);
108 if (!fmt.has_value()) {
109 return false;
110 }
111 HLOGI("GraphicPixelFormat need update: configured(%{public}s) -> portdefinition(%{public}s)",
112 configuredFmt_.strFmt.c_str(), fmt->strFmt.c_str());
113 configuredFmt_ = fmt.value();
114 }
115 return true;
116 }
117
UpdateInPortFormat()118 int32_t ImageDecoder::UpdateInPortFormat()
119 {
120 OMX_PARAM_PORTDEFINITIONTYPE def;
121 InitOMXParam(def);
122 def.nPortIndex = OMX_DirInput;
123 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
124 HLOGE("get input port definition failed");
125 return IC_ERR_UNKNOWN;
126 }
127 PrintPortDefinition(def);
128 if (inputFormat_ == nullptr) {
129 inputFormat_ = make_shared<Format>();
130 }
131 inputFormat_->SetValue(ImageCodecDescriptionKey::WIDTH, def.format.video.nFrameWidth);
132 inputFormat_->SetValue(ImageCodecDescriptionKey::HEIGHT, def.format.video.nFrameHeight);
133 return IC_ERR_OK;
134 }
135
UpdateOutPortFormat()136 int32_t ImageDecoder::UpdateOutPortFormat()
137 {
138 OMX_PARAM_PORTDEFINITIONTYPE def;
139 InitOMXParam(def);
140 def.nPortIndex = OMX_DirOutput;
141 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
142 HLOGE("get output port definition failed");
143 return IC_ERR_UNKNOWN;
144 }
145 PrintPortDefinition(def);
146 if (def.nBufferCountActual == 0) {
147 HLOGE("invalid bufferCount");
148 return IC_ERR_UNKNOWN;
149 }
150 (void)UpdateConfiguredFmt(def.format.video.eColorFormat);
151
152 uint32_t w = def.format.video.nFrameWidth;
153 uint32_t h = def.format.video.nFrameHeight;
154
155 // save into member variable
156 requestCfg_.timeout = 0;
157 requestCfg_.width = static_cast<int32_t>(w);
158 requestCfg_.height = static_cast<int32_t>(h);
159 requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
160 requestCfg_.format = configuredFmt_.graphicFmt;
161 requestCfg_.usage = GetProducerUsage();
162 UpdateDisplaySizeByCrop();
163
164 // save into format
165 if (outputFormat_ == nullptr) {
166 outputFormat_ = make_shared<Format>();
167 }
168 if (!outputFormat_->ContainKey(ImageCodecDescriptionKey::WIDTH)) {
169 outputFormat_->SetValue(ImageCodecDescriptionKey::WIDTH, w);
170 }
171 if (!outputFormat_->ContainKey(ImageCodecDescriptionKey::HEIGHT)) {
172 outputFormat_->SetValue(ImageCodecDescriptionKey::HEIGHT, h);
173 }
174 outputFormat_->SetValue(ImageCodecDescriptionKey::VIDEO_DISPLAY_WIDTH, requestCfg_.width);
175 outputFormat_->SetValue(ImageCodecDescriptionKey::VIDEO_DISPLAY_HEIGHT, requestCfg_.height);
176 outputFormat_->SetValue(ImageCodecDescriptionKey::PIXEL_FORMAT,
177 static_cast<int32_t>(configuredFmt_.graphicFmt));
178 return IC_ERR_OK;
179 }
180
UpdateColorAspects()181 void ImageDecoder::UpdateColorAspects()
182 {
183 CodecVideoColorspace param;
184 InitOMXParamExt(param);
185 param.portIndex = OMX_DirOutput;
186 if (!GetParameter(OMX_IndexColorAspects, param, true)) {
187 return;
188 }
189 HLOGI("range:%{public}d, primary:%{public}d, transfer:%{public}d, matrix:%{public}d)",
190 param.aspects.range, param.aspects.primaries, param.aspects.transfer, param.aspects.matrixCoeffs);
191 if (outputFormat_) {
192 outputFormat_->SetValue(ImageCodecDescriptionKey::RANGE_FLAG, param.aspects.range);
193 outputFormat_->SetValue(ImageCodecDescriptionKey::COLOR_PRIMARIES, param.aspects.primaries);
194 outputFormat_->SetValue(ImageCodecDescriptionKey::TRANSFER_CHARACTERISTICS, param.aspects.transfer);
195 outputFormat_->SetValue(ImageCodecDescriptionKey::MATRIX_COEFFICIENTS, param.aspects.matrixCoeffs);
196 callback_->OnOutputFormatChanged(*(outputFormat_.get()));
197 }
198 }
199
UpdateDisplaySizeByCrop()200 void ImageDecoder::UpdateDisplaySizeByCrop()
201 {
202 OMX_CONFIG_RECTTYPE rect;
203 InitOMXParam(rect);
204 rect.nPortIndex = OMX_DirOutput;
205 if (!GetParameter(OMX_IndexConfigCommonOutputCrop, rect, true)) {
206 HLOGW("get crop failed, use default");
207 return;
208 }
209 if (rect.nLeft < 0 || rect.nTop < 0 || rect.nWidth == 0 || rect.nHeight == 0 ||
210 static_cast<int32_t>(rect.nLeft) + static_cast<int32_t>(rect.nWidth) > requestCfg_.width ||
211 static_cast<int32_t>(rect.nTop) + static_cast<int32_t>(rect.nHeight) > requestCfg_.height) {
212 HLOGW("wrong crop rect (%{public}d, %{public}d, %{public}u, %{public}u), use default",
213 rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
214 return;
215 }
216 HLOGI("crop rect (%{public}d, %{public}d, %{public}u, %{public}u)",
217 rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
218 requestCfg_.width = static_cast<int32_t>(rect.nWidth);
219 requestCfg_.height = static_cast<int32_t>(rect.nHeight);
220 }
221
ReConfigureOutputBufferCnt()222 int32_t ImageDecoder::ReConfigureOutputBufferCnt()
223 {
224 IF_TRUE_RETURN_VAL(enableHeifGrid_, IC_ERR_OK);
225 OMX_PARAM_PORTDEFINITIONTYPE def;
226 InitOMXParam(def);
227 def.nPortIndex = OMX_DirOutput;
228 IF_TRUE_RETURN_VAL_WITH_MSG(!GetParameter(OMX_IndexParamPortDefinition, def), IC_ERR_UNKNOWN,
229 "failed to get output port def");
230 uint32_t outputBufferCnt = 0;
231 (void)configFormat_->GetValue(ImageCodecDescriptionKey::OUTPUT_BUFFER_COUNT, outputBufferCnt);
232 IF_TRUE_RETURN_VAL_WITH_MSG(outputBufferCnt == 0, IC_ERR_UNKNOWN, "failed to get output buffer cnt");
233 def.nBufferCountActual = outputBufferCnt;
234 IF_TRUE_RETURN_VAL_WITH_MSG(!SetParameter(OMX_IndexParamPortDefinition, def), IC_ERR_UNKNOWN,
235 "failed to set output port def");
236 return IC_ERR_OK;
237 }
238
GetProducerUsage()239 uint64_t ImageDecoder::GetProducerUsage()
240 {
241 uint64_t producerUsage = BUFFER_MODE_REQUEST_USAGE;
242
243 GetBufferHandleUsageParams vendorUsage;
244 InitOMXParamExt(vendorUsage);
245 vendorUsage.portIndex = static_cast<uint32_t>(OMX_DirOutput);
246 if (GetParameter(OMX_IndexParamGetBufferHandleUsage, vendorUsage)) {
247 HLOGD("vendor producer usage = 0x%" PRIx64 "", vendorUsage.usage);
248 producerUsage |= vendorUsage.usage;
249 }
250 HLOGD("decoder producer usage = 0x%" PRIx64 "", producerUsage);
251 return producerUsage;
252 }
253
OnGetOutputBufferUsage()254 uint64_t ImageDecoder::OnGetOutputBufferUsage()
255 {
256 uint64_t usage = GetProducerUsage();
257 usage |= BUFFER_USAGE_CPU_WRITE;
258 return usage;
259 }
260
OnSetOutputBuffer(sptr<SurfaceBuffer> output)261 int32_t ImageDecoder::OnSetOutputBuffer(sptr<SurfaceBuffer> output)
262 {
263 if (output == nullptr) {
264 HLOGE("invalid output buffer");
265 return IC_ERR_INVALID_VAL;
266 }
267 outputBuffer_ = output;
268 return IC_ERR_OK;
269 }
270
OnSetPackedInputFlag(bool flag)271 bool ImageDecoder::OnSetPackedInputFlag(bool flag)
272 {
273 OMX_CONFIG_BOOLEANTYPE packedInputFlag;
274 InitOMXParam(packedInputFlag);
275 packedInputFlag.bEnabled = flag ? OMX_TRUE : OMX_FALSE;
276 if (!SetParameter(OMX_IndexParamEnablePackInput, packedInputFlag)) {
277 HLOGE("set packed input flag failed");
278 return IC_ERR_UNKNOWN;
279 }
280 return IC_ERR_OK;
281 }
282
OnGetPackedInputCapability()283 bool ImageDecoder::OnGetPackedInputCapability()
284 {
285 OMX_CONFIG_BOOLEANTYPE packedInputCapability;
286 InitOMXParam(packedInputCapability);
287 if (GetParameter(OMX_IndexParamSupportPackInput, packedInputCapability)) {
288 isPackedInputSupported_ = static_cast<bool>(packedInputCapability.bEnabled);
289 } else {
290 HLOGW("get packed input flag failed, use false as default");
291 isPackedInputSupported_ = false;
292 }
293 return isPackedInputSupported_;
294 }
295
ReadyToStart()296 bool ImageDecoder::ReadyToStart()
297 {
298 if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
299 HLOGE("callback not set or format is not configured, can't start");
300 return false;
301 }
302 if (enableHeifGrid_ && outputBuffer_ != nullptr) {
303 HLOGE("can not set output buffer when heif grid is enabled");
304 return false;
305 }
306 if (!enableHeifGrid_ && outputBuffer_ == nullptr) {
307 HLOGE("must set output buffer when heif grid is not enabled");
308 return false;
309 }
310 return true;
311 }
312
AllocateBuffersOnPort(OMX_DIRTYPE portIndex,bool isOutputPortSettingChanged)313 int32_t ImageDecoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex, bool isOutputPortSettingChanged)
314 {
315 if (portIndex == OMX_DirInput) {
316 return AllocateHardwareBuffers(portIndex);
317 }
318 int32_t ret = AllocateSurfaceBuffers(portIndex, isOutputPortSettingChanged, outputBuffer_);
319 if (ret == IC_ERR_OK) {
320 UpdateFormatFromSurfaceBuffer();
321 }
322 return ret;
323 }
324
UpdateFormatFromSurfaceBuffer()325 void ImageDecoder::UpdateFormatFromSurfaceBuffer()
326 {
327 if (outputBufferPool_.empty()) {
328 return;
329 }
330 sptr<SurfaceBuffer> surfaceBuffer = outputBufferPool_.front().surfaceBuffer;
331 if (surfaceBuffer == nullptr) {
332 return;
333 }
334 outputFormat_->SetValue(ImageCodecDescriptionKey::VIDEO_DISPLAY_WIDTH, surfaceBuffer->GetWidth());
335 outputFormat_->SetValue(ImageCodecDescriptionKey::VIDEO_DISPLAY_HEIGHT, surfaceBuffer->GetHeight());
336 outputFormat_->SetValue(ImageCodecDescriptionKey::WIDTH, surfaceBuffer->GetStride());
337
338 OMX_PARAM_PORTDEFINITIONTYPE def;
339 int32_t ret = GetPortDefinition(OMX_DirOutput, def);
340 int32_t sliceHeight = static_cast<int32_t>(def.format.video.nSliceHeight);
341 if (ret == IC_ERR_OK && sliceHeight >= surfaceBuffer->GetHeight()) {
342 outputFormat_->SetValue(ImageCodecDescriptionKey::HEIGHT, sliceHeight);
343 }
344 }
345
SubmitAllBuffersOwnedByUs()346 int32_t ImageDecoder::SubmitAllBuffersOwnedByUs()
347 {
348 HLOGI(">>");
349 if (isBufferCirculating_) {
350 HLOGI("buffer is already circulating, no need to do again");
351 return IC_ERR_OK;
352 }
353 int32_t ret = SubmitOutputBuffersToOmxNode();
354 if (ret != IC_ERR_OK) {
355 return ret;
356 }
357 for (BufferInfo& info : inputBufferPool_) {
358 if (info.owner == BufferOwner::OWNED_BY_US) {
359 NotifyUserToFillThisInBuffer(info);
360 }
361 }
362 isBufferCirculating_ = true;
363 return IC_ERR_OK;
364 }
365
SubmitOutputBuffersToOmxNode()366 int32_t ImageDecoder::SubmitOutputBuffersToOmxNode()
367 {
368 for (BufferInfo& info : outputBufferPool_) {
369 switch (info.owner) {
370 case BufferOwner::OWNED_BY_US: {
371 int32_t ret = NotifyOmxToFillThisOutBuffer(info);
372 if (ret != IC_ERR_OK) {
373 return ret;
374 }
375 continue;
376 }
377 case BufferOwner::OWNED_BY_OMX: {
378 continue;
379 }
380 default: {
381 HLOGE("buffer id %{public}u has invalid owner %{public}d", info.bufferId, info.owner);
382 return IC_ERR_UNKNOWN;
383 }
384 }
385 }
386 return IC_ERR_OK;
387 }
388
OnOMXEmptyBufferDone(uint32_t bufferId,BufferOperationMode mode)389 void ImageDecoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
390 {
391 BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
392 if (info == nullptr) {
393 HLOGE("unknown buffer id %{public}u", bufferId);
394 return;
395 }
396 if (info->owner != BufferOwner::OWNED_BY_OMX) {
397 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info->owner));
398 return;
399 }
400 ChangeOwner(*info, BufferOwner::OWNED_BY_US);
401
402 switch (mode) {
403 case KEEP_BUFFER:
404 return;
405 case RESUBMIT_BUFFER: {
406 if (!inputPortEos_) {
407 NotifyUserToFillThisInBuffer(*info);
408 }
409 return;
410 }
411 default: {
412 HLOGE("SHOULD NEVER BE HERE");
413 return;
414 }
415 }
416 }
417
EraseBufferFromPool(OMX_DIRTYPE portIndex,size_t i)418 void ImageDecoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
419 {
420 vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
421 if (i >= pool.size()) {
422 HLOGE("EraseBufferFromPool invalid params i: %{public}lu, pool size: %{public}lu", i, pool.size());
423 return;
424 }
425 BufferInfo& info = pool[i];
426 FreeOmxBuffer(portIndex, info);
427 pool.erase(pool.begin() + i);
428 }
429
430
431 } // namespace OHOS::ImagePlugin