• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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