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