1da853ecaSopenharmony_ci/*
2da853ecaSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3da853ecaSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4da853ecaSopenharmony_ci * you may not use this file except in compliance with the License.
5da853ecaSopenharmony_ci * You may obtain a copy of the License at
6da853ecaSopenharmony_ci *
7da853ecaSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8da853ecaSopenharmony_ci *
9da853ecaSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10da853ecaSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11da853ecaSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12da853ecaSopenharmony_ci * See the License for the specific language governing permissions and
13da853ecaSopenharmony_ci * limitations under the License.
14da853ecaSopenharmony_ci */
15da853ecaSopenharmony_ci
16da853ecaSopenharmony_ci#include "hdecoder.h"
17da853ecaSopenharmony_ci#include <cassert>
18da853ecaSopenharmony_ci#include <sys/ioctl.h>
19da853ecaSopenharmony_ci#include <linux/dma-buf.h>
20da853ecaSopenharmony_ci#include "utils/hdf_base.h"
21da853ecaSopenharmony_ci#include "codec_omx_ext.h"
22da853ecaSopenharmony_ci#include "media_description.h"  // foundation/multimedia/av_codec/interfaces/inner_api/native/
23da853ecaSopenharmony_ci#include "sync_fence.h"  // foundation/graphic/graphic_2d/utils/sync_fence/export/
24da853ecaSopenharmony_ci#include "OMX_VideoExt.h"
25da853ecaSopenharmony_ci#include "hcodec_log.h"
26da853ecaSopenharmony_ci#include "hcodec_dfx.h"
27da853ecaSopenharmony_ci#include "type_converter.h"
28da853ecaSopenharmony_ci#include "surface_buffer.h"
29da853ecaSopenharmony_ci#include "buffer_extra_data_impl.h"  // foundation/graphic/graphic_surface/surface/include/
30da853ecaSopenharmony_ci
31da853ecaSopenharmony_cinamespace OHOS::MediaAVCodec {
32da853ecaSopenharmony_ciusing namespace std;
33da853ecaSopenharmony_ciusing namespace CodecHDI;
34da853ecaSopenharmony_ci
35da853ecaSopenharmony_ciHDecoder::~HDecoder()
36da853ecaSopenharmony_ci{
37da853ecaSopenharmony_ci    MsgHandleLoop::Stop();
38da853ecaSopenharmony_ci}
39da853ecaSopenharmony_ci
40da853ecaSopenharmony_ciint32_t HDecoder::OnConfigure(const Format &format)
41da853ecaSopenharmony_ci{
42da853ecaSopenharmony_ci    configFormat_ = make_shared<Format>(format);
43da853ecaSopenharmony_ci
44da853ecaSopenharmony_ci    SupportBufferType type;
45da853ecaSopenharmony_ci    InitOMXParamExt(type);
46da853ecaSopenharmony_ci    type.portIndex = OMX_DirOutput;
47da853ecaSopenharmony_ci    if (GetParameter(OMX_IndexParamSupportBufferType, type) &&
48da853ecaSopenharmony_ci        (type.bufferTypes & CODEC_BUFFER_TYPE_DYNAMIC_HANDLE) &&
49da853ecaSopenharmony_ci        UseHandleOnOutputPort(true)) {
50da853ecaSopenharmony_ci        HLOGI("dynamic mode");
51da853ecaSopenharmony_ci        isDynamic_ = true;
52da853ecaSopenharmony_ci    } else if (UseHandleOnOutputPort(false)) {
53da853ecaSopenharmony_ci        HLOGI("normal mode");
54da853ecaSopenharmony_ci        isDynamic_ = false;
55da853ecaSopenharmony_ci    } else {
56da853ecaSopenharmony_ci        HLOGE("invalid output buffer type");
57da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
58da853ecaSopenharmony_ci    }
59da853ecaSopenharmony_ci    int32_t ret = SetLowLatency(format);
60da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
61da853ecaSopenharmony_ci        return ret;
62da853ecaSopenharmony_ci    }
63da853ecaSopenharmony_ci    SaveTransform(format);
64da853ecaSopenharmony_ci    SaveScaleMode(format);
65da853ecaSopenharmony_ci    (void)SetProcessName();
66da853ecaSopenharmony_ci    (void)SetFrameRateAdaptiveMode(format);
67da853ecaSopenharmony_ci#ifdef USE_VIDEO_PROCESSING_ENGINE
68da853ecaSopenharmony_ci    ret = SetVrrEnable(format);
69da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
70da853ecaSopenharmony_ci        return ret;
71da853ecaSopenharmony_ci    }
72da853ecaSopenharmony_ci#endif
73da853ecaSopenharmony_ci    return SetupPort(format);
74da853ecaSopenharmony_ci}
75da853ecaSopenharmony_ci
76da853ecaSopenharmony_ciint32_t HDecoder::SetupPort(const Format &format)
77da853ecaSopenharmony_ci{
78da853ecaSopenharmony_ci    int32_t width;
79da853ecaSopenharmony_ci    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) || width <= 0) {
80da853ecaSopenharmony_ci        HLOGE("format should contain width");
81da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
82da853ecaSopenharmony_ci    }
83da853ecaSopenharmony_ci    int32_t height;
84da853ecaSopenharmony_ci    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) || height <= 0) {
85da853ecaSopenharmony_ci        HLOGE("format should contain height");
86da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
87da853ecaSopenharmony_ci    }
88da853ecaSopenharmony_ci    HLOGI("user set width %d, height %d", width, height);
89da853ecaSopenharmony_ci    if (!GetPixelFmtFromUser(format)) {
90da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
91da853ecaSopenharmony_ci    }
92da853ecaSopenharmony_ci
93da853ecaSopenharmony_ci    optional<double> frameRate = GetFrameRateFromUser(format);
94da853ecaSopenharmony_ci    if (frameRate.has_value()) {
95da853ecaSopenharmony_ci        codecRate_ = frameRate.value();
96da853ecaSopenharmony_ci    } else {
97da853ecaSopenharmony_ci        HLOGI("user don't set valid frame rate, use default 60.0");
98da853ecaSopenharmony_ci        frameRate = 60.0;  // default frame rate 60.0
99da853ecaSopenharmony_ci    }
100da853ecaSopenharmony_ci
101da853ecaSopenharmony_ci    PortInfo inputPortInfo {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
102da853ecaSopenharmony_ci                            codingType_, std::nullopt, frameRate.value()};
103da853ecaSopenharmony_ci    int32_t maxInputSize = 0;
104da853ecaSopenharmony_ci    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize)) {
105da853ecaSopenharmony_ci        if (maxInputSize > 0) {
106da853ecaSopenharmony_ci            inputPortInfo.inputBufSize = static_cast<uint32_t>(maxInputSize);
107da853ecaSopenharmony_ci        } else {
108da853ecaSopenharmony_ci            HLOGW("user don't set valid input buffer size");
109da853ecaSopenharmony_ci        }
110da853ecaSopenharmony_ci    }
111da853ecaSopenharmony_ci
112da853ecaSopenharmony_ci    int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
113da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
114da853ecaSopenharmony_ci        return ret;
115da853ecaSopenharmony_ci    }
116da853ecaSopenharmony_ci
117da853ecaSopenharmony_ci    PortInfo outputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
118da853ecaSopenharmony_ci                               OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
119da853ecaSopenharmony_ci    ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
120da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
121da853ecaSopenharmony_ci        return ret;
122da853ecaSopenharmony_ci    }
123da853ecaSopenharmony_ci
124da853ecaSopenharmony_ci    return AVCS_ERR_OK;
125da853ecaSopenharmony_ci}
126da853ecaSopenharmony_ci
127da853ecaSopenharmony_ciint32_t HDecoder::UpdateInPortFormat()
128da853ecaSopenharmony_ci{
129da853ecaSopenharmony_ci    OMX_PARAM_PORTDEFINITIONTYPE def;
130da853ecaSopenharmony_ci    InitOMXParam(def);
131da853ecaSopenharmony_ci    def.nPortIndex = OMX_DirInput;
132da853ecaSopenharmony_ci    if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
133da853ecaSopenharmony_ci        HLOGE("get input port definition failed");
134da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
135da853ecaSopenharmony_ci    }
136da853ecaSopenharmony_ci    PrintPortDefinition(def);
137da853ecaSopenharmony_ci    if (inputFormat_ == nullptr) {
138da853ecaSopenharmony_ci        inputFormat_ = make_shared<Format>();
139da853ecaSopenharmony_ci    }
140da853ecaSopenharmony_ci    inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, def.format.video.nFrameWidth);
141da853ecaSopenharmony_ci    inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, def.format.video.nFrameHeight);
142da853ecaSopenharmony_ci    return AVCS_ERR_OK;
143da853ecaSopenharmony_ci}
144da853ecaSopenharmony_ci
145da853ecaSopenharmony_cibool HDecoder::UpdateConfiguredFmt(OMX_COLOR_FORMATTYPE portFmt)
146da853ecaSopenharmony_ci{
147da853ecaSopenharmony_ci    auto graphicFmt = static_cast<GraphicPixelFormat>(portFmt);
148da853ecaSopenharmony_ci    if (graphicFmt != configuredFmt_.graphicFmt) {
149da853ecaSopenharmony_ci        optional<PixelFmt> fmt = TypeConverter::GraphicFmtToFmt(graphicFmt);
150da853ecaSopenharmony_ci        if (!fmt.has_value()) {
151da853ecaSopenharmony_ci            return false;
152da853ecaSopenharmony_ci        }
153da853ecaSopenharmony_ci        HLOGI("GraphicPixelFormat need update: configured(%s) -> portdefinition(%s)",
154da853ecaSopenharmony_ci            configuredFmt_.strFmt.c_str(), fmt->strFmt.c_str());
155da853ecaSopenharmony_ci        configuredFmt_ = fmt.value();
156da853ecaSopenharmony_ci    }
157da853ecaSopenharmony_ci    return true;
158da853ecaSopenharmony_ci}
159da853ecaSopenharmony_ci
160da853ecaSopenharmony_ciint32_t HDecoder::UpdateOutPortFormat()
161da853ecaSopenharmony_ci{
162da853ecaSopenharmony_ci    OMX_PARAM_PORTDEFINITIONTYPE def;
163da853ecaSopenharmony_ci    InitOMXParam(def);
164da853ecaSopenharmony_ci    def.nPortIndex = OMX_DirOutput;
165da853ecaSopenharmony_ci    if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
166da853ecaSopenharmony_ci        HLOGE("get output port definition failed");
167da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
168da853ecaSopenharmony_ci    }
169da853ecaSopenharmony_ci    PrintPortDefinition(def);
170da853ecaSopenharmony_ci    if (def.nBufferCountActual == 0) {
171da853ecaSopenharmony_ci        HLOGE("invalid bufferCount");
172da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
173da853ecaSopenharmony_ci    }
174da853ecaSopenharmony_ci    (void)UpdateConfiguredFmt(def.format.video.eColorFormat);
175da853ecaSopenharmony_ci
176da853ecaSopenharmony_ci    uint32_t w = def.format.video.nFrameWidth;
177da853ecaSopenharmony_ci    uint32_t h = def.format.video.nFrameHeight;
178da853ecaSopenharmony_ci
179da853ecaSopenharmony_ci    // save into member variable
180da853ecaSopenharmony_ci    OHOS::Rect damage{};
181da853ecaSopenharmony_ci    GetCropFromOmx(w, h, damage);
182da853ecaSopenharmony_ci    outBufferCnt_ = def.nBufferCountActual;
183da853ecaSopenharmony_ci    requestCfg_.timeout = 0; // never wait when request
184da853ecaSopenharmony_ci    requestCfg_.width = damage.w;
185da853ecaSopenharmony_ci    requestCfg_.height = damage.h;
186da853ecaSopenharmony_ci    requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
187da853ecaSopenharmony_ci    requestCfg_.format = configuredFmt_.graphicFmt;
188da853ecaSopenharmony_ci    requestCfg_.usage = GetProducerUsage();
189da853ecaSopenharmony_ci
190da853ecaSopenharmony_ci    // save into format
191da853ecaSopenharmony_ci    if (outputFormat_ == nullptr) {
192da853ecaSopenharmony_ci        outputFormat_ = make_shared<Format>();
193da853ecaSopenharmony_ci    }
194da853ecaSopenharmony_ci    if (!outputFormat_->ContainKey(MediaDescriptionKey::MD_KEY_WIDTH)) {
195da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, w); // deprecated
196da853ecaSopenharmony_ci    }
197da853ecaSopenharmony_ci    if (!outputFormat_->ContainKey(MediaDescriptionKey::MD_KEY_HEIGHT)) {
198da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, h); // deprecated
199da853ecaSopenharmony_ci    }
200da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_WIDTH, damage.w);
201da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_HEIGHT, damage.h);
202da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_WIDTH, damage.w);
203da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_HEIGHT, damage.h);
204da853ecaSopenharmony_ci    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT,
205da853ecaSopenharmony_ci        static_cast<int32_t>(configuredFmt_.innerFmt));
206da853ecaSopenharmony_ci    HLOGI("output format: %s", outputFormat_->Stringify().c_str());
207da853ecaSopenharmony_ci    return AVCS_ERR_OK;
208da853ecaSopenharmony_ci}
209da853ecaSopenharmony_ci
210da853ecaSopenharmony_civoid HDecoder::UpdateColorAspects()
211da853ecaSopenharmony_ci{
212da853ecaSopenharmony_ci    CodecVideoColorspace param;
213da853ecaSopenharmony_ci    InitOMXParamExt(param);
214da853ecaSopenharmony_ci    param.portIndex = OMX_DirOutput;
215da853ecaSopenharmony_ci    if (!GetParameter(OMX_IndexColorAspects, param, true)) {
216da853ecaSopenharmony_ci        return;
217da853ecaSopenharmony_ci    }
218da853ecaSopenharmony_ci    HLOGI("isFullRange %d, primary %u, transfer %u, matrix %u",
219da853ecaSopenharmony_ci        param.aspects.range, param.aspects.primaries, param.aspects.transfer, param.aspects.matrixCoeffs);
220da853ecaSopenharmony_ci    if (outputFormat_) {
221da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_RANGE_FLAG, param.aspects.range);
222da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_COLOR_PRIMARIES, param.aspects.primaries);
223da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_TRANSFER_CHARACTERISTICS, param.aspects.transfer);
224da853ecaSopenharmony_ci        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_MATRIX_COEFFICIENTS, param.aspects.matrixCoeffs);
225da853ecaSopenharmony_ci        HLOGI("output format changed: %s", outputFormat_->Stringify().c_str());
226da853ecaSopenharmony_ci        callback_->OnOutputFormatChanged(*(outputFormat_.get()));
227da853ecaSopenharmony_ci    }
228da853ecaSopenharmony_ci}
229da853ecaSopenharmony_ci
230da853ecaSopenharmony_civoid HDecoder::GetCropFromOmx(uint32_t w, uint32_t h, OHOS::Rect& damage)
231da853ecaSopenharmony_ci{
232da853ecaSopenharmony_ci    damage.x = 0;
233da853ecaSopenharmony_ci    damage.y = 0;
234da853ecaSopenharmony_ci    damage.w = static_cast<int32_t>(w);
235da853ecaSopenharmony_ci    damage.h = static_cast<int32_t>(h);
236da853ecaSopenharmony_ci
237da853ecaSopenharmony_ci    OMX_CONFIG_RECTTYPE rect;
238da853ecaSopenharmony_ci    InitOMXParam(rect);
239da853ecaSopenharmony_ci    rect.nPortIndex = OMX_DirOutput;
240da853ecaSopenharmony_ci    if (!GetParameter(OMX_IndexConfigCommonOutputCrop, rect, true)) {
241da853ecaSopenharmony_ci        HLOGW("get crop failed, use default");
242da853ecaSopenharmony_ci        return;
243da853ecaSopenharmony_ci    }
244da853ecaSopenharmony_ci    if (rect.nLeft < 0 || rect.nTop < 0 ||
245da853ecaSopenharmony_ci        rect.nWidth == 0 || rect.nHeight == 0 ||
246da853ecaSopenharmony_ci        rect.nLeft + static_cast<int32_t>(rect.nWidth) > static_cast<int32_t>(w) ||
247da853ecaSopenharmony_ci        rect.nTop + static_cast<int32_t>(rect.nHeight) > static_cast<int32_t>(h)) {
248da853ecaSopenharmony_ci        HLOGW("wrong crop rect (%d, %d, %u, %u) vs. frame (%u," \
249da853ecaSopenharmony_ci              "%u), use default", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight, w, h);
250da853ecaSopenharmony_ci        return;
251da853ecaSopenharmony_ci    }
252da853ecaSopenharmony_ci    HLOGI("crop rect (%d, %d, %u, %u)",
253da853ecaSopenharmony_ci          rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
254da853ecaSopenharmony_ci    damage.x = rect.nLeft;
255da853ecaSopenharmony_ci    damage.y = rect.nTop;
256da853ecaSopenharmony_ci    damage.w = static_cast<int32_t>(rect.nWidth);
257da853ecaSopenharmony_ci    damage.h = static_cast<int32_t>(rect.nHeight);
258da853ecaSopenharmony_ci    if (outputFormat_) {
259da853ecaSopenharmony_ci        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_LEFT, rect.nLeft);
260da853ecaSopenharmony_ci        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_TOP, rect.nTop);
261da853ecaSopenharmony_ci        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_RIGHT,
262da853ecaSopenharmony_ci            static_cast<int32_t>(rect.nLeft + rect.nWidth) - 1);
263da853ecaSopenharmony_ci        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_BOTTOM,
264da853ecaSopenharmony_ci            static_cast<int32_t>(rect.nTop + rect.nHeight) - 1);
265da853ecaSopenharmony_ci    }
266da853ecaSopenharmony_ci}
267da853ecaSopenharmony_ci
268da853ecaSopenharmony_civoid HDecoder::OnSetOutputSurface(const MsgInfo &msg, BufferOperationMode mode)
269da853ecaSopenharmony_ci{
270da853ecaSopenharmony_ci    sptr<Surface> surface;
271da853ecaSopenharmony_ci    (void)msg.param->GetValue("surface", surface);
272da853ecaSopenharmony_ci    if (mode == KEEP_BUFFER) {
273da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, OnSetOutputSurfaceWhenCfg(surface));
274da853ecaSopenharmony_ci        return;
275da853ecaSopenharmony_ci    }
276da853ecaSopenharmony_ci    OnSetOutputSurfaceWhenRunning(surface, msg, mode);
277da853ecaSopenharmony_ci}
278da853ecaSopenharmony_ci
279da853ecaSopenharmony_ciint32_t HDecoder::OnSetOutputSurfaceWhenCfg(const sptr<Surface> &surface)
280da853ecaSopenharmony_ci{
281da853ecaSopenharmony_ci    SCOPED_TRACE();
282da853ecaSopenharmony_ci    HLOGI(">>");
283da853ecaSopenharmony_ci    if (surface == nullptr) {
284da853ecaSopenharmony_ci        HLOGE("surface is null");
285da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
286da853ecaSopenharmony_ci    }
287da853ecaSopenharmony_ci    if (surface->IsConsumer()) {
288da853ecaSopenharmony_ci        HLOGE("expect a producer surface but got a consumer surface");
289da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
290da853ecaSopenharmony_ci    }
291da853ecaSopenharmony_ci    int32_t ret = RegisterListenerToSurface(surface);
292da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
293da853ecaSopenharmony_ci        return ret;
294da853ecaSopenharmony_ci    }
295da853ecaSopenharmony_ci    currSurface_ = SurfaceItem(surface);
296da853ecaSopenharmony_ci    HLOGI("set surface(%" PRIu64 ")(%s) succ", surface->GetUniqueId(), surface->GetName().c_str());
297da853ecaSopenharmony_ci    return AVCS_ERR_OK;
298da853ecaSopenharmony_ci}
299da853ecaSopenharmony_ci
300da853ecaSopenharmony_ciint32_t HDecoder::OnSetParameters(const Format &format)
301da853ecaSopenharmony_ci{
302da853ecaSopenharmony_ci    int32_t ret = SaveTransform(format, true);
303da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
304da853ecaSopenharmony_ci        return ret;
305da853ecaSopenharmony_ci    }
306da853ecaSopenharmony_ci    ret = SaveScaleMode(format, true);
307da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
308da853ecaSopenharmony_ci        return ret;
309da853ecaSopenharmony_ci    }
310da853ecaSopenharmony_ci    optional<double> frameRate = GetFrameRateFromUser(format);
311da853ecaSopenharmony_ci    if (frameRate.has_value()) {
312da853ecaSopenharmony_ci        OMX_PARAM_U32TYPE framerateCfgType;
313da853ecaSopenharmony_ci        InitOMXParam(framerateCfgType);
314da853ecaSopenharmony_ci        framerateCfgType.nPortIndex = OMX_DirInput;
315da853ecaSopenharmony_ci        framerateCfgType.nU32 = frameRate.value() * FRAME_RATE_COEFFICIENT;
316da853ecaSopenharmony_ci        if (SetParameter(OMX_IndexCodecExtConfigOperatingRate, framerateCfgType, true)) {
317da853ecaSopenharmony_ci            HLOGI("succ to set frameRate %.f", frameRate.value());
318da853ecaSopenharmony_ci        } else {
319da853ecaSopenharmony_ci            HLOGW("succ to set frameRate %.f", frameRate.value());
320da853ecaSopenharmony_ci        }
321da853ecaSopenharmony_ci        codecRate_ = frameRate.value();
322da853ecaSopenharmony_ci    }
323da853ecaSopenharmony_ci    return AVCS_ERR_OK;
324da853ecaSopenharmony_ci}
325da853ecaSopenharmony_ci
326da853ecaSopenharmony_ciint32_t HDecoder::SaveTransform(const Format &format, bool set)
327da853ecaSopenharmony_ci{
328da853ecaSopenharmony_ci    int32_t orientation = 0;
329da853ecaSopenharmony_ci    if (format.GetIntValue(OHOS::Media::Tag::VIDEO_ORIENTATION_TYPE, orientation)) {
330da853ecaSopenharmony_ci        HLOGI("GraphicTransformType = %d", orientation);
331da853ecaSopenharmony_ci        transform_ = static_cast<GraphicTransformType>(orientation);
332da853ecaSopenharmony_ci        if (set) {
333da853ecaSopenharmony_ci            return SetTransform();
334da853ecaSopenharmony_ci        }
335da853ecaSopenharmony_ci        return AVCS_ERR_OK;
336da853ecaSopenharmony_ci    }
337da853ecaSopenharmony_ci    int32_t rotate;
338da853ecaSopenharmony_ci    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotate)) {
339da853ecaSopenharmony_ci        return AVCS_ERR_OK;
340da853ecaSopenharmony_ci    }
341da853ecaSopenharmony_ci    optional<GraphicTransformType> transform = TypeConverter::InnerRotateToDisplayRotate(
342da853ecaSopenharmony_ci        static_cast<VideoRotation>(rotate));
343da853ecaSopenharmony_ci    if (!transform.has_value()) {
344da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
345da853ecaSopenharmony_ci    }
346da853ecaSopenharmony_ci    HLOGI("VideoRotation = %d, GraphicTransformType = %d", rotate, transform.value());
347da853ecaSopenharmony_ci    transform_ = transform.value();
348da853ecaSopenharmony_ci    if (set) {
349da853ecaSopenharmony_ci        return SetTransform();
350da853ecaSopenharmony_ci    }
351da853ecaSopenharmony_ci    return AVCS_ERR_OK;
352da853ecaSopenharmony_ci}
353da853ecaSopenharmony_ci
354da853ecaSopenharmony_ciint32_t HDecoder::SetTransform()
355da853ecaSopenharmony_ci{
356da853ecaSopenharmony_ci    if (currSurface_.surface_ == nullptr) {
357da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
358da853ecaSopenharmony_ci    }
359da853ecaSopenharmony_ci    GSError err = currSurface_.surface_->SetTransform(transform_);
360da853ecaSopenharmony_ci    if (err != GSERROR_OK) {
361da853ecaSopenharmony_ci        HLOGW("set GraphicTransformType %d to surface failed", transform_);
362da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
363da853ecaSopenharmony_ci    }
364da853ecaSopenharmony_ci    HLOGI("set GraphicTransformType %d to surface succ", transform_);
365da853ecaSopenharmony_ci    return AVCS_ERR_OK;
366da853ecaSopenharmony_ci}
367da853ecaSopenharmony_ci
368da853ecaSopenharmony_ciint32_t HDecoder::SaveScaleMode(const Format &format, bool set)
369da853ecaSopenharmony_ci{
370da853ecaSopenharmony_ci    int scaleType;
371da853ecaSopenharmony_ci    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, scaleType)) {
372da853ecaSopenharmony_ci        return AVCS_ERR_OK;
373da853ecaSopenharmony_ci    }
374da853ecaSopenharmony_ci    auto scaleMode = static_cast<ScalingMode>(scaleType);
375da853ecaSopenharmony_ci    if (scaleMode != SCALING_MODE_SCALE_TO_WINDOW && scaleMode != SCALING_MODE_SCALE_CROP) {
376da853ecaSopenharmony_ci        HLOGW("user set invalid scale mode %d", scaleType);
377da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
378da853ecaSopenharmony_ci    }
379da853ecaSopenharmony_ci    HLOGI("user set ScalingType = %d", scaleType);
380da853ecaSopenharmony_ci    scaleMode_ = scaleMode;
381da853ecaSopenharmony_ci    if (set) {
382da853ecaSopenharmony_ci        return SetScaleMode();
383da853ecaSopenharmony_ci    }
384da853ecaSopenharmony_ci    return AVCS_ERR_OK;
385da853ecaSopenharmony_ci}
386da853ecaSopenharmony_ci
387da853ecaSopenharmony_ciint32_t HDecoder::SetScaleMode()
388da853ecaSopenharmony_ci{
389da853ecaSopenharmony_ci    if (currSurface_.surface_ == nullptr || !scaleMode_.has_value()) {
390da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_VAL;
391da853ecaSopenharmony_ci    }
392da853ecaSopenharmony_ci    GSError err = currSurface_.surface_->SetScalingMode(scaleMode_.value());
393da853ecaSopenharmony_ci    if (err != GSERROR_OK) {
394da853ecaSopenharmony_ci        HLOGW("set ScalingMode %d to surface failed", scaleMode_.value());
395da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
396da853ecaSopenharmony_ci    }
397da853ecaSopenharmony_ci    HLOGI("set ScalingMode %d to surface succ", scaleMode_.value());
398da853ecaSopenharmony_ci    return AVCS_ERR_OK;
399da853ecaSopenharmony_ci}
400da853ecaSopenharmony_ci
401da853ecaSopenharmony_ci#ifdef USE_VIDEO_PROCESSING_ENGINE
402da853ecaSopenharmony_ciint32_t HDecoder::SetVrrEnable(const Format &format)
403da853ecaSopenharmony_ci{
404da853ecaSopenharmony_ci    int32_t vrrEnable = 0;
405da853ecaSopenharmony_ci    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_DECODER_ENABLE_VRR, vrrEnable) || vrrEnable == 0) {
406da853ecaSopenharmony_ci        HLOGI("VRR disabled");
407da853ecaSopenharmony_ci        return AVCS_ERR_OK;
408da853ecaSopenharmony_ci    }
409da853ecaSopenharmony_ci    optional<double> frameRate = GetFrameRateFromUser(format);
410da853ecaSopenharmony_ci    if (frameRate.has_value() && floor(frameRate.value()) != VRR_DEFAULT_INPUT_FRAME_RATE
411da853ecaSopenharmony_ci        && ceil(frameRate.value()) != VRR_DEFAULT_INPUT_FRAME_RATE) {
412da853ecaSopenharmony_ci        HLOGE("VRR only support for 60fps, current frameRate = %f", frameRate.value());
413da853ecaSopenharmony_ci        return AVCS_ERR_UNSUPPORT;
414da853ecaSopenharmony_ci    }
415da853ecaSopenharmony_ci
416da853ecaSopenharmony_ci    OMX_CONFIG_BOOLEANTYPE param {};
417da853ecaSopenharmony_ci    InitOMXParam(param);
418da853ecaSopenharmony_ci    param.bEnabled = OMX_TRUE;
419da853ecaSopenharmony_ci    if (!SetParameter(OMX_IndexParamIsMvUpload, param)) {
420da853ecaSopenharmony_ci        HLOGE("VRR SetIsMvUploadParam SetParameter failed");
421da853ecaSopenharmony_ci        return AVCS_ERR_UNSUPPORT;
422da853ecaSopenharmony_ci    }
423da853ecaSopenharmony_ci    vrrPredictor_ = OHOS::Media::VideoProcessingEngine::VideoRefreshRatePrediction::Create();
424da853ecaSopenharmony_ci    if (vrrPredictor_ == nullptr) {
425da853ecaSopenharmony_ci        HLOGE("VRR VideoRefreshRatePrediction create failed");
426da853ecaSopenharmony_ci        return AVCS_ERR_UNSUPPORT;
427da853ecaSopenharmony_ci    }
428da853ecaSopenharmony_ci    int32_t ret = vrrPredictor_->CheckLtpoSupport();
429da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
430da853ecaSopenharmony_ci        HLOGE("VRR SetParameter failed");
431da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
432da853ecaSopenharmony_ci    }
433da853ecaSopenharmony_ci    isVrrEnable_ = true;
434da853ecaSopenharmony_ci    HLOGI("VRR enabled");
435da853ecaSopenharmony_ci    return AVCS_ERR_OK;
436da853ecaSopenharmony_ci}
437da853ecaSopenharmony_ci#endif
438da853ecaSopenharmony_ci
439da853ecaSopenharmony_ciint32_t HDecoder::SubmitOutputBuffersToOmxNode()
440da853ecaSopenharmony_ci{
441da853ecaSopenharmony_ci    for (BufferInfo& info : outputBufferPool_) {
442da853ecaSopenharmony_ci        if (info.owner != BufferOwner::OWNED_BY_US) {
443da853ecaSopenharmony_ci            continue;
444da853ecaSopenharmony_ci        }
445da853ecaSopenharmony_ci        if (info.surfaceBuffer != nullptr) {
446da853ecaSopenharmony_ci            int32_t ret = NotifyOmxToFillThisOutBuffer(info);
447da853ecaSopenharmony_ci            if (ret != AVCS_ERR_OK) {
448da853ecaSopenharmony_ci                return ret;
449da853ecaSopenharmony_ci            }
450da853ecaSopenharmony_ci        }
451da853ecaSopenharmony_ci    }
452da853ecaSopenharmony_ci    auto inCnt = std::count_if(inputBufferPool_.begin(), inputBufferPool_.end(), [](const BufferInfo& info) {
453da853ecaSopenharmony_ci        return info.owner == BufferOwner::OWNED_BY_OMX;
454da853ecaSopenharmony_ci    });
455da853ecaSopenharmony_ci    inCnt++; // at least submit one out buffer to omx
456da853ecaSopenharmony_ci    while (inCnt > 0) {
457da853ecaSopenharmony_ci        DynamicModeSubmitBuffer();
458da853ecaSopenharmony_ci        inCnt--;
459da853ecaSopenharmony_ci    }
460da853ecaSopenharmony_ci    return AVCS_ERR_OK;
461da853ecaSopenharmony_ci}
462da853ecaSopenharmony_ci
463da853ecaSopenharmony_cibool HDecoder::UseHandleOnOutputPort(bool isDynamic)
464da853ecaSopenharmony_ci{
465da853ecaSopenharmony_ci    UseBufferType useBufferTypes;
466da853ecaSopenharmony_ci    InitOMXParamExt(useBufferTypes);
467da853ecaSopenharmony_ci    useBufferTypes.portIndex = OMX_DirOutput;
468da853ecaSopenharmony_ci    useBufferTypes.bufferType = (isDynamic ? CODEC_BUFFER_TYPE_DYNAMIC_HANDLE : CODEC_BUFFER_TYPE_HANDLE);
469da853ecaSopenharmony_ci    return SetParameter(OMX_IndexParamUseBufferType, useBufferTypes);
470da853ecaSopenharmony_ci}
471da853ecaSopenharmony_ci
472da853ecaSopenharmony_cibool HDecoder::ReadyToStart()
473da853ecaSopenharmony_ci{
474da853ecaSopenharmony_ci    if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
475da853ecaSopenharmony_ci        return false;
476da853ecaSopenharmony_ci    }
477da853ecaSopenharmony_ci    if (currSurface_.surface_) {
478da853ecaSopenharmony_ci        HLOGI("surface mode");
479da853ecaSopenharmony_ci        SetTransform();
480da853ecaSopenharmony_ci        SetScaleMode();
481da853ecaSopenharmony_ci    } else {
482da853ecaSopenharmony_ci        HLOGI("buffer mode");
483da853ecaSopenharmony_ci    }
484da853ecaSopenharmony_ci    return true;
485da853ecaSopenharmony_ci}
486da853ecaSopenharmony_ci
487da853ecaSopenharmony_ciint32_t HDecoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex)
488da853ecaSopenharmony_ci{
489da853ecaSopenharmony_ci    if (portIndex == OMX_DirInput) {
490da853ecaSopenharmony_ci        return AllocateAvLinearBuffers(portIndex);
491da853ecaSopenharmony_ci    }
492da853ecaSopenharmony_ci    int32_t ret;
493da853ecaSopenharmony_ci    if (isDynamic_) {
494da853ecaSopenharmony_ci        ret = AllocOutDynamicSurfaceBuf();
495da853ecaSopenharmony_ci    } else {
496da853ecaSopenharmony_ci        ret = (currSurface_.surface_ ? AllocateOutputBuffersFromSurface() : AllocateAvSurfaceBuffers(portIndex));
497da853ecaSopenharmony_ci    }
498da853ecaSopenharmony_ci    if (ret == AVCS_ERR_OK) {
499da853ecaSopenharmony_ci        UpdateFormatFromSurfaceBuffer();
500da853ecaSopenharmony_ci    }
501da853ecaSopenharmony_ci    return ret;
502da853ecaSopenharmony_ci}
503da853ecaSopenharmony_ci
504da853ecaSopenharmony_civoid HDecoder::SetCallerToBuffer(int fd)
505da853ecaSopenharmony_ci{
506da853ecaSopenharmony_ci    if (currSurface_.surface_ == nullptr) {
507da853ecaSopenharmony_ci        return; // only set on surface mode
508da853ecaSopenharmony_ci    }
509da853ecaSopenharmony_ci    string pid = std::to_string(calledByAvcodec_ ? avcodecCaller_.pid : playerCaller_.pid);
510da853ecaSopenharmony_ci    int ret = ioctl(fd, DMA_BUF_SET_NAME_A, pid.c_str());
511da853ecaSopenharmony_ci    if (ret != 0) {
512da853ecaSopenharmony_ci        HLOGW("set pid %s to fd %d failed", pid.c_str(), fd);
513da853ecaSopenharmony_ci        return;
514da853ecaSopenharmony_ci    }
515da853ecaSopenharmony_ci    HLOGD("set pid %s to fd %d succ", pid.c_str(), fd);
516da853ecaSopenharmony_ci}
517da853ecaSopenharmony_ci
518da853ecaSopenharmony_civoid HDecoder::UpdateFormatFromSurfaceBuffer()
519da853ecaSopenharmony_ci{
520da853ecaSopenharmony_ci    if (outputBufferPool_.empty()) {
521da853ecaSopenharmony_ci        return;
522da853ecaSopenharmony_ci    }
523da853ecaSopenharmony_ci    sptr<SurfaceBuffer> surfaceBuffer = outputBufferPool_.front().surfaceBuffer;
524da853ecaSopenharmony_ci    if (surfaceBuffer == nullptr) {
525da853ecaSopenharmony_ci        return;
526da853ecaSopenharmony_ci    }
527da853ecaSopenharmony_ci    HLOGI(">>");
528da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_WIDTH, surfaceBuffer->GetWidth());
529da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_HEIGHT, surfaceBuffer->GetHeight());
530da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_WIDTH, surfaceBuffer->GetWidth());
531da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_HEIGHT, surfaceBuffer->GetHeight());
532da853ecaSopenharmony_ci    int32_t stride = surfaceBuffer->GetStride();
533da853ecaSopenharmony_ci    if (stride <= 0) {
534da853ecaSopenharmony_ci        HLOGW("invalid stride %d", stride);
535da853ecaSopenharmony_ci        return;
536da853ecaSopenharmony_ci    }
537da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_STRIDE, stride);
538da853ecaSopenharmony_ci    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, stride); // deprecated
539da853ecaSopenharmony_ci
540da853ecaSopenharmony_ci    OH_NativeBuffer_Planes *planes = nullptr;
541da853ecaSopenharmony_ci    GSError err = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
542da853ecaSopenharmony_ci    if (err != GSERROR_OK || planes == nullptr) {
543da853ecaSopenharmony_ci        HLOGI("can not get plane info, ignore");
544da853ecaSopenharmony_ci        return;
545da853ecaSopenharmony_ci    }
546da853ecaSopenharmony_ci    for (uint32_t i = 0; i < planes->planeCount; i++) {
547da853ecaSopenharmony_ci        HLOGI("plane[%u]: offset=%" PRIu64 ", rowStride=%u, columnStride=%u",
548da853ecaSopenharmony_ci              i, planes->planes[i].offset, planes->planes[i].rowStride, planes->planes[i].columnStride);
549da853ecaSopenharmony_ci    }
550da853ecaSopenharmony_ci    int32_t sliceHeight = static_cast<int32_t>(static_cast<int64_t>(planes->planes[1].offset) / stride);
551da853ecaSopenharmony_ci    HLOGI("[%dx%d][%dx%d]", surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight(), stride, sliceHeight);
552da853ecaSopenharmony_ci    outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_SLICE_HEIGHT, sliceHeight);
553da853ecaSopenharmony_ci    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, sliceHeight);
554da853ecaSopenharmony_ci}
555da853ecaSopenharmony_ci
556da853ecaSopenharmony_ciint32_t HDecoder::SubmitAllBuffersOwnedByUs()
557da853ecaSopenharmony_ci{
558da853ecaSopenharmony_ci    HLOGI(">>");
559da853ecaSopenharmony_ci    if (isBufferCirculating_) {
560da853ecaSopenharmony_ci        HLOGI("buffer is already circulating, no need to do again");
561da853ecaSopenharmony_ci        return AVCS_ERR_OK;
562da853ecaSopenharmony_ci    }
563da853ecaSopenharmony_ci    int32_t ret = SubmitOutputBuffersToOmxNode();
564da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
565da853ecaSopenharmony_ci        return ret;
566da853ecaSopenharmony_ci    }
567da853ecaSopenharmony_ci    for (BufferInfo& info : inputBufferPool_) {
568da853ecaSopenharmony_ci        if (info.owner == BufferOwner::OWNED_BY_US) {
569da853ecaSopenharmony_ci            NotifyUserToFillThisInBuffer(info);
570da853ecaSopenharmony_ci        }
571da853ecaSopenharmony_ci    }
572da853ecaSopenharmony_ci    isBufferCirculating_ = true;
573da853ecaSopenharmony_ci    return AVCS_ERR_OK;
574da853ecaSopenharmony_ci}
575da853ecaSopenharmony_ci
576da853ecaSopenharmony_civoid HDecoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
577da853ecaSopenharmony_ci{
578da853ecaSopenharmony_ci    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
579da853ecaSopenharmony_ci    if (i >= pool.size()) {
580da853ecaSopenharmony_ci        return;
581da853ecaSopenharmony_ci    }
582da853ecaSopenharmony_ci    BufferInfo& info = pool[i];
583da853ecaSopenharmony_ci    if (portIndex == OMX_DirOutput && info.owner != BufferOwner::OWNED_BY_SURFACE) {
584da853ecaSopenharmony_ci        CancelBufferToSurface(info);
585da853ecaSopenharmony_ci    }
586da853ecaSopenharmony_ci    FreeOmxBuffer(portIndex, info);
587da853ecaSopenharmony_ci    ReduceOwner((portIndex == OMX_DirInput), info.owner);
588da853ecaSopenharmony_ci    pool.erase(pool.begin() + i);
589da853ecaSopenharmony_ci}
590da853ecaSopenharmony_ci
591da853ecaSopenharmony_civoid HDecoder::OnClearBufferPool(OMX_DIRTYPE portIndex)
592da853ecaSopenharmony_ci{
593da853ecaSopenharmony_ci    if ((portIndex == OMX_DirOutput) && currSurface_.surface_) {
594da853ecaSopenharmony_ci        GSError err = currSurface_.surface_->CleanCache();
595da853ecaSopenharmony_ci        if (err != GSERROR_OK) {
596da853ecaSopenharmony_ci            HLOGW("clean cache failed, GSError=%d", err);
597da853ecaSopenharmony_ci        }
598da853ecaSopenharmony_ci        freeList_.clear();
599da853ecaSopenharmony_ci    }
600da853ecaSopenharmony_ci}
601da853ecaSopenharmony_ci
602da853ecaSopenharmony_ciuint64_t HDecoder::GetProducerUsage()
603da853ecaSopenharmony_ci{
604da853ecaSopenharmony_ci    uint64_t producerUsage = currSurface_.surface_ ? SURFACE_MODE_PRODUCER_USAGE : BUFFER_MODE_REQUEST_USAGE;
605da853ecaSopenharmony_ci
606da853ecaSopenharmony_ci    GetBufferHandleUsageParams vendorUsage;
607da853ecaSopenharmony_ci    InitOMXParamExt(vendorUsage);
608da853ecaSopenharmony_ci    vendorUsage.portIndex = static_cast<uint32_t>(OMX_DirOutput);
609da853ecaSopenharmony_ci    if (GetParameter(OMX_IndexParamGetBufferHandleUsage, vendorUsage)) {
610da853ecaSopenharmony_ci        HLOGI("vendor producer usage = 0x%" PRIx64 "", vendorUsage.usage);
611da853ecaSopenharmony_ci        producerUsage |= vendorUsage.usage;
612da853ecaSopenharmony_ci    } else {
613da853ecaSopenharmony_ci        HLOGW("get vendor producer usage failed, add CPU_READ");
614da853ecaSopenharmony_ci        producerUsage |= BUFFER_USAGE_CPU_READ;
615da853ecaSopenharmony_ci    }
616da853ecaSopenharmony_ci    HLOGI("decoder producer usage = 0x%" PRIx64 "", producerUsage);
617da853ecaSopenharmony_ci    return producerUsage;
618da853ecaSopenharmony_ci}
619da853ecaSopenharmony_ci
620da853ecaSopenharmony_civoid HDecoder::CombineConsumerUsage()
621da853ecaSopenharmony_ci{
622da853ecaSopenharmony_ci    uint32_t consumerUsage = currSurface_.surface_->GetDefaultUsage();
623da853ecaSopenharmony_ci    uint64_t finalUsage = requestCfg_.usage | consumerUsage;
624da853ecaSopenharmony_ci    HLOGI("producer usage 0x%" PRIx64 " | consumer usage 0x%x -> 0x%" PRIx64 "",
625da853ecaSopenharmony_ci        requestCfg_.usage, consumerUsage, finalUsage);
626da853ecaSopenharmony_ci    requestCfg_.usage = finalUsage;
627da853ecaSopenharmony_ci}
628da853ecaSopenharmony_ci
629da853ecaSopenharmony_ciint32_t HDecoder::SetQueueSize(const sptr<Surface> &surface, uint32_t targetSize)
630da853ecaSopenharmony_ci{
631da853ecaSopenharmony_ci    GSError err = surface->SetQueueSize(targetSize);
632da853ecaSopenharmony_ci    if (err != GSERROR_OK) {
633da853ecaSopenharmony_ci        HLOGE("surface(%" PRIu64 "), SetQueueSize to %u failed, GSError=%d",
634da853ecaSopenharmony_ci              surface->GetUniqueId(), targetSize, err);
635da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
636da853ecaSopenharmony_ci    }
637da853ecaSopenharmony_ci    HLOGI("surface(%" PRIu64 "), SetQueueSize to %u succ", surface->GetUniqueId(), targetSize);
638da853ecaSopenharmony_ci    return AVCS_ERR_OK;
639da853ecaSopenharmony_ci}
640da853ecaSopenharmony_ci
641da853ecaSopenharmony_ciint32_t HDecoder::AllocOutDynamicSurfaceBuf()
642da853ecaSopenharmony_ci{
643da853ecaSopenharmony_ci    SCOPED_TRACE();
644da853ecaSopenharmony_ci    if (currSurface_.surface_) {
645da853ecaSopenharmony_ci        currGeneration_++;
646da853ecaSopenharmony_ci        currSurface_.surface_->CleanCache();
647da853ecaSopenharmony_ci        int32_t ret = SetQueueSize(currSurface_.surface_, outBufferCnt_);
648da853ecaSopenharmony_ci        if (ret != AVCS_ERR_OK) {
649da853ecaSopenharmony_ci            return ret;
650da853ecaSopenharmony_ci        }
651da853ecaSopenharmony_ci    }
652da853ecaSopenharmony_ci    outputBufferPool_.clear();
653da853ecaSopenharmony_ci
654da853ecaSopenharmony_ci    for (uint32_t i = 0; i < outBufferCnt_; ++i) {
655da853ecaSopenharmony_ci        shared_ptr<OmxCodecBuffer> omxBuffer = DynamicSurfaceBufferToOmxBuffer();
656da853ecaSopenharmony_ci        shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
657da853ecaSopenharmony_ci        int32_t ret = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
658da853ecaSopenharmony_ci        if (ret != HDF_SUCCESS) {
659da853ecaSopenharmony_ci            HLOGE("Failed to UseBuffer on input port");
660da853ecaSopenharmony_ci            return AVCS_ERR_UNKNOWN;
661da853ecaSopenharmony_ci        }
662da853ecaSopenharmony_ci        BufferInfo info {};
663da853ecaSopenharmony_ci        info.isInput = false;
664da853ecaSopenharmony_ci        info.owner = BufferOwner::OWNED_BY_US;
665da853ecaSopenharmony_ci        info.surfaceBuffer = nullptr;
666da853ecaSopenharmony_ci        info.avBuffer = (currSurface_.surface_ ? AVBuffer::CreateAVBuffer() : nullptr);
667da853ecaSopenharmony_ci        info.omxBuffer = outBuffer;
668da853ecaSopenharmony_ci        info.bufferId = outBuffer->bufferId;
669da853ecaSopenharmony_ci        outputBufferPool_.push_back(info);
670da853ecaSopenharmony_ci    }
671da853ecaSopenharmony_ci    HLOGI("succ");
672da853ecaSopenharmony_ci    return AVCS_ERR_OK;
673da853ecaSopenharmony_ci}
674da853ecaSopenharmony_ci
675da853ecaSopenharmony_ciint32_t HDecoder::AllocateOutputBuffersFromSurface()
676da853ecaSopenharmony_ci{
677da853ecaSopenharmony_ci    SCOPED_TRACE();
678da853ecaSopenharmony_ci    currGeneration_++;
679da853ecaSopenharmony_ci    currSurface_.surface_->CleanCache();
680da853ecaSopenharmony_ci    int32_t ret = SetQueueSize(currSurface_.surface_, outBufferCnt_);
681da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
682da853ecaSopenharmony_ci        return ret;
683da853ecaSopenharmony_ci    }
684da853ecaSopenharmony_ci    outputBufferPool_.clear();
685da853ecaSopenharmony_ci    CombineConsumerUsage();
686da853ecaSopenharmony_ci    for (uint32_t i = 0; i < outBufferCnt_; ++i) {
687da853ecaSopenharmony_ci        sptr<SurfaceBuffer> surfaceBuffer;
688da853ecaSopenharmony_ci        sptr<SyncFence> fence;
689da853ecaSopenharmony_ci        GSError err = currSurface_.surface_->RequestBuffer(surfaceBuffer, fence, requestCfg_);
690da853ecaSopenharmony_ci        if (err != GSERROR_OK || surfaceBuffer == nullptr) {
691da853ecaSopenharmony_ci            HLOGE("RequestBuffer %u failed, GSError=%d", i, err);
692da853ecaSopenharmony_ci            return AVCS_ERR_UNKNOWN;
693da853ecaSopenharmony_ci        }
694da853ecaSopenharmony_ci        shared_ptr<OmxCodecBuffer> omxBuffer = SurfaceBufferToOmxBuffer(surfaceBuffer);
695da853ecaSopenharmony_ci        if (omxBuffer == nullptr) {
696da853ecaSopenharmony_ci            currSurface_.surface_->CancelBuffer(surfaceBuffer);
697da853ecaSopenharmony_ci            return AVCS_ERR_UNKNOWN;
698da853ecaSopenharmony_ci        }
699da853ecaSopenharmony_ci        shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
700da853ecaSopenharmony_ci        int32_t hdfRet = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
701da853ecaSopenharmony_ci        if (hdfRet != HDF_SUCCESS) {
702da853ecaSopenharmony_ci            currSurface_.surface_->CancelBuffer(surfaceBuffer);
703da853ecaSopenharmony_ci            HLOGE("Failed to UseBuffer with output port");
704da853ecaSopenharmony_ci            return AVCS_ERR_NO_MEMORY;
705da853ecaSopenharmony_ci        }
706da853ecaSopenharmony_ci        SetCallerToBuffer(surfaceBuffer->GetFileDescriptor());
707da853ecaSopenharmony_ci        outBuffer->fenceFd = -1;
708da853ecaSopenharmony_ci        BufferInfo info {};
709da853ecaSopenharmony_ci        info.isInput = false;
710da853ecaSopenharmony_ci        info.owner = BufferOwner::OWNED_BY_US;
711da853ecaSopenharmony_ci        info.surfaceBuffer = surfaceBuffer;
712da853ecaSopenharmony_ci        info.avBuffer = AVBuffer::CreateAVBuffer();
713da853ecaSopenharmony_ci        info.omxBuffer = outBuffer;
714da853ecaSopenharmony_ci        info.bufferId = outBuffer->bufferId;
715da853ecaSopenharmony_ci        outputBufferPool_.push_back(info);
716da853ecaSopenharmony_ci        HLOGI("generation=%d, bufferId=%u, seq=%u", currGeneration_, info.bufferId, surfaceBuffer->GetSeqNum());
717da853ecaSopenharmony_ci    }
718da853ecaSopenharmony_ci    return AVCS_ERR_OK;
719da853ecaSopenharmony_ci}
720da853ecaSopenharmony_ci
721da853ecaSopenharmony_civoid HDecoder::CancelBufferToSurface(BufferInfo& info)
722da853ecaSopenharmony_ci{
723da853ecaSopenharmony_ci    if (currSurface_.surface_ && info.surfaceBuffer) {
724da853ecaSopenharmony_ci        GSError err = currSurface_.surface_->CancelBuffer(info.surfaceBuffer);
725da853ecaSopenharmony_ci        if (err != GSERROR_OK) {
726da853ecaSopenharmony_ci            HLOGW("surface(%" PRIu64 "), CancelBuffer(seq=%u) failed, GSError=%d",
727da853ecaSopenharmony_ci                  currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum(), err);
728da853ecaSopenharmony_ci        } else {
729da853ecaSopenharmony_ci            HLOGI("surface(%" PRIu64 "), CancelBuffer(seq=%u) succ",
730da853ecaSopenharmony_ci                  currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum());
731da853ecaSopenharmony_ci        }
732da853ecaSopenharmony_ci    }
733da853ecaSopenharmony_ci    ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE); // change owner even if cancel failed
734da853ecaSopenharmony_ci}
735da853ecaSopenharmony_ci
736da853ecaSopenharmony_ciint32_t HDecoder::RegisterListenerToSurface(const sptr<Surface> &surface)
737da853ecaSopenharmony_ci{
738da853ecaSopenharmony_ci    uint64_t surfaceId = surface->GetUniqueId();
739da853ecaSopenharmony_ci    std::weak_ptr<HCodec> weakThis = weak_from_this();
740da853ecaSopenharmony_ci    GSError err = surface->RegisterReleaseListener([weakThis, surfaceId](sptr<SurfaceBuffer>&) {
741da853ecaSopenharmony_ci        std::shared_ptr<HCodec> codec = weakThis.lock();
742da853ecaSopenharmony_ci        if (codec == nullptr) {
743da853ecaSopenharmony_ci            LOGD("decoder is gone");
744da853ecaSopenharmony_ci            return GSERROR_OK;
745da853ecaSopenharmony_ci        }
746da853ecaSopenharmony_ci        return codec->OnBufferReleasedByConsumer(surfaceId);
747da853ecaSopenharmony_ci    });
748da853ecaSopenharmony_ci    if (err != GSERROR_OK) {
749da853ecaSopenharmony_ci        HLOGE("surface(%" PRIu64 "), RegisterReleaseListener failed, GSError=%d", surfaceId, err);
750da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
751da853ecaSopenharmony_ci    }
752da853ecaSopenharmony_ci    return AVCS_ERR_OK;
753da853ecaSopenharmony_ci}
754da853ecaSopenharmony_ci
755da853ecaSopenharmony_ciGSError HDecoder::OnBufferReleasedByConsumer(uint64_t surfaceId)
756da853ecaSopenharmony_ci{
757da853ecaSopenharmony_ci    ParamSP param = make_shared<ParamBundle>();
758da853ecaSopenharmony_ci    param->SetValue("surfaceId", surfaceId);
759da853ecaSopenharmony_ci    SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, param);
760da853ecaSopenharmony_ci    return GSERROR_OK;
761da853ecaSopenharmony_ci}
762da853ecaSopenharmony_ci
763da853ecaSopenharmony_ciHDecoder::SurfaceBufferItem HDecoder::RequestBuffer()
764da853ecaSopenharmony_ci{
765da853ecaSopenharmony_ci    SurfaceBufferItem item{};
766da853ecaSopenharmony_ci    item.generation = currGeneration_;
767da853ecaSopenharmony_ci    GSError err = currSurface_.surface_->RequestBuffer(item.buffer, item.fence, requestCfg_);
768da853ecaSopenharmony_ci    if (err != GSERROR_OK || item.buffer == nullptr || item.buffer->GetBufferHandle() == nullptr) {
769da853ecaSopenharmony_ci        HLOGW("RequestBuffer failed, GSError=%d", err);
770da853ecaSopenharmony_ci        return { nullptr, nullptr };
771da853ecaSopenharmony_ci    }
772da853ecaSopenharmony_ci    return item;
773da853ecaSopenharmony_ci}
774da853ecaSopenharmony_ci
775da853ecaSopenharmony_cistd::vector<HCodec::BufferInfo>::iterator HDecoder::FindBelongTo(sptr<SurfaceBuffer>& buffer)
776da853ecaSopenharmony_ci{
777da853ecaSopenharmony_ci    BufferHandle* handle = buffer->GetBufferHandle();
778da853ecaSopenharmony_ci    return std::find_if(outputBufferPool_.begin(), outputBufferPool_.end(), [handle](const BufferInfo& info) {
779da853ecaSopenharmony_ci        return (info.owner == BufferOwner::OWNED_BY_SURFACE) &&
780da853ecaSopenharmony_ci               info.surfaceBuffer && (info.surfaceBuffer->GetBufferHandle() == handle);
781da853ecaSopenharmony_ci    });
782da853ecaSopenharmony_ci}
783da853ecaSopenharmony_ci
784da853ecaSopenharmony_civoid HDecoder::OnGetBufferFromSurface(const ParamSP& param)
785da853ecaSopenharmony_ci{
786da853ecaSopenharmony_ci    SCOPED_TRACE();
787da853ecaSopenharmony_ci    uint64_t surfaceId = 0;
788da853ecaSopenharmony_ci    param->GetValue("surfaceId", surfaceId);
789da853ecaSopenharmony_ci    if (!currSurface_.surface_ || currSurface_.surface_->GetUniqueId() != surfaceId) {
790da853ecaSopenharmony_ci        return;
791da853ecaSopenharmony_ci    }
792da853ecaSopenharmony_ci    SurfaceBufferItem item = RequestBuffer();
793da853ecaSopenharmony_ci    if (item.buffer == nullptr) {
794da853ecaSopenharmony_ci        return;
795da853ecaSopenharmony_ci    }
796da853ecaSopenharmony_ci    ScopedTrace tracePoint("requested:" + std::to_string(item.buffer->GetSeqNum()));
797da853ecaSopenharmony_ci    freeList_.push_back(item); // push to list, retrive it later, to avoid wait fence too early
798da853ecaSopenharmony_ci    static constexpr size_t MAX_CACHE_CNT = 2;
799da853ecaSopenharmony_ci    if (item.fence == nullptr || !item.fence->IsValid() || freeList_.size() > MAX_CACHE_CNT) {
800da853ecaSopenharmony_ci        SurfaceModeSubmitBuffer();
801da853ecaSopenharmony_ci    }
802da853ecaSopenharmony_ci}
803da853ecaSopenharmony_ci
804da853ecaSopenharmony_civoid HDecoder::SurfaceModeSubmitBuffer()
805da853ecaSopenharmony_ci{
806da853ecaSopenharmony_ci    if (!isDynamic_) {
807da853ecaSopenharmony_ci        // in surface normal mode, just get one surfacebuffer
808da853ecaSopenharmony_ci        SurfaceModeSubmitBufferFromFreeList();
809da853ecaSopenharmony_ci        return;
810da853ecaSopenharmony_ci    }
811da853ecaSopenharmony_ci    // in dynamic mode, find slot which has null surfacebuffer
812da853ecaSopenharmony_ci    auto nullSlot = std::find_if(outputBufferPool_.begin(), outputBufferPool_.end(), [](const BufferInfo& info) {
813da853ecaSopenharmony_ci        return info.surfaceBuffer == nullptr;
814da853ecaSopenharmony_ci    });
815da853ecaSopenharmony_ci    if (nullSlot == outputBufferPool_.end()) {
816da853ecaSopenharmony_ci        // if every slot is not null, just get one surfacebuffer
817da853ecaSopenharmony_ci        SurfaceModeSubmitBufferFromFreeList();
818da853ecaSopenharmony_ci        return;
819da853ecaSopenharmony_ci    }
820da853ecaSopenharmony_ci    SurfaceDynamicModeSubmitBuffer(nullSlot);
821da853ecaSopenharmony_ci}
822da853ecaSopenharmony_ci
823da853ecaSopenharmony_civoid HDecoder::SurfaceModeSubmitBufferFromFreeList()
824da853ecaSopenharmony_ci{
825da853ecaSopenharmony_ci    while (!freeList_.empty()) {
826da853ecaSopenharmony_ci        SurfaceBufferItem item = freeList_.front();
827da853ecaSopenharmony_ci        freeList_.pop_front();
828da853ecaSopenharmony_ci        if (SurfaceModeSubmitOneItem(item)) {
829da853ecaSopenharmony_ci            return;
830da853ecaSopenharmony_ci        }
831da853ecaSopenharmony_ci    }
832da853ecaSopenharmony_ci}
833da853ecaSopenharmony_ci
834da853ecaSopenharmony_cibool HDecoder::SurfaceModeSubmitOneItem(SurfaceBufferItem& item)
835da853ecaSopenharmony_ci{
836da853ecaSopenharmony_ci    SCOPED_TRACE_WITH_ID(item.buffer->GetSeqNum());
837da853ecaSopenharmony_ci    if (item.generation != currGeneration_) {
838da853ecaSopenharmony_ci        HLOGI("buffer generation %d != current generation %d, ignore", item.generation, currGeneration_);
839da853ecaSopenharmony_ci        return false;
840da853ecaSopenharmony_ci    }
841da853ecaSopenharmony_ci    auto iter = FindBelongTo(item.buffer);
842da853ecaSopenharmony_ci    if (iter == outputBufferPool_.end()) {
843da853ecaSopenharmony_ci        HLOGI("seq=%u dont belong to output set, ignore", item.buffer->GetSeqNum());
844da853ecaSopenharmony_ci        return false;
845da853ecaSopenharmony_ci    }
846da853ecaSopenharmony_ci    WaitFence(item.fence);
847da853ecaSopenharmony_ci    ChangeOwner(*iter, BufferOwner::OWNED_BY_US);
848da853ecaSopenharmony_ci    NotifyOmxToFillThisOutBuffer(*iter);
849da853ecaSopenharmony_ci    return true;
850da853ecaSopenharmony_ci}
851da853ecaSopenharmony_ci
852da853ecaSopenharmony_civoid HDecoder::DynamicModeSubmitBuffer()
853da853ecaSopenharmony_ci{
854da853ecaSopenharmony_ci    if (!isDynamic_) {
855da853ecaSopenharmony_ci        return;
856da853ecaSopenharmony_ci    }
857da853ecaSopenharmony_ci    auto nullSlot = std::find_if(outputBufferPool_.begin(), outputBufferPool_.end(), [](const BufferInfo& info) {
858da853ecaSopenharmony_ci        return info.surfaceBuffer == nullptr;
859da853ecaSopenharmony_ci    });
860da853ecaSopenharmony_ci    if (nullSlot == outputBufferPool_.end()) {
861da853ecaSopenharmony_ci        return;
862da853ecaSopenharmony_ci    }
863da853ecaSopenharmony_ci    if (currSurface_.surface_) {
864da853ecaSopenharmony_ci        SurfaceDynamicModeSubmitBuffer(nullSlot);
865da853ecaSopenharmony_ci    } else {
866da853ecaSopenharmony_ci        BufferDynamicModeSubmitBuffer(nullSlot);
867da853ecaSopenharmony_ci    }
868da853ecaSopenharmony_ci}
869da853ecaSopenharmony_ci
870da853ecaSopenharmony_civoid HDecoder::SurfaceDynamicModeSubmitBuffer(std::vector<BufferInfo>::iterator nullSlot)
871da853ecaSopenharmony_ci{
872da853ecaSopenharmony_ci    SCOPED_TRACE();
873da853ecaSopenharmony_ci    for (size_t i = 0; i < outputBufferPool_.size(); i++) {
874da853ecaSopenharmony_ci        SurfaceBufferItem item{};
875da853ecaSopenharmony_ci        if (!freeList_.empty()) {
876da853ecaSopenharmony_ci            item = freeList_.front();
877da853ecaSopenharmony_ci            freeList_.pop_front();
878da853ecaSopenharmony_ci        } else {
879da853ecaSopenharmony_ci            item = RequestBuffer();
880da853ecaSopenharmony_ci            if (item.buffer == nullptr) {
881da853ecaSopenharmony_ci                return;
882da853ecaSopenharmony_ci            }
883da853ecaSopenharmony_ci        }
884da853ecaSopenharmony_ci        if (item.generation != currGeneration_) {
885da853ecaSopenharmony_ci            HLOGI("buffer generation %d != current generation %d, ignore", item.generation, currGeneration_);
886da853ecaSopenharmony_ci            continue;
887da853ecaSopenharmony_ci        }
888da853ecaSopenharmony_ci        auto iter = FindBelongTo(item.buffer);
889da853ecaSopenharmony_ci        WaitFence(item.fence);
890da853ecaSopenharmony_ci        if (iter != outputBufferPool_.end()) {
891da853ecaSopenharmony_ci            // familiar buffer
892da853ecaSopenharmony_ci            ChangeOwner(*iter, BufferOwner::OWNED_BY_US);
893da853ecaSopenharmony_ci            NotifyOmxToFillThisOutBuffer(*iter);
894da853ecaSopenharmony_ci            continue; // keep request until we got a new surfacebuffer
895da853ecaSopenharmony_ci        }
896da853ecaSopenharmony_ci        // unfamiliar buffer
897da853ecaSopenharmony_ci        SetCallerToBuffer(item.buffer->GetFileDescriptor());
898da853ecaSopenharmony_ci        HLOGI("generation=%d, bufferId=%u, seq=%u", currGeneration_, nullSlot->bufferId, item.buffer->GetSeqNum());
899da853ecaSopenharmony_ci        WrapSurfaceBufferToSlot(*nullSlot, item.buffer, 0, 0);
900da853ecaSopenharmony_ci        if (nullSlot == outputBufferPool_.begin()) {
901da853ecaSopenharmony_ci            UpdateFormatFromSurfaceBuffer();
902da853ecaSopenharmony_ci        }
903da853ecaSopenharmony_ci        NotifyOmxToFillThisOutBuffer(*nullSlot);
904da853ecaSopenharmony_ci        nullSlot->omxBuffer->bufferhandle = nullptr;
905da853ecaSopenharmony_ci        return;
906da853ecaSopenharmony_ci    }
907da853ecaSopenharmony_ci}
908da853ecaSopenharmony_ci
909da853ecaSopenharmony_civoid HDecoder::BufferDynamicModeSubmitBuffer(std::vector<BufferInfo>::iterator nullSlot)
910da853ecaSopenharmony_ci{
911da853ecaSopenharmony_ci    SCOPED_TRACE();
912da853ecaSopenharmony_ci    sptr<SurfaceBuffer> buffer = SurfaceBuffer::Create();
913da853ecaSopenharmony_ci    IF_TRUE_RETURN_VOID_WITH_MSG(buffer == nullptr, "CreateSurfaceBuffer failed");
914da853ecaSopenharmony_ci    GSError err = buffer->Alloc(requestCfg_);
915da853ecaSopenharmony_ci    IF_TRUE_RETURN_VOID_WITH_MSG(err != GSERROR_OK, "AllocSurfaceBuffer failed");
916da853ecaSopenharmony_ci    std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(buffer);
917da853ecaSopenharmony_ci    if (avBuffer == nullptr || avBuffer->memory_ == nullptr) {
918da853ecaSopenharmony_ci        HLOGE("CreateAVBuffer failed");
919da853ecaSopenharmony_ci        return;
920da853ecaSopenharmony_ci    }
921da853ecaSopenharmony_ci    SetCallerToBuffer(buffer->GetFileDescriptor());
922da853ecaSopenharmony_ci    HLOGI("bufferId=%u, seq=%u", nullSlot->bufferId, buffer->GetSeqNum());
923da853ecaSopenharmony_ci    WrapSurfaceBufferToSlot(*nullSlot, buffer, 0, 0);
924da853ecaSopenharmony_ci    nullSlot->avBuffer = avBuffer;
925da853ecaSopenharmony_ci    nullSlot->needDealWithCache = (requestCfg_.usage & BUFFER_USAGE_MEM_MMZ_CACHE);
926da853ecaSopenharmony_ci    if (nullSlot == outputBufferPool_.begin()) {
927da853ecaSopenharmony_ci        UpdateFormatFromSurfaceBuffer();
928da853ecaSopenharmony_ci    }
929da853ecaSopenharmony_ci    NotifyOmxToFillThisOutBuffer(*nullSlot);
930da853ecaSopenharmony_ci    nullSlot->omxBuffer->bufferhandle = nullptr;
931da853ecaSopenharmony_ci}
932da853ecaSopenharmony_ci
933da853ecaSopenharmony_ciint32_t HDecoder::NotifySurfaceToRenderOutputBuffer(BufferInfo &info)
934da853ecaSopenharmony_ci{
935da853ecaSopenharmony_ci    SCOPED_TRACE_WITH_ID(info.omxBuffer->pts);
936da853ecaSopenharmony_ci    info.lastFlushTime = GetNowUs();
937da853ecaSopenharmony_ci    if (std::abs(lastFlushRate_ - codecRate_) > std::numeric_limits<float>::epsilon()) {
938da853ecaSopenharmony_ci        sptr<BufferExtraData> extraData = new BufferExtraDataImpl();
939da853ecaSopenharmony_ci        extraData->ExtraSet("VIDEO_RATE", codecRate_);
940da853ecaSopenharmony_ci        info.surfaceBuffer->SetExtraData(extraData);
941da853ecaSopenharmony_ci        lastFlushRate_ = codecRate_;
942da853ecaSopenharmony_ci        HLOGI("flush video rate(%d)", static_cast<int32_t>(codecRate_));
943da853ecaSopenharmony_ci    }
944da853ecaSopenharmony_ci    BufferFlushConfig cfg {
945da853ecaSopenharmony_ci        .damage = {.x = 0, .y = 0, .w = info.surfaceBuffer->GetWidth(), .h = info.surfaceBuffer->GetHeight() },
946da853ecaSopenharmony_ci        .timestamp = info.omxBuffer->pts,
947da853ecaSopenharmony_ci        .desiredPresentTimestamp = -1,
948da853ecaSopenharmony_ci    };
949da853ecaSopenharmony_ci    if (info.avBuffer->meta_->Find(OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP) !=
950da853ecaSopenharmony_ci        info.avBuffer->meta_->end()) {
951da853ecaSopenharmony_ci        info.avBuffer->meta_->Get<OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP>(
952da853ecaSopenharmony_ci            cfg.desiredPresentTimestamp);
953da853ecaSopenharmony_ci        info.avBuffer->meta_->Remove(OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP);
954da853ecaSopenharmony_ci    }
955da853ecaSopenharmony_ci    GSError ret = currSurface_.surface_->FlushBuffer(info.surfaceBuffer, -1, cfg);
956da853ecaSopenharmony_ci    if (ret != GSERROR_OK) {
957da853ecaSopenharmony_ci        HLOGW("surface(%" PRIu64 "), FlushBuffer(seq=%u) failed, GSError=%d",
958da853ecaSopenharmony_ci              currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum(), ret);
959da853ecaSopenharmony_ci        return AVCS_ERR_UNKNOWN;
960da853ecaSopenharmony_ci    }
961da853ecaSopenharmony_ci    ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE);
962da853ecaSopenharmony_ci    return AVCS_ERR_OK;
963da853ecaSopenharmony_ci}
964da853ecaSopenharmony_ci
965da853ecaSopenharmony_civoid HDecoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
966da853ecaSopenharmony_ci{
967da853ecaSopenharmony_ci    SCOPED_TRACE_WITH_ID(bufferId);
968da853ecaSopenharmony_ci    BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
969da853ecaSopenharmony_ci    if (info == nullptr) {
970da853ecaSopenharmony_ci        HLOGE("unknown buffer id %u", bufferId);
971da853ecaSopenharmony_ci        return;
972da853ecaSopenharmony_ci    }
973da853ecaSopenharmony_ci    if (info->owner != BufferOwner::OWNED_BY_OMX) {
974da853ecaSopenharmony_ci        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info->owner));
975da853ecaSopenharmony_ci        return;
976da853ecaSopenharmony_ci    }
977da853ecaSopenharmony_ci    ChangeOwner(*info, BufferOwner::OWNED_BY_US);
978da853ecaSopenharmony_ci
979da853ecaSopenharmony_ci    switch (mode) {
980da853ecaSopenharmony_ci        case KEEP_BUFFER:
981da853ecaSopenharmony_ci            return;
982da853ecaSopenharmony_ci        case RESUBMIT_BUFFER: {
983da853ecaSopenharmony_ci            if (!inputPortEos_) {
984da853ecaSopenharmony_ci                NotifyUserToFillThisInBuffer(*info);
985da853ecaSopenharmony_ci            }
986da853ecaSopenharmony_ci            return;
987da853ecaSopenharmony_ci        }
988da853ecaSopenharmony_ci        default: {
989da853ecaSopenharmony_ci            HLOGE("SHOULD NEVER BE HERE");
990da853ecaSopenharmony_ci            return;
991da853ecaSopenharmony_ci        }
992da853ecaSopenharmony_ci    }
993da853ecaSopenharmony_ci}
994da853ecaSopenharmony_ci
995da853ecaSopenharmony_civoid HDecoder::OnReleaseOutputBuffer(const BufferInfo &info)
996da853ecaSopenharmony_ci{
997da853ecaSopenharmony_ci    if (currSurface_.surface_) {
998da853ecaSopenharmony_ci        HLOGI("outBufId = %u, discard by user, pts = %" PRId64, info.bufferId, info.omxBuffer->pts);
999da853ecaSopenharmony_ci    }
1000da853ecaSopenharmony_ci}
1001da853ecaSopenharmony_ci
1002da853ecaSopenharmony_civoid HDecoder::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
1003da853ecaSopenharmony_ci{
1004da853ecaSopenharmony_ci    if (currSurface_.surface_ == nullptr) {
1005da853ecaSopenharmony_ci        HLOGE("can only render in surface mode");
1006da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
1007da853ecaSopenharmony_ci        return;
1008da853ecaSopenharmony_ci    }
1009da853ecaSopenharmony_ci    uint32_t bufferId = 0;
1010da853ecaSopenharmony_ci    (void)msg.param->GetValue(BUFFER_ID, bufferId);
1011da853ecaSopenharmony_ci    SCOPED_TRACE_WITH_ID(bufferId);
1012da853ecaSopenharmony_ci    optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
1013da853ecaSopenharmony_ci    if (!idx.has_value()) {
1014da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1015da853ecaSopenharmony_ci        return;
1016da853ecaSopenharmony_ci    }
1017da853ecaSopenharmony_ci    BufferInfo& info = outputBufferPool_[idx.value()];
1018da853ecaSopenharmony_ci    if (info.owner != BufferOwner::OWNED_BY_USER) {
1019da853ecaSopenharmony_ci        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info.owner));
1020da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1021da853ecaSopenharmony_ci        return;
1022da853ecaSopenharmony_ci    }
1023da853ecaSopenharmony_ci    info.omxBuffer->pts = info.avBuffer->pts_;
1024da853ecaSopenharmony_ci    ChangeOwner(info, BufferOwner::OWNED_BY_US);
1025da853ecaSopenharmony_ci    ReplyErrorCode(msg.id, AVCS_ERR_OK);
1026da853ecaSopenharmony_ci
1027da853ecaSopenharmony_ci    if (info.omxBuffer->filledLen != 0) {
1028da853ecaSopenharmony_ci        NotifySurfaceToRenderOutputBuffer(info);
1029da853ecaSopenharmony_ci    }
1030da853ecaSopenharmony_ci    if (mode == FREE_BUFFER) {
1031da853ecaSopenharmony_ci        EraseBufferFromPool(OMX_DirOutput, idx.value());
1032da853ecaSopenharmony_ci    } else {
1033da853ecaSopenharmony_ci        SurfaceModeSubmitBuffer();
1034da853ecaSopenharmony_ci    }
1035da853ecaSopenharmony_ci}
1036da853ecaSopenharmony_ci
1037da853ecaSopenharmony_civoid HDecoder::OnEnterUninitializedState()
1038da853ecaSopenharmony_ci{
1039da853ecaSopenharmony_ci    freeList_.clear();
1040da853ecaSopenharmony_ci    currSurface_.Release();
1041da853ecaSopenharmony_ci}
1042da853ecaSopenharmony_ci
1043da853ecaSopenharmony_ciHDecoder::SurfaceItem::SurfaceItem(const sptr<Surface> &surface)
1044da853ecaSopenharmony_ci    : surface_(surface), originalTransform_(surface->GetTransform()) {}
1045da853ecaSopenharmony_ci
1046da853ecaSopenharmony_civoid HDecoder::SurfaceItem::Release()
1047da853ecaSopenharmony_ci{
1048da853ecaSopenharmony_ci    if (surface_) {
1049da853ecaSopenharmony_ci        LOGI("release surface(%" PRIu64 ")", surface_->GetUniqueId());
1050da853ecaSopenharmony_ci        if (originalTransform_.has_value()) {
1051da853ecaSopenharmony_ci            surface_->SetTransform(originalTransform_.value());
1052da853ecaSopenharmony_ci            originalTransform_ = std::nullopt;
1053da853ecaSopenharmony_ci        }
1054da853ecaSopenharmony_ci        surface_ = nullptr;
1055da853ecaSopenharmony_ci    }
1056da853ecaSopenharmony_ci}
1057da853ecaSopenharmony_ci
1058da853ecaSopenharmony_civoid HDecoder::OnSetOutputSurfaceWhenRunning(const sptr<Surface> &newSurface,
1059da853ecaSopenharmony_ci    const MsgInfo &msg, BufferOperationMode mode)
1060da853ecaSopenharmony_ci{
1061da853ecaSopenharmony_ci    SCOPED_TRACE();
1062da853ecaSopenharmony_ci    if (currSurface_.surface_ == nullptr) {
1063da853ecaSopenharmony_ci        HLOGE("can only switch surface on surface mode");
1064da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
1065da853ecaSopenharmony_ci        return;
1066da853ecaSopenharmony_ci    }
1067da853ecaSopenharmony_ci    if (newSurface == nullptr) {
1068da853ecaSopenharmony_ci        HLOGE("surface is null");
1069da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1070da853ecaSopenharmony_ci        return;
1071da853ecaSopenharmony_ci    }
1072da853ecaSopenharmony_ci    if (newSurface->IsConsumer()) {
1073da853ecaSopenharmony_ci        HLOGE("expect a producer surface but got a consumer surface");
1074da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1075da853ecaSopenharmony_ci        return;
1076da853ecaSopenharmony_ci    }
1077da853ecaSopenharmony_ci    uint64_t oldId = currSurface_.surface_->GetUniqueId();
1078da853ecaSopenharmony_ci    uint64_t newId = newSurface->GetUniqueId();
1079da853ecaSopenharmony_ci    HLOGI("surface %" PRIu64 " -> %" PRIu64, oldId, newId);
1080da853ecaSopenharmony_ci    if (oldId == newId) {
1081da853ecaSopenharmony_ci        HLOGI("same surface, no need to set again");
1082da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, AVCS_ERR_OK);
1083da853ecaSopenharmony_ci        return;
1084da853ecaSopenharmony_ci    }
1085da853ecaSopenharmony_ci    int32_t ret = RegisterListenerToSurface(newSurface);
1086da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
1087da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, ret);
1088da853ecaSopenharmony_ci        return;
1089da853ecaSopenharmony_ci    }
1090da853ecaSopenharmony_ci    ret = SetQueueSize(newSurface, outBufferCnt_);
1091da853ecaSopenharmony_ci    if (ret != AVCS_ERR_OK) {
1092da853ecaSopenharmony_ci        ReplyErrorCode(msg.id, ret);
1093da853ecaSopenharmony_ci        return;
1094da853ecaSopenharmony_ci    }
1095da853ecaSopenharmony_ci    SwitchBetweenSurface(newSurface, msg, mode);
1096da853ecaSopenharmony_ci}
1097da853ecaSopenharmony_ci
1098da853ecaSopenharmony_civoid HDecoder::ConsumeFreeList(BufferOperationMode mode)
1099da853ecaSopenharmony_ci{
1100da853ecaSopenharmony_ci    SCOPED_TRACE();
1101da853ecaSopenharmony_ci    while (!freeList_.empty()) {
1102da853ecaSopenharmony_ci        SurfaceBufferItem item = freeList_.front();
1103da853ecaSopenharmony_ci        freeList_.pop_front();
1104da853ecaSopenharmony_ci        auto iter = FindBelongTo(item.buffer);
1105da853ecaSopenharmony_ci        if (iter == outputBufferPool_.end()) {
1106da853ecaSopenharmony_ci            continue;
1107da853ecaSopenharmony_ci        }
1108da853ecaSopenharmony_ci        ChangeOwner(*iter, BufferOwner::OWNED_BY_US);
1109da853ecaSopenharmony_ci        if (mode == RESUBMIT_BUFFER) {
1110da853ecaSopenharmony_ci            WaitFence(item.fence);
1111da853ecaSopenharmony_ci            NotifyOmxToFillThisOutBuffer(*iter);
1112da853ecaSopenharmony_ci        }
1113da853ecaSopenharmony_ci    }
1114da853ecaSopenharmony_ci}
1115da853ecaSopenharmony_ci
1116da853ecaSopenharmony_civoid HDecoder::SwitchBetweenSurface(const sptr<Surface> &newSurface,
1117da853ecaSopenharmony_ci    const MsgInfo &msg, BufferOperationMode mode)
1118da853ecaSopenharmony_ci{
1119da853ecaSopenharmony_ci    SCOPED_TRACE();
1120da853ecaSopenharmony_ci    newSurface->Connect(); // cleancache will work only if the surface is connected by us
1121da853ecaSopenharmony_ci    newSurface->CleanCache(); // make sure new surface is empty
1122da853ecaSopenharmony_ci    uint64_t newId = newSurface->GetUniqueId();
1123da853ecaSopenharmony_ci    for (size_t i = 0; i < outputBufferPool_.size(); i++) {
1124da853ecaSopenharmony_ci        BufferInfo& info = outputBufferPool_[i];
1125da853ecaSopenharmony_ci        if (info.surfaceBuffer == nullptr) {
1126da853ecaSopenharmony_ci            continue;
1127da853ecaSopenharmony_ci        }
1128da853ecaSopenharmony_ci        GSError err = newSurface->AttachBufferToQueue(info.surfaceBuffer);
1129da853ecaSopenharmony_ci        if (err != GSERROR_OK) {
1130da853ecaSopenharmony_ci            HLOGE("surface(%" PRIu64 "), AttachBufferToQueue(seq=%u) failed, GSError=%d",
1131da853ecaSopenharmony_ci                  newId, info.surfaceBuffer->GetSeqNum(), err);
1132da853ecaSopenharmony_ci            ReplyErrorCode(msg.id, AVCS_ERR_UNKNOWN);
1133da853ecaSopenharmony_ci            return;
1134da853ecaSopenharmony_ci        }
1135da853ecaSopenharmony_ci    }
1136da853ecaSopenharmony_ci    ReplyErrorCode(msg.id, AVCS_ERR_OK);
1137da853ecaSopenharmony_ci
1138da853ecaSopenharmony_ci    ConsumeFreeList(mode);
1139da853ecaSopenharmony_ci    map<int64_t, size_t> ownedBySurfaceFlushTime2BufferIndex;
1140da853ecaSopenharmony_ci    vector<size_t> ownedByUs;
1141da853ecaSopenharmony_ci    for (size_t i = 0; i < outputBufferPool_.size(); i++) {
1142da853ecaSopenharmony_ci        BufferInfo& info = outputBufferPool_[i];
1143da853ecaSopenharmony_ci        if (info.surfaceBuffer == nullptr) {
1144da853ecaSopenharmony_ci            continue;
1145da853ecaSopenharmony_ci        }
1146da853ecaSopenharmony_ci        if (info.owner == OWNED_BY_SURFACE) {
1147da853ecaSopenharmony_ci            ownedBySurfaceFlushTime2BufferIndex[info.lastFlushTime] = i;
1148da853ecaSopenharmony_ci        } else if (info.owner == OWNED_BY_US) {
1149da853ecaSopenharmony_ci            ownedByUs.push_back(i);
1150da853ecaSopenharmony_ci        }
1151da853ecaSopenharmony_ci    }
1152da853ecaSopenharmony_ci
1153da853ecaSopenharmony_ci    SurfaceItem oldSurface = currSurface_;
1154da853ecaSopenharmony_ci    currSurface_ = SurfaceItem(newSurface);
1155da853ecaSopenharmony_ci    // if owned by old surface, we need to transfer them to new surface
1156da853ecaSopenharmony_ci    for (auto [flushTime, i] : ownedBySurfaceFlushTime2BufferIndex) {
1157da853ecaSopenharmony_ci        ChangeOwner(outputBufferPool_[i], BufferOwner::OWNED_BY_US);
1158da853ecaSopenharmony_ci        NotifySurfaceToRenderOutputBuffer(outputBufferPool_[i]);
1159da853ecaSopenharmony_ci    }
1160da853ecaSopenharmony_ci    // the consumer of old surface may be destroyed, so flushbuffer will fail, and they are owned by us
1161da853ecaSopenharmony_ci    for (size_t i : ownedByUs) {
1162da853ecaSopenharmony_ci        if (mode == RESUBMIT_BUFFER) {
1163da853ecaSopenharmony_ci            NotifyOmxToFillThisOutBuffer(outputBufferPool_[i]);
1164da853ecaSopenharmony_ci        }
1165da853ecaSopenharmony_ci    }
1166da853ecaSopenharmony_ci
1167da853ecaSopenharmony_ci    oldSurface.surface_->CleanCache(true); // make sure old surface is empty and go black
1168da853ecaSopenharmony_ci    oldSurface.Release();
1169da853ecaSopenharmony_ci    SetTransform();
1170da853ecaSopenharmony_ci    SetScaleMode();
1171da853ecaSopenharmony_ci    HLOGI("set surface(%" PRIu64 ")(%s) succ", newId, newSurface->GetName().c_str());
1172da853ecaSopenharmony_ci}
1173da853ecaSopenharmony_ci
1174da853ecaSopenharmony_ci#ifdef USE_VIDEO_PROCESSING_ENGINE
1175da853ecaSopenharmony_ciint32_t HDecoder::VrrPrediction(BufferInfo &info)
1176da853ecaSopenharmony_ci{
1177da853ecaSopenharmony_ci    SCOPED_TRACE();
1178da853ecaSopenharmony_ci    if (vrrPredictor_ == nullptr) {
1179da853ecaSopenharmony_ci        HLOGE("vrrPredictor_ is nullptr");
1180da853ecaSopenharmony_ci        return AVCS_ERR_INVALID_OPERATION;
1181da853ecaSopenharmony_ci    }
1182da853ecaSopenharmony_ci    int vrrMvType = Media::VideoProcessingEngine::MOTIONVECTOR_TYPE_NONE;
1183da853ecaSopenharmony_ci    if (static_cast<int>(codingType_) == CODEC_OMX_VIDEO_CodingHEVC) {
1184da853ecaSopenharmony_ci        vrrMvType = Media::VideoProcessingEngine::MOTIONVECTOR_TYPE_HEVC;
1185da853ecaSopenharmony_ci    } else if (static_cast<int>(codingType_) == OMX_VIDEO_CodingAVC) {
1186da853ecaSopenharmony_ci        vrrMvType = Media::VideoProcessingEngine::MOTIONVECTOR_TYPE_AVC;
1187da853ecaSopenharmony_ci    } else {
1188da853ecaSopenharmony_ci        HLOGE("VRR only support for HEVC or AVC");
1189da853ecaSopenharmony_ci        return AVCS_ERR_UNSUPPORT;
1190da853ecaSopenharmony_ci    }
1191da853ecaSopenharmony_ci    vrrPredictor_->Process(info.surfaceBuffer, static_cast<int32_t>(codecRate_), vrrMvType);
1192da853ecaSopenharmony_ci    return AVCS_ERR_OK;
1193da853ecaSopenharmony_ci}
1194da853ecaSopenharmony_ci#endif
1195da853ecaSopenharmony_ci} // namespace OHOS::MediaAVCodec