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