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