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