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