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