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 <fstream>
22 #include "syspara/parameters.h" // base/startup/init/interfaces/innerkits/include/
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 "hcodec_log.h"
29 #include "utils.h"
30
31 namespace OHOS::MediaAVCodec {
32 using namespace std;
33 using namespace OHOS::HDI::Codec::V1_0;
34
Create(const std::string & name)35 std::shared_ptr<HCodec> HCodec::Create(const std::string &name)
36 {
37 vector<CodecCompCapability> capList = GetCapList();
38 shared_ptr<HCodec> codec;
39 for (const auto& cap : capList) {
40 if (cap.compName != name) {
41 continue;
42 }
43 optional<OMX_VIDEO_CODINGTYPE> type = TypeConverter::HdiRoleToOmxCodingType(cap.role);
44 if (!type) {
45 LOGE("unsupported role %{public}d", cap.role);
46 return nullptr;
47 }
48 if (cap.type == VIDEO_DECODER) {
49 codec = make_shared<HDecoder>(cap, type.value());
50 } else if (cap.type == VIDEO_ENCODER) {
51 codec = make_shared<HEncoder>(cap, type.value());
52 }
53 break;
54 }
55 if (codec == nullptr) {
56 LOGE("cannot find %{public}s", name.c_str());
57 return nullptr;
58 }
59 if (codec->InitWithName(name) != AVCS_ERR_OK) {
60 return nullptr;
61 }
62 return codec;
63 }
64
SetCallback(const shared_ptr<AVCodecCallback> & callback)65 int32_t HCodec::SetCallback(const shared_ptr<AVCodecCallback> &callback)
66 {
67 HLOGI(">>");
68 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
69 msg->SetValue("callback", callback);
70 };
71 return DoSyncCall(MsgWhat::SET_CALLBACK, proc);
72 }
73
Configure(const Format & format)74 int32_t HCodec::Configure(const Format &format)
75 {
76 HLOGI(">>");
77 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
78 msg->SetValue("format", format);
79 };
80 return DoSyncCall(MsgWhat::CONFIGURE, proc);
81 }
82
SetOutputSurface(sptr<Surface> surface)83 int32_t HCodec::SetOutputSurface(sptr<Surface> surface)
84 {
85 HLOGI(">>");
86 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
87 msg->SetValue("surface", surface);
88 };
89 return DoSyncCall(MsgWhat::SET_OUTPUT_SURFACE, proc);
90 }
91
Start()92 int32_t HCodec::Start()
93 {
94 HLOGI(">>");
95 return DoSyncCall(MsgWhat::START, nullptr);
96 }
97
Stop()98 int32_t HCodec::Stop()
99 {
100 HLOGI(">>");
101 return DoSyncCall(MsgWhat::STOP, nullptr);
102 }
103
Flush()104 int32_t HCodec::Flush()
105 {
106 HLOGI(">>");
107 return DoSyncCall(MsgWhat::FLUSH, nullptr);
108 }
109
Reset()110 int32_t HCodec::Reset()
111 {
112 HLOGI(">>");
113 string previouslyConfiguredName = componentName_;
114 int32_t ret = Release();
115 if (ret == AVCS_ERR_OK) {
116 ret = InitWithName(previouslyConfiguredName);
117 }
118 return ret;
119 }
120
Release()121 int32_t HCodec::Release()
122 {
123 HLOGI(">>");
124 return DoSyncCall(MsgWhat::RELEASE, nullptr);
125 }
126
NotifyEos()127 int32_t HCodec::NotifyEos()
128 {
129 HLOGI(">>");
130 return DoSyncCall(MsgWhat::NOTIFY_EOS, nullptr);
131 }
132
SetParameter(const Format & format)133 int32_t HCodec::SetParameter(const Format &format)
134 {
135 HLOGI(">>");
136 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
137 msg->SetValue("params", format);
138 };
139 return DoSyncCall(MsgWhat::SET_PARAMETERS, proc);
140 }
141
GetInputFormat(Format & format)142 int32_t HCodec::GetInputFormat(Format& format)
143 {
144 HLOGI(">>");
145 ParamSP reply;
146 int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_INPUT_FORMAT, nullptr, reply);
147 if (ret != AVCS_ERR_OK) {
148 HLOGE("failed to get input format");
149 return ret;
150 }
151 IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
152 AVCS_ERR_UNKNOWN, "input format not replied");
153 return AVCS_ERR_OK;
154 }
155
GetOutputFormat(Format & format)156 int32_t HCodec::GetOutputFormat(Format &format)
157 {
158 HLOGI(">>");
159 ParamSP reply;
160 int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_OUTPUT_FORMAT, nullptr, reply);
161 if (ret != AVCS_ERR_OK) {
162 HLOGE("failed to get output format");
163 return ret;
164 }
165 IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
166 AVCS_ERR_UNKNOWN, "output format not replied");
167 format.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_NAME, componentName_);
168 return AVCS_ERR_OK;
169 }
170
CreateInputSurface()171 sptr<Surface> HCodec::CreateInputSurface()
172 {
173 HLOGI(">>");
174 ParamSP reply;
175 int32_t ret = DoSyncCallAndGetReply(MsgWhat::CREATE_INPUT_SURFACE, nullptr, reply);
176 if (ret != AVCS_ERR_OK) {
177 HLOGE("failed to create input surface");
178 return nullptr;
179 }
180 sptr<Surface> inputSurface;
181 IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("surface", inputSurface), nullptr, "input surface not replied");
182 return inputSurface;
183 }
184
SetInputSurface(sptr<Surface> surface)185 int32_t HCodec::SetInputSurface(sptr<Surface> surface)
186 {
187 HLOGI(">>");
188 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
189 msg->SetValue("surface", surface);
190 };
191 return DoSyncCall(MsgWhat::SET_INPUT_SURFACE, proc);
192 }
193
SignalRequestIDRFrame()194 int32_t HCodec::SignalRequestIDRFrame()
195 {
196 HLOGI(">>");
197 return DoSyncCall(MsgWhat::REQUEST_IDR_FRAME, nullptr);
198 }
199
QueueInputBuffer(uint32_t index,const AVCodecBufferInfo & info,AVCodecBufferFlag flag)200 int32_t HCodec::QueueInputBuffer(uint32_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag flag)
201 {
202 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
203 msg->SetValue(BUFFER_ID, index);
204 msg->SetValue("buffer-info", info);
205 msg->SetValue("buffer-flag", flag);
206 };
207 return DoSyncCall(MsgWhat::QUEUE_INPUT_BUFFER, proc);
208 }
209
RenderOutputBuffer(uint32_t index)210 int32_t HCodec::RenderOutputBuffer(uint32_t index)
211 {
212 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
213 msg->SetValue(BUFFER_ID, index);
214 };
215 return DoSyncCall(MsgWhat::RENDER_OUTPUT_BUFFER, proc);
216 }
217
ReleaseOutputBuffer(uint32_t index)218 int32_t HCodec::ReleaseOutputBuffer(uint32_t index)
219 {
220 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
221 msg->SetValue(BUFFER_ID, index);
222 };
223 return DoSyncCall(MsgWhat::RELEASE_OUTPUT_BUFFER, proc);
224 }
225 /**************************** public functions end ****************************/
226
227
HCodec(CodecCompCapability caps,OMX_VIDEO_CODINGTYPE codingType,bool isEncoder)228 HCodec::HCodec(CodecCompCapability caps, OMX_VIDEO_CODINGTYPE codingType, bool isEncoder)
229 : caps_(caps), codingType_(codingType), isEncoder_(isEncoder)
230 {
231 InitCreationTime();
232 debugMode_ = OHOS::system::GetBoolParameter("hcodec.debug", false);
233 dumpMode_ = static_cast<DumpMode>(OHOS::system::GetIntParameter<int>("hcodec.dump", DUMP_NONE));
234 LOGI(">> debug mode = %{public}s, dump input = %{public}s, dump output = %{public}s",
235 debugMode_ ? "true" : "false",
236 (dumpMode_ & DUMP_INPUT) ? "true" : "false",
237 (dumpMode_ & DUMP_OUTPUT) ? "true" : "false");
238
239 uninitializedState_ = make_shared<UninitializedState>(this);
240 initializedState_ = make_shared<InitializedState>(this);
241 startingState_ = make_shared<StartingState>(this);
242 runningState_ = make_shared<RunningState>(this);
243 outputPortChangedState_ = make_shared<OutputPortChangedState>(this);
244 stoppingState_ = make_shared<StoppingState>(this);
245 flushingState_ = make_shared<FlushingState>(this);
246 StateMachine::ChangeStateTo(uninitializedState_);
247 }
248
InitCreationTime()249 void HCodec::InitCreationTime()
250 {
251 chrono::system_clock::time_point now = chrono::system_clock::now();
252 time_t nowTimeT = chrono::system_clock::to_time_t(now);
253 tm *localTm = localtime(&nowTimeT);
254 if (localTm == nullptr) {
255 return;
256 }
257 char buffer[32] = "\0";
258 if (strftime(buffer, sizeof(buffer), "%Y%m%d_%H%M%S", localTm) > 0) {
259 ctorTime_ = string(buffer);
260 }
261 }
262
~HCodec()263 HCodec::~HCodec()
264 {
265 HLOGI(">>");
266 MsgHandleLoop::Stop();
267 ReleaseComponent();
268 }
269
InitWithName(const std::string & name)270 int32_t HCodec::InitWithName(const std::string &name)
271 {
272 std::function<void(ParamSP)> proc = [&](ParamSP msg) {
273 msg->SetValue("name", name);
274 };
275 return DoSyncCall(MsgWhat::INIT, proc);
276 }
277
EventHandler(CodecEventType event,const EventInfo & info)278 int32_t HCodec::HdiCallback::EventHandler(CodecEventType event, const EventInfo &info)
279 {
280 LOGI("event = %{public}d, data1 = %{public}u, data2 = %{public}u", event, info.data1, info.data2);
281 ParamSP msg = ParamBundle::Create();
282 msg->SetValue("event", event);
283 msg->SetValue("data1", info.data1);
284 msg->SetValue("data2", info.data2);
285 codec_->SendAsyncMsg(MsgWhat::CODEC_EVENT, msg);
286 return HDF_SUCCESS;
287 }
288
EmptyBufferDone(int64_t appData,const OmxCodecBuffer & buffer)289 int32_t HCodec::HdiCallback::EmptyBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
290 {
291 ParamSP msg = ParamBundle::Create();
292 msg->SetValue(BUFFER_ID, buffer.bufferId);
293 codec_->SendAsyncMsg(MsgWhat::OMX_EMPTY_BUFFER_DONE, msg);
294 return HDF_SUCCESS;
295 }
296
FillBufferDone(int64_t appData,const OmxCodecBuffer & buffer)297 int32_t HCodec::HdiCallback::FillBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
298 {
299 ParamSP msg = ParamBundle::Create();
300 msg->SetValue("omxBuffer", buffer);
301 codec_->SendAsyncMsg(MsgWhat::OMX_FILL_BUFFER_DONE, msg);
302 return HDF_SUCCESS;
303 }
304
GetPixelFmtFromUser(const Format & format)305 bool HCodec::GetPixelFmtFromUser(const Format &format)
306 {
307 optional<PixelFmt> fmt;
308 VideoPixelFormat innerFmt;
309 if (format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, *(int*)&innerFmt) &&
310 innerFmt != SURFACE_FORMAT) {
311 fmt = TypeConverter::InnerFmtToFmt(innerFmt);
312 } else {
313 HLOGI("user don't set VideoPixelFormat, use default");
314 for (int32_t f : caps_.port.video.supportPixFmts) {
315 fmt = TypeConverter::GraphicFmtToFmt(static_cast<GraphicPixelFormat>(f));
316 if (fmt.has_value()) {
317 break;
318 }
319 }
320 }
321 if (!fmt) {
322 HLOGE("pixel format unspecified");
323 return false;
324 }
325 configuredFmt_ = fmt.value();
326 HLOGI("GraphicPixelFormat %{public}d, VideoPixelFormat %{public}d",
327 configuredFmt_.graphicFmt, configuredFmt_.innerFmt);
328 return true;
329 }
330
GetFrameRateFromUser(const Format & format)331 std::optional<double> HCodec::GetFrameRateFromUser(const Format &format)
332 {
333 double frameRateDouble;
334 if (format.GetDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRateDouble) && frameRateDouble > 0) {
335 LOGI("user set frame rate %{public}.2f", frameRateDouble);
336 return frameRateDouble;
337 }
338 int frameRateInt;
339 if (format.GetIntValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRateInt) && frameRateInt > 0) {
340 LOGI("user set frame rate %{public}d", frameRateInt);
341 return static_cast<double>(frameRateInt);
342 }
343 return nullopt;
344 }
345
SetVideoPortInfo(OMX_DIRTYPE portIndex,const PortInfo & info)346 int32_t HCodec::SetVideoPortInfo(OMX_DIRTYPE portIndex, const PortInfo& info)
347 {
348 {
349 OMX_PARAM_PORTDEFINITIONTYPE def;
350 InitOMXParam(def);
351 def.nPortIndex = portIndex;
352 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
353 HLOGE("get port definition failed");
354 return AVCS_ERR_UNKNOWN;
355 }
356 def.format.video.nFrameWidth = info.width;
357 def.format.video.nFrameHeight = info.height;
358 def.format.video.eCompressionFormat = info.codingType;
359 // we dont set eColorFormat here because it will be set below
360 def.format.video.xFramerate = info.frameRate * FRAME_RATE_COEFFICIENT;
361 if (portIndex == OMX_DirInput && info.inputBufSize.has_value()) {
362 def.nBufferSize = info.inputBufSize.value();
363 }
364 if (!SetParameter(OMX_IndexParamPortDefinition, def)) {
365 HLOGE("set port definition failed");
366 return AVCS_ERR_UNKNOWN;
367 }
368 if (portIndex == OMX_DirOutput) {
369 if (outputFormat_ == nullptr) {
370 outputFormat_ = make_shared<Format>();
371 }
372 outputFormat_->PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, info.frameRate);
373 }
374 }
375 if (info.pixelFmt.has_value()) {
376 CodecVideoPortFormatParam param;
377 InitOMXParamExt(param);
378 param.portIndex = portIndex;
379 param.codecCompressFormat = info.codingType;
380 param.codecColorFormat = info.pixelFmt->graphicFmt;
381 param.framerate = info.frameRate * FRAME_RATE_COEFFICIENT;
382 if (!SetParameter(OMX_IndexCodecVideoPortFormat, param)) {
383 HLOGE("set port format failed");
384 return AVCS_ERR_UNKNOWN;
385 }
386 }
387 return (portIndex == OMX_DirInput) ? UpdateInPortFormat() : UpdateOutPortFormat();
388 }
389
PrintPortDefinition(const OMX_PARAM_PORTDEFINITIONTYPE & def)390 void HCodec::PrintPortDefinition(const OMX_PARAM_PORTDEFINITIONTYPE& def)
391 {
392 const OMX_VIDEO_PORTDEFINITIONTYPE& video = def.format.video;
393 HLOGI("----- %{public}s port definition -----", (def.nPortIndex == OMX_DirInput) ? "INPUT" : "OUTPUT");
394 HLOGI("bEnabled %{public}d, bPopulated %{public}d", def.bEnabled, def.bPopulated);
395 HLOGI("nBufferCountActual %{public}u, nBufferSize %{public}u", def.nBufferCountActual, def.nBufferSize);
396 HLOGI("nFrameWidth x nFrameHeight (%{public}u x %{public}u), framerate %{public}u(%{public}.2f)",
397 video.nFrameWidth, video.nFrameHeight, video.xFramerate, video.xFramerate / FRAME_RATE_COEFFICIENT);
398 HLOGI(" nStride x nSliceHeight (%{public}u x %{public}u)", video.nStride, video.nSliceHeight);
399 HLOGI("eCompressionFormat %{public}d(%{public}#x), eColorFormat %{public}d(%{public}#x)",
400 video.eCompressionFormat, video.eCompressionFormat, video.eColorFormat, video.eColorFormat);
401 HLOGI("----------------------------------");
402 }
403
AllocateSharedBuffers(OMX_DIRTYPE portIndex,bool isImageData)404 int32_t HCodec::AllocateSharedBuffers(OMX_DIRTYPE portIndex, bool isImageData)
405 {
406 OMX_PARAM_PORTDEFINITIONTYPE def;
407 InitOMXParam(def);
408 def.nPortIndex = portIndex;
409 if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
410 HLOGE("get %{public}s port definition failed", (portIndex == OMX_DirInput ? "input" : "output"));
411 return AVCS_ERR_INVALID_VAL;
412 }
413 if (def.nBufferSize == 0 || def.nBufferSize > MAX_HCODEC_BUFFER_SIZE) {
414 HLOGE("invalid nBufferSize %{public}u", def.nBufferSize);
415 return AVCS_ERR_INVALID_VAL;
416 }
417 HLOGI("%{public}s port definition: nBufferCountActual %{public}u, nBufferSize %{public}u",
418 (portIndex == OMX_DirInput ? "input" : "output"), def.nBufferCountActual, def.nBufferSize);
419
420 vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
421 pool.clear();
422 for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
423 shared_ptr<AVSharedMemoryBase> ashm = std::static_pointer_cast<AVSharedMemoryBase>(
424 AVSharedMemoryBase::CreateFromLocal(static_cast<int32_t>(def.nBufferSize),
425 static_cast<int32_t>(AVSharedMemory::FLAGS_READ_WRITE), "HCodecAshmem"));
426 if (ashm == nullptr || ashm->GetSize() != (int)def.nBufferSize) {
427 HLOGE("allocate AVSharedMemory failed");
428 return AVCS_ERR_NO_MEMORY;
429 }
430 shared_ptr<OmxCodecBuffer> omxBuffer = AshmemToOmxBuffer(portIndex, ashm->GetFd(), ashm->GetSize());
431 shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
432 int32_t ret = compNode_->UseBuffer(portIndex, *omxBuffer, *outBuffer);
433 if (ret != HDF_SUCCESS) {
434 LOGE("Failed to UseBuffer on %{public}s port", (portIndex == OMX_DirInput ? "input" : "output"));
435 return AVCS_ERR_INVALID_VAL;
436 }
437 BufferInfo bufInfo;
438 bufInfo.isImageDataInSharedBuffer = isImageData;
439 bufInfo.isInput = (portIndex == OMX_DirInput) ? true : false;
440 bufInfo.owner = BufferOwner::OWNED_BY_US;
441 bufInfo.surfaceBuffer = nullptr;
442 bufInfo.sharedBuffer = ashm;
443 bufInfo.omxBuffer = outBuffer;
444 bufInfo.bufferId = outBuffer->bufferId;
445 pool.push_back(bufInfo);
446 }
447 return AVCS_ERR_OK;
448 }
449
AshmemToOmxBuffer(OMX_DIRTYPE portIndex,int32_t fd,uint32_t size)450 shared_ptr<OmxCodecBuffer> HCodec::AshmemToOmxBuffer(OMX_DIRTYPE portIndex, int32_t fd, uint32_t size)
451 {
452 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
453 omxBuffer->size = sizeof(OmxCodecBuffer);
454 omxBuffer->version.version.majorVersion = 1;
455 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
456 if (IsPassthrough()) {
457 omxBuffer->fd = dup(fd); // codec HDI will close this duped fd
458 HLOGD("fd=%{public}d, duped fd=%{public}d", fd, omxBuffer->fd);
459 } else {
460 omxBuffer->fd = fd;
461 }
462 omxBuffer->allocLen = size;
463 omxBuffer->fenceFd = -1;
464 omxBuffer->pts = 0;
465 omxBuffer->flag = 0;
466 omxBuffer->type = (portIndex == OMX_DirInput) ? READ_ONLY_TYPE : READ_WRITE_TYPE;
467 return omxBuffer;
468 }
469
ToString(BufferOwner owner)470 const char* HCodec::ToString(BufferOwner owner)
471 {
472 switch (owner) {
473 case BufferOwner::OWNED_BY_US:
474 return "us";
475 case BufferOwner::OWNED_BY_USER:
476 return "user";
477 case BufferOwner::OWNED_BY_OMX:
478 return "omx";
479 case BufferOwner::OWNED_BY_SURFACE:
480 return "surface";
481 default:
482 return "";
483 }
484 }
485
ChangeOwner(BufferInfo & info,BufferOwner targetOwner,bool printInfo)486 void HCodec::ChangeOwner(BufferInfo& info, BufferOwner targetOwner, bool printInfo)
487 {
488 if (!debugMode_) {
489 info.owner = targetOwner;
490 return;
491 }
492 auto now = chrono::steady_clock::now();
493 if (info.lastOwnerChangeTime) {
494 uint64_t costUs = chrono::duration_cast<chrono::microseconds>(now - info.lastOwnerChangeTime.value()).count();
495 double costMs = static_cast<double>(costUs) / TIME_RATIO_MS_TO_US;
496 const char* id = info.isInput ? "inBufId" : "outBufId";
497 const char* oldOwner = ToString(info.owner);
498 const char* newOwner = ToString(targetOwner);
499 if (printInfo) {
500 HLOGD("%{public}s = %{public}u, after hold %{public}.1f ms, %{public}s -> %{public}s, "
501 "len = %{public}u, flags = 0x%{public}x, pts = %{public}" PRId64 "",
502 id, info.bufferId, costMs, oldOwner, newOwner,
503 info.omxBuffer->filledLen, info.omxBuffer->flag, info.omxBuffer->pts);
504 } else {
505 HLOGD("%{public}s = %{public}u, after hold %{public}.1f ms, %{public}s -> %{public}s",
506 id, info.bufferId, costMs, oldOwner, newOwner);
507 }
508 }
509 info.lastOwnerChangeTime = now;
510 info.owner = targetOwner;
511 }
512
IsValidFrame() const513 bool HCodec::BufferInfo::IsValidFrame() const
514 {
515 if (omxBuffer->flag & OMX_BUFFERFLAG_EOS) {
516 return false;
517 }
518 if (omxBuffer->flag & OMX_BUFFERFLAG_CODECCONFIG) {
519 return false;
520 }
521 if (omxBuffer->filledLen == 0) {
522 return false;
523 }
524 return true;
525 }
526
Dump(const string & prefix,DumpMode dumpMode,const optional<PortInfo> & bufferFormat) const527 void HCodec::BufferInfo::Dump(const string& prefix, DumpMode dumpMode,
528 const optional<PortInfo>& bufferFormat) const
529 {
530 if ((dumpMode & DUMP_INPUT) && isInput) {
531 Dump(prefix + "_Input", bufferFormat);
532 }
533 if ((dumpMode & DUMP_OUTPUT) && !isInput) {
534 Dump(prefix + "_Output", bufferFormat);
535 }
536 }
537
Dump(const string & prefix,const optional<PortInfo> & bufferFormat) const538 void HCodec::BufferInfo::Dump(const string& prefix, const optional<PortInfo>& bufferFormat) const
539 {
540 DumpSurfaceBuffer(prefix);
541 DumpAshmemBuffer(prefix, bufferFormat);
542 }
543
DumpSurfaceBuffer(const std::string & prefix) const544 void HCodec::BufferInfo::DumpSurfaceBuffer(const std::string& prefix) const
545 {
546 if (surfaceBuffer == nullptr) {
547 return;
548 }
549 bool eos = (omxBuffer->flag & OMX_BUFFERFLAG_EOS);
550 if (eos || omxBuffer->filledLen == 0) {
551 return;
552 }
553 int w = surfaceBuffer->GetWidth();
554 int h = surfaceBuffer->GetHeight();
555 int alignedW = surfaceBuffer->GetStride();
556 void* va = surfaceBuffer->GetVirAddr();
557 uint32_t totalSize = surfaceBuffer->GetSize();
558 if (w <= 0 || h <= 0 || alignedW <= 0 || w > alignedW || va == nullptr) {
559 LOGW("invalid buffer");
560 return;
561 }
562 GraphicPixelFormat fmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
563 optional<uint32_t> assumeAlignedH;
564 string suffix;
565 bool dumpAsVideo = true; // we could only save it as individual image if we don't know aligned height
566 DecideDumpInfo(assumeAlignedH, suffix, dumpAsVideo);
567
568 static char name[128];
569 int ret = 0;
570 if (dumpAsVideo) {
571 ret = sprintf_s(name, sizeof(name), "%s/%s_%dx%d(%dx%d)_fmt%d.%s",
572 DUMP_PATH, prefix.c_str(), w, h, alignedW, assumeAlignedH.value_or(h), fmt, suffix.c_str());
573 } else {
574 ret = sprintf_s(name, sizeof(name), "%s/%s_%dx%d(%d)_fmt%d_pts%" PRId64 ".%s",
575 DUMP_PATH, prefix.c_str(), w, h, alignedW, fmt, omxBuffer->pts, suffix.c_str());
576 }
577 if (ret > 0) {
578 ofstream ofs(name, ios::binary | ios::app);
579 if (ofs.is_open()) {
580 ofs.write(reinterpret_cast<const char*>(va), totalSize);
581 } else {
582 LOGW("cannot open %{public}s", name);
583 }
584 }
585 surfaceBuffer->Unmap();
586 }
587
DecideDumpInfo(optional<uint32_t> & assumeAlignedH,string & suffix,bool & dumpAsVideo) const588 void HCodec::BufferInfo::DecideDumpInfo(optional<uint32_t>& assumeAlignedH, string& suffix, bool& dumpAsVideo) const
589 {
590 int h = surfaceBuffer->GetHeight();
591 int alignedW = surfaceBuffer->GetStride();
592 if (alignedW <= 0) {
593 return;
594 }
595 uint32_t totalSize = surfaceBuffer->GetSize();
596 GraphicPixelFormat fmt = static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat());
597 switch (fmt) {
598 case GRAPHIC_PIXEL_FMT_YCBCR_420_P:
599 case GRAPHIC_PIXEL_FMT_YCRCB_420_SP:
600 case GRAPHIC_PIXEL_FMT_YCBCR_420_SP: {
601 suffix = "yuv";
602 if (GetYuv420Size(alignedW, h) == totalSize) {
603 break;
604 }
605 uint32_t alignedH = totalSize * 2 / 3 / alignedW; // 2 bytes per pixel for UV, 3 bytes per pixel for YUV
606 if (GetYuv420Size(alignedW, alignedH) == totalSize) {
607 dumpAsVideo = true;
608 assumeAlignedH = alignedH;
609 } else {
610 dumpAsVideo = false;
611 }
612 break;
613 }
614 case GRAPHIC_PIXEL_FMT_RGBA_8888: {
615 suffix = "rgba";
616 if (static_cast<uint32_t>(alignedW * h) != totalSize) {
617 dumpAsVideo = false;
618 }
619 break;
620 }
621 default: {
622 suffix = "bin";
623 dumpAsVideo = false;
624 break;
625 }
626 }
627 }
628
DumpAshmemBuffer(const string & prefix,const std::optional<PortInfo> & bufferFormat) const629 void HCodec::BufferInfo::DumpAshmemBuffer(const string& prefix, const std::optional<PortInfo>& bufferFormat) const
630 {
631 if (sharedBuffer == nullptr) {
632 return;
633 }
634 bool eos = (omxBuffer->flag & OMX_BUFFERFLAG_EOS);
635 if (eos || omxBuffer->filledLen == 0) {
636 return;
637 }
638
639 static char name[128];
640 int ret;
641 if (isImageDataInSharedBuffer && bufferFormat.has_value()) {
642 ret = sprintf_s(name, sizeof(name), "%s/%s_%dx%d(%dx%d)_fmt%d.bin",
643 DUMP_PATH, prefix.c_str(), bufferFormat->width, bufferFormat->height, bufferFormat->stride,
644 bufferFormat->height, bufferFormat->pixelFmt->graphicFmt);
645 } else {
646 ret = sprintf_s(name, sizeof(name), "%s/%s.bin", DUMP_PATH, prefix.c_str());
647 }
648 if (ret <= 0) {
649 LOGW("sprintf_s failed");
650 return;
651 }
652 ofstream ofs(name, ios::binary | ios::app);
653 if (ofs.is_open()) {
654 ofs.write(reinterpret_cast<const char*>(sharedBuffer->GetBase()), omxBuffer->filledLen);
655 } else {
656 LOGW("cannot open %{public}s", name);
657 }
658 }
659
PrintAllBufferInfo()660 void HCodec::PrintAllBufferInfo()
661 {
662 HLOGI("------------INPUT-----------");
663 for (const BufferInfo& info : inputBufferPool_) {
664 HLOGI("inBufId = %{public}u, owner = %{public}s", info.bufferId, ToString(info.owner));
665 }
666 HLOGI("----------------------------");
667 HLOGI("------------OUTPUT----------");
668 for (const BufferInfo& info : outputBufferPool_) {
669 HLOGI("outBufId = %{public}u, owner = %{public}s", info.bufferId, ToString(info.owner));
670 }
671 HLOGI("----------------------------");
672 }
673
FindBufferInfoByID(OMX_DIRTYPE portIndex,uint32_t bufferId)674 HCodec::BufferInfo* HCodec::FindBufferInfoByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
675 {
676 vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
677 for (BufferInfo &info : pool) {
678 if (info.bufferId == bufferId) {
679 return &info;
680 }
681 }
682 HLOGE("unknown buffer id %{public}u", bufferId);
683 return nullptr;
684 }
685
FindBufferIndexByID(OMX_DIRTYPE portIndex,uint32_t bufferId)686 optional<size_t> HCodec::FindBufferIndexByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
687 {
688 const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
689 for (size_t i = 0; i < pool.size(); i++) {
690 if (pool[i].bufferId == bufferId) {
691 return i;
692 }
693 }
694 HLOGE("unknown buffer id %{public}u", bufferId);
695 return nullopt;
696 }
697
UserFlagToOmxFlag(AVCodecBufferFlag userFlag)698 uint32_t HCodec::UserFlagToOmxFlag(AVCodecBufferFlag userFlag)
699 {
700 uint32_t flags = 0;
701 if (userFlag & AVCODEC_BUFFER_FLAG_EOS) {
702 flags |= OMX_BUFFERFLAG_EOS;
703 HLOGI("got input eos");
704 }
705 if (userFlag & AVCODEC_BUFFER_FLAG_SYNC_FRAME) {
706 flags |= OMX_BUFFERFLAG_SYNCFRAME;
707 HLOGI("got input sync frame");
708 }
709 if (userFlag & AVCODEC_BUFFER_FLAG_CODEC_DATA) {
710 flags |= OMX_BUFFERFLAG_CODECCONFIG;
711 HLOGI("got input codec config data");
712 }
713 return flags;
714 }
715
OmxFlagToUserFlag(uint32_t omxFlag)716 AVCodecBufferFlag HCodec::OmxFlagToUserFlag(uint32_t omxFlag)
717 {
718 uint32_t flags = 0;
719 if (omxFlag & OMX_BUFFERFLAG_EOS) {
720 flags |= AVCODEC_BUFFER_FLAG_EOS;
721 HLOGI("got output eos");
722 }
723 if (omxFlag & OMX_BUFFERFLAG_SYNCFRAME) {
724 flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME;
725 HLOGI("got output sync frame");
726 }
727 if (omxFlag & OMX_BUFFERFLAG_CODECCONFIG) {
728 flags |= AVCODEC_BUFFER_FLAG_CODEC_DATA;
729 HLOGI("got output codec config data");
730 }
731 return static_cast<AVCodecBufferFlag>(flags);
732 }
733
NotifyUserToFillThisInBuffer(BufferInfo & info)734 void HCodec::NotifyUserToFillThisInBuffer(BufferInfo &info)
735 {
736 callback_->OnInputBufferAvailable(info.bufferId, info.sharedBuffer);
737 ChangeOwner(info, BufferOwner::OWNED_BY_USER);
738 }
739
OnQueueInputBuffer(const MsgInfo & msg,BufferOperationMode mode)740 void HCodec::OnQueueInputBuffer(const MsgInfo &msg, BufferOperationMode mode)
741 {
742 uint32_t bufferId;
743 AVCodecBufferInfo info;
744 AVCodecBufferFlag flag;
745 (void)msg.param->GetValue(BUFFER_ID, bufferId);
746 (void)msg.param->GetValue("buffer-info", info);
747 (void)msg.param->GetValue("buffer-flag", flag);
748 BufferInfo* bufferInfo = FindBufferInfoByID(OMX_DirInput, bufferId);
749 if (bufferInfo == nullptr) {
750 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
751 return;
752 }
753 if (bufferInfo->owner != BufferOwner::OWNED_BY_USER) {
754 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(bufferInfo->owner));
755 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
756 return;
757 }
758 bufferInfo->omxBuffer->filledLen = info.size;
759 bufferInfo->omxBuffer->offset = info.offset;
760 bufferInfo->omxBuffer->pts = info.presentationTimeUs;
761 bufferInfo->omxBuffer->flag = UserFlagToOmxFlag(flag);
762 ChangeOwner(*bufferInfo, BufferOwner::OWNED_BY_US);
763 ReplyErrorCode(msg.id, AVCS_ERR_OK);
764 OnQueueInputBuffer(mode, bufferInfo);
765 }
766
OnQueueInputBuffer(BufferOperationMode mode,BufferInfo * info)767 void HCodec::OnQueueInputBuffer(BufferOperationMode mode, BufferInfo* info)
768 {
769 switch (mode) {
770 case KEEP_BUFFER: {
771 return;
772 }
773 case RESUBMIT_BUFFER: {
774 if (inputPortEos_) {
775 HLOGI("input already eos, keep this buffer");
776 return;
777 }
778 bool eos = (info->omxBuffer->flag & OMX_BUFFERFLAG_EOS);
779 if (!eos && info->omxBuffer->filledLen == 0) {
780 HLOGI("this is not a eos buffer but not filled, ask user to re-fill it");
781 NotifyUserToFillThisInBuffer(*info);
782 return;
783 }
784 if (eos) {
785 inputPortEos_ = true;
786 }
787 int32_t ret = NotifyOmxToEmptyThisInBuffer(*info);
788 if (ret != AVCS_ERR_OK) {
789 SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
790 }
791 return;
792 }
793 default: {
794 HLOGE("SHOULD NEVER BE HERE");
795 return;
796 }
797 }
798 }
799
OnSignalEndOfInputStream(const MsgInfo & msg)800 void HCodec::OnSignalEndOfInputStream(const MsgInfo &msg)
801 {
802 ReplyErrorCode(msg.id, AVCS_ERR_UNSUPPORT);
803 }
804
NotifyOmxToEmptyThisInBuffer(BufferInfo & info)805 int32_t HCodec::NotifyOmxToEmptyThisInBuffer(BufferInfo& info)
806 {
807 info.Dump(ctorTime_ + "_" + componentName_, dumpMode_, sharedBufferFormat_);
808 int32_t ret = compNode_->EmptyThisBuffer(*(info.omxBuffer));
809 if (ret != HDF_SUCCESS) {
810 HLOGE("EmptyThisBuffer failed");
811 return AVCS_ERR_UNKNOWN;
812 }
813 if (info.IsValidFrame()) {
814 etbCnt_++;
815 if (debugMode_) {
816 etbMap_[info.omxBuffer->pts] = chrono::steady_clock::now();
817 }
818 }
819 ChangeOwner(info, BufferOwner::OWNED_BY_OMX, true);
820 return AVCS_ERR_OK;
821 }
822
NotifyOmxToFillThisOutBuffer(BufferInfo & info)823 int32_t HCodec::NotifyOmxToFillThisOutBuffer(BufferInfo& info)
824 {
825 info.omxBuffer->flag = 0;
826 int32_t ret = compNode_->FillThisBuffer(*(info.omxBuffer));
827 if (ret != HDF_SUCCESS) {
828 HLOGE("outBufId = %{public}u failed", info.bufferId);
829 return AVCS_ERR_UNKNOWN;
830 }
831 ChangeOwner(info, BufferOwner::OWNED_BY_OMX);
832 return AVCS_ERR_OK;
833 }
834
OnOMXFillBufferDone(const OmxCodecBuffer & omxBuffer,BufferOperationMode mode)835 void HCodec::OnOMXFillBufferDone(const OmxCodecBuffer& omxBuffer, BufferOperationMode mode)
836 {
837 optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, omxBuffer.bufferId);
838 if (!idx.has_value()) {
839 return;
840 }
841 BufferInfo& info = outputBufferPool_[idx.value()];
842 if (info.owner != BufferOwner::OWNED_BY_OMX) {
843 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", info.bufferId, ToString(info.owner));
844 return;
845 }
846 info.omxBuffer->offset = omxBuffer.offset;
847 info.omxBuffer->filledLen = omxBuffer.filledLen;
848 info.omxBuffer->pts = omxBuffer.pts;
849 info.omxBuffer->flag = omxBuffer.flag;
850 ChangeOwner(info, BufferOwner::OWNED_BY_US, true);
851 info.Dump(ctorTime_ + "_" + componentName_, dumpMode_, sharedBufferFormat_);
852 OnOMXFillBufferDone(mode, info, idx.value());
853 }
854
OnOMXFillBufferDone(BufferOperationMode mode,BufferInfo & info,size_t bufferIdx)855 void HCodec::OnOMXFillBufferDone(BufferOperationMode mode, BufferInfo& info, size_t bufferIdx)
856 {
857 switch (mode) {
858 case KEEP_BUFFER:
859 return;
860 case RESUBMIT_BUFFER: {
861 if (outputPortEos_) {
862 HLOGI("output eos, keep this buffer");
863 return;
864 }
865 bool eos = (info.omxBuffer->flag & OMX_BUFFERFLAG_EOS);
866 if (!eos && info.omxBuffer->filledLen == 0) {
867 HLOGI("it's not a eos buffer but not filled, ask omx to re-fill it");
868 NotifyOmxToFillThisOutBuffer(info);
869 return;
870 }
871 UpdateFbdRecord(info);
872 NotifyUserOutBufferAvaliable(info);
873 if (eos) {
874 outputPortEos_ = true;
875 }
876 return;
877 }
878 case FREE_BUFFER:
879 EraseBufferFromPool(OMX_DirOutput, bufferIdx);
880 return;
881 default:
882 HLOGE("SHOULD NEVER BE HERE");
883 return;
884 }
885 }
886
UpdateFbdRecord(const BufferInfo & info)887 void HCodec::UpdateFbdRecord(const BufferInfo& info)
888 {
889 if (!info.IsValidFrame()) {
890 return;
891 }
892 if (fbdCnt_ == 0) {
893 firstFbdTime_ = std::chrono::steady_clock::now();
894 }
895 fbdCnt_++;
896 if (!debugMode_) {
897 return;
898 }
899 auto it = etbMap_.find(info.omxBuffer->pts);
900 if (it != etbMap_.end()) {
901 auto now = chrono::steady_clock::now();
902 uint64_t fromEtbToFbd = chrono::duration_cast<chrono::microseconds>(now - it->second).count();
903 etbMap_.erase(it);
904 double oneFrameCostMs = static_cast<double>(fromEtbToFbd) / TIME_RATIO_MS_TO_US;
905 uint64_t fromFbdToFbd = chrono::duration_cast<chrono::microseconds>(now - firstFbdTime_).count();
906 totalCost_ += fromEtbToFbd;
907 double averageCostMs = static_cast<double>(totalCost_) / TIME_RATIO_MS_TO_US / fbdCnt_;
908 if (fromFbdToFbd == 0) {
909 HLOGD("pts = %{public}" PRId64 ", cost %{public}.2f ms, average %{public}.2f ms",
910 info.omxBuffer->pts, oneFrameCostMs, averageCostMs);
911 } else {
912 HLOGD("pts = %{public}" PRId64 ", cost %{public}.2f ms, average %{public}.2f ms, fbd fps %{public}.2f",
913 info.omxBuffer->pts, oneFrameCostMs, averageCostMs,
914 static_cast<double>(fbdCnt_) / fromFbdToFbd * TIME_RATIO_S_TO_US);
915 }
916 }
917 }
918
NotifyUserOutBufferAvaliable(BufferInfo & info)919 void HCodec::NotifyUserOutBufferAvaliable(BufferInfo &info)
920 {
921 shared_ptr<OmxCodecBuffer> omxBuffer = info.omxBuffer;
922 AVCodecBufferInfo userInfo {
923 .presentationTimeUs = omxBuffer->pts,
924 .size = omxBuffer->filledLen,
925 .offset = omxBuffer->offset,
926 };
927 AVCodecBufferFlag userFlag = OmxFlagToUserFlag(omxBuffer->flag);
928 callback_->OnOutputBufferAvailable(info.bufferId, userInfo, userFlag, info.sharedBuffer);
929 ChangeOwner(info, BufferOwner::OWNED_BY_USER);
930 }
931
OnReleaseOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)932 void HCodec::OnReleaseOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
933 {
934 uint32_t bufferId;
935 (void)msg.param->GetValue(BUFFER_ID, bufferId);
936 optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
937 if (!idx.has_value()) {
938 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
939 return;
940 }
941 BufferInfo& info = outputBufferPool_[idx.value()];
942 if (info.owner != BufferOwner::OWNED_BY_USER) {
943 HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info.owner));
944 ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
945 return;
946 }
947 HLOGD("outBufId = %{public}u", bufferId);
948 ChangeOwner(info, BufferOwner::OWNED_BY_US);
949 ReplyErrorCode(msg.id, AVCS_ERR_OK);
950
951 switch (mode) {
952 case KEEP_BUFFER: {
953 return;
954 }
955 case RESUBMIT_BUFFER: {
956 if (outputPortEos_) {
957 HLOGI("output eos, keep this buffer");
958 return;
959 }
960 int32_t ret = NotifyOmxToFillThisOutBuffer(info);
961 if (ret != AVCS_ERR_OK) {
962 SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
963 }
964 return;
965 }
966 case FREE_BUFFER: {
967 EraseBufferFromPool(OMX_DirOutput, idx.value());
968 return;
969 }
970 default: {
971 HLOGE("SHOULD NEVER BE HERE");
972 return;
973 }
974 }
975 }
976
OnRenderOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)977 void HCodec::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
978 {
979 ReplyErrorCode(msg.id, AVCS_ERR_UNSUPPORT);
980 }
981
ReclaimBuffer(OMX_DIRTYPE portIndex,BufferOwner owner)982 void HCodec::ReclaimBuffer(OMX_DIRTYPE portIndex, BufferOwner owner)
983 {
984 vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
985 for (BufferInfo& info : pool) {
986 if (info.owner == owner) {
987 ChangeOwner(info, BufferOwner::OWNED_BY_US);
988 }
989 }
990 }
991
IsAllBufferOwnedByUsOrSurface(OMX_DIRTYPE portIndex)992 bool HCodec::IsAllBufferOwnedByUsOrSurface(OMX_DIRTYPE portIndex)
993 {
994 const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
995 for (const BufferInfo& info : pool) {
996 if (info.owner != BufferOwner::OWNED_BY_US &&
997 info.owner != BufferOwner::OWNED_BY_SURFACE) {
998 return false;
999 }
1000 }
1001 return true;
1002 }
1003
IsAllBufferOwnedByUsOrSurface()1004 bool HCodec::IsAllBufferOwnedByUsOrSurface()
1005 {
1006 return IsAllBufferOwnedByUsOrSurface(OMX_DirInput) &&
1007 IsAllBufferOwnedByUsOrSurface(OMX_DirOutput);
1008 }
1009
ClearBufferPool(OMX_DIRTYPE portIndex)1010 void HCodec::ClearBufferPool(OMX_DIRTYPE portIndex)
1011 {
1012 const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
1013 for (size_t i = pool.size(); i > 0;) {
1014 i--;
1015 EraseBufferFromPool(portIndex, i);
1016 }
1017 }
1018
FreeOmxBuffer(OMX_DIRTYPE portIndex,const BufferInfo & info)1019 void HCodec::FreeOmxBuffer(OMX_DIRTYPE portIndex, const BufferInfo& info)
1020 {
1021 if (compNode_ && info.omxBuffer) {
1022 int32_t omxRet = compNode_->FreeBuffer(portIndex, *(info.omxBuffer));
1023 if (omxRet != HDF_SUCCESS) {
1024 HLOGW("notify omx to free buffer failed");
1025 }
1026 }
1027 }
1028
EraseOutBuffersOwnedByUsOrSurface()1029 void HCodec::EraseOutBuffersOwnedByUsOrSurface()
1030 {
1031 // traverse index in reverse order because we need to erase index from vector
1032 for (size_t i = outputBufferPool_.size(); i > 0;) {
1033 i--;
1034 const BufferInfo& info = outputBufferPool_[i];
1035 if (info.owner == BufferOwner::OWNED_BY_US || info.owner == BufferOwner::OWNED_BY_SURFACE) {
1036 EraseBufferFromPool(OMX_DirOutput, i);
1037 }
1038 }
1039 }
1040
ForceShutdown(int32_t generation)1041 int32_t HCodec::ForceShutdown(int32_t generation)
1042 {
1043 if (generation != stateGeneration_) {
1044 HLOGE("ignoring stale force shutdown message: #%{public}d (now #%{public}d)",
1045 generation, stateGeneration_);
1046 return AVCS_ERR_OK;
1047 }
1048 HLOGI("force to shutdown");
1049 isShutDownFromRunning_ = true;
1050 notifyCallerAfterShutdownComplete_ = false;
1051 keepComponentAllocated_ = false;
1052 auto err = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
1053 if (err == HDF_SUCCESS) {
1054 ChangeStateTo(stoppingState_);
1055 }
1056 return AVCS_ERR_OK;
1057 }
1058
SignalError(AVCodecErrorType errorType,int32_t errorCode)1059 void HCodec::SignalError(AVCodecErrorType errorType, int32_t errorCode)
1060 {
1061 HLOGE("fatal error happened: errType=%{public}d, errCode=%{public}d", errorType, errorCode);
1062 hasFatalError_ = true;
1063 callback_->OnError(errorType, errorCode);
1064 }
1065
DoSyncCall(MsgWhat msgType,std::function<void (ParamSP)> oper)1066 int32_t HCodec::DoSyncCall(MsgWhat msgType, std::function<void(ParamSP)> oper)
1067 {
1068 ParamSP reply;
1069 return DoSyncCallAndGetReply(msgType, oper, reply);
1070 }
1071
DoSyncCallAndGetReply(MsgWhat msgType,std::function<void (ParamSP)> oper,ParamSP & reply)1072 int32_t HCodec::DoSyncCallAndGetReply(MsgWhat msgType, std::function<void(ParamSP)> oper, ParamSP &reply)
1073 {
1074 ParamSP msg = ParamBundle::Create();
1075 IF_TRUE_RETURN_VAL_WITH_MSG(msg == nullptr, AVCS_ERR_NO_MEMORY, "out of memory");
1076 if (oper) {
1077 oper(msg);
1078 }
1079 bool ret = MsgHandleLoop::SendSyncMsg(msgType, msg, reply);
1080 IF_TRUE_RETURN_VAL_WITH_MSG(!ret, AVCS_ERR_UNKNOWN, "wait msg %{public}d time out", msgType);
1081 int32_t err;
1082 IF_TRUE_RETURN_VAL_WITH_MSG(reply == nullptr || !reply->GetValue("err", err),
1083 AVCS_ERR_UNKNOWN, "error code of msg %{public}d not replied", msgType);
1084 return err;
1085 }
1086
DeferMessage(const MsgInfo & info)1087 void HCodec::DeferMessage(const MsgInfo &info)
1088 {
1089 deferredQueue_.push_back(info);
1090 }
1091
ProcessDeferredMessages()1092 void HCodec::ProcessDeferredMessages()
1093 {
1094 for (const MsgInfo &info : deferredQueue_) {
1095 StateMachine::OnMsgReceived(info);
1096 }
1097 deferredQueue_.clear();
1098 }
1099
ReplyToSyncMsgLater(const MsgInfo & msg)1100 void HCodec::ReplyToSyncMsgLater(const MsgInfo& msg)
1101 {
1102 syncMsgToReply_[msg.type].push(std::make_pair(msg.id, msg.param));
1103 }
1104
GetFirstSyncMsgToReply(MsgInfo & msg)1105 bool HCodec::GetFirstSyncMsgToReply(MsgInfo& msg)
1106 {
1107 auto iter = syncMsgToReply_.find(msg.type);
1108 if (iter == syncMsgToReply_.end()) {
1109 return false;
1110 }
1111 msg.id = iter->second.front().first;
1112 msg.param = iter->second.front().second;
1113 iter->second.pop();
1114 return true;
1115 }
1116
ReplyErrorCode(MsgId id,int32_t err)1117 void HCodec::ReplyErrorCode(MsgId id, int32_t err)
1118 {
1119 if (id == ASYNC_MSG_ID) {
1120 return;
1121 }
1122 ParamSP reply = ParamBundle::Create();
1123 reply->SetValue("err", err);
1124 PostReply(id, reply);
1125 }
1126
ChangeOmxToTargetState(CodecStateType & state,CodecStateType targetState)1127 void HCodec::ChangeOmxToTargetState(CodecStateType &state, CodecStateType targetState)
1128 {
1129 int32_t ret = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, targetState, {});
1130 if (ret != HDF_SUCCESS) {
1131 HLOGE("failed to change omx state, ret=%{public}d", ret);
1132 return;
1133 }
1134
1135 int tryCnt = 0;
1136 do {
1137 if (tryCnt++ > 10) { // try up to 10 times
1138 HLOGE("failed to change to state(%{public}d), abort", targetState);
1139 state = CODEC_STATE_INVALID;
1140 break;
1141 }
1142 this_thread::sleep_for(10ms); // wait 10ms
1143 ret = compNode_->GetState(state);
1144 if (ret != HDF_SUCCESS) {
1145 HLOGE("failed to get omx state, ret=%{public}d", ret);
1146 }
1147 } while (ret == HDF_SUCCESS && state != targetState && state != CODEC_STATE_INVALID);
1148 }
1149
RollOmxBackToLoaded()1150 bool HCodec::RollOmxBackToLoaded()
1151 {
1152 CodecStateType state;
1153 int32_t ret = compNode_->GetState(state);
1154 if (ret != HDF_SUCCESS) {
1155 HLOGE("failed to get omx node status(ret=%{public}d), can not perform state rollback", ret);
1156 return false;
1157 }
1158 HLOGI("current omx state (%{public}d)", state);
1159 switch (state) {
1160 case CODEC_STATE_EXECUTING: {
1161 ChangeOmxToTargetState(state, CODEC_STATE_IDLE);
1162 [[fallthrough]];
1163 }
1164 case CODEC_STATE_IDLE: {
1165 ChangeOmxToTargetState(state, CODEC_STATE_LOADED);
1166 [[fallthrough]];
1167 }
1168 case CODEC_STATE_LOADED:
1169 case CODEC_STATE_INVALID: {
1170 return true;
1171 }
1172 default: {
1173 HLOGE("invalid omx state: %{public}d", state);
1174 return false;
1175 }
1176 }
1177 }
1178
CleanUpOmxNode()1179 void HCodec::CleanUpOmxNode()
1180 {
1181 if (compNode_ == nullptr) {
1182 return;
1183 }
1184
1185 if (RollOmxBackToLoaded()) {
1186 for (const BufferInfo& info : inputBufferPool_) {
1187 FreeOmxBuffer(OMX_DirInput, info);
1188 }
1189 for (const BufferInfo& info : outputBufferPool_) {
1190 FreeOmxBuffer(OMX_DirOutput, info);
1191 }
1192 }
1193 }
1194
ReleaseComponent()1195 void HCodec::ReleaseComponent()
1196 {
1197 CleanUpOmxNode();
1198 if (compMgr_ != nullptr) {
1199 compMgr_->DestroyComponent(componentId_);
1200 }
1201 compNode_ = nullptr;
1202 compCb_ = nullptr;
1203 compMgr_ = nullptr;
1204 componentId_ = 0;
1205 componentName_.clear();
1206 }
1207
ToString(MsgWhat what)1208 const char* HCodec::ToString(MsgWhat what)
1209 {
1210 static const map<MsgWhat, const char*> m = {
1211 { INIT, "INIT" }, { SET_CALLBACK, "SET_CALLBACK" }, { CONFIGURE, "CONFIGURE" },
1212 { CREATE_INPUT_SURFACE, "CREATE_INPUT_SURFACE" }, { SET_INPUT_SURFACE, "SET_INPUT_SURFACE" },
1213 { SET_OUTPUT_SURFACE, "SET_OUTPUT_SURFACE" }, { START, "START" },
1214 { GET_INPUT_FORMAT, "GET_INPUT_FORMAT" }, { GET_OUTPUT_FORMAT, "GET_OUTPUT_FORMAT" },
1215 { SET_PARAMETERS, "SET_PARAMETERS" }, { REQUEST_IDR_FRAME, "REQUEST_IDR_FRAME" },
1216 { FLUSH, "FLUSH" }, { QUEUE_INPUT_BUFFER, "QUEUE_INPUT_BUFFER" },
1217 { NOTIFY_EOS, "NOTIFY_EOS" }, { RELEASE_OUTPUT_BUFFER, "RELEASE_OUTPUT_BUFFER" },
1218 { RENDER_OUTPUT_BUFFER, "RENDER_OUTPUT_BUFFER" }, { STOP, "STOP" }, { RELEASE, "RELEASE" },
1219 { CODEC_EVENT, "CODEC_EVENT" }, { OMX_EMPTY_BUFFER_DONE, "OMX_EMPTY_BUFFER_DONE" },
1220 { OMX_FILL_BUFFER_DONE, "OMX_FILL_BUFFER_DONE" }, { GET_BUFFER_FROM_SURFACE, "GET_BUFFER_FROM_SURFACE" },
1221 { CHECK_IF_STUCK, "CHECK_IF_STUCK" }, { FORCE_SHUTDOWN, "FORCE_SHUTDOWN" },
1222 };
1223 auto it = m.find(what);
1224 if (it != m.end()) {
1225 return it->second;
1226 }
1227 return "UNKNOWN";
1228 }
1229 } // namespace OHOS::MediaAVCodec