• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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