1/*
2 * Copyright (C) 2023 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 "hencoder.h"
17#include <map>
18#include <utility>
19#include "utils/hdf_base.h"
20#include "OMX_VideoExt.h"
21#include "media_description.h"  // foundation/multimedia/av_codec/interfaces/inner_api/native/
22#include "type_converter.h"
23#include "hcodec_log.h"
24#include "hcodec_dfx.h"
25#include "v3_0/codec_ext_types.h"
26
27namespace OHOS::MediaAVCodec {
28using namespace std;
29
30HEncoder::~HEncoder()
31{
32    MsgHandleLoop::Stop();
33}
34
35int32_t HEncoder::OnConfigure(const Format &format)
36{
37    configFormat_ = make_shared<Format>(format);
38    int32_t ret = ConfigureBufferType();
39    if (ret != AVCS_ERR_OK) {
40        return ret;
41    }
42
43    optional<double> frameRate = GetFrameRateFromUser(format);
44    ret = SetupPort(format, frameRate);
45    if (ret != AVCS_ERR_OK) {
46        return ret;
47    }
48    ConfigureProtocol(format, frameRate);
49
50    ret = ConfigureOutputBitrate(format);
51    if (ret != AVCS_ERR_OK) {
52        HLOGW("ConfigureOutputBitrate failed");
53    }
54    ret = SetColorAspects(format);
55    if (ret != AVCS_ERR_OK) {
56        HLOGW("set color aspect failed");
57    }
58    (void)SetProcessName();
59    (void)SetFrameRateAdaptiveMode(format);
60    CheckIfEnableCb(format);
61    ret = SetTemperalLayer(format);
62    if (ret != AVCS_ERR_OK) {
63        return ret;
64    }
65    ret = SetLTRParam(format);
66    if (ret != AVCS_ERR_OK) {
67        return ret;
68    }
69    ret = SetQpRange(format, false);
70    if (ret != AVCS_ERR_OK) {
71        return ret;
72    }
73    ret = SetLowLatency(format);
74    if (ret != AVCS_ERR_OK) {
75        return ret;
76    }
77    ret = SetRepeat(format);
78    if (ret != AVCS_ERR_OK) {
79        return ret;
80    }
81    (void)EnableEncoderParamsFeedback(format);
82    return AVCS_ERR_OK;
83}
84
85int32_t HEncoder::ConfigureBufferType()
86{
87    UseBufferType useBufferTypes;
88    InitOMXParamExt(useBufferTypes);
89    useBufferTypes.portIndex = OMX_DirInput;
90    useBufferTypes.bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE;
91    if (!SetParameter(OMX_IndexParamUseBufferType, useBufferTypes)) {
92        HLOGE("component don't support CODEC_BUFFER_TYPE_DYNAMIC_HANDLE");
93        return AVCS_ERR_INVALID_VAL;
94    }
95    return AVCS_ERR_OK;
96}
97
98void HEncoder::CheckIfEnableCb(const Format &format)
99{
100    int32_t enableCb = 0;
101    if (format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_SURFACE_INPUT_CALLBACK, enableCb)) {
102        HLOGI("enable surface mode callback flag %d", enableCb);
103        enableSurfaceModeInputCb_ = static_cast<bool>(enableCb);
104    }
105}
106
107int32_t HEncoder::SetRepeat(const Format &format)
108{
109    int repeatMs = 0;
110    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_REPEAT_PREVIOUS_FRAME_AFTER, repeatMs)) {
111        return AVCS_ERR_OK;
112    }
113    if (repeatMs <= 0) {
114        HLOGW("invalid repeatMs %d", repeatMs);
115        return AVCS_ERR_INVALID_VAL;
116    }
117    repeatUs_ = static_cast<uint64_t>(repeatMs * TIME_RATIO_S_TO_MS);
118
119    int repeatMaxCnt = 0;
120    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_REPEAT_PREVIOUS_MAX_COUNT, repeatMaxCnt)) {
121        return AVCS_ERR_OK;
122    }
123    if (repeatMaxCnt == 0) {
124        HLOGW("invalid repeatMaxCnt %d", repeatMaxCnt);
125        return AVCS_ERR_INVALID_VAL;
126    }
127    repeatMaxCnt_ = repeatMaxCnt;
128    return AVCS_ERR_OK;
129}
130
131int32_t HEncoder::SetLTRParam(const Format &format)
132{
133    int32_t ltrFrameNum = -1;
134    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, ltrFrameNum)) {
135        return AVCS_ERR_OK;
136    }
137    if (!caps_.port.video.isSupportLTR) {
138        HLOGW("platform not support LTR");
139        return AVCS_ERR_OK;
140    }
141    if (ltrFrameNum <= 0 || ltrFrameNum > caps_.port.video.maxLTRFrameNum) {
142        HLOGE("invalid ltrFrameNum %d", ltrFrameNum);
143        return AVCS_ERR_INVALID_VAL;
144    }
145    if (enableTSVC_) {
146        HLOGW("user has enabled temporal scale, can not set LTR param");
147        return AVCS_ERR_INVALID_VAL;
148    }
149    CodecLTRParam info;
150    InitOMXParamExt(info);
151    info.ltrFrameListLen = static_cast<uint32_t>(ltrFrameNum);
152    if (!SetParameter(OMX_IndexParamLTR, info)) {
153        HLOGE("configure LTR failed");
154        return AVCS_ERR_INVALID_VAL;
155    }
156    enableLTR_ = true;
157    return AVCS_ERR_OK;
158}
159
160int32_t HEncoder::EnableEncoderParamsFeedback(const Format &format)
161{
162    int32_t enableParamsFeedback {};
163    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_PARAMS_FEEDBACK, enableParamsFeedback)) {
164        return AVCS_ERR_OK;
165    }
166    OMX_CONFIG_BOOLEANTYPE param {};
167    InitOMXParam(param);
168    param.bEnabled = enableParamsFeedback ? OMX_TRUE : OMX_FALSE;
169    if (!SetParameter(OMX_IndexParamEncParamsFeedback, param)) {
170        HLOGE("configure encoder params feedback[%d] failed", enableParamsFeedback);
171        return AVCS_ERR_INVALID_VAL;
172    }
173    HLOGI("configure encoder params feedback[%d] success", enableParamsFeedback);
174    return AVCS_ERR_OK;
175}
176
177int32_t HEncoder::SetQpRange(const Format &format, bool isCfg)
178{
179    int32_t minQp;
180    int32_t maxQp;
181    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, minQp) ||
182        !format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, maxQp)) {
183        return AVCS_ERR_OK;
184    }
185
186    CodecQPRangeParam QPRangeParam;
187    InitOMXParamExt(QPRangeParam);
188    QPRangeParam.minQp = static_cast<uint32_t>(minQp);
189    QPRangeParam.maxQp = static_cast<uint32_t>(maxQp);
190    if (!SetParameter(OMX_IndexParamQPRange, QPRangeParam, isCfg)) {
191        HLOGE("set qp range (%d~%d) failed", minQp, maxQp);
192        return AVCS_ERR_UNKNOWN;
193    }
194    HLOGI("set qp range (%d~%d) succ", minQp, maxQp);
195    return AVCS_ERR_OK;
196}
197
198int32_t HEncoder::SetTemperalLayer(const Format &format)
199{
200    int32_t enableTemporalScale = 0;
201    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, enableTemporalScale) ||
202        (enableTemporalScale == 0)) {
203        return AVCS_ERR_OK;
204    }
205    if (!caps_.port.video.isSupportTSVC) {
206        HLOGW("platform not support temporal scale");
207        return AVCS_ERR_OK;
208    }
209    Media::Plugins::TemporalGopReferenceMode GopReferenceMode{};
210    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE,
211        *reinterpret_cast<int *>(&GopReferenceMode)) ||
212        static_cast<int32_t>(GopReferenceMode) != 2) { // 2: gop mode
213        HLOGE("user enable temporal scalability but not set invalid temporal gop mode");
214        return AVCS_ERR_INVALID_VAL;
215    }
216    int32_t temporalGopSize = 0;
217    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize)) {
218        HLOGE("user enable temporal scalability but not set invalid temporal gop size");
219        return AVCS_ERR_INVALID_VAL;
220    }
221
222    CodecTemperalLayerParam temperalLayerParam;
223    InitOMXParamExt(temperalLayerParam);
224    switch (temporalGopSize) {
225        case 2: // 2: picture size of the temporal group
226            temperalLayerParam.layerCnt = 2; // 2: layer of the temporal group
227            break;
228        case 4: // 4: picture size of the temporal group
229            temperalLayerParam.layerCnt = 3; // 3: layer of the temporal group
230            break;
231        default:
232            HLOGE("user set invalid temporal gop size %d", temporalGopSize);
233            return AVCS_ERR_INVALID_VAL;
234    }
235
236    if (!SetParameter(OMX_IndexParamTemperalLayer, temperalLayerParam)) {
237        HLOGE("set temporal layer param failed");
238        return AVCS_ERR_UNKNOWN;
239    }
240    HLOGI("set temporal layer param %d succ", temperalLayerParam.layerCnt);
241    enableTSVC_ = true;
242    return AVCS_ERR_OK;
243}
244
245int32_t HEncoder::OnConfigureBuffer(std::shared_ptr<AVBuffer> buffer)
246{
247    if (!caps_.port.video.isSupportWaterMark) {
248        HLOGE("this device dont support water mark");
249        return AVCS_ERR_UNSUPPORT;
250    }
251    if (buffer == nullptr || buffer->memory_ == nullptr || buffer->meta_ == nullptr) {
252        HLOGE("invalid buffer");
253        return AVCS_ERR_INVALID_VAL;
254    }
255    sptr<SurfaceBuffer> waterMarkBuffer = buffer->memory_->GetSurfaceBuffer();
256    if (waterMarkBuffer == nullptr) {
257        HLOGE("null surfacebuffer");
258        return AVCS_ERR_INVALID_VAL;
259    }
260    if (waterMarkBuffer->GetFormat() != GRAPHIC_PIXEL_FMT_RGBA_8888) {
261        HLOGE("pixel fmt should be RGBA8888");
262        return AVCS_ERR_INVALID_VAL;
263    }
264    bool enableWaterMark = false;
265    int32_t x = 0;
266    int32_t y = 0;
267    int32_t w = 0;
268    int32_t h = 0;
269    if (!buffer->meta_->GetData(OHOS::Media::Tag::VIDEO_ENCODER_ENABLE_WATERMARK, enableWaterMark) ||
270        !buffer->meta_->GetData(OHOS::Media::Tag::VIDEO_COORDINATE_X, x) ||
271        !buffer->meta_->GetData(OHOS::Media::Tag::VIDEO_COORDINATE_Y, y) ||
272        !buffer->meta_->GetData(OHOS::Media::Tag::VIDEO_COORDINATE_W, w) ||
273        !buffer->meta_->GetData(OHOS::Media::Tag::VIDEO_COORDINATE_H, h)) {
274        HLOGE("invalid value");
275        return AVCS_ERR_INVALID_VAL;
276    }
277    if (x < 0 || y < 0 || w <= 0 || h <= 0) {
278        HLOGE("invalid coordinate, x %d, y %d, w %d, h %d", x, y, w, h);
279        return AVCS_ERR_INVALID_VAL;
280    }
281    CodecHDI::CodecParamOverlay param {
282        .size = sizeof(param), .enable = enableWaterMark, .dstX = static_cast<uint32_t>(x),
283        .dstY = static_cast<uint32_t>(y), .dstW = static_cast<uint32_t>(w), .dstH = static_cast<uint32_t>(h),
284    };
285    int8_t* p = reinterpret_cast<int8_t*>(&param);
286    std::vector<int8_t> inVec(p, p + sizeof(param));
287    CodecHDI::OmxCodecBuffer omxbuffer {};
288    omxbuffer.bufferhandle = new HDI::Base::NativeBuffer(waterMarkBuffer->GetBufferHandle());
289    int32_t ret = compNode_->SetParameterWithBuffer(CodecHDI::Codec_IndexParamOverlayBuffer, inVec, omxbuffer);
290    if (ret != HDF_SUCCESS) {
291        HLOGE("SetParameterWithBuffer failed");
292        return AVCS_ERR_INVALID_VAL;
293    }
294    HLOGI("SetParameterWithBuffer succ");
295    return AVCS_ERR_OK;
296}
297
298int32_t HEncoder::SetColorAspects(const Format &format)
299{
300    int range = 0;
301    int primary = static_cast<int>(COLOR_PRIMARY_UNSPECIFIED);
302    int transfer = static_cast<int>(TRANSFER_CHARACTERISTIC_UNSPECIFIED);
303    int matrix = static_cast<int>(MATRIX_COEFFICIENT_UNSPECIFIED);
304
305    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_RANGE_FLAG, range)) {
306        HLOGI("user set range flag %d", range);
307    }
308    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_COLOR_PRIMARIES, primary)) {
309        HLOGI("user set primary %d", primary);
310    }
311    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_TRANSFER_CHARACTERISTICS, transfer)) {
312        HLOGI("user set transfer %d", transfer);
313    }
314    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_MATRIX_COEFFICIENTS, matrix)) {
315        HLOGI("user set matrix %d", matrix);
316    }
317    if (primary < 0 || primary > UINT8_MAX ||
318        transfer < 0 || transfer > UINT8_MAX ||
319        matrix < 0 || matrix > UINT8_MAX) {
320        HLOGW("invalid color");
321        return AVCS_ERR_INVALID_VAL;
322    }
323
324    CodecVideoColorspace param;
325    InitOMXParamExt(param);
326    param.portIndex = OMX_DirInput;
327    param.aspects.range = static_cast<bool>(range);
328    param.aspects.primaries = static_cast<uint8_t>(primary);
329    param.aspects.transfer = static_cast<uint8_t>(transfer);
330    param.aspects.matrixCoeffs = static_cast<uint8_t>(matrix);
331
332    if (!SetParameter(OMX_IndexColorAspects, param, true)) {
333        HLOGE("failed to set CodecVideoColorSpace");
334        return AVCS_ERR_UNKNOWN;
335    }
336    HLOGI("set color aspects (isFullRange %d, primary %u, transfer %u, matrix %u) succ",
337          param.aspects.range, param.aspects.primaries,
338          param.aspects.transfer, param.aspects.matrixCoeffs);
339    return AVCS_ERR_OK;
340}
341
342void HEncoder::CalcInputBufSize(PortInfo &info, VideoPixelFormat pixelFmt)
343{
344    uint32_t inSize = AlignTo(info.width, 128u) * AlignTo(info.height, 128u); // 128: block size
345    if (pixelFmt == VideoPixelFormat::RGBA) {
346        inSize = inSize * 4; // 4 byte per pixel
347    } else {
348        inSize = inSize * 3 / 2; // 3: nom, 2: denom
349    }
350    info.inputBufSize = inSize;
351}
352
353int32_t HEncoder::SetupPort(const Format &format, std::optional<double> frameRate)
354{
355    constexpr int32_t MAX_ENCODE_WIDTH = 10000;
356    constexpr int32_t MAX_ENCODE_HEIGHT = 10000;
357    int32_t width;
358    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) || width <= 0 || width > MAX_ENCODE_WIDTH) {
359        HLOGE("format should contain width");
360        return AVCS_ERR_INVALID_VAL;
361    }
362    int32_t height;
363    if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) || height <= 0 || height > MAX_ENCODE_HEIGHT) {
364        HLOGE("format should contain height");
365        return AVCS_ERR_INVALID_VAL;
366    }
367    width_ = static_cast<uint32_t>(width);
368    height_ = static_cast<uint32_t>(height);
369    HLOGI("user set width %d, height %d", width, height);
370    if (!GetPixelFmtFromUser(format)) {
371        return AVCS_ERR_INVALID_VAL;
372    }
373
374    if (!frameRate.has_value()) {
375        HLOGI("user don't set valid frame rate, use default 60.0");
376        frameRate = 60.0; // default frame rate 60.0
377    }
378
379    PortInfo inputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
380                              OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
381    CalcInputBufSize(inputPortInfo, configuredFmt_.innerFmt);
382    int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
383    if (ret != AVCS_ERR_OK) {
384        return ret;
385    }
386
387    PortInfo outputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
388                               codingType_, std::nullopt, frameRate.value()};
389    ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
390    if (ret != AVCS_ERR_OK) {
391        return ret;
392    }
393    return AVCS_ERR_OK;
394}
395
396int32_t HEncoder::UpdateInPortFormat()
397{
398    OMX_PARAM_PORTDEFINITIONTYPE def;
399    InitOMXParam(def);
400    def.nPortIndex = OMX_DirInput;
401    if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
402        HLOGE("get input port definition failed");
403        return AVCS_ERR_UNKNOWN;
404    }
405    PrintPortDefinition(def);
406    uint32_t w = def.format.video.nFrameWidth;
407    uint32_t h = def.format.video.nFrameHeight;
408    inBufferCnt_ = def.nBufferCountActual;
409
410    // save into member variable
411    requestCfg_.timeout = 0;
412    requestCfg_.width = static_cast<int32_t>(w);
413    requestCfg_.height = static_cast<int32_t>(h);
414    requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
415    requestCfg_.format = configuredFmt_.graphicFmt;
416    requestCfg_.usage = BUFFER_MODE_REQUEST_USAGE;
417
418    if (inputFormat_ == nullptr) {
419        inputFormat_ = make_shared<Format>();
420    }
421    inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, w);
422    inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, h);
423    inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT,
424        static_cast<int32_t>(configuredFmt_.innerFmt));
425    return AVCS_ERR_OK;
426}
427
428int32_t HEncoder::UpdateOutPortFormat()
429{
430    OMX_PARAM_PORTDEFINITIONTYPE def;
431    InitOMXParam(def);
432    def.nPortIndex = OMX_DirOutput;
433    if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
434        HLOGE("get output port definition failed");
435        return AVCS_ERR_UNKNOWN;
436    }
437    PrintPortDefinition(def);
438    if (outputFormat_ == nullptr) {
439        outputFormat_ = make_shared<Format>();
440    }
441    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, def.format.video.nFrameWidth);
442    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, def.format.video.nFrameHeight);
443    return AVCS_ERR_OK;
444}
445
446static uint32_t SetPFramesSpacing(int32_t iFramesIntervalInMs, double frameRate, uint32_t bFramesSpacing = 0)
447{
448    if (iFramesIntervalInMs < 0) { // IPPPP...
449        return UINT32_MAX - 1;
450    }
451    if (iFramesIntervalInMs == 0) { // IIIII...
452        return 0;
453    }
454    uint32_t iFramesInterval = iFramesIntervalInMs * frameRate / TIME_RATIO_S_TO_MS;
455    uint32_t pFramesSpacing = iFramesInterval / (bFramesSpacing + 1);
456    return pFramesSpacing > 0 ? pFramesSpacing - 1 : 0;
457}
458
459std::optional<uint32_t> HEncoder::GetBitRateFromUser(const Format &format)
460{
461    int64_t bitRateLong;
462    if (format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, bitRateLong) && bitRateLong > 0 &&
463        bitRateLong <= UINT32_MAX) {
464        LOGI("user set bit rate %" PRId64 "", bitRateLong);
465        return static_cast<uint32_t>(bitRateLong);
466    }
467    int32_t bitRateInt;
468    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_BITRATE, bitRateInt) && bitRateInt > 0) {
469        LOGI("user set bit rate %d", bitRateInt);
470        return static_cast<uint32_t>(bitRateInt);
471    }
472    return nullopt;
473}
474
475std::optional<VideoEncodeBitrateMode> HEncoder::GetBitRateModeFromUser(const Format &format)
476{
477    VideoEncodeBitrateMode mode;
478    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, *reinterpret_cast<int *>(&mode))) {
479        return mode;
480    }
481    return nullopt;
482}
483
484int32_t HEncoder::SetConstantQualityMode(int32_t quality)
485{
486    ControlRateConstantQuality bitrateType;
487    InitOMXParamExt(bitrateType);
488    bitrateType.portIndex = OMX_DirOutput;
489    bitrateType.qualityValue = static_cast<uint32_t>(quality);
490    if (!SetParameter(OMX_IndexParamControlRateConstantQuality, bitrateType)) {
491        HLOGE("failed to set OMX_IndexParamControlRateConstantQuality");
492        return AVCS_ERR_UNKNOWN;
493    }
494    HLOGI("set CQ mode and target quality %u succ", bitrateType.qualityValue);
495    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, CQ);
496    outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_QUALITY, quality);
497    return AVCS_ERR_OK;
498}
499
500int32_t HEncoder::ConfigureOutputBitrate(const Format &format)
501{
502    OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
503    InitOMXParam(bitrateType);
504    bitrateType.nPortIndex = OMX_DirOutput;
505    if (!GetParameter(OMX_IndexParamVideoBitrate, bitrateType)) {
506        HLOGE("get OMX_IndexParamVideoBitrate failed");
507        return AVCS_ERR_UNKNOWN;
508    }
509    optional<VideoEncodeBitrateMode> bitRateMode = GetBitRateModeFromUser(format);
510    int32_t quality;
511    if (bitRateMode.has_value() && bitRateMode.value() == CQ &&
512        format.GetIntValue(MediaDescriptionKey::MD_KEY_QUALITY, quality) && quality >= 0) {
513        return SetConstantQualityMode(quality);
514    }
515    optional<uint32_t> bitRate = GetBitRateFromUser(format);
516    if (bitRate.has_value()) {
517        bitrateType.nTargetBitrate = bitRate.value();
518    }
519    if (bitRateMode.has_value()) {
520        auto omxBitrateMode = TypeConverter::InnerModeToOmxBitrateMode(bitRateMode.value());
521        if (omxBitrateMode.has_value()) {
522            bitrateType.eControlRate = omxBitrateMode.value();
523        }
524    }
525    if (!SetParameter(OMX_IndexParamVideoBitrate, bitrateType)) {
526        HLOGE("failed to set OMX_IndexParamVideoBitrate");
527        return AVCS_ERR_UNKNOWN;
528    }
529    outputFormat_->PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE,
530        static_cast<int64_t>(bitrateType.nTargetBitrate));
531    auto innerMode = TypeConverter::OmxBitrateModeToInnerMode(bitrateType.eControlRate);
532    if (innerMode.has_value()) {
533        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE,
534            static_cast<int32_t>(innerMode.value()));
535        HLOGI("set %d mode and target bitrate %u bps succ", bitRateMode.value(), bitrateType.nTargetBitrate);
536    } else {
537        HLOGI("set default bitratemode and target bitrate %u bps succ", bitrateType.nTargetBitrate);
538    }
539    return AVCS_ERR_OK;
540}
541
542void HEncoder::ConfigureProtocol(const Format &format, std::optional<double> frameRate)
543{
544    int32_t ret = AVCS_ERR_OK;
545    switch (static_cast<int>(codingType_)) {
546        case OMX_VIDEO_CodingAVC:
547            ret = SetupAVCEncoderParameters(format, frameRate);
548            break;
549        case CODEC_OMX_VIDEO_CodingHEVC:
550            ret = SetupHEVCEncoderParameters(format, frameRate);
551            break;
552        default:
553            break;
554    }
555    if (ret != AVCS_ERR_OK) {
556        HLOGW("set protocol param failed");
557    }
558}
559
560int32_t HEncoder::SetupAVCEncoderParameters(const Format &format, std::optional<double> frameRate)
561{
562    OMX_VIDEO_PARAM_AVCTYPE avcType;
563    InitOMXParam(avcType);
564    avcType.nPortIndex = OMX_DirOutput;
565    if (!GetParameter(OMX_IndexParamVideoAvc, avcType)) {
566        HLOGE("get OMX_IndexParamVideoAvc parameter fail");
567        return AVCS_ERR_UNKNOWN;
568    }
569    avcType.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
570    avcType.nBFrames = 0;
571
572    AVCProfile profile;
573    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_PROFILE, *reinterpret_cast<int *>(&profile))) {
574        optional<OMX_VIDEO_AVCPROFILETYPE> omxAvcProfile = TypeConverter::InnerAvcProfileToOmxProfile(profile);
575        if (omxAvcProfile.has_value()) {
576            avcType.eProfile = omxAvcProfile.value();
577        }
578    }
579    int32_t iFrameInterval;
580    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_I_FRAME_INTERVAL, iFrameInterval) && frameRate.has_value()) {
581        SetAvcFields(avcType, iFrameInterval, frameRate.value());
582    }
583
584    if (avcType.nBFrames != 0) {
585        avcType.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
586    }
587    avcType.bEnableUEP = OMX_FALSE;
588    avcType.bEnableFMO = OMX_FALSE;
589    avcType.bEnableASO = OMX_FALSE;
590    avcType.bEnableRS = OMX_FALSE;
591    avcType.bFrameMBsOnly = OMX_TRUE;
592    avcType.bMBAFF = OMX_FALSE;
593    avcType.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
594
595    if (!SetParameter(OMX_IndexParamVideoAvc, avcType)) {
596        HLOGE("failed to set OMX_IndexParamVideoAvc");
597        return AVCS_ERR_UNKNOWN;
598    }
599    return AVCS_ERR_OK;
600}
601
602void HEncoder::SetAvcFields(OMX_VIDEO_PARAM_AVCTYPE &avcType, int32_t iFrameInterval, double frameRate)
603{
604    HLOGI("iFrameInterval:%d, frameRate:%.2f, eProfile:0x%x, eLevel:0x%x",
605          iFrameInterval, frameRate, avcType.eProfile, avcType.eLevel);
606
607    if (avcType.eProfile == OMX_VIDEO_AVCProfileBaseline) {
608        avcType.nSliceHeaderSpacing = 0;
609        avcType.bUseHadamard = OMX_TRUE;
610        avcType.nRefFrames = 1;
611        avcType.nPFrames = SetPFramesSpacing(iFrameInterval, frameRate, avcType.nBFrames);
612        if (avcType.nPFrames == 0) {
613            avcType.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
614        }
615        avcType.nRefIdx10ActiveMinus1 = 0;
616        avcType.nRefIdx11ActiveMinus1 = 0;
617        avcType.bEntropyCodingCABAC = OMX_FALSE;
618        avcType.bWeightedPPrediction = OMX_FALSE;
619        avcType.bconstIpred = OMX_FALSE;
620        avcType.bDirect8x8Inference = OMX_FALSE;
621        avcType.bDirectSpatialTemporal = OMX_FALSE;
622        avcType.nCabacInitIdc = 0;
623    } else if (avcType.eProfile == OMX_VIDEO_AVCProfileMain || avcType.eProfile == OMX_VIDEO_AVCProfileHigh) {
624        avcType.nSliceHeaderSpacing = 0;
625        avcType.bUseHadamard = OMX_TRUE;
626        avcType.nRefFrames = avcType.nBFrames == 0 ? 1 : 2; // 2 is number of reference frames
627        avcType.nPFrames = SetPFramesSpacing(iFrameInterval, frameRate, avcType.nBFrames);
628        avcType.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
629        avcType.nRefIdx10ActiveMinus1 = 0;
630        avcType.nRefIdx11ActiveMinus1 = 0;
631        avcType.bEntropyCodingCABAC = OMX_TRUE;
632        avcType.bWeightedPPrediction = OMX_TRUE;
633        avcType.bconstIpred = OMX_TRUE;
634        avcType.bDirect8x8Inference = OMX_TRUE;
635        avcType.bDirectSpatialTemporal = OMX_TRUE;
636        avcType.nCabacInitIdc = 1;
637    }
638}
639
640int32_t HEncoder::SetupHEVCEncoderParameters(const Format &format, std::optional<double> frameRate)
641{
642    CodecVideoParamHevc hevcType;
643    InitOMXParamExt(hevcType);
644    hevcType.portIndex = OMX_DirOutput;
645    if (!GetParameter(OMX_IndexParamVideoHevc, hevcType)) {
646        HLOGE("get OMX_IndexParamVideoHevc parameter fail");
647        return AVCS_ERR_UNKNOWN;
648    }
649
650    HEVCProfile profile;
651    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_PROFILE, *reinterpret_cast<int *>(&profile))) {
652        optional<CodecHevcProfile> omxHevcProfile = TypeConverter::InnerHevcProfileToOmxProfile(profile);
653        if (omxHevcProfile.has_value()) {
654            hevcType.profile = omxHevcProfile.value();
655            HLOGI("HEVCProfile %d, CodecHevcProfile 0x%x", profile, hevcType.profile);
656        }
657    }
658
659    int32_t iFrameInterval;
660    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_I_FRAME_INTERVAL, iFrameInterval) && frameRate.has_value()) {
661        if (iFrameInterval < 0) { // IPPPP...
662            hevcType.keyFrameInterval = UINT32_MAX - 1;
663        } else if (iFrameInterval == 0) { // all intra
664            hevcType.keyFrameInterval = 1;
665        } else {
666            hevcType.keyFrameInterval = iFrameInterval * frameRate.value() / TIME_RATIO_S_TO_MS;
667        }
668        HLOGI("frameRate %.2f, iFrameInterval %d, keyFrameInterval %u", frameRate.value(),
669              iFrameInterval, hevcType.keyFrameInterval);
670    }
671
672    if (!SetParameter(OMX_IndexParamVideoHevc, hevcType)) {
673        HLOGE("failed to set OMX_IndexParamVideoHevc");
674        return AVCS_ERR_INVALID_VAL;
675    }
676    return AVCS_ERR_OK;
677}
678
679int32_t HEncoder::RequestIDRFrame()
680{
681    OMX_CONFIG_INTRAREFRESHVOPTYPE params;
682    InitOMXParam(params);
683    params.nPortIndex = OMX_DirOutput;
684    params.IntraRefreshVOP = OMX_TRUE;
685    if (!SetParameter(OMX_IndexConfigVideoIntraVOPRefresh, params, true)) {
686        HLOGE("failed to request IDR frame");
687        return AVCS_ERR_UNKNOWN;
688    }
689    HLOGI("Set IDR Frame success");
690    return AVCS_ERR_OK;
691}
692
693int32_t HEncoder::OnSetParameters(const Format &format)
694{
695    optional<uint32_t> bitRate = GetBitRateFromUser(format);
696    if (bitRate.has_value()) {
697        OMX_VIDEO_CONFIG_BITRATETYPE bitrateCfgType;
698        InitOMXParam(bitrateCfgType);
699        bitrateCfgType.nPortIndex = OMX_DirOutput;
700        bitrateCfgType.nEncodeBitrate = bitRate.value();
701        if (!SetParameter(OMX_IndexConfigVideoBitrate, bitrateCfgType, true)) {
702            HLOGW("failed to config OMX_IndexConfigVideoBitrate");
703        }
704    }
705
706    optional<double> frameRate = GetFrameRateFromUser(format);
707    if (frameRate.has_value()) {
708        OMX_CONFIG_FRAMERATETYPE framerateCfgType;
709        InitOMXParam(framerateCfgType);
710        framerateCfgType.nPortIndex = OMX_DirInput;
711        framerateCfgType.xEncodeFramerate = frameRate.value() * FRAME_RATE_COEFFICIENT;
712        if (!SetParameter(OMX_IndexConfigVideoFramerate, framerateCfgType, true)) {
713            HLOGW("failed to config OMX_IndexConfigVideoFramerate");
714        }
715    }
716
717    int32_t requestIdr;
718    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_REQUEST_I_FRAME, requestIdr) && requestIdr != 0) {
719        int32_t ret = RequestIDRFrame();
720        if (ret != AVCS_ERR_OK) {
721            return ret;
722        }
723    }
724
725    int32_t ret = SetQpRange(format, true);
726    if (ret != AVCS_ERR_OK) {
727        return ret;
728    }
729    return AVCS_ERR_OK;
730}
731
732int32_t HEncoder::SubmitOutputBuffersToOmxNode()
733{
734    for (BufferInfo &info : outputBufferPool_) {
735        if (info.owner == BufferOwner::OWNED_BY_US) {
736            int32_t ret = NotifyOmxToFillThisOutBuffer(info);
737            if (ret != AVCS_ERR_OK) {
738                return ret;
739            }
740        } else {
741            HLOGE("buffer should be owned by us");
742            return AVCS_ERR_UNKNOWN;
743        }
744    }
745    return AVCS_ERR_OK;
746}
747
748bool HEncoder::ReadyToStart()
749{
750    if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
751        return false;
752    }
753    if (inputSurface_) {
754        HLOGI("surface mode, surface id = %" PRIu64, inputSurface_->GetUniqueId());
755    } else {
756        HLOGI("buffer mode");
757    }
758    return true;
759}
760
761int32_t HEncoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex)
762{
763    if (portIndex == OMX_DirOutput) {
764        return AllocateAvLinearBuffers(portIndex);
765    }
766    if (inputSurface_) {
767        return AllocInBufsForDynamicSurfaceBuf();
768    } else {
769        int32_t ret = AllocateAvSurfaceBuffers(portIndex);
770        if (ret == AVCS_ERR_OK) {
771            UpdateFormatFromSurfaceBuffer();
772        }
773        return ret;
774    }
775}
776
777void HEncoder::UpdateFormatFromSurfaceBuffer()
778{
779    if (inputBufferPool_.empty()) {
780        return;
781    }
782    sptr<SurfaceBuffer> surfaceBuffer = inputBufferPool_.front().surfaceBuffer;
783    if (surfaceBuffer == nullptr) {
784        return;
785    }
786    int32_t stride = surfaceBuffer->GetStride();
787    HLOGI("input stride = %d", stride);
788    inputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_STRIDE, stride);
789}
790
791void HEncoder::ClearDirtyList()
792{
793    sptr<SurfaceBuffer> buffer;
794    sptr<SyncFence> fence;
795    int64_t pts = -1;
796    OHOS::Rect damage;
797    while (true) {
798        GSError ret = inputSurface_->AcquireBuffer(buffer, fence, pts, damage);
799        if (ret != GSERROR_OK || buffer == nullptr) {
800            return;
801        }
802        HLOGI("return stale buffer to surface, seq = %u, pts = %" PRId64 "", buffer->GetSeqNum(), pts);
803        inputSurface_->ReleaseBuffer(buffer, -1);
804    }
805}
806
807int32_t HEncoder::SubmitAllBuffersOwnedByUs()
808{
809    HLOGI(">>");
810    if (isBufferCirculating_) {
811        HLOGI("buffer is already circulating, no need to do again");
812        return AVCS_ERR_OK;
813    }
814    int32_t ret = SubmitOutputBuffersToOmxNode();
815    if (ret != AVCS_ERR_OK) {
816        return ret;
817    }
818    if (inputSurface_) {
819        ClearDirtyList();
820        sptr<IBufferConsumerListener> listener = new EncoderBuffersConsumerListener(this);
821        inputSurface_->RegisterConsumerListener(listener);
822        SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, nullptr);
823    } else {
824        for (BufferInfo &info : inputBufferPool_) {
825            if (info.owner == BufferOwner::OWNED_BY_US) {
826                NotifyUserToFillThisInBuffer(info);
827            }
828        }
829    }
830
831    isBufferCirculating_ = true;
832    return AVCS_ERR_OK;
833}
834
835sptr<Surface> HEncoder::OnCreateInputSurface()
836{
837    if (inputSurface_) {
838        HLOGE("inputSurface_ already exists");
839        return nullptr;
840    }
841
842    sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer("HEncoderSurface");
843    if (consumerSurface == nullptr) {
844        HLOGE("Create the surface consummer fail");
845        return nullptr;
846    }
847    GSError err = consumerSurface->SetDefaultUsage(SURFACE_MODE_CONSUMER_USAGE);
848    if (err == GSERROR_OK) {
849        HLOGI("set consumer usage 0x%x succ", SURFACE_MODE_CONSUMER_USAGE);
850    } else {
851        HLOGW("set consumer usage 0x%x failed", SURFACE_MODE_CONSUMER_USAGE);
852    }
853
854    sptr<IBufferProducer> producer = consumerSurface->GetProducer();
855    if (producer == nullptr) {
856        HLOGE("Get the surface producer fail");
857        return nullptr;
858    }
859
860    sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
861    if (producerSurface == nullptr) {
862        HLOGE("CreateSurfaceAsProducer fail");
863        return nullptr;
864    }
865
866    inputSurface_ = consumerSurface;
867    if (inBufferCnt_ > inputSurface_->GetQueueSize()) {
868        inputSurface_->SetQueueSize(inBufferCnt_);
869    }
870    HLOGI("succ, surface id = %" PRIu64 ", queue size %u",
871          inputSurface_->GetUniqueId(), inputSurface_->GetQueueSize());
872    return producerSurface;
873}
874
875int32_t HEncoder::OnSetInputSurface(sptr<Surface> &inputSurface)
876{
877    if (inputSurface_) {
878        HLOGW("inputSurface_ already exists");
879    }
880
881    if (inputSurface == nullptr) {
882        HLOGE("surface is null");
883        return AVCS_ERR_INVALID_VAL;
884    }
885    if (!inputSurface->IsConsumer()) {
886        HLOGE("expect consumer surface");
887        return AVCS_ERR_INVALID_VAL;
888    }
889
890    inputSurface_ = inputSurface;
891    if (inBufferCnt_ > inputSurface_->GetQueueSize()) {
892        inputSurface_->SetQueueSize(inBufferCnt_);
893    }
894    HLOGI("succ");
895    return AVCS_ERR_OK;
896}
897
898void HEncoder::WrapPerFrameParamIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
899                                              const shared_ptr<Media::Meta> &meta)
900{
901    omxBuffer->alongParam.clear();
902    WrapLTRParamIntoOmxBuffer(omxBuffer, meta);
903    WrapRequestIFrameParamIntoOmxBuffer(omxBuffer, meta);
904    WrapQPRangeParamIntoOmxBuffer(omxBuffer, meta);
905    WrapStartQPIntoOmxBuffer(omxBuffer, meta);
906    WrapIsSkipFrameIntoOmxBuffer(omxBuffer, meta);
907    meta->Clear();
908}
909
910void HEncoder::WrapLTRParamIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
911                                         const shared_ptr<Media::Meta> &meta)
912{
913    if (!enableLTR_) {
914        return;
915    }
916    AppendToVector(omxBuffer->alongParam, OMX_IndexParamLTR);
917    CodecLTRPerFrameParam param;
918    bool markLTR = false;
919    meta->GetData(OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_MARK_LTR, markLTR);
920    param.markAsLTR = markLTR;
921    int32_t useLtrPoc = 0;
922    param.useLTR = meta->GetData(OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_USE_LTR, useLtrPoc);
923    param.useLTRPoc = static_cast<uint32_t>(useLtrPoc);
924    AppendToVector(omxBuffer->alongParam, param);
925}
926
927void HEncoder::WrapRequestIFrameParamIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
928                                                   const shared_ptr<Media::Meta> &meta)
929{
930    bool requestIFrame = false;
931    meta->GetData(OHOS::Media::Tag::VIDEO_REQUEST_I_FRAME, requestIFrame);
932    if (!requestIFrame) {
933        return;
934    }
935    AppendToVector(omxBuffer->alongParam, OMX_IndexConfigVideoIntraVOPRefresh);
936    OMX_CONFIG_INTRAREFRESHVOPTYPE params;
937    InitOMXParam(params);
938    params.nPortIndex = OMX_DirOutput;
939    params.IntraRefreshVOP = OMX_TRUE;
940    AppendToVector(omxBuffer->alongParam, params);
941    HLOGI("pts=%" PRId64 ", requestIFrame", omxBuffer->pts);
942}
943
944void HEncoder::WrapQPRangeParamIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
945                                             const shared_ptr<Media::Meta> &meta)
946{
947    int32_t minQp;
948    int32_t maxQp;
949    if (!meta->GetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MIN, minQp) ||
950        !meta->GetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_MAX, maxQp)) {
951        return;
952    }
953    AppendToVector(omxBuffer->alongParam, OMX_IndexParamQPRange);
954    CodecQPRangeParam param;
955    InitOMXParamExt(param);
956    param.minQp = static_cast<uint32_t>(minQp);
957    param.maxQp = static_cast<uint32_t>(maxQp);
958    AppendToVector(omxBuffer->alongParam, param);
959    HLOGI("pts=%" PRId64 ", qp=(%d~%d)", omxBuffer->pts, minQp, maxQp);
960}
961
962void HEncoder::WrapStartQPIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
963                                        const shared_ptr<Media::Meta> &meta)
964{
965    int32_t startQp {};
966    if (!meta->GetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_START, startQp)) {
967        return;
968    }
969    AppendToVector(omxBuffer->alongParam, OMX_IndexParamQPStsart);
970    AppendToVector(omxBuffer->alongParam, startQp);
971}
972
973void HEncoder::WrapIsSkipFrameIntoOmxBuffer(shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer,
974                                            const shared_ptr<Media::Meta> &meta)
975{
976    bool isSkip {};
977    if (!meta->GetData(OHOS::Media::Tag::VIDEO_PER_FRAME_IS_SKIP, isSkip)) {
978        return;
979    }
980    AppendToVector(omxBuffer->alongParam, OMX_IndexParamSkipFrame);
981    AppendToVector(omxBuffer->alongParam, isSkip);
982}
983
984void HEncoder::DealWithResolutionChange(uint32_t newWidth, uint32_t newHeight)
985{
986    if (width_ != newWidth || height_ != newHeight) {
987        HLOGI("resolution changed, %ux%u -> %ux%u", width_, height_, newWidth, newHeight);
988        width_ = newWidth;
989        height_ = newHeight;
990        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width_);
991        outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height_);
992        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_WIDTH, width_);
993        outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_HEIGHT, height_);
994        HLOGI("output format changed: %s", outputFormat_->Stringify().c_str());
995        callback_->OnOutputFormatChanged(*(outputFormat_.get()));
996    }
997}
998
999void HEncoder::ExtractPerFrameParamFromOmxBuffer(
1000    const shared_ptr<CodecHDI::OmxCodecBuffer> &omxBuffer, shared_ptr<Media::Meta> &meta)
1001{
1002    meta->Clear();
1003    BinaryReader reader(static_cast<uint8_t*>(omxBuffer->alongParam.data()), omxBuffer->alongParam.size());
1004    int* index = nullptr;
1005    while ((index = reader.Read<int>()) != nullptr) {
1006        switch (*index) {
1007            case OMX_IndexConfigCommonOutputSize: {
1008                auto *param = reader.Read<OMX_FRAMESIZETYPE>();
1009                IF_TRUE_RETURN_VOID(param == nullptr);
1010                DealWithResolutionChange(param->nWidth, param->nHeight);
1011                break;
1012            }
1013            case OMX_IndexParamEncOutQp:
1014                ExtractPerFrameAveQpParam(reader, meta);
1015                break;
1016            case OMX_IndexParamEncOutMse:
1017                ExtractPerFrameMSEParam(reader, meta);
1018                break;
1019            case OMX_IndexParamEncOutLTR:
1020                ExtractPerFrameLTRParam(reader, meta);
1021                break;
1022            case OMX_IndexParamEncOutFrameLayer:
1023                ExtractPerFrameLayerParam(reader, meta);
1024                break;
1025            case OMX_IndexParamEncOutRealBitrate:
1026                ExtractPerFrameRealBitrateParam(reader, meta);
1027                break;
1028            case OMX_IndexParamEncOutFrameQp:
1029                ExtractPerFrameFrameQpParam(reader, meta);
1030                break;
1031            case OMX_IndexParamEncOutMad:
1032                ExtractPerFrameMadParam(reader, meta);
1033                break;
1034            case OMX_IndexParamEncOutIRatio:
1035                ExtractPerFrameIRitioParam(reader, meta);
1036                break;
1037            default:
1038                break;
1039        }
1040    }
1041    omxBuffer->alongParam.clear();
1042    if (debugMode_) {
1043        auto metaStr = StringifyMeta(meta);
1044        HLOGI("%s", metaStr.c_str());
1045    }
1046}
1047
1048void HEncoder::ExtractPerFrameLTRParam(BinaryReader &reader, shared_ptr<Media::Meta> &meta)
1049{
1050    auto *ltrParam = reader.Read<CodecEncOutLTRParam>();
1051    IF_TRUE_RETURN_VOID(ltrParam == nullptr);
1052    meta->SetData(OHOS::Media::Tag::VIDEO_PER_FRAME_IS_LTR, ltrParam->isLTR);
1053    meta->SetData(OHOS::Media::Tag::VIDEO_PER_FRAME_POC, static_cast<int32_t>(ltrParam->poc));
1054}
1055
1056void HEncoder::ExtractPerFrameMadParam(BinaryReader &reader, shared_ptr<Media::Meta> &meta)
1057{
1058    auto *madParam = reader.Read<CodecEncOutMadParam>();
1059    IF_TRUE_RETURN_VOID(madParam == nullptr);
1060    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_FRAME_MADI, madParam->frameMadi);
1061    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_FRAME_MADP, madParam->frameMadp);
1062    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_SUM_MADI, madParam->sumMadi);
1063}
1064
1065void HEncoder::ExtractPerFrameRealBitrateParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1066{
1067    auto *realBitrate = reader.Read<OMX_S32>();
1068    IF_TRUE_RETURN_VOID(realBitrate == nullptr);
1069    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_REAL_BITRATE, *realBitrate);
1070}
1071
1072void HEncoder::ExtractPerFrameFrameQpParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1073{
1074    auto *frameQp = reader.Read<OMX_S32>();
1075    IF_TRUE_RETURN_VOID(frameQp == nullptr);
1076    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_FRAME_QP, *frameQp);
1077}
1078
1079void HEncoder::ExtractPerFrameIRitioParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1080{
1081    auto *iRatio = reader.Read<OMX_S32>();
1082    IF_TRUE_RETURN_VOID(iRatio == nullptr);
1083    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_FRAME_I_RATIO, *iRatio);
1084}
1085
1086void HEncoder::ExtractPerFrameAveQpParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1087{
1088    auto *averageQp = reader.Read<OMX_S32>();
1089    IF_TRUE_RETURN_VOID(averageQp == nullptr);
1090    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_QP_AVERAGE, *averageQp);
1091}
1092
1093void HEncoder::ExtractPerFrameMSEParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1094{
1095    auto *averageMseLcu = reader.Read<double>();
1096    IF_TRUE_RETURN_VOID(averageMseLcu == nullptr);
1097    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_MSE, *averageMseLcu);
1098}
1099
1100void HEncoder::ExtractPerFrameLayerParam(BinaryReader &reader, std::shared_ptr<Media::Meta> &meta)
1101{
1102    auto *frameLayer = reader.Read<OMX_S32>();
1103    IF_TRUE_RETURN_VOID(frameLayer == nullptr);
1104    meta->SetData(OHOS::Media::Tag::VIDEO_ENCODER_FRAME_TEMPORAL_ID, *frameLayer);
1105}
1106
1107int32_t HEncoder::AllocInBufsForDynamicSurfaceBuf()
1108{
1109    inputBufferPool_.clear();
1110    for (uint32_t i = 0; i < inBufferCnt_; ++i) {
1111        shared_ptr<CodecHDI::OmxCodecBuffer> omxBuffer = DynamicSurfaceBufferToOmxBuffer();
1112        shared_ptr<CodecHDI::OmxCodecBuffer> outBuffer = make_shared<CodecHDI::OmxCodecBuffer>();
1113        int32_t ret = compNode_->UseBuffer(OMX_DirInput, *omxBuffer, *outBuffer);
1114        if (ret != HDF_SUCCESS) {
1115            HLOGE("Failed to UseBuffer on input port");
1116            return AVCS_ERR_UNKNOWN;
1117        }
1118        BufferInfo info {};
1119        info.isInput = true;
1120        info.owner = BufferOwner::OWNED_BY_SURFACE;
1121        info.surfaceBuffer = nullptr;
1122        info.avBuffer = AVBuffer::CreateAVBuffer();
1123        info.omxBuffer = outBuffer;
1124        info.bufferId = outBuffer->bufferId;
1125        inputBufferPool_.push_back(info);
1126    }
1127
1128    return AVCS_ERR_OK;
1129}
1130
1131void HEncoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
1132{
1133    vector<BufferInfo> &pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
1134    if (i >= pool.size()) {
1135        return;
1136    }
1137    const BufferInfo &info = pool[i];
1138    FreeOmxBuffer(portIndex, info);
1139    ReduceOwner((portIndex == OMX_DirInput), info.owner);
1140    pool.erase(pool.begin() + i);
1141}
1142
1143void HEncoder::OnQueueInputBuffer(const MsgInfo &msg, BufferOperationMode mode)
1144{
1145    if (inputSurface_ && !enableSurfaceModeInputCb_) {
1146        HLOGE("cannot queue input on surface mode");
1147        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
1148        return;
1149    }
1150    // buffer mode or surface callback mode
1151    uint32_t bufferId = 0;
1152    (void)msg.param->GetValue(BUFFER_ID, bufferId);
1153    SCOPED_TRACE_WITH_ID(bufferId);
1154    BufferInfo* bufferInfo = FindBufferInfoByID(OMX_DirInput, bufferId);
1155    if (bufferInfo == nullptr) {
1156        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1157        return;
1158    }
1159    if (bufferInfo->owner != BufferOwner::OWNED_BY_USER) {
1160        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(bufferInfo->owner));
1161        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1162        return;
1163    }
1164
1165    bool discard = false;
1166    if (inputSurface_ && bufferInfo->avBuffer->meta_->GetData(
1167        OHOS::Media::Tag::VIDEO_ENCODER_PER_FRAME_DISCARD, discard) && discard) {
1168        HLOGI("inBufId = %u, discard by user, pts = %" PRId64, bufferId, bufferInfo->avBuffer->pts_);
1169        bufferInfo->avBuffer->meta_->Clear();
1170        ResetSlot(*bufferInfo);
1171        ReplyErrorCode(msg.id, AVCS_ERR_OK);
1172        return;
1173    }
1174    ChangeOwner(*bufferInfo, BufferOwner::OWNED_BY_US);
1175    WrapSurfaceBufferToSlot(*bufferInfo, bufferInfo->surfaceBuffer, bufferInfo->avBuffer->pts_,
1176        UserFlagToOmxFlag(static_cast<AVCodecBufferFlag>(bufferInfo->avBuffer->flag_)));
1177    WrapPerFrameParamIntoOmxBuffer(bufferInfo->omxBuffer, bufferInfo->avBuffer->meta_);
1178    ReplyErrorCode(msg.id, AVCS_ERR_OK);
1179    int32_t err = HCodec::OnQueueInputBuffer(mode, bufferInfo);
1180    if (err != AVCS_ERR_OK) {
1181        ResetSlot(*bufferInfo);
1182        callback_->OnError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_INPUT_DATA_ERROR);
1183    }
1184}
1185
1186void HEncoder::OnGetBufferFromSurface(const ParamSP& param)
1187{
1188    if (GetOneBufferFromSurface()) {
1189        TraverseAvaliableBuffers();
1190    }
1191}
1192
1193bool HEncoder::GetOneBufferFromSurface()
1194{
1195    SCOPED_TRACE();
1196    InSurfaceBufferEntry entry{};
1197    entry.item = make_shared<BufferItem>();
1198    GSError ret = inputSurface_->AcquireBuffer(
1199        entry.item->buffer, entry.item->fence, entry.pts, entry.item->damage);
1200    if (ret != GSERROR_OK || entry.item->buffer == nullptr) {
1201        return false;
1202    }
1203    if (!CheckBufPixFmt(entry.item->buffer)) {
1204        return false;
1205    }
1206    entry.item->generation = ++currGeneration_;
1207    entry.item->surface = inputSurface_;
1208    avaliableBuffers_.push_back(entry);
1209    newestBuffer_ = entry;
1210    HLOGD("generation = %" PRIu64 ", seq = %u, pts = %" PRId64 ", now list size = %zu",
1211          entry.item->generation, entry.item->buffer->GetSeqNum(), entry.pts, avaliableBuffers_.size());
1212    if (repeatUs_ != 0) {
1213        SendRepeatMsg(entry.item->generation);
1214    }
1215    return true;
1216}
1217
1218void HEncoder::SendRepeatMsg(uint64_t generation)
1219{
1220    ParamSP param = make_shared<ParamBundle>();
1221    param->SetValue("generation", generation);
1222    SendAsyncMsg(MsgWhat::CHECK_IF_REPEAT, param, repeatUs_);
1223}
1224
1225void HEncoder::RepeatIfNecessary(const ParamSP& param)
1226{
1227    uint64_t generation = 0;
1228    param->GetValue("generation", generation);
1229    if (inputPortEos_ || (repeatUs_ == 0) || newestBuffer_.item == nullptr ||
1230        newestBuffer_.item->generation != generation) {
1231        return;
1232    }
1233    if (repeatMaxCnt_ > 0 && newestBuffer_.repeatTimes >= repeatMaxCnt_) {
1234        HLOGD("stop repeat generation = %" PRIu64 ", seq = %u, pts = %" PRId64 ", which has been repeated %d times",
1235              generation, newestBuffer_.item->buffer->GetSeqNum(), newestBuffer_.pts, newestBuffer_.repeatTimes);
1236        return;
1237    }
1238    if (avaliableBuffers_.size() >= MAX_LIST_SIZE) {
1239        HLOGW("stop repeat, list size to big: %zu", avaliableBuffers_.size());
1240        return;
1241    }
1242    int64_t newPts = newestBuffer_.pts + static_cast<int64_t>(repeatUs_);
1243    HLOGD("generation = %" PRIu64 ", seq = %u, pts %" PRId64 " -> %" PRId64,
1244          generation, newestBuffer_.item->buffer->GetSeqNum(), newestBuffer_.pts, newPts);
1245    newestBuffer_.pts = newPts;
1246    newestBuffer_.repeatTimes++;
1247    avaliableBuffers_.push_back(newestBuffer_);
1248    SendRepeatMsg(generation);
1249    TraverseAvaliableBuffers();
1250}
1251
1252void HEncoder::TraverseAvaliableBuffers()
1253{
1254    while (!avaliableBuffers_.empty()) {
1255        auto it = find_if(inputBufferPool_.begin(), inputBufferPool_.end(),
1256                          [](const BufferInfo &info) { return info.owner == BufferOwner::OWNED_BY_SURFACE; });
1257        if (it == inputBufferPool_.end()) {
1258            HLOGD("buffer cnt = %zu, but no avaliable slot", avaliableBuffers_.size());
1259            return;
1260        }
1261        InSurfaceBufferEntry entry = avaliableBuffers_.front();
1262        avaliableBuffers_.pop_front();
1263        SubmitOneBuffer(entry, *it);
1264    }
1265}
1266
1267void HEncoder::TraverseAvaliableSlots()
1268{
1269    for (BufferInfo& info : inputBufferPool_) {
1270        if (info.owner != BufferOwner::OWNED_BY_SURFACE) {
1271            continue;
1272        }
1273        if (avaliableBuffers_.empty() && !GetOneBufferFromSurface()) {
1274            HLOGD("slot %u is avaliable, but no buffer", info.bufferId);
1275            return;
1276        }
1277        InSurfaceBufferEntry entry = avaliableBuffers_.front();
1278        avaliableBuffers_.pop_front();
1279        SubmitOneBuffer(entry, info);
1280    }
1281}
1282
1283void HEncoder::SubmitOneBuffer(InSurfaceBufferEntry& entry, BufferInfo &info)
1284{
1285    if (entry.item == nullptr) {
1286        ChangeOwner(info, BufferOwner::OWNED_BY_US);
1287        HLOGI("got input eos");
1288        inputPortEos_ = true;
1289        info.omxBuffer->flag = OMX_BUFFERFLAG_EOS;
1290        info.omxBuffer->bufferhandle = nullptr;
1291        info.omxBuffer->filledLen = 0;
1292        info.surfaceBuffer = nullptr;
1293        NotifyOmxToEmptyThisInBuffer(info);
1294        return;
1295    }
1296    if (!WaitFence(entry.item->fence)) {
1297        return;
1298    }
1299    ChangeOwner(info, BufferOwner::OWNED_BY_US);
1300    WrapSurfaceBufferToSlot(info, entry.item->buffer, entry.pts, 0);
1301    encodingBuffers_[info.bufferId] = entry;
1302    if (enableSurfaceModeInputCb_) {
1303        info.avBuffer->pts_ = entry.pts;
1304        NotifyUserToFillThisInBuffer(info);
1305    } else {
1306        int32_t err = NotifyOmxToEmptyThisInBuffer(info);
1307        if (err != AVCS_ERR_OK) {
1308            ResetSlot(info);
1309            callback_->OnError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_INPUT_DATA_ERROR);
1310        }
1311    }
1312}
1313
1314void HEncoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
1315{
1316    SCOPED_TRACE_WITH_ID(bufferId);
1317    BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
1318    if (info == nullptr) {
1319        HLOGE("unknown buffer id %u", bufferId);
1320        return;
1321    }
1322    if (info->owner != BufferOwner::OWNED_BY_OMX) {
1323        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info->owner));
1324        return;
1325    }
1326    if (inputSurface_) {
1327        ResetSlot(*info);
1328        if (mode == RESUBMIT_BUFFER && !inputPortEos_) {
1329            TraverseAvaliableSlots();
1330        }
1331    } else {
1332        ChangeOwner(*info, BufferOwner::OWNED_BY_US);
1333        if (mode == RESUBMIT_BUFFER && !inputPortEos_) {
1334            NotifyUserToFillThisInBuffer(*info);
1335        }
1336    }
1337}
1338
1339void HEncoder::ResetSlot(BufferInfo& info)
1340{
1341    ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE);
1342    encodingBuffers_.erase(info.bufferId);
1343    info.surfaceBuffer = nullptr;
1344}
1345
1346void HEncoder::EncoderBuffersConsumerListener::OnBufferAvailable()
1347{
1348    codec_->SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, nullptr);
1349}
1350
1351void HEncoder::OnSignalEndOfInputStream(const MsgInfo &msg)
1352{
1353    if (inputSurface_ == nullptr) {
1354        HLOGE("can only be called in surface mode");
1355        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
1356        return;
1357    }
1358    ReplyErrorCode(msg.id, AVCS_ERR_OK);
1359    avaliableBuffers_.push_back(InSurfaceBufferEntry {});
1360    TraverseAvaliableBuffers();
1361}
1362
1363void HEncoder::OnEnterUninitializedState()
1364{
1365    if (inputSurface_) {
1366        inputSurface_->UnregisterConsumerListener();
1367    }
1368    avaliableBuffers_.clear();
1369    newestBuffer_.item.reset();
1370    encodingBuffers_.clear();
1371}
1372
1373HEncoder::BufferItem::~BufferItem()
1374{
1375    if (surface && buffer) {
1376        LOGD("release seq = %u", buffer->GetSeqNum());
1377        surface->ReleaseBuffer(buffer, -1);
1378    }
1379}
1380
1381} // namespace OHOS::MediaAVCodec
1382