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 "utils/hdf_base.h"
19 #include "codec_omx_ext.h"
20 #include "media_description.h" // foundation/multimedia/av_codec/interfaces/inner_api/native/
21 #include "sync_fence.h" // foundation/graphic/graphic_2d/utils/sync_fence/export/
22 #include "OMX_VideoExt.h"
23 #include "hcodec_log.h"
24 #include "type_converter.h"
25
26 namespace OHOS::MediaAVCodec {
27 using namespace std;
28 using namespace OHOS::HDI::Codec::V1_0;
29
OnConfigure(const Format & format)30 int32_t HDecoder::OnConfigure(const Format &format)
31 {
32 configFormat_ = make_shared<Format>(format);
33
34 return SetupPort(format);
35 }
36
SetupPort(const Format & format)37 int32_t HDecoder::SetupPort(const Format &format)
38 {
39 int32_t width;
40 if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) || width <= 0) {
41 HLOGE("format should contain width");
42 return AVCS_ERR_INVALID_VAL;
43 }
44 int32_t height;
45 if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) || height <= 0) {
46 HLOGE("format should contain height");
47 return AVCS_ERR_INVALID_VAL;
48 }
49 HLOGI("user set width %{public}d, height %{public}d", width, height);
50 if (!GetPixelFmtFromUser(format)) {
51 return AVCS_ERR_INVALID_VAL;
52 }
53
54 optional<double> frameRate = GetFrameRateFromUser(format);
55 if (!frameRate.has_value()) {
56 HLOGI("user don't set valid frame rate, use default 30.0");
57 frameRate = 30.0; // default frame rate 30.0
58 }
59
60 PortInfo inputPortInfo {static_cast<uint32_t>(width), static_cast<uint32_t>(height), std::nullopt,
61 codingType_, std::nullopt, frameRate.value()};
62 int32_t maxInputSize = 0;
63 (void)format.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize);
64 if (maxInputSize > 0) {
65 inputPortInfo.inputBufSize = static_cast<uint32_t>(maxInputSize);
66 }
67 int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
68 if (ret != AVCS_ERR_OK) {
69 return ret;
70 }
71
72 PortInfo outputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), std::nullopt,
73 OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
74 ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
75 if (ret != AVCS_ERR_OK) {
76 return ret;
77 }
78
79 return AVCS_ERR_OK;
80 }
81
UpdateInPortFormat()82 int32_t HDecoder::UpdateInPortFormat()
83 {
84 OMX_PARAM_PORTDEFINITIONTYPE def;
85 InitOMXParam(def);
86 def.nPortIndex = OMX_DirInput;
87 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
88 HLOGE("get input port definition failed");
89 return AVCS_ERR_UNKNOWN;
90 }
91 PrintPortDefinition(def);
92 if (inputFormat_ == nullptr) {
93 inputFormat_ = make_shared<Format>();
94 }
95 inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, def.format.video.nFrameWidth);
96 inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, def.format.video.nFrameHeight);
97 inputFormat_->PutIntValue("stride", def.format.video.nStride);
98 return AVCS_ERR_OK;
99 }
100
UpdateOutPortFormat()101 int32_t HDecoder::UpdateOutPortFormat()
102 {
103 OMX_PARAM_PORTDEFINITIONTYPE def;
104 InitOMXParam(def);
105 def.nPortIndex = OMX_DirOutput;
106 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
107 HLOGE("get output port definition failed");
108 return AVCS_ERR_UNKNOWN;
109 }
110 PrintPortDefinition(def);
111 if (def.nBufferCountActual == 0) {
112 HLOGE("invalid bufferCount");
113 return AVCS_ERR_UNKNOWN;
114 }
115 uint32_t w = def.format.video.nFrameWidth;
116 uint32_t h = def.format.video.nFrameHeight;
117
118 // save into member variable
119 outBufferCnt_ = def.nBufferCountActual;
120 requestCfg_.timeout = 0;
121 requestCfg_.width = w;
122 requestCfg_.height = h;
123 requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
124 requestCfg_.format = configuredFmt_.graphicFmt;
125 requestCfg_.usage = GetUsageFromOmx();
126 GetCropFromOmx(w, h);
127
128 // save into format
129 if (outputFormat_ == nullptr) {
130 outputFormat_ = make_shared<Format>();
131 }
132 outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, w);
133 outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, h);
134 outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, configuredFmt_.innerFmt);
135
136 sharedBufferFormat_ = { w, h, def.format.video.nStride, OMX_VIDEO_CodingUnused, configuredFmt_ };
137 return AVCS_ERR_OK;
138 }
139
GetCropFromOmx(uint32_t w,uint32_t h)140 void HDecoder::GetCropFromOmx(uint32_t w, uint32_t h)
141 {
142 flushCfg_.damage.x = 0;
143 flushCfg_.damage.y = 0;
144 flushCfg_.damage.w = w;
145 flushCfg_.damage.h = h;
146
147 OMX_CONFIG_RECTTYPE rect;
148 InitOMXParam(rect);
149 rect.nPortIndex = OMX_DirOutput;
150 if (!GetParameter(OMX_IndexConfigCommonOutputCrop, rect, true)) {
151 HLOGW("get crop failed, use default");
152 return;
153 }
154 if (rect.nLeft < 0 || rect.nTop < 0 ||
155 rect.nWidth == 0 || rect.nHeight == 0 ||
156 rect.nLeft + rect.nWidth > w ||
157 rect.nTop + rect.nHeight > h) {
158 HLOGW("wrong crop rect (%{public}d, %{public}d, %{public}u, %{public}u) vs. frame (%{public}u," \
159 "%{public}u), use default", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight, w, h);
160 return;
161 }
162 HLOGI("crop rect (%{public}d, %{public}d, %{public}u, %{public}u)",
163 rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
164 flushCfg_.damage.x = rect.nLeft;
165 flushCfg_.damage.y = rect.nTop;
166 flushCfg_.damage.w = rect.nWidth;
167 flushCfg_.damage.h = rect.nHeight;
168 }
169
GetUsageFromOmx()170 uint64_t HDecoder::GetUsageFromOmx()
171 {
172 GetBufferHandleUsageParams usageParams;
173 InitOMXParamExt(usageParams);
174 usageParams.portIndex = static_cast<uint32_t>(OMX_DirOutput);
175 if (!GetParameter(OMX_IndexParamGetBufferHandleUsage, usageParams)) {
176 HLOGW("get buffer handle usage failed, use default");
177 return BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA;
178 }
179 return usageParams.usage;
180 }
181
OnSetOutputSurface(const sptr<Surface> & surface)182 int32_t HDecoder::OnSetOutputSurface(const sptr<Surface> &surface)
183 {
184 if (surface == nullptr) {
185 HLOGE("surface is null");
186 return AVCS_ERR_INVALID_VAL;
187 }
188 if (surface->IsConsumer()) {
189 HLOGE("expect a producer surface but got a consumer surface");
190 return AVCS_ERR_INVALID_VAL;
191 }
192 GSError err = surface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
193 return OnBufferReleasedByConsumer(buffer);
194 });
195 if (err != GSERROR_OK) {
196 HLOGE("RegisterReleaseListener failed, GSError=%{public}d", err);
197 return AVCS_ERR_UNKNOWN;
198 }
199 UseBufferType param;
200 InitOMXParamExt(param);
201 param.portIndex = OMX_DirOutput;
202 param.bufferType = CODEC_BUFFER_TYPE_HANDLE;
203 if (!SetParameter(OMX_IndexParamUseBufferType, param)) {
204 HLOGE("component don't support CODEC_BUFFER_TYPE_HANDLE");
205 return AVCS_ERR_INVALID_OPERATION;
206 }
207 outputSurface_ = surface;
208 HLOGI("set surface (%{public}s) succ", surface->GetName().c_str());
209 return AVCS_ERR_OK;
210 }
211
OnSetParameters(const Format & format)212 int32_t HDecoder::OnSetParameters(const Format &format)
213 {
214 int32_t rotate;
215 if (outputSurface_ && format.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotate)) {
216 optional<GraphicTransformType> transform = TypeConverter::InnerRotateToDisplayRotate((VideoRotation)rotate);
217 if (!transform.has_value()) {
218 return AVCS_ERR_INVALID_VAL;
219 }
220 GSError err = outputSurface_->SetTransform(transform.value());
221 if (err != GSERROR_OK) {
222 HLOGE("set rotate angle %{public}d to surface failed", transform.value());
223 return AVCS_ERR_UNKNOWN;
224 }
225 HLOGI("set rotate angle %{public}d to surface succ", rotate);
226 }
227 return AVCS_ERR_OK;
228 }
229
OnBufferReleasedByConsumer(sptr<SurfaceBuffer> & buffer)230 GSError HDecoder::OnBufferReleasedByConsumer(sptr<SurfaceBuffer> &buffer)
231 {
232 SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, nullptr);
233 return GSERROR_OK;
234 }
235
SubmitOutputBuffersToOmxNode()236 int32_t HDecoder::SubmitOutputBuffersToOmxNode()
237 {
238 for (BufferInfo& info : outputBufferPool_) {
239 switch (info.owner) {
240 case BufferOwner::OWNED_BY_US: {
241 int32_t ret = NotifyOmxToFillThisOutBuffer(info);
242 if (ret != AVCS_ERR_OK) {
243 return ret;
244 }
245 continue;
246 }
247 case BufferOwner::OWNED_BY_SURFACE: {
248 continue;
249 }
250 case BufferOwner::OWNED_BY_OMX: {
251 continue;
252 }
253 default: {
254 HLOGE("buffer id %{public}u has invalid owner %{public}d", info.bufferId, info.owner);
255 return AVCS_ERR_UNKNOWN;
256 }
257 }
258 }
259 return AVCS_ERR_OK;
260 }
261
ReadyToStart()262 bool HDecoder::ReadyToStart()
263 {
264 if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
265 return false;
266 }
267 if (outputSurface_ == nullptr) {
268 outputBufferType_ = BufferType::PRESET_ASHM_BUFFER;
269 HLOGI("buffer mode");
270 return true;
271 }
272 HLOGI("surface mode");
273 outputBufferType_ = BufferType::PRESET_SURFACE_BUFFER;
274 if (configFormat_) {
275 OnSetParameters(*configFormat_);
276 }
277 return true;
278 }
279
SubmitAllBuffersOwnedByUs()280 int32_t HDecoder::SubmitAllBuffersOwnedByUs()
281 {
282 HLOGI(">>");
283 if (isBufferCirculating_) {
284 HLOGI("buffer is already circulating, no need to do again");
285 return AVCS_ERR_OK;
286 }
287 int32_t ret = SubmitOutputBuffersToOmxNode();
288 if (ret != AVCS_ERR_OK) {
289 return ret;
290 }
291 for (BufferInfo& info : inputBufferPool_) {
292 if (info.owner == BufferOwner::OWNED_BY_US) {
293 NotifyUserToFillThisInBuffer(info);
294 }
295 }
296 isBufferCirculating_ = true;
297 return AVCS_ERR_OK;
298 }
299
EraseBufferFromPool(OMX_DIRTYPE portIndex,size_t i)300 void HDecoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
301 {
302 vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
303 if (i >= pool.size()) {
304 return;
305 }
306 BufferInfo& info = pool[i];
307 if (portIndex == OMX_DirOutput && outputSurface_ &&
308 info.owner != BufferOwner::OWNED_BY_SURFACE) {
309 CancelBufferToSurface(info);
310 }
311 FreeOmxBuffer(portIndex, info);
312 pool.erase(pool.begin() + i);
313 }
314
SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer> & surfaceBuffer)315 shared_ptr<OmxCodecBuffer> HDecoder::SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer>& surfaceBuffer)
316 {
317 BufferHandle* bufferHandle = surfaceBuffer->GetBufferHandle();
318 if (bufferHandle == nullptr) {
319 HLOGE("null BufferHandle");
320 return nullptr;
321 }
322 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
323 omxBuffer->size = sizeof(OmxCodecBuffer);
324 omxBuffer->version.version.majorVersion = 1;
325 omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
326 omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
327 omxBuffer->allocLen = surfaceBuffer->GetSize();
328 omxBuffer->fenceFd = -1;
329 omxBuffer->pts = 0;
330 omxBuffer->flag = 0;
331 return omxBuffer;
332 }
333
AllocateOutputBuffersFromSurface()334 int32_t HDecoder::AllocateOutputBuffersFromSurface()
335 {
336 GSError err = outputSurface_->CleanCache();
337 if (err != GSERROR_OK) {
338 HLOGW("clean cache failed");
339 }
340 err = outputSurface_->SetQueueSize(outBufferCnt_);
341 if (err != GSERROR_OK) {
342 HLOGE("set surface queue size failed");
343 return AVCS_ERR_INVALID_VAL;
344 }
345 if (!outputBufferPool_.empty()) {
346 HLOGW("output buffer pool should be empty");
347 }
348 outputBufferPool_.clear();
349 for (uint32_t i = 0; i < outBufferCnt_; ++i) {
350 sptr<SurfaceBuffer> surfaceBuffer;
351 {
352 sptr<SyncFence> fence;
353 err = outputSurface_->RequestBuffer(surfaceBuffer, fence, requestCfg_);
354 if (err != GSERROR_OK || surfaceBuffer == nullptr) {
355 HLOGE("RequestBuffer %{public}u failed, GSError=%{public}d", i, err);
356 return AVCS_ERR_UNKNOWN;
357 }
358 }
359
360 shared_ptr<OmxCodecBuffer> omxBuffer = SurfaceBufferToOmxBuffer(surfaceBuffer);
361 if (omxBuffer == nullptr) {
362 outputSurface_->CancelBuffer(surfaceBuffer);
363 return AVCS_ERR_UNKNOWN;
364 }
365 shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
366 int32_t ret = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
367 if (ret != HDF_SUCCESS) {
368 outputSurface_->CancelBuffer(surfaceBuffer);
369 HLOGE("Failed to UseBuffer with output port");
370 return AVCS_ERR_NO_MEMORY;
371 }
372 outBuffer->fenceFd = -1;
373 BufferInfo info {};
374 info.isInput = false;
375 info.owner = BufferOwner::OWNED_BY_US;
376 info.surfaceBuffer = surfaceBuffer;
377 info.sharedBuffer = nullptr;
378 info.omxBuffer = outBuffer;
379 info.bufferId = outBuffer->bufferId;
380 outputBufferPool_.push_back(info);
381 }
382 return AVCS_ERR_OK;
383 }
384
AllocateBuffersOnPort(OMX_DIRTYPE portIndex)385 int32_t HDecoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex)
386 {
387 if ((portIndex == OMX_DirOutput) && (outputBufferType_ == BufferType::PRESET_SURFACE_BUFFER)) {
388 return AllocateOutputBuffersFromSurface();
389 } else {
390 return AllocateSharedBuffers(portIndex, (portIndex == OMX_DirOutput));
391 }
392 }
393
CancelBufferToSurface(BufferInfo & info)394 void HDecoder::CancelBufferToSurface(BufferInfo& info)
395 {
396 HLOGD("outBufId = %{public}u", info.bufferId);
397 GSError ret = outputSurface_->CancelBuffer(info.surfaceBuffer);
398 if (ret != OHOS::GSERROR_OK) {
399 HLOGW("bufferId=%{public}u cancel failed, GSError=%{public}d", info.bufferId, ret);
400 }
401 ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE); // change owner even if cancel failed
402 }
403
OnGetBufferFromSurface()404 void HDecoder::OnGetBufferFromSurface()
405 {
406 while (true) {
407 if (!GetOneBufferFromSurface()) {
408 break;
409 }
410 }
411 }
412
GetOneBufferFromSurface()413 bool HDecoder::GetOneBufferFromSurface()
414 {
415 sptr<SurfaceBuffer> buffer;
416 sptr<SyncFence> fence;
417 GSError ret = outputSurface_->RequestBuffer(buffer, fence, requestCfg_);
418 if (ret != GSERROR_OK || buffer == nullptr) {
419 return false;
420 }
421 if (fence != nullptr && fence->IsValid()) {
422 int waitRes = fence->Wait(WAIT_FENCE_MS);
423 if (waitRes != 0) {
424 HLOGW("wait fence time out");
425 }
426 }
427 for (BufferInfo& info : outputBufferPool_) {
428 if (info.owner == BufferOwner::OWNED_BY_SURFACE &&
429 info.surfaceBuffer->GetBufferHandle() == buffer->GetBufferHandle()) {
430 int32_t err = NotifyOmxToFillThisOutBuffer(info);
431 if (err == AVCS_ERR_OK) {
432 return true;
433 }
434 break;
435 }
436 }
437 HLOGW("cannot find slot or submit to omx failed, cancel it");
438 outputSurface_->CancelBuffer(buffer);
439 return false;
440 }
441
NotifySurfaceToRenderOutputBuffer(BufferInfo & info)442 int32_t HDecoder::NotifySurfaceToRenderOutputBuffer(BufferInfo &info)
443 {
444 flushCfg_.timestamp = info.omxBuffer->pts;
445 GSError ret = outputSurface_->FlushBuffer(info.surfaceBuffer, -1, flushCfg_);
446 if (ret != GSERROR_OK) {
447 HLOGE("FlushBuffer failed, GSError=%{public}d", ret);
448 return AVCS_ERR_UNKNOWN;
449 }
450 HLOGD("outBufId = %{public}u, render succ, pts = %{public}" PRId64 ", "
451 "[%{public}d %{public}d %{public}d %{public}d]", info.bufferId, flushCfg_.timestamp,
452 flushCfg_.damage.x, flushCfg_.damage.y, flushCfg_.damage.w, flushCfg_.damage.h);
453 ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE);
454 return AVCS_ERR_OK;
455 }
456
OnOMXEmptyBufferDone(uint32_t bufferId,BufferOperationMode mode)457 void HDecoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
458 {
459 BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
460 if (info == nullptr) {
461 HLOGE("unknown buffer id %{public}u", bufferId);
462 return;
463 }
464 if (info->owner != BufferOwner::OWNED_BY_OMX) {
465 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info->owner));
466 return;
467 }
468 ChangeOwner(*info, BufferOwner::OWNED_BY_US);
469
470 switch (mode) {
471 case KEEP_BUFFER:
472 return;
473 case RESUBMIT_BUFFER: {
474 if (!inputPortEos_) {
475 NotifyUserToFillThisInBuffer(*info);
476 }
477 return;
478 }
479 default: {
480 HLOGE("SHOULD NEVER BE HERE");
481 return;
482 }
483 }
484 }
485
OnRenderOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)486 void HDecoder::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
487 {
488 if (outputBufferType_ == BufferType::PRESET_ASHM_BUFFER) {
489 HLOGE("can only render in surface mode");
490 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
491 return;
492 }
493 uint32_t bufferId;
494 (void)msg.param->GetValue(BUFFER_ID, bufferId);
495 optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
496 if (!idx.has_value()) {
497 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
498 return;
499 }
500 BufferInfo& info = outputBufferPool_[idx.value()];
501 if (info.owner != BufferOwner::OWNED_BY_USER) {
502 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info.owner));
503 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
504 return;
505 }
506 HLOGD("outBufId = %{public}u", info.bufferId);
507 ChangeOwner(info, BufferOwner::OWNED_BY_US);
508 ReplyErrorCode(msg.id, AVCS_ERR_OK);
509
510 NotifySurfaceToRenderOutputBuffer(info);
511 if (mode == FREE_BUFFER) {
512 EraseBufferFromPool(OMX_DirOutput, idx.value());
513 }
514 }
515 } // namespace OHOS::MediaAVCodec