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 "hcodec.h"
17#include <cassert>
18#include <vector>
19#include <algorithm>
20#include <thread>
21#include "syspara/parameters.h" // base/startup/init/interfaces/innerkits/include/
22#include "qos.h"
23#include "utils/hdf_base.h"
24#include "codec_omx_ext.h"
25#include "hcodec_list.h"
26#include "hencoder.h"
27#include "hdecoder.h"
28#include "hitrace_meter.h"
29#include "hcodec_log.h"
30#include "hcodec_dfx.h"
31#include "hcodec_utils.h"
32#include "av_hardware_memory.h"
33#include "av_hardware_allocator.h"
34#include "av_shared_memory_ext.h"
35#include "av_shared_allocator.h"
36#include "av_surface_memory.h"
37#include "av_surface_allocator.h"
38
39namespace OHOS::MediaAVCodec {
40using namespace std;
41using namespace CodecHDI;
42using namespace Media;
43
44std::shared_ptr<HCodec> HCodec::Create(const std::string &name)
45{
46    vector<CodecCompCapability> capList = GetCapList();
47    shared_ptr<HCodec> codec;
48    for (const auto& cap : capList) {
49        if (cap.compName != name) {
50            continue;
51        }
52        optional<OMX_VIDEO_CODINGTYPE> type = TypeConverter::HdiRoleToOmxCodingType(cap.role);
53        if (!type) {
54            LOGE("unsupported role %d", cap.role);
55            return nullptr;
56        }
57        if (cap.type == VIDEO_DECODER) {
58            codec = make_shared<HDecoder>(cap, type.value());
59        } else if (cap.type == VIDEO_ENCODER) {
60            codec = make_shared<HEncoder>(cap, type.value());
61        }
62        break;
63    }
64    if (codec == nullptr) {
65        LOGE("cannot find %s", name.c_str());
66        return nullptr;
67    }
68    return codec;
69}
70
71int32_t HCodec::Init(Media::Meta &callerInfo)
72{
73    if (callerInfo.GetData(Tag::AV_CODEC_FORWARD_CALLER_PID, playerCaller_.pid) &&
74        callerInfo.GetData(Tag::AV_CODEC_FORWARD_CALLER_PROCESS_NAME, playerCaller_.processName)) {
75        calledByAvcodec_ = false;
76    } else if (callerInfo.GetData(Tag::AV_CODEC_CALLER_PID, avcodecCaller_.pid) &&
77               callerInfo.GetData(Tag::AV_CODEC_CALLER_PROCESS_NAME, avcodecCaller_.processName)) {
78        calledByAvcodec_ = true;
79    }
80    return DoSyncCall(MsgWhat::INIT, nullptr);
81}
82
83void HCodec::PrintCaller()
84{
85    if (calledByAvcodec_) {
86        HLOGI("[pid %d][%s] -> avcodec", avcodecCaller_.pid, avcodecCaller_.processName.c_str());
87    } else {
88        HLOGI("[pid %d][%s] -> player -> avcodec", playerCaller_.pid, playerCaller_.processName.c_str());
89    }
90}
91
92int32_t HCodec::SetCallback(const std::shared_ptr<MediaCodecCallback> &callback)
93{
94    HLOGI(">>");
95    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
96        msg->SetValue("callback", callback);
97    };
98    return DoSyncCall(MsgWhat::SET_CALLBACK, proc);
99}
100
101int32_t HCodec::Configure(const Format &format)
102{
103    SCOPED_TRACE();
104    HLOGI("%s", format.Stringify().c_str());
105    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
106        msg->SetValue("format", format);
107    };
108    return DoSyncCall(MsgWhat::CONFIGURE, proc);
109}
110
111int32_t HCodec::SetCustomBuffer(std::shared_ptr<AVBuffer> buffer)
112{
113    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
114        msg->SetValue("buffer", buffer);
115    };
116    return DoSyncCall(MsgWhat::CONFIGURE_BUFFER, proc);
117}
118
119int32_t HCodec::SetOutputSurface(sptr<Surface> surface)
120{
121    HLOGI(">>");
122    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
123        msg->SetValue("surface", surface);
124    };
125    return DoSyncCall(MsgWhat::SET_OUTPUT_SURFACE, proc);
126}
127
128int32_t HCodec::Start()
129{
130    SCOPED_TRACE();
131    FUNC_TRACKER();
132    return DoSyncCall(MsgWhat::START, nullptr);
133}
134
135int32_t HCodec::Stop()
136{
137    SCOPED_TRACE();
138    FUNC_TRACKER();
139    return DoSyncCall(MsgWhat::STOP, nullptr);
140}
141
142int32_t HCodec::Flush()
143{
144    SCOPED_TRACE();
145    FUNC_TRACKER();
146    return DoSyncCall(MsgWhat::FLUSH, nullptr);
147}
148
149int32_t HCodec::Reset()
150{
151    SCOPED_TRACE();
152    FUNC_TRACKER();
153    int32_t ret = Release();
154    if (ret == AVCS_ERR_OK) {
155        ret = DoSyncCall(MsgWhat::INIT, nullptr);
156    }
157    return ret;
158}
159
160int32_t HCodec::Release()
161{
162    SCOPED_TRACE();
163    FUNC_TRACKER();
164    return DoSyncCall(MsgWhat::RELEASE, nullptr);
165}
166
167int32_t HCodec::NotifyEos()
168{
169    HLOGI(">>");
170    return DoSyncCall(MsgWhat::NOTIFY_EOS, nullptr);
171}
172
173int32_t HCodec::SetParameter(const Format &format)
174{
175    HLOGI("%s", format.Stringify().c_str());
176    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
177        msg->SetValue("params", format);
178    };
179    return DoSyncCall(MsgWhat::SET_PARAMETERS, proc);
180}
181
182int32_t HCodec::GetInputFormat(Format& format)
183{
184    HLOGI(">>");
185    ParamSP reply;
186    int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_INPUT_FORMAT, nullptr, reply);
187    if (ret != AVCS_ERR_OK) {
188        HLOGE("failed to get input format");
189        return ret;
190    }
191    IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
192        AVCS_ERR_UNKNOWN, "input format not replied");
193    return AVCS_ERR_OK;
194}
195
196int32_t HCodec::GetOutputFormat(Format &format)
197{
198    ParamSP reply;
199    int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_OUTPUT_FORMAT, nullptr, reply);
200    if (ret != AVCS_ERR_OK) {
201        HLOGE("failed to get output format");
202        return ret;
203    }
204    IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
205        AVCS_ERR_UNKNOWN, "output format not replied");
206    format.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_NAME, caps_.compName);
207    format.PutIntValue("IS_VENDOR", 1);
208    return AVCS_ERR_OK;
209}
210
211std::string HCodec::GetHidumperInfo()
212{
213    HLOGI(">>");
214    ParamSP reply;
215    int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_HIDUMPER_INFO, nullptr, reply);
216    if (ret != AVCS_ERR_OK) {
217        HLOGW("failed to get hidumper info");
218        return "";
219    }
220    string info;
221    IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("hidumper-info", info),
222        "", "hidumper info not replied");
223    return info;
224}
225
226sptr<Surface> HCodec::CreateInputSurface()
227{
228    HLOGI(">>");
229    ParamSP reply;
230    int32_t ret = DoSyncCallAndGetReply(MsgWhat::CREATE_INPUT_SURFACE, nullptr, reply);
231    if (ret != AVCS_ERR_OK) {
232        HLOGE("failed to create input surface");
233        return nullptr;
234    }
235    sptr<Surface> inputSurface;
236    IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("surface", inputSurface), nullptr, "input surface not replied");
237    return inputSurface;
238}
239
240int32_t HCodec::SetInputSurface(sptr<Surface> surface)
241{
242    HLOGI(">>");
243    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
244        msg->SetValue("surface", surface);
245    };
246    return DoSyncCall(MsgWhat::SET_INPUT_SURFACE, proc);
247}
248
249int32_t HCodec::SignalRequestIDRFrame()
250{
251    HLOGI(">>");
252    return DoSyncCall(MsgWhat::REQUEST_IDR_FRAME, nullptr);
253}
254
255int32_t HCodec::QueueInputBuffer(uint32_t index)
256{
257    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
258        msg->SetValue(BUFFER_ID, index);
259    };
260    return DoSyncCall(MsgWhat::QUEUE_INPUT_BUFFER, proc);
261}
262
263int32_t HCodec::RenderOutputBuffer(uint32_t index)
264{
265    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
266        msg->SetValue(BUFFER_ID, index);
267    };
268    return DoSyncCall(MsgWhat::RENDER_OUTPUT_BUFFER, proc);
269}
270
271int32_t HCodec::ReleaseOutputBuffer(uint32_t index)
272{
273    std::function<void(ParamSP)> proc = [&](ParamSP msg) {
274        msg->SetValue(BUFFER_ID, index);
275    };
276    return DoSyncCall(MsgWhat::RELEASE_OUTPUT_BUFFER, proc);
277}
278/**************************** public functions end ****************************/
279
280
281HCodec::HCodec(CodecCompCapability caps, OMX_VIDEO_CODINGTYPE codingType, bool isEncoder)
282    : caps_(caps), codingType_(codingType), isEncoder_(isEncoder)
283{
284    debugMode_ = HiLogIsLoggable(HCODEC_DOMAIN, HCODEC_TAG, LOG_DEBUG);
285    string dumpModeStr = OHOS::system::GetParameter("hcodec.dump", "0");
286    dumpMode_ = static_cast<DumpMode>(strtoul(dumpModeStr.c_str(), nullptr, 2)); // 2 is binary
287    LOGI(">> debug mode = %d, dump mode = %s(%lu)",
288        debugMode_, dumpModeStr.c_str(), dumpMode_);
289
290    string isEncoderStr = isEncoder ? "enc." : "dec.";
291    switch (static_cast<int>(codingType_)) {
292        case OMX_VIDEO_CodingAVC:
293            shortName_ = isEncoderStr + "avc";
294            break;
295        case CODEC_OMX_VIDEO_CodingHEVC:
296            shortName_ = isEncoderStr + "hevc";
297            break;
298        case CODEC_OMX_VIDEO_CodingVVC:
299            shortName_ = isEncoderStr + "vvc";
300            break;
301        default:
302            shortName_ = isEncoderStr;
303            break;
304    };
305    isSecure_ = IsSecureMode(caps_.compName);
306    if (isSecure_) {
307        shortName_ += ".secure";
308    }
309
310    uninitializedState_ = make_shared<UninitializedState>(this);
311    initializedState_ = make_shared<InitializedState>(this);
312    startingState_ = make_shared<StartingState>(this);
313    runningState_ = make_shared<RunningState>(this);
314    outputPortChangedState_ = make_shared<OutputPortChangedState>(this);
315    stoppingState_ = make_shared<StoppingState>(this);
316    flushingState_ = make_shared<FlushingState>(this);
317    StateMachine::ChangeStateTo(uninitializedState_);
318}
319
320HCodec::~HCodec()
321{
322    HLOGI(">>");
323    MsgHandleLoop::Stop();
324    ReleaseComponent();
325}
326
327int32_t HCodec::HdiCallback::EventHandler(CodecEventType event, const EventInfo &info)
328{
329    LOGI("event = %d, data1 = %u, data2 = %u", event, info.data1, info.data2);
330    ParamSP msg = make_shared<ParamBundle>();
331    msg->SetValue("event", event);
332    msg->SetValue("data1", info.data1);
333    msg->SetValue("data2", info.data2);
334    std::shared_ptr<HCodec> codec = codec_.lock();
335    if (codec == nullptr) {
336        LOGI("HCodec is gone");
337        return HDF_SUCCESS;
338    }
339    codec->SendAsyncMsg(MsgWhat::CODEC_EVENT, msg);
340    return HDF_SUCCESS;
341}
342
343int32_t HCodec::HdiCallback::EmptyBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
344{
345    ParamSP msg = make_shared<ParamBundle>();
346    msg->SetValue(BUFFER_ID, buffer.bufferId);
347    std::shared_ptr<HCodec> codec = codec_.lock();
348    if (codec == nullptr) {
349        LOGI("HCodec is gone");
350        return HDF_SUCCESS;
351    }
352    codec->SendAsyncMsg(MsgWhat::OMX_EMPTY_BUFFER_DONE, msg);
353    return HDF_SUCCESS;
354}
355
356int32_t HCodec::HdiCallback::FillBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
357{
358    ParamSP msg = make_shared<ParamBundle>();
359    msg->SetValue("omxBuffer", buffer);
360    std::shared_ptr<HCodec> codec = codec_.lock();
361    if (codec == nullptr) {
362        LOGI("HCodec is gone");
363        return HDF_SUCCESS;
364    }
365    codec->SendAsyncMsg(MsgWhat::OMX_FILL_BUFFER_DONE, msg);
366    return HDF_SUCCESS;
367}
368
369int32_t HCodec::SetFrameRateAdaptiveMode(const Format &format)
370{
371    if (!format.ContainKey(OHOS::Media::Tag::VIDEO_FRAME_RATE_ADAPTIVE_MODE)) {
372        return AVCS_ERR_UNKNOWN;
373    }
374
375    WorkingFrequencyParam param {};
376    InitOMXParamExt(param);
377    if (!GetParameter(OMX_IndexParamWorkingFrequency, param)) {
378        HLOGW("get working freq param failed");
379        return AVCS_ERR_UNKNOWN;
380    }
381    if (param.level == 0) {
382        return AVCS_ERR_UNKNOWN;
383    }
384    HLOGI("level cnt is %d, set level to %d", param.level, param.level - 1);
385    param.level = param.level - 1;
386
387    if (!SetParameter(OMX_IndexParamWorkingFrequency, param)) {
388        HLOGW("set working freq param failed");
389        return AVCS_ERR_UNKNOWN;
390    }
391    return AVCS_ERR_OK;
392}
393
394int32_t HCodec::SetProcessName()
395{
396    const std::string& processName = calledByAvcodec_ ? avcodecCaller_.processName : playerCaller_.processName;
397    HLOGI("processName is %s", processName.c_str());
398
399    ProcessNameParam param {};
400    InitOMXParamExt(param);
401    if (strcpy_s(param.processName, sizeof(param.processName), processName.c_str()) != EOK) {
402        HLOGW("strcpy failed");
403        return AVCS_ERR_UNKNOWN;
404    }
405    if (!SetParameter(OMX_IndexParamProcessName, param)) {
406        HLOGW("set process name failed");
407        return AVCS_ERR_UNKNOWN;
408    }
409    return AVCS_ERR_OK;
410}
411
412int32_t HCodec::SetLowLatency(const Format &format)
413{
414    int32_t enableLowLatency;
415    if (!format.GetIntValue(OHOS::Media::Tag::VIDEO_ENABLE_LOW_LATENCY, enableLowLatency)) {
416        return AVCS_ERR_OK;
417    }
418    if (!caps_.port.video.isSupportLowLatency) {
419        HLOGW("platform not support LowLatency");
420        return AVCS_ERR_OK;
421    }
422
423    OMX_CONFIG_BOOLEANTYPE param {};
424    InitOMXParam(param);
425    param.bEnabled = enableLowLatency ? OMX_TRUE : OMX_FALSE;
426    if (!SetParameter(OMX_IndexParamLowLatency, param)) {
427        HLOGW("set low latency failed");
428        return AVCS_ERR_UNKNOWN;
429    }
430    HLOGI("set low latency succ %d", enableLowLatency);
431    return AVCS_ERR_OK;
432}
433
434bool HCodec::GetPixelFmtFromUser(const Format &format)
435{
436    optional<PixelFmt> fmt;
437    VideoPixelFormat innerFmt;
438    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, *(int *)&innerFmt) &&
439        innerFmt != VideoPixelFormat::SURFACE_FORMAT) {
440        fmt = TypeConverter::InnerFmtToFmt(innerFmt);
441    } else {
442        HLOGI("user don't set VideoPixelFormat, use default");
443        for (int32_t f : caps_.port.video.supportPixFmts) {
444            fmt = TypeConverter::GraphicFmtToFmt(static_cast<GraphicPixelFormat>(f));
445            if (fmt.has_value()) {
446                break;
447            }
448        }
449    }
450    if (!fmt) {
451        HLOGE("pixel format unspecified");
452        return false;
453    }
454    configuredFmt_ = fmt.value();
455    HLOGI("configured pixel format is %s", configuredFmt_.strFmt.c_str());
456    return true;
457}
458
459std::optional<double> HCodec::GetFrameRateFromUser(const Format &format)
460{
461    double frameRateDouble;
462    if (format.GetDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRateDouble) && frameRateDouble > 0) {
463        LOGI("user set frame rate %.2f", frameRateDouble);
464        return frameRateDouble;
465    }
466    int frameRateInt;
467    if (format.GetIntValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRateInt) && frameRateInt > 0) {
468        LOGI("user set frame rate %d", frameRateInt);
469        return static_cast<double>(frameRateInt);
470    }
471    return nullopt;
472}
473
474bool HCodec::CheckBufPixFmt(const sptr<SurfaceBuffer>& buffer)
475{
476    int32_t dispFmt = buffer->GetFormat();
477    const std::vector<int32_t>& supportFmts = caps_.port.video.supportPixFmts;
478    if (std::find(supportFmts.begin(), supportFmts.end(), dispFmt) == supportFmts.end()) {
479        LOGE("unsupported buffer pixel format %d", dispFmt);
480        callback_->OnError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_INPUT_DATA_ERROR);
481        return false;
482    }
483    return true;
484}
485
486int32_t HCodec::SetVideoPortInfo(OMX_DIRTYPE portIndex, const PortInfo& info)
487{
488    if (info.pixelFmt.has_value()) {
489        CodecVideoPortFormatParam param;
490        InitOMXParamExt(param);
491        param.portIndex = portIndex;
492        param.codecCompressFormat = info.codingType;
493        param.codecColorFormat = info.pixelFmt->graphicFmt;
494        param.framerate = info.frameRate * FRAME_RATE_COEFFICIENT;
495        if (!SetParameter(OMX_IndexCodecVideoPortFormat, param)) {
496            HLOGE("set port format failed");
497            return AVCS_ERR_UNKNOWN;
498        }
499    }
500    {
501        OMX_PARAM_PORTDEFINITIONTYPE def;
502        InitOMXParam(def);
503        def.nPortIndex = portIndex;
504        if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
505            HLOGE("get port definition failed");
506            return AVCS_ERR_UNKNOWN;
507        }
508        def.format.video.nFrameWidth = info.width;
509        def.format.video.nFrameHeight = info.height;
510        def.format.video.eCompressionFormat = info.codingType;
511        // we dont set eColorFormat here because it has been set by CodecVideoPortFormatParam
512        def.format.video.xFramerate = info.frameRate * FRAME_RATE_COEFFICIENT;
513        if (portIndex == OMX_DirInput && info.inputBufSize.has_value()) {
514            def.nBufferSize = info.inputBufSize.value();
515        }
516        if (!SetParameter(OMX_IndexParamPortDefinition, def)) {
517            HLOGE("set port definition failed");
518            return AVCS_ERR_UNKNOWN;
519        }
520        if (portIndex == OMX_DirOutput) {
521            if (outputFormat_ == nullptr) {
522                outputFormat_ = make_shared<Format>();
523            }
524            outputFormat_->PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, info.frameRate);
525        }
526    }
527
528    return (portIndex == OMX_DirInput) ? UpdateInPortFormat() : UpdateOutPortFormat();
529}
530
531void HCodec::PrintPortDefinition(const OMX_PARAM_PORTDEFINITIONTYPE& def)
532{
533    const OMX_VIDEO_PORTDEFINITIONTYPE& video = def.format.video;
534    HLOGI("----- %s port definition -----", (def.nPortIndex == OMX_DirInput) ? "INPUT" : "OUTPUT");
535    HLOGI("bEnabled %d, bPopulated %d", def.bEnabled, def.bPopulated);
536    HLOGI("nBufferCountActual %u, nBufferSize %u", def.nBufferCountActual, def.nBufferSize);
537    HLOGI("nFrameWidth x nFrameHeight (%u x %u), framerate %u(%.2f)",
538        video.nFrameWidth, video.nFrameHeight, video.xFramerate, video.xFramerate / FRAME_RATE_COEFFICIENT);
539    HLOGI("    nStride x nSliceHeight (%u x %u)", video.nStride, video.nSliceHeight);
540    HLOGI("eCompressionFormat %d(%#x), eColorFormat %d(%#x)",
541        video.eCompressionFormat, video.eCompressionFormat, video.eColorFormat, video.eColorFormat);
542    HLOGI("----------------------------------");
543}
544
545int32_t HCodec::GetPortDefinition(OMX_DIRTYPE portIndex, OMX_PARAM_PORTDEFINITIONTYPE& def)
546{
547    InitOMXParam(def);
548    def.nPortIndex = portIndex;
549    if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
550        HLOGE("get %s port definition failed", (portIndex == OMX_DirInput ? "input" : "output"));
551        return AVCS_ERR_INVALID_VAL;
552    }
553    if (def.nBufferSize == 0 || def.nBufferSize > MAX_HCODEC_BUFFER_SIZE) {
554        HLOGE("invalid nBufferSize %u", def.nBufferSize);
555        return AVCS_ERR_INVALID_VAL;
556    }
557    return AVCS_ERR_OK;
558}
559
560int32_t HCodec::AllocateAvLinearBuffers(OMX_DIRTYPE portIndex)
561{
562    SCOPED_TRACE();
563    OMX_PARAM_PORTDEFINITIONTYPE def;
564    int32_t ret = GetPortDefinition(portIndex, def);
565    if (ret != AVCS_ERR_OK) {
566        return ret;
567    }
568
569    SupportBufferType type;
570    InitOMXParamExt(type);
571    type.portIndex = portIndex;
572    if (GetParameter(OMX_IndexParamSupportBufferType, type) && (type.bufferTypes & CODEC_BUFFER_TYPE_DMA_MEM_FD)) {
573        HLOGI("allocate hardware buffer");
574        return AllocateAvHardwareBuffers(portIndex, def);
575    } else {
576        HLOGI("allocate shared buffer");
577        return AllocateAvSharedBuffers(portIndex, def);
578    }
579}
580
581int32_t HCodec::AllocateAvHardwareBuffers(OMX_DIRTYPE portIndex, const OMX_PARAM_PORTDEFINITIONTYPE& def)
582{
583    SCOPED_TRACE();
584    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
585    pool.clear();
586    for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
587        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
588        omxBuffer->size = sizeof(OmxCodecBuffer);
589        omxBuffer->version.version.majorVersion = 1;
590        omxBuffer->bufferType = CODEC_BUFFER_TYPE_DMA_MEM_FD;
591        omxBuffer->fd = -1;
592        omxBuffer->allocLen = def.nBufferSize;
593        omxBuffer->fenceFd = -1;
594        shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
595        int32_t ret = compNode_->AllocateBuffer(portIndex, *omxBuffer, *outBuffer);
596        if (ret != HDF_SUCCESS) {
597            HLOGE("Failed to AllocateBuffer on %s port", (portIndex == OMX_DirInput ? "input" : "output"));
598            return AVCS_ERR_INVALID_VAL;
599        }
600        MemoryFlag memFlag = MEMORY_READ_WRITE;
601        std::shared_ptr<AVAllocator> avAllocator = AVAllocatorFactory::CreateHardwareAllocator(
602            outBuffer->fd, static_cast<int32_t>(def.nBufferSize), memFlag, isSecure_);
603        IF_TRUE_RETURN_VAL_WITH_MSG(avAllocator == nullptr, AVCS_ERR_INVALID_VAL, "CreateHardwareAllocator failed");
604
605        std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(
606            avAllocator, static_cast<int32_t>(def.nBufferSize));
607        if (avBuffer == nullptr || avBuffer->memory_ == nullptr ||
608            avBuffer->memory_->GetCapacity() != static_cast<int32_t>(def.nBufferSize)) {
609            HLOGE("CreateAVBuffer failed");
610            return AVCS_ERR_NO_MEMORY;
611        }
612        SetCallerToBuffer(outBuffer->fd);
613        BufferInfo bufInfo;
614        bufInfo.isInput        = (portIndex == OMX_DirInput) ? true : false;
615        bufInfo.owner          = BufferOwner::OWNED_BY_US;
616        bufInfo.surfaceBuffer  = nullptr;
617        bufInfo.avBuffer       = avBuffer;
618        bufInfo.omxBuffer      = outBuffer;
619        bufInfo.bufferId       = outBuffer->bufferId;
620        bufInfo.CleanUpUnusedInfo();
621        pool.push_back(bufInfo);
622    }
623    return AVCS_ERR_OK;
624}
625
626int32_t HCodec::AllocateAvSharedBuffers(OMX_DIRTYPE portIndex, const OMX_PARAM_PORTDEFINITIONTYPE& def)
627{
628    SCOPED_TRACE();
629    MemoryFlag memFlag = MEMORY_READ_WRITE;
630    std::shared_ptr<AVAllocator> avAllocator = AVAllocatorFactory::CreateSharedAllocator(memFlag);
631    IF_TRUE_RETURN_VAL_WITH_MSG(avAllocator == nullptr, AVCS_ERR_INVALID_VAL, "CreateSharedAllocator failed");
632
633    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
634    pool.clear();
635    for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
636        std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(avAllocator,
637                                                                      static_cast<int32_t>(def.nBufferSize));
638        if (avBuffer == nullptr || avBuffer->memory_ == nullptr ||
639            avBuffer->memory_->GetCapacity() != static_cast<int32_t>(def.nBufferSize)) {
640            HLOGE("CreateAVBuffer failed");
641            return AVCS_ERR_NO_MEMORY;
642        }
643        std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
644        omxBuffer->size = sizeof(OmxCodecBuffer);
645        omxBuffer->version.version.majorVersion = 1;
646        omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
647        omxBuffer->fd = avBuffer->memory_->GetFileDescriptor();
648        omxBuffer->allocLen = def.nBufferSize;
649        omxBuffer->fenceFd = -1;
650        omxBuffer->type = (portIndex == OMX_DirInput) ? READ_ONLY_TYPE : READ_WRITE_TYPE;
651        shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
652        int32_t ret = compNode_->UseBuffer(portIndex, *omxBuffer, *outBuffer);
653        if (ret != HDF_SUCCESS) {
654            HLOGE("Failed to UseBuffer on %s port", (portIndex == OMX_DirInput ? "input" : "output"));
655            return AVCS_ERR_INVALID_VAL;
656        }
657        BufferInfo bufInfo;
658        bufInfo.isInput        = (portIndex == OMX_DirInput) ? true : false;
659        bufInfo.owner          = BufferOwner::OWNED_BY_US;
660        bufInfo.surfaceBuffer  = nullptr;
661        bufInfo.avBuffer       = avBuffer;
662        bufInfo.omxBuffer      = outBuffer;
663        bufInfo.bufferId       = outBuffer->bufferId;
664        pool.push_back(bufInfo);
665    }
666    return AVCS_ERR_OK;
667}
668
669int32_t HCodec::AllocateAvSurfaceBuffers(OMX_DIRTYPE portIndex)
670{
671    SCOPED_TRACE();
672    OMX_PARAM_PORTDEFINITIONTYPE def;
673    int32_t ret = GetPortDefinition(portIndex, def);
674    if (ret != AVCS_ERR_OK) {
675        return ret;
676    }
677    std::shared_ptr<AVAllocator> avAllocator = AVAllocatorFactory::CreateSurfaceAllocator(requestCfg_);
678    IF_TRUE_RETURN_VAL_WITH_MSG(avAllocator == nullptr, AVCS_ERR_INVALID_VAL, "CreateSurfaceAllocator failed");
679    bool needDealWithCache = (requestCfg_.usage & BUFFER_USAGE_MEM_MMZ_CACHE);
680
681    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
682    pool.clear();
683    for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
684        std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(avAllocator,
685                                                                      static_cast<int32_t>(def.nBufferSize));
686        if (avBuffer == nullptr || avBuffer->memory_ == nullptr) {
687            HLOGE("CreateAVBuffer failed");
688            return AVCS_ERR_NO_MEMORY;
689        }
690        sptr<SurfaceBuffer> surfaceBuffer = avBuffer->memory_->GetSurfaceBuffer();
691        IF_TRUE_RETURN_VAL_WITH_MSG(surfaceBuffer == nullptr, AVCS_ERR_INVALID_VAL, "avbuffer has null surfacebuffer");
692        shared_ptr<OmxCodecBuffer> omxBuffer = isEncoder_ ?
693            DynamicSurfaceBufferToOmxBuffer() : SurfaceBufferToOmxBuffer(surfaceBuffer);
694        IF_TRUE_RETURN_VAL(omxBuffer == nullptr, AVCS_ERR_INVALID_VAL);
695        shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
696        int32_t hdiRet = compNode_->UseBuffer(portIndex, *omxBuffer, *outBuffer);
697        if (hdiRet != HDF_SUCCESS) {
698            HLOGE("Failed to UseBuffer on %s port", (portIndex == OMX_DirInput ? "input" : "output"));
699            return AVCS_ERR_INVALID_VAL;
700        }
701        BufferInfo bufInfo;
702        bufInfo.isInput        = (portIndex == OMX_DirInput) ? true : false;
703        bufInfo.owner          = BufferOwner::OWNED_BY_US;
704        bufInfo.surfaceBuffer  = surfaceBuffer;
705        bufInfo.avBuffer       = avBuffer;
706        bufInfo.omxBuffer      = outBuffer;
707        bufInfo.bufferId       = outBuffer->bufferId;
708        bufInfo.needDealWithCache = needDealWithCache;
709        pool.push_back(bufInfo);
710    }
711
712    return AVCS_ERR_OK;
713}
714
715shared_ptr<OmxCodecBuffer> HCodec::SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer>& surfaceBuffer)
716{
717    BufferHandle* bufferHandle = surfaceBuffer->GetBufferHandle();
718    IF_TRUE_RETURN_VAL_WITH_MSG(bufferHandle == nullptr, nullptr, "surfacebuffer has null bufferhandle");
719    auto omxBuffer = std::make_shared<OmxCodecBuffer>();
720    omxBuffer->size = sizeof(OmxCodecBuffer);
721    omxBuffer->version.version.majorVersion = 1;
722    omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
723    omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
724    omxBuffer->fd = -1;
725    omxBuffer->allocLen = surfaceBuffer->GetSize();
726    omxBuffer->fenceFd = -1;
727    return omxBuffer;
728}
729
730shared_ptr<OmxCodecBuffer> HCodec::DynamicSurfaceBufferToOmxBuffer()
731{
732    auto omxBuffer = make_shared<OmxCodecBuffer>();
733    omxBuffer->size = sizeof(OmxCodecBuffer);
734    omxBuffer->version.version.majorVersion = 1;
735    omxBuffer->bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE;
736    omxBuffer->fd = -1;
737    omxBuffer->allocLen = 0;
738    omxBuffer->fenceFd = -1;
739    return omxBuffer;
740}
741
742const char* HCodec::ToString(BufferOwner owner)
743{
744    switch (owner) {
745        case BufferOwner::OWNED_BY_US:
746            return "us";
747        case BufferOwner::OWNED_BY_USER:
748            return "user";
749        case BufferOwner::OWNED_BY_OMX:
750            return "omx";
751        case BufferOwner::OWNED_BY_SURFACE:
752            return "surface";
753        default:
754            return "";
755    }
756}
757
758void HCodec::BufferInfo::CleanUpUnusedInfo()
759{
760    if (omxBuffer == nullptr || omxBuffer->fd < 0) {
761        return;
762    }
763    if (omxBuffer->fd == 0) {
764        LOGW("fd of omxbuffer should never be 0");
765    }
766    close(omxBuffer->fd);
767    omxBuffer->fd = -1;
768}
769
770void HCodec::BufferInfo::BeginCpuAccess()
771{
772    if (surfaceBuffer && needDealWithCache) {
773        GSError err = surfaceBuffer->InvalidateCache();
774        if (err != GSERROR_OK) {
775            LOGW("InvalidateCache failed, GSError=%d", err);
776        }
777    }
778}
779
780void HCodec::BufferInfo::EndCpuAccess()
781{
782    if (surfaceBuffer && needDealWithCache) {
783        GSError err = surfaceBuffer->Map();
784        if (err != GSERROR_OK) {
785            LOGW("Map failed, GSError=%d", err);
786            return;
787        }
788        err = surfaceBuffer->FlushCache();
789        if (err != GSERROR_OK) {
790            LOGW("FlushCache failed, GSError=%d", err);
791        }
792    }
793}
794
795HCodec::BufferInfo* HCodec::FindBufferInfoByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
796{
797    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
798    for (BufferInfo &info : pool) {
799        if (info.bufferId == bufferId) {
800            return &info;
801        }
802    }
803    HLOGE("unknown buffer id %u", bufferId);
804    return nullptr;
805}
806
807optional<size_t> HCodec::FindBufferIndexByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
808{
809    const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
810    for (size_t i = 0; i < pool.size(); i++) {
811        if (pool[i].bufferId == bufferId) {
812            return i;
813        }
814    }
815    HLOGE("unknown buffer id %u", bufferId);
816    return nullopt;
817}
818
819uint32_t HCodec::UserFlagToOmxFlag(AVCodecBufferFlag userFlag)
820{
821    uint32_t flags = 0;
822    if (userFlag & AVCODEC_BUFFER_FLAG_EOS) {
823        flags |= OMX_BUFFERFLAG_EOS;
824        HLOGI("got input eos");
825    }
826    if (userFlag & AVCODEC_BUFFER_FLAG_SYNC_FRAME) {
827        flags |= OMX_BUFFERFLAG_SYNCFRAME;
828    }
829    if (userFlag & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
830        flags |= OMX_BUFFERFLAG_CODECCONFIG;
831    }
832    return flags;
833}
834
835AVCodecBufferFlag HCodec::OmxFlagToUserFlag(uint32_t omxFlag)
836{
837    uint32_t flags = 0;
838    if (omxFlag & OMX_BUFFERFLAG_EOS) {
839        flags |= AVCODEC_BUFFER_FLAG_EOS;
840        HLOGI("got output eos");
841    }
842    if (omxFlag & OMX_BUFFERFLAG_SYNCFRAME) {
843        flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME;
844    }
845    if (omxFlag & OMX_BUFFERFLAG_CODECCONFIG) {
846        flags |= AVCODEC_BUFFER_FLAG_CODEC_DATA;
847    }
848    return static_cast<AVCodecBufferFlag>(flags);
849}
850
851bool HCodec::WaitFence(const sptr<SyncFence>& fence)
852{
853    if (fence == nullptr || !fence->IsValid()) {
854        return true;
855    }
856    SCOPED_TRACE();
857    auto before = chrono::steady_clock::now();
858    int waitRes = fence->Wait(WAIT_FENCE_MS);
859    if (waitRes == 0) {
860        int64_t costMs = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - before).count();
861        if (costMs >= WARN_FENCE_MS) {
862            HLOGW("wait fence succ but cost %" PRId64 " ms", costMs);
863        }
864        return true;
865    } else {
866        HLOGE("wait fence time out, cost more than %u ms", WAIT_FENCE_MS);
867        return false;
868    }
869}
870
871void HCodec::NotifyUserToFillThisInBuffer(BufferInfo &info)
872{
873    SCOPED_TRACE_WITH_ID(info.bufferId);
874    callback_->OnInputBufferAvailable(info.bufferId, info.avBuffer);
875    ChangeOwner(info, BufferOwner::OWNED_BY_USER);
876}
877
878void HCodec::OnQueueInputBuffer(const MsgInfo &msg, BufferOperationMode mode)
879{
880    uint32_t bufferId = 0;
881    (void)msg.param->GetValue(BUFFER_ID, bufferId);
882    SCOPED_TRACE_WITH_ID(bufferId);
883    BufferInfo* bufferInfo = FindBufferInfoByID(OMX_DirInput, bufferId);
884    if (bufferInfo == nullptr) {
885        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
886        return;
887    }
888    if (bufferInfo->owner != BufferOwner::OWNED_BY_USER) {
889        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(bufferInfo->owner));
890        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
891        return;
892    }
893    if (!gotFirstInput_) {
894        HLOGI("got first input");
895        gotFirstInput_ = true;
896    }
897    bufferInfo->omxBuffer->filledLen = static_cast<uint32_t>
898        (bufferInfo->avBuffer->memory_->GetSize());
899    bufferInfo->omxBuffer->offset = static_cast<uint32_t>(bufferInfo->avBuffer->memory_->GetOffset());
900    bufferInfo->omxBuffer->pts = bufferInfo->avBuffer->pts_;
901    bufferInfo->omxBuffer->flag = UserFlagToOmxFlag(static_cast<AVCodecBufferFlag>(bufferInfo->avBuffer->flag_));
902    ChangeOwner(*bufferInfo, BufferOwner::OWNED_BY_US);
903    ReplyErrorCode(msg.id, AVCS_ERR_OK);
904    int32_t ret = OnQueueInputBuffer(mode, bufferInfo);
905    if (ret != AVCS_ERR_OK) {
906        SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
907    }
908}
909
910int32_t HCodec::OnQueueInputBuffer(BufferOperationMode mode, BufferInfo* info)
911{
912    switch (mode) {
913        case KEEP_BUFFER: {
914            return AVCS_ERR_OK;
915        }
916        case RESUBMIT_BUFFER: {
917            if (inputPortEos_) {
918                HLOGI("input already eos, keep this buffer");
919                return AVCS_ERR_OK;
920            }
921            bool eos = (info->omxBuffer->flag & OMX_BUFFERFLAG_EOS);
922            if (!eos && info->omxBuffer->filledLen == 0) {
923                HLOGI("this is not a eos buffer but not filled, ask user to re-fill it");
924                NotifyUserToFillThisInBuffer(*info);
925                return AVCS_ERR_OK;
926            }
927            if (eos) {
928                inputPortEos_ = true;
929            }
930            return NotifyOmxToEmptyThisInBuffer(*info);
931        }
932        default: {
933            HLOGE("SHOULD NEVER BE HERE");
934            return AVCS_ERR_UNKNOWN;
935        }
936    }
937}
938
939void HCodec::WrapSurfaceBufferToSlot(BufferInfo &info,
940    const sptr<SurfaceBuffer>& surfaceBuffer, int64_t pts, uint32_t flag)
941{
942    info.surfaceBuffer = surfaceBuffer;
943    info.omxBuffer->bufferhandle = new NativeBuffer(surfaceBuffer->GetBufferHandle());
944    info.omxBuffer->filledLen = surfaceBuffer->GetSize();
945    info.omxBuffer->fd = -1;
946    info.omxBuffer->fenceFd = -1;
947    info.omxBuffer->pts = pts;
948    info.omxBuffer->flag = flag;
949}
950
951void HCodec::OnSignalEndOfInputStream(const MsgInfo &msg)
952{
953    ReplyErrorCode(msg.id, AVCS_ERR_UNSUPPORT);
954}
955
956int32_t HCodec::NotifyOmxToEmptyThisInBuffer(BufferInfo& info)
957{
958    SCOPED_TRACE_WITH_ID(info.bufferId);
959#ifdef BUILD_ENG_VERSION
960    info.Dump(compUniqueStr_, inTotalCnt_, dumpMode_, isEncoder_);
961#endif
962    info.EndCpuAccess();
963    int32_t ret = compNode_->EmptyThisBuffer(*(info.omxBuffer));
964    if (ret != HDF_SUCCESS) {
965        HLOGE("EmptyThisBuffer failed");
966        return AVCS_ERR_UNKNOWN;
967    }
968    ChangeOwner(info, BufferOwner::OWNED_BY_OMX);
969    return AVCS_ERR_OK;
970}
971
972int32_t HCodec::NotifyOmxToFillThisOutBuffer(BufferInfo& info)
973{
974    SCOPED_TRACE_WITH_ID(info.bufferId);
975    info.omxBuffer->flag = 0;
976    int32_t ret = compNode_->FillThisBuffer(*(info.omxBuffer));
977    if (ret != HDF_SUCCESS) {
978        HLOGE("outBufId = %u failed", info.bufferId);
979        return AVCS_ERR_UNKNOWN;
980    }
981    ChangeOwner(info, BufferOwner::OWNED_BY_OMX);
982    return AVCS_ERR_OK;
983}
984
985void HCodec::OnOMXFillBufferDone(const OmxCodecBuffer& omxBuffer, BufferOperationMode mode)
986{
987    SCOPED_TRACE_WITH_ID(omxBuffer.bufferId);
988    optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, omxBuffer.bufferId);
989    if (!idx.has_value()) {
990        return;
991    }
992    BufferInfo& info = outputBufferPool_[idx.value()];
993    if (info.owner != BufferOwner::OWNED_BY_OMX) {
994        HLOGE("wrong ownership: buffer id=%d, owner=%s", info.bufferId, ToString(info.owner));
995        return;
996    }
997    info.omxBuffer->offset = omxBuffer.offset;
998    info.omxBuffer->filledLen = omxBuffer.filledLen;
999    info.omxBuffer->pts = omxBuffer.pts;
1000    info.omxBuffer->flag = omxBuffer.flag;
1001    info.omxBuffer->alongParam = std::move(omxBuffer.alongParam);
1002    ChangeOwner(info, BufferOwner::OWNED_BY_US);
1003    OnOMXFillBufferDone(mode, info, idx.value());
1004}
1005
1006void HCodec::OnOMXFillBufferDone(BufferOperationMode mode, BufferInfo& info, size_t bufferIdx)
1007{
1008    switch (mode) {
1009        case KEEP_BUFFER:
1010            return;
1011        case RESUBMIT_BUFFER: {
1012            if (outputPortEos_) {
1013                HLOGI("output eos, keep this buffer");
1014                return;
1015            }
1016            bool eos = (info.omxBuffer->flag & OMX_BUFFERFLAG_EOS);
1017            if (!eos && info.omxBuffer->filledLen == 0) {
1018                HLOGW("it's not a eos buffer but not filled, ask omx to re-fill it");
1019                NotifyOmxToFillThisOutBuffer(info);
1020                return;
1021            }
1022#ifdef USE_VIDEO_PROCESSING_ENGINE
1023            if (!isEncoder_ && isVrrEnable_) {
1024                (void)VrrPrediction(info);
1025            }
1026#endif
1027            NotifyUserOutBufferAvaliable(info);
1028            if (eos) {
1029                outputPortEos_ = true;
1030            }
1031            return;
1032        }
1033        case FREE_BUFFER:
1034            EraseBufferFromPool(OMX_DirOutput, bufferIdx);
1035            return;
1036        default:
1037            HLOGE("SHOULD NEVER BE HERE");
1038            return;
1039    }
1040}
1041
1042void HCodec::NotifyUserOutBufferAvaliable(BufferInfo &info)
1043{
1044    SCOPED_TRACE_WITH_ID(info.bufferId);
1045    if (!gotFirstOutput_) {
1046        HLOGI("got first output");
1047        OHOS::QOS::ResetThreadQos();
1048        gotFirstOutput_ = true;
1049    }
1050    info.BeginCpuAccess();
1051#ifdef BUILD_ENG_VERSION
1052    info.Dump(compUniqueStr_, outRecord_.totalCnt, dumpMode_, isEncoder_);
1053#endif
1054    shared_ptr<OmxCodecBuffer> omxBuffer = info.omxBuffer;
1055    info.avBuffer->pts_ = omxBuffer->pts;
1056    info.avBuffer->flag_ = OmxFlagToUserFlag(omxBuffer->flag);
1057    if (info.avBuffer->memory_) {
1058        info.avBuffer->memory_->SetSize(static_cast<int32_t>(omxBuffer->filledLen));
1059        info.avBuffer->memory_->SetOffset(static_cast<int32_t>(omxBuffer->offset));
1060    }
1061    ExtractPerFrameParamFromOmxBuffer(omxBuffer, info.avBuffer->meta_);
1062    callback_->OnOutputBufferAvailable(info.bufferId, info.avBuffer);
1063    ChangeOwner(info, BufferOwner::OWNED_BY_USER);
1064}
1065
1066void HCodec::OnReleaseOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
1067{
1068    uint32_t bufferId = 0;
1069    (void)msg.param->GetValue(BUFFER_ID, bufferId);
1070    SCOPED_TRACE_WITH_ID(bufferId);
1071    optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
1072    if (!idx.has_value()) {
1073        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1074        return;
1075    }
1076    BufferInfo& info = outputBufferPool_[idx.value()];
1077    if (info.owner != BufferOwner::OWNED_BY_USER) {
1078        HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info.owner));
1079        ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
1080        return;
1081    }
1082    OnReleaseOutputBuffer(info);
1083    ChangeOwner(info, BufferOwner::OWNED_BY_US);
1084    ReplyErrorCode(msg.id, AVCS_ERR_OK);
1085
1086    switch (mode) {
1087        case KEEP_BUFFER: {
1088            return;
1089        }
1090        case RESUBMIT_BUFFER: {
1091            if (outputPortEos_) {
1092                HLOGI("output eos, keep this buffer");
1093                return;
1094            }
1095            int32_t ret = NotifyOmxToFillThisOutBuffer(info);
1096            if (ret != AVCS_ERR_OK) {
1097                SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
1098            }
1099            return;
1100        }
1101        case FREE_BUFFER: {
1102            EraseBufferFromPool(OMX_DirOutput, idx.value());
1103            return;
1104        }
1105        default: {
1106            HLOGE("SHOULD NEVER BE HERE");
1107            return;
1108        }
1109    }
1110}
1111
1112void HCodec::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
1113{
1114    ReplyErrorCode(msg.id, AVCS_ERR_UNSUPPORT);
1115}
1116
1117void HCodec::ReclaimBuffer(OMX_DIRTYPE portIndex, BufferOwner owner, bool erase)
1118{
1119    vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
1120    for (size_t i = pool.size(); i > 0;) {
1121        i--;
1122        BufferInfo& info = pool[i];
1123        if (info.owner == owner) {
1124            ChangeOwner(info, BufferOwner::OWNED_BY_US);
1125            if (erase) {
1126                EraseBufferFromPool(portIndex, i);
1127            }
1128        }
1129    }
1130}
1131
1132bool HCodec::IsAllBufferOwnedByUsOrSurface(OMX_DIRTYPE portIndex)
1133{
1134    const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
1135    for (const BufferInfo& info : pool) {
1136        if (info.owner != BufferOwner::OWNED_BY_US &&
1137            info.owner != BufferOwner::OWNED_BY_SURFACE) {
1138            return false;
1139        }
1140    }
1141    return true;
1142}
1143
1144bool HCodec::IsAllBufferOwnedByUsOrSurface()
1145{
1146    return IsAllBufferOwnedByUsOrSurface(OMX_DirInput) &&
1147           IsAllBufferOwnedByUsOrSurface(OMX_DirOutput);
1148}
1149
1150void HCodec::ClearBufferPool(OMX_DIRTYPE portIndex)
1151{
1152    const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
1153    for (size_t i = pool.size(); i > 0;) {
1154        i--;
1155        EraseBufferFromPool(portIndex, i);
1156    }
1157    OnClearBufferPool(portIndex);
1158}
1159
1160void HCodec::FreeOmxBuffer(OMX_DIRTYPE portIndex, const BufferInfo& info)
1161{
1162    if (compNode_ && info.omxBuffer) {
1163        int32_t omxRet = compNode_->FreeBuffer(portIndex, *(info.omxBuffer));
1164        if (omxRet != HDF_SUCCESS) {
1165            HLOGW("notify omx to free buffer failed");
1166        }
1167    }
1168}
1169
1170void HCodec::EraseOutBuffersOwnedByUsOrSurface()
1171{
1172    // traverse index in reverse order because we need to erase index from vector
1173    for (size_t i = outputBufferPool_.size(); i > 0;) {
1174        i--;
1175        const BufferInfo& info = outputBufferPool_[i];
1176        if (info.owner == BufferOwner::OWNED_BY_US || info.owner == BufferOwner::OWNED_BY_SURFACE) {
1177            EraseBufferFromPool(OMX_DirOutput, i);
1178        }
1179    }
1180}
1181
1182void HCodec::OnSetOutputSurface(const MsgInfo &msg, BufferOperationMode mode)
1183{
1184    (void)msg;
1185    (void)mode;
1186    ReplyErrorCode(msg.id, AVCS_ERR_UNSUPPORT);
1187}
1188
1189int32_t HCodec::ForceShutdown(int32_t generation, bool isNeedNotifyCaller)
1190{
1191    if (generation != stateGeneration_) {
1192        HLOGE("ignoring stale force shutdown message: #%d (now #%d)",
1193            generation, stateGeneration_);
1194        return AVCS_ERR_OK;
1195    }
1196    HLOGI("force to shutdown");
1197    isShutDownFromRunning_ = true;
1198    notifyCallerAfterShutdownComplete_ = isNeedNotifyCaller;
1199    keepComponentAllocated_ = false;
1200    auto err = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
1201    if (err == HDF_SUCCESS) {
1202        ChangeStateTo(stoppingState_);
1203    }
1204    return AVCS_ERR_OK;
1205}
1206
1207void HCodec::SignalError(AVCodecErrorType errorType, int32_t errorCode)
1208{
1209    HLOGE("fatal error happened: errType=%d, errCode=%d", errorType, errorCode);
1210    hasFatalError_ = true;
1211    callback_->OnError(errorType, errorCode);
1212}
1213
1214int32_t HCodec::DoSyncCall(MsgWhat msgType, std::function<void(ParamSP)> oper)
1215{
1216    ParamSP reply;
1217    return DoSyncCallAndGetReply(msgType, oper, reply);
1218}
1219
1220int32_t HCodec::DoSyncCallAndGetReply(MsgWhat msgType, std::function<void(ParamSP)> oper, ParamSP &reply)
1221{
1222    ParamSP msg = make_shared<ParamBundle>();
1223    IF_TRUE_RETURN_VAL_WITH_MSG(msg == nullptr, AVCS_ERR_NO_MEMORY, "out of memory");
1224    if (oper) {
1225        oper(msg);
1226    }
1227    bool ret = MsgHandleLoop::SendSyncMsg(msgType, msg, reply, FIVE_SECONDS_IN_MS);
1228    if (!ret) {
1229        HLOGE("wait msg %d(%s) time out", msgType, ToString(msgType));
1230        return AVCS_ERR_UNKNOWN;
1231    }
1232    int32_t err;
1233    IF_TRUE_RETURN_VAL_WITH_MSG(reply == nullptr || !reply->GetValue("err", err),
1234        AVCS_ERR_UNKNOWN, "error code of msg %d not replied", msgType);
1235    return err;
1236}
1237
1238void HCodec::DeferMessage(const MsgInfo &info)
1239{
1240    deferredQueue_.push_back(info);
1241}
1242
1243void HCodec::ProcessDeferredMessages()
1244{
1245    for (const MsgInfo &info : deferredQueue_) {
1246        StateMachine::OnMsgReceived(info);
1247    }
1248    deferredQueue_.clear();
1249}
1250
1251void HCodec::ReplyToSyncMsgLater(const MsgInfo& msg)
1252{
1253    syncMsgToReply_[msg.type].push(std::make_pair(msg.id, msg.param));
1254}
1255
1256bool HCodec::GetFirstSyncMsgToReply(MsgInfo& msg)
1257{
1258    auto iter = syncMsgToReply_.find(msg.type);
1259    if (iter == syncMsgToReply_.end()) {
1260        return false;
1261    }
1262    std::tie(msg.id, msg.param) = iter->second.front();
1263    iter->second.pop();
1264    return true;
1265}
1266
1267void HCodec::ReplyErrorCode(MsgId id, int32_t err)
1268{
1269    if (id == ASYNC_MSG_ID) {
1270        return;
1271    }
1272    ParamSP reply = make_shared<ParamBundle>();
1273    reply->SetValue("err", err);
1274    PostReply(id, reply);
1275}
1276
1277void HCodec::ChangeOmxToTargetState(CodecStateType &state, CodecStateType targetState)
1278{
1279    int32_t ret = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, targetState, {});
1280    if (ret != HDF_SUCCESS) {
1281        HLOGE("failed to change omx state, ret=%d", ret);
1282        return;
1283    }
1284
1285    int tryCnt = 0;
1286    do {
1287        if (tryCnt++ > 10) { // try up to 10 times
1288            HLOGE("failed to change to state(%d), abort", targetState);
1289            state = CODEC_STATE_INVALID;
1290            break;
1291        }
1292        this_thread::sleep_for(10ms); // wait 10ms
1293        ret = compNode_->GetState(state);
1294        if (ret != HDF_SUCCESS) {
1295            HLOGE("failed to get omx state, ret=%d", ret);
1296        }
1297    } while (ret == HDF_SUCCESS && state != targetState && state != CODEC_STATE_INVALID);
1298}
1299
1300bool HCodec::RollOmxBackToLoaded()
1301{
1302    CodecStateType state;
1303    int32_t ret = compNode_->GetState(state);
1304    if (ret != HDF_SUCCESS) {
1305        HLOGE("failed to get omx node status(ret=%d), can not perform state rollback", ret);
1306        return false;
1307    }
1308    HLOGI("current omx state (%d)", state);
1309    switch (state) {
1310        case CODEC_STATE_EXECUTING: {
1311            ChangeOmxToTargetState(state, CODEC_STATE_IDLE);
1312            [[fallthrough]];
1313        }
1314        case CODEC_STATE_IDLE: {
1315            ChangeOmxToTargetState(state, CODEC_STATE_LOADED);
1316            [[fallthrough]];
1317        }
1318        case CODEC_STATE_LOADED:
1319        case CODEC_STATE_INVALID: {
1320            return true;
1321        }
1322        default: {
1323            HLOGE("invalid omx state: %d", state);
1324            return false;
1325        }
1326    }
1327}
1328
1329void HCodec::CleanUpOmxNode()
1330{
1331    if (compNode_ == nullptr) {
1332        return;
1333    }
1334
1335    if (RollOmxBackToLoaded()) {
1336        for (const BufferInfo& info : inputBufferPool_) {
1337            FreeOmxBuffer(OMX_DirInput, info);
1338        }
1339        for (const BufferInfo& info : outputBufferPool_) {
1340            FreeOmxBuffer(OMX_DirOutput, info);
1341        }
1342    }
1343}
1344
1345int32_t HCodec::OnAllocateComponent()
1346{
1347    HitraceScoped trace(HITRACE_TAG_ZMEDIA, "hcodec_AllocateComponent_" + caps_.compName);
1348    compMgr_ = GetManager(false, caps_.port.video.isSupportPassthrough, isSecure_);
1349    if (compMgr_ == nullptr) {
1350        HLOGE("GetCodecComponentManager failed");
1351        return AVCS_ERR_UNKNOWN;
1352    }
1353    compCb_ = new HdiCallback(weak_from_this());
1354    int32_t ret = compMgr_->CreateComponent(compNode_, componentId_, caps_.compName, 0, compCb_);
1355    if (ret != HDF_SUCCESS || compNode_ == nullptr) {
1356        compCb_ = nullptr;
1357        compMgr_ = nullptr;
1358        HLOGE("CreateComponent failed, ret=%d", ret);
1359        return AVCS_ERR_UNKNOWN;
1360    }
1361    compUniqueStr_ = "[" + to_string(componentId_) + "][" + shortName_ + "]";
1362    inputOwnerStr_ = { compUniqueStr_ + "in_us", compUniqueStr_ + "in_user",
1363                       compUniqueStr_ + "in_omx", compUniqueStr_ + "in_surface"};
1364    outputOwnerStr_ = { compUniqueStr_ + "out_us", compUniqueStr_ + "out_user",
1365                        compUniqueStr_ + "out_omx", compUniqueStr_ + "out_surface"};
1366    HLOGI("create omx node %s succ", caps_.compName.c_str());
1367    PrintCaller();
1368    return AVCS_ERR_OK;
1369}
1370
1371void HCodec::ReleaseComponent()
1372{
1373    CleanUpOmxNode();
1374    if (compMgr_ != nullptr) {
1375        compMgr_->DestroyComponent(componentId_);
1376    }
1377    compNode_ = nullptr;
1378    compCb_ = nullptr;
1379    compMgr_ = nullptr;
1380    componentId_ = 0;
1381}
1382
1383const char* HCodec::ToString(MsgWhat what)
1384{
1385    static const map<MsgWhat, const char*> m = {
1386        { INIT, "INIT" }, { SET_CALLBACK, "SET_CALLBACK" }, { CONFIGURE, "CONFIGURE" },
1387        { CREATE_INPUT_SURFACE, "CREATE_INPUT_SURFACE" }, { SET_INPUT_SURFACE, "SET_INPUT_SURFACE" },
1388        { SET_OUTPUT_SURFACE, "SET_OUTPUT_SURFACE" }, { START, "START" },
1389        { GET_INPUT_FORMAT, "GET_INPUT_FORMAT" }, { GET_OUTPUT_FORMAT, "GET_OUTPUT_FORMAT" },
1390        { SET_PARAMETERS, "SET_PARAMETERS" }, { REQUEST_IDR_FRAME, "REQUEST_IDR_FRAME" },
1391        { FLUSH, "FLUSH" }, { QUEUE_INPUT_BUFFER, "QUEUE_INPUT_BUFFER" },
1392        { NOTIFY_EOS, "NOTIFY_EOS" }, { RELEASE_OUTPUT_BUFFER, "RELEASE_OUTPUT_BUFFER" },
1393        { RENDER_OUTPUT_BUFFER, "RENDER_OUTPUT_BUFFER" }, { STOP, "STOP" }, { RELEASE, "RELEASE" },
1394        { CODEC_EVENT, "CODEC_EVENT" }, { OMX_EMPTY_BUFFER_DONE, "OMX_EMPTY_BUFFER_DONE" },
1395        { OMX_FILL_BUFFER_DONE, "OMX_FILL_BUFFER_DONE" }, { GET_BUFFER_FROM_SURFACE, "GET_BUFFER_FROM_SURFACE" },
1396        { CHECK_IF_STUCK, "CHECK_IF_STUCK" }, { FORCE_SHUTDOWN, "FORCE_SHUTDOWN" },
1397    };
1398    auto it = m.find(what);
1399    if (it != m.end()) {
1400        return it->second;
1401    }
1402    return "UNKNOWN";
1403}
1404} // namespace OHOS::MediaAVCodec