1 /*
2  * Copyright (c) 2024 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 "hardware/imagecodec/image_codec.h"
17 #include "hardware/imagecodec/image_decoder.h"
18 #include "hardware/imagecodec/image_codec_list.h"
19 #include "hardware/imagecodec/image_codec_log.h"
20 #include "syspara/parameters.h" // base/startup/init/interfaces/innerkits/include/
21 #include "qos.h"
22 
23 namespace OHOS::ImagePlugin {
24 using namespace std;
25 using namespace HdiCodecNamespace;
26 
IsSecureMode(const string & name)27 static bool IsSecureMode(const string &name)
28 {
29     string prefix = ".secure";
30     if (name.length() <= prefix.length()) {
31         return false;
32     }
33     return (name.rfind(prefix) == (name.length() - prefix.length()));
34 }
35 
Create()36 shared_ptr<ImageCodec> ImageCodec::Create()
37 {
38     vector<CodecCompCapability> capList = GetCapList();
39     shared_ptr<ImageCodec> codec;
40     string name;
41     for (const auto& cap : capList) {
42         if (cap.role == MEDIA_ROLETYPE_VIDEO_HEVC && cap.type == VIDEO_DECODER && !IsSecureMode(cap.compName)) {
43             name = cap.compName;
44             codec = make_shared<ImageDecoder>();
45             break;
46         }
47     }
48     if ((codec != nullptr) && (codec->InitWithName(name) == IC_ERR_OK)) {
49         return codec;
50     }
51     return nullptr;
52 }
53 
SetCallback(const shared_ptr<ImageCodecCallback> & callback)54 int32_t ImageCodec::SetCallback(const shared_ptr<ImageCodecCallback> &callback)
55 {
56     HLOGI(">>");
57     function<void(ParamSP)> proc = [&](ParamSP msg) {
58         msg->SetValue("callback", callback);
59     };
60     return DoSyncCall(MsgWhat::SET_CALLBACK, proc);
61 }
62 
Configure(const Format & format)63 int32_t ImageCodec::Configure(const Format &format)
64 {
65     function<void(ParamSP)> proc = [&](ParamSP msg) {
66         msg->SetValue("format", format);
67     };
68     return DoSyncCall(MsgWhat::CONFIGURE, proc);
69 }
70 
QueueInputBuffer(uint32_t index)71 int32_t ImageCodec::QueueInputBuffer(uint32_t index)
72 {
73     function<void(ParamSP)> proc = [&](ParamSP msg) {
74         msg->SetValue(BUFFER_ID, index);
75     };
76     return DoSyncCall(MsgWhat::QUEUE_INPUT_BUFFER, proc);
77 }
78 
ReleaseOutputBuffer(uint32_t index)79 int32_t ImageCodec::ReleaseOutputBuffer(uint32_t index)
80 {
81     function<void(ParamSP)> proc = [&](ParamSP msg) {
82         msg->SetValue(BUFFER_ID, index);
83     };
84     return DoSyncCall(MsgWhat::RELEASE_OUTPUT_BUFFER, proc);
85 }
86 
GetInputFormat(Format & format)87 int32_t ImageCodec::GetInputFormat(Format& format)
88 {
89     HLOGI(">>");
90     ParamSP reply;
91     int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_INPUT_FORMAT, nullptr, reply);
92     if (ret != IC_ERR_OK) {
93         HLOGE("failed to get input format");
94         return ret;
95     }
96     IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
97         IC_ERR_UNKNOWN, "input format not replied");
98     return IC_ERR_OK;
99 }
100 
GetOutputFormat(Format & format)101 int32_t ImageCodec::GetOutputFormat(Format& format)
102 {
103     ParamSP reply;
104     int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_OUTPUT_FORMAT, nullptr, reply);
105     if (ret != IC_ERR_OK) {
106         HLOGE("failed to get output format");
107         return ret;
108     }
109     IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("format", format),
110         IC_ERR_UNKNOWN, "output format not replied");
111     return IC_ERR_OK;
112 }
113 
Start()114 int32_t ImageCodec::Start()
115 {
116     HLOGI(">>");
117     return DoSyncCall(MsgWhat::START, nullptr);
118 }
119 
Release()120 int32_t ImageCodec::Release()
121 {
122     HLOGI(">>");
123     return DoSyncCall(MsgWhat::RELEASE, nullptr);
124 }
125 
GetOutputBufferUsage(uint64_t & usage)126 int32_t ImageCodec::GetOutputBufferUsage(uint64_t& usage)
127 {
128     ParamSP reply;
129     int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_OUTPUT_BUFFER_USAGE, nullptr, reply);
130     if (ret != IC_ERR_OK) {
131         HLOGE("failed to get output buffer usage");
132         return ret;
133     }
134     IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("usage", usage),
135         IC_ERR_UNKNOWN, "output buffer usage not replied");
136     return IC_ERR_OK;
137 }
138 
SetOutputBuffer(sptr<SurfaceBuffer> output)139 int32_t ImageCodec::SetOutputBuffer(sptr<SurfaceBuffer> output)
140 {
141     HLOGI(">>");
142     std::function<void(ParamSP)> proc = [&](ParamSP msg) {
143         msg->SetValue("output", output);
144     };
145     return DoSyncCall(MsgWhat::SET_OUTPUT_BUFFER, proc);
146 }
147 
GetPackedInputFlag(bool & flag)148 int32_t ImageCodec::GetPackedInputFlag(bool& flag)
149 {
150     ParamSP reply;
151     int32_t ret = DoSyncCallAndGetReply(MsgWhat::GET_PACKED_INPUT_FLAG, nullptr, reply);
152     if (ret != IC_ERR_OK) {
153         HLOGE("failed to get packed input flag");
154         return ret;
155     }
156     IF_TRUE_RETURN_VAL_WITH_MSG(!reply->GetValue("packedInputFlag", flag),
157         IC_ERR_UNKNOWN, "packed input flag not replied");
158     return IC_ERR_OK;
159 }
160 /**************************** public functions end ****************************/
161 
ImageCodec(OMX_VIDEO_CODINGTYPE codingType,bool isEncoder)162 ImageCodec::ImageCodec(OMX_VIDEO_CODINGTYPE codingType, bool isEncoder)
163     : isEncoder_(isEncoder), codingType_(codingType)
164 {
165     debugMode_ = OHOS::system::GetBoolParameter("image.codec.debug", false);
166     dumpMode_ = OHOS::system::GetBoolParameter("image.codec.dump", false);
167     LOGD(">> debug mode = %{public}d, dump mode = %{public}d", debugMode_, dumpMode_);
168 
169     uninitializedState_ = make_shared<UninitializedState>(this);
170     initializedState_ = make_shared<InitializedState>(this);
171     startingState_ = make_shared<StartingState>(this);
172     runningState_ = make_shared<RunningState>(this);
173     outputPortChangedState_ = make_shared<OutputPortChangedState>(this);
174     stoppingState_ = make_shared<StoppingState>(this);
175     StateMachine::ChangeStateTo(uninitializedState_);
176 }
177 
~ImageCodec()178 ImageCodec::~ImageCodec()
179 {
180     HLOGI(">>");
181     MsgHandleLoop::Stop();
182     ReleaseComponent();
183 }
184 
InitWithName(const string & name)185 int32_t ImageCodec::InitWithName(const string &name)
186 {
187     function<void(ParamSP)> proc = [&](ParamSP msg) {
188         msg->SetValue("name", name);
189     };
190     return DoSyncCall(MsgWhat::INIT, proc);
191 }
192 
ToString(BufferOwner owner)193 const char* ImageCodec::ToString(BufferOwner owner)
194 {
195     switch (owner) {
196         case BufferOwner::OWNED_BY_US:
197             return "us";
198         case BufferOwner::OWNED_BY_USER:
199             return "user";
200         case BufferOwner::OWNED_BY_OMX:
201             return "omx";
202         default:
203             return "";
204     }
205 }
206 
ToString(MsgWhat what)207 const char* ImageCodec::ToString(MsgWhat what)
208 {
209     static const map<MsgWhat, const char*> m = {
210         { INIT,                    "INIT"                    },
211         { SET_CALLBACK,            "SET_CALLBACK"            },
212         { CONFIGURE,               "CONFIGURE"               },
213         { START,                   "START"                   },
214         { GET_INPUT_FORMAT,        "GET_INPUT_FORMAT"        },
215         { GET_OUTPUT_FORMAT,       "GET_OUTPUT_FORMAT"       },
216         { QUEUE_INPUT_BUFFER,      "QUEUE_INPUT_BUFFER"      },
217         { RELEASE_OUTPUT_BUFFER,   "RELEASE_OUTPUT_BUFFER"   },
218         { RELEASE,                 "RELEASE"                 },
219         { GET_OUTPUT_BUFFER_USAGE, "GET_OUTPUT_BUFFER_USAGE" },
220         { SET_OUTPUT_BUFFER,       "SET_OUTPUT_BUFFER"       },
221         { GET_PACKED_INPUT_FLAG,   "GET_PACKED_INPUT_FLAG"   },
222         { CODEC_EVENT,             "CODEC_EVENT"             },
223         { OMX_EMPTY_BUFFER_DONE,   "OMX_EMPTY_BUFFER_DONE"   },
224         { OMX_FILL_BUFFER_DONE,    "OMX_FILL_BUFFER_DONE"    },
225         { CHECK_IF_STUCK,          "CHECK_IF_STUCK"          },
226         { FORCE_SHUTDOWN,          "FORCE_SHUTDOWN"          },
227     };
228     auto it = m.find(what);
229     if (it != m.end()) {
230         return it->second;
231     }
232     return "UNKNOWN";
233 }
234 
ReplyErrorCode(MsgId id,int32_t err)235 void ImageCodec::ReplyErrorCode(MsgId id, int32_t err)
236 {
237     if (id == ASYNC_MSG_ID) {
238         return;
239     }
240     ParamSP reply = make_shared<ParamBundle>();
241     reply->SetValue("err", err);
242     PostReply(id, reply);
243 }
244 
GetPixelFmtFromUser(const Format & format)245 bool ImageCodec::GetPixelFmtFromUser(const Format &format)
246 {
247     is10Bit_ = false;
248     optional<PixelFmt> fmt;
249     int32_t graphicFmt;
250     if (format.GetValue(ImageCodecDescriptionKey::PIXEL_FORMAT, graphicFmt)) {
251         if (!isPackedInputSupported_) {
252             if (graphicFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) {
253                 is10Bit_ = true;
254                 graphicFmt = GRAPHIC_PIXEL_FMT_YCBCR_420_SP;
255             } else if (graphicFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010) {
256                 is10Bit_ = true;
257                 graphicFmt = GRAPHIC_PIXEL_FMT_YCRCB_420_SP;
258             }
259         }
260         fmt = TypeConverter::GraphicFmtToFmt(static_cast<GraphicPixelFormat>(graphicFmt));
261     } else {
262         HLOGE("pixel format unspecified");
263         return false;
264     }
265     configuredFmt_ = fmt.value();
266     HLOGI("configured pixel format is %{public}s", configuredFmt_.strFmt.c_str());
267     return true;
268 }
269 
GetFrameRateFromUser(const Format & format)270 optional<double> ImageCodec::GetFrameRateFromUser(const Format &format)
271 {
272     double frameRate;
273     if (format.GetValue(ImageCodecDescriptionKey::FRAME_RATE, frameRate) && frameRate > 0) {
274         LOGD("user set frame rate %{public}.2f", frameRate);
275         return frameRate;
276     }
277     return nullopt;
278 }
279 
SetFrameRateAdaptiveMode(const Format & format)280 int32_t ImageCodec::SetFrameRateAdaptiveMode(const Format &format)
281 {
282     if (!format.ContainKey(ImageCodecDescriptionKey::VIDEO_FRAME_RATE_ADAPTIVE_MODE)) {
283         return IC_ERR_UNKNOWN;
284     }
285 
286     WorkingFrequencyParam param {};
287     InitOMXParamExt(param);
288     if (!GetParameter(OMX_IndexParamWorkingFrequency, param)) {
289         HLOGW("get working freq param failed");
290         return IC_ERR_UNKNOWN;
291     }
292     HLOGI("level cnt is %{public}d, set level to %{public}d", param.level, param.level - 1);
293     param.level = param.level - 1;
294 
295     if (!SetParameter(OMX_IndexParamWorkingFrequency, param)) {
296         HLOGW("set working freq param failed");
297         return IC_ERR_UNKNOWN;
298     }
299     return IC_ERR_OK;
300 }
301 
SetProcessName(const Format & format)302 int32_t ImageCodec::SetProcessName(const Format &format)
303 {
304     string processName;
305     if (!format.GetValue(ImageCodecDescriptionKey::PROCESS_NAME, processName)) {
306         return IC_ERR_UNKNOWN;
307     }
308     HLOGI("processName name is %{public}s", processName.c_str());
309 
310     ProcessNameParam param {};
311     InitOMXParamExt(param);
312     if (strcpy_s(param.processName, sizeof(param.processName), processName.c_str()) != EOK) {
313         HLOGW("strcpy failed");
314         return IC_ERR_UNKNOWN;
315     }
316     if (!SetParameter(OMX_IndexParamProcessName, param)) {
317         HLOGW("set process name failed");
318         return IC_ERR_UNKNOWN;
319     }
320     return IC_ERR_OK;
321 }
322 
SetVideoPortInfo(OMX_DIRTYPE portIndex,const PortInfo & info)323 int32_t ImageCodec::SetVideoPortInfo(OMX_DIRTYPE portIndex, const PortInfo& info)
324 {
325     if (info.pixelFmt.has_value()) {
326         CodecVideoPortFormatParam param;
327         InitOMXParamExt(param);
328         param.portIndex = portIndex;
329         param.codecCompressFormat = info.codingType;
330         param.codecColorFormat = info.pixelFmt->graphicFmt;
331         param.framerate = info.frameRate * FRAME_RATE_COEFFICIENT;
332         if (!SetParameter(OMX_IndexCodecVideoPortFormat, param)) {
333             HLOGE("set port format failed");
334             return IC_ERR_UNKNOWN;
335         }
336     }
337     {
338         OMX_PARAM_PORTDEFINITIONTYPE def;
339         InitOMXParam(def);
340         def.nPortIndex = portIndex;
341         if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
342             HLOGE("get port definition failed");
343             return IC_ERR_UNKNOWN;
344         }
345         def.format.video.nFrameWidth = info.width;
346         def.format.video.nFrameHeight = info.height;
347         def.format.video.eCompressionFormat = info.codingType;
348         // we dont set eColorFormat here because it has been set by CodecVideoPortFormatParam
349         def.format.video.xFramerate = info.frameRate * FRAME_RATE_COEFFICIENT;
350         if (portIndex == OMX_DirInput && info.inputBufSize.has_value()) {
351             def.nBufferSize = info.inputBufSize.value();
352         }
353         if (info.bufferCnt.has_value()) {
354             def.nBufferCountActual = info.bufferCnt.value();
355         }
356         if (!SetParameter(OMX_IndexParamPortDefinition, def)) {
357             HLOGE("set port definition failed");
358             return IC_ERR_UNKNOWN;
359         }
360         if (portIndex == OMX_DirOutput) {
361             if (outputFormat_ == nullptr) {
362                 outputFormat_ = make_shared<Format>();
363             }
364             outputFormat_->SetValue(ImageCodecDescriptionKey::FRAME_RATE, info.frameRate);
365         }
366     }
367 
368     return (portIndex == OMX_DirInput) ? UpdateInPortFormat() : UpdateOutPortFormat();
369 }
370 
PrintPortDefinition(const OMX_PARAM_PORTDEFINITIONTYPE & def)371 void ImageCodec::PrintPortDefinition(const OMX_PARAM_PORTDEFINITIONTYPE& def)
372 {
373     const OMX_VIDEO_PORTDEFINITIONTYPE& video = def.format.video;
374     HLOGI("----- %{public}s port definition -----", (def.nPortIndex == OMX_DirInput) ? "INPUT" : "OUTPUT");
375     HLOGI("bEnabled %{public}d, bPopulated %{public}d", def.bEnabled, def.bPopulated);
376     HLOGI("nBufferCountActual %{public}u, nBufferSize %{public}u", def.nBufferCountActual, def.nBufferSize);
377     HLOGI("nFrameWidth x nFrameHeight (%{public}u x %{public}u), framerate %{public}u(%{public}.2f)",
378         video.nFrameWidth, video.nFrameHeight, video.xFramerate, video.xFramerate / FRAME_RATE_COEFFICIENT);
379     HLOGI("    nStride x nSliceHeight (%{public}u x %{public}u)", video.nStride, video.nSliceHeight);
380     HLOGI("eCompressionFormat %{public}d(%{public}#x), eColorFormat %{public}d(%{public}#x)",
381         video.eCompressionFormat, video.eCompressionFormat, video.eColorFormat, video.eColorFormat);
382     HLOGI("----------------------------------");
383 }
384 
GetPortDefinition(OMX_DIRTYPE portIndex,OMX_PARAM_PORTDEFINITIONTYPE & def)385 int32_t ImageCodec::GetPortDefinition(OMX_DIRTYPE portIndex, OMX_PARAM_PORTDEFINITIONTYPE& def)
386 {
387     InitOMXParam(def);
388     def.nPortIndex = portIndex;
389     if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
390         HLOGE("get %{public}s port definition failed", (portIndex == OMX_DirInput ? "input" : "output"));
391         return IC_ERR_INVALID_VAL;
392     }
393     if (def.nBufferSize == 0 || def.nBufferSize > MAX_IMAGE_CODEC_BUFFER_SIZE) {
394         HLOGE("invalid nBufferSize %{public}u", def.nBufferSize);
395         return IC_ERR_INVALID_VAL;
396     }
397     PrintPortDefinition(def);
398     return IC_ERR_OK;
399 }
400 
AllocateHardwareBuffers(OMX_DIRTYPE portIndex)401 int32_t ImageCodec::AllocateHardwareBuffers(OMX_DIRTYPE portIndex)
402 {
403     HeifPerfTracker tracker(__FUNCTION__);
404     OMX_PARAM_PORTDEFINITIONTYPE def;
405     int32_t ret = GetPortDefinition(portIndex, def);
406     IF_TRUE_RETURN_VAL(ret != IC_ERR_OK, ret);
407 
408     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
409     pool.clear();
410     for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
411         shared_ptr<OmxCodecBuffer> omxBuffer = make_shared<OmxCodecBuffer>();
412         omxBuffer->size = sizeof(OmxCodecBuffer);
413         omxBuffer->version.version.majorVersion = 1;
414         omxBuffer->bufferType = CODEC_BUFFER_TYPE_DMA_MEM_FD;
415         omxBuffer->fd = -1;
416         omxBuffer->allocLen = def.nBufferSize;
417         omxBuffer->fenceFd = -1;
418         shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
419         ret = compNode_->AllocateBuffer(portIndex, *omxBuffer, *outBuffer);
420         if (ret != HDF_SUCCESS) {
421             HLOGE("Failed to AllocateBuffer on %{public}s port", (portIndex == OMX_DirInput ? "input" : "output"));
422             return IC_ERR_INVALID_VAL;
423         }
424         shared_ptr<ImageCodecBuffer> imgCodecBuffer = ImageCodecBuffer::CreateDmaBuffer(outBuffer->fd,
425             static_cast<int32_t>(def.nBufferSize), static_cast<int32_t>(def.format.video.nStride));
426         if (imgCodecBuffer == nullptr || imgCodecBuffer->GetCapacity() != static_cast<int32_t>(def.nBufferSize)) {
427             HLOGE("AllocateHardwareBuffers failed");
428             return IC_ERR_NO_MEMORY;
429         }
430         BufferInfo bufInfo;
431         bufInfo.isInput        = (portIndex == OMX_DirInput) ? true : false;
432         bufInfo.owner          = BufferOwner::OWNED_BY_US;
433         bufInfo.surfaceBuffer  = nullptr;
434         bufInfo.imgCodecBuffer = imgCodecBuffer;
435         bufInfo.omxBuffer      = outBuffer;
436         bufInfo.bufferId       = outBuffer->bufferId;
437         bufInfo.CleanUpUnusedInfo();
438         pool.push_back(bufInfo);
439     }
440     return IC_ERR_OK;
441 }
442 
AllocateSurfaceBuffers(OMX_DIRTYPE portIndex,bool isOutputPortSettingChanged,sptr<SurfaceBuffer> output)443 int32_t ImageCodec::AllocateSurfaceBuffers(OMX_DIRTYPE portIndex, bool isOutputPortSettingChanged,
444                                            sptr<SurfaceBuffer> output)
445 {
446     HeifPerfTracker tracker(__FUNCTION__);
447     OMX_PARAM_PORTDEFINITIONTYPE def;
448     int32_t ret = GetPortDefinition(portIndex, def);
449     if (ret != IC_ERR_OK) {
450         return ret;
451     }
452     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
453     pool.clear();
454     bool canReuseOutputBuffer = false;
455     if (isPackedInputSupported_) {
456         canReuseOutputBuffer = (output != nullptr);
457     } else {
458         canReuseOutputBuffer = (output != nullptr) && (!is10Bit_ || isOutputPortSettingChanged);
459     }
460     for (uint32_t i = 0; i < def.nBufferCountActual; ++i) {
461         shared_ptr<ImageCodecBuffer> imgCodecBuffer = canReuseOutputBuffer ?
462             ImageCodecBuffer::CreateSurfaceBuffer(output) : ImageCodecBuffer::CreateSurfaceBuffer(requestCfg_);
463         if (imgCodecBuffer == nullptr) {
464             HLOGE("AllocateSurfaceBuffers failed");
465             return IC_ERR_NO_MEMORY;
466         }
467         sptr<SurfaceBuffer> surfaceBuffer = imgCodecBuffer->GetSurfaceBuffer();
468         IF_TRUE_RETURN_VAL_WITH_MSG(surfaceBuffer == nullptr, IC_ERR_INVALID_VAL, "failed to get surfacebuffer");
469         shared_ptr<OmxCodecBuffer> omxBuffer = isEncoder_ ?
470             DynamicSurfaceBufferToOmxBuffer() : SurfaceBufferToOmxBuffer(surfaceBuffer);
471         IF_TRUE_RETURN_VAL(omxBuffer == nullptr, IC_ERR_INVALID_VAL);
472         shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
473         int32_t hdiRet = compNode_->UseBuffer(portIndex, *omxBuffer, *outBuffer);
474         if (hdiRet != HDF_SUCCESS) {
475             HLOGE("Failed to UseBuffer on %{public}s port", (portIndex == OMX_DirInput ? "input" : "output"));
476             return IC_ERR_INVALID_VAL;
477         }
478         BufferInfo bufInfo;
479         bufInfo.isInput        = (portIndex == OMX_DirInput) ? true : false;
480         bufInfo.owner          = BufferOwner::OWNED_BY_US;
481         bufInfo.surfaceBuffer  = surfaceBuffer;
482         bufInfo.imgCodecBuffer = imgCodecBuffer;
483         bufInfo.omxBuffer      = outBuffer;
484         bufInfo.bufferId       = outBuffer->bufferId;
485         pool.push_back(bufInfo);
486     }
487 
488     return IC_ERR_OK;
489 }
490 
SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer> & surfaceBuffer)491 shared_ptr<OmxCodecBuffer> ImageCodec::SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer>& surfaceBuffer)
492 {
493     BufferHandle* bufferHandle = surfaceBuffer->GetBufferHandle();
494     IF_TRUE_RETURN_VAL_WITH_MSG(bufferHandle == nullptr, nullptr, "surfacebuffer has null bufferhandle");
495     auto omxBuffer = make_shared<OmxCodecBuffer>();
496     omxBuffer->size = sizeof(OmxCodecBuffer);
497     omxBuffer->version.version.majorVersion = 1;
498     omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
499     omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
500     omxBuffer->fd = -1;
501     omxBuffer->allocLen = surfaceBuffer->GetSize();
502     omxBuffer->fenceFd = -1;
503     return omxBuffer;
504 }
505 
DynamicSurfaceBufferToOmxBuffer()506 shared_ptr<OmxCodecBuffer> ImageCodec::DynamicSurfaceBufferToOmxBuffer()
507 {
508     auto omxBuffer = make_shared<OmxCodecBuffer>();
509     omxBuffer->size = sizeof(OmxCodecBuffer);
510     omxBuffer->version.version.majorVersion = 1;
511     omxBuffer->bufferType = CODEC_BUFFER_TYPE_DYNAMIC_HANDLE;
512     omxBuffer->fd = -1;
513     omxBuffer->allocLen = 0;
514     omxBuffer->fenceFd = -1;
515     return omxBuffer;
516 }
517 
FindBufferInfoByID(OMX_DIRTYPE portIndex,uint32_t bufferId)518 ImageCodec::BufferInfo* ImageCodec::FindBufferInfoByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
519 {
520     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
521     for (BufferInfo &info : pool) {
522         if (info.bufferId == bufferId) {
523             return &info;
524         }
525     }
526     HLOGE("unknown buffer id %{public}u", bufferId);
527     return nullptr;
528 }
529 
FindBufferIndexByID(OMX_DIRTYPE portIndex,uint32_t bufferId)530 optional<size_t> ImageCodec::FindBufferIndexByID(OMX_DIRTYPE portIndex, uint32_t bufferId)
531 {
532     const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
533     for (size_t i = 0; i < pool.size(); i++) {
534         if (pool[i].bufferId == bufferId) {
535             return i;
536         }
537     }
538     HLOGE("unknown buffer id %{public}u", bufferId);
539     return nullopt;
540 }
541 
NotifyUserToFillThisInBuffer(BufferInfo & info)542 void ImageCodec::NotifyUserToFillThisInBuffer(BufferInfo &info)
543 {
544     callback_->OnInputBufferAvailable(info.bufferId, info.imgCodecBuffer);
545     ChangeOwner(info, BufferOwner::OWNED_BY_USER);
546 }
547 
OnQueueInputBuffer(const MsgInfo & msg,BufferOperationMode mode)548 void ImageCodec::OnQueueInputBuffer(const MsgInfo &msg, BufferOperationMode mode)
549 {
550     uint32_t bufferId;
551     (void)msg.param->GetValue(BUFFER_ID, bufferId);
552     BufferInfo* bufferInfo = FindBufferInfoByID(OMX_DirInput, bufferId);
553     if (bufferInfo == nullptr) {
554         ReplyErrorCode(msg.id, IC_ERR_INVALID_VAL);
555         return;
556     }
557     if (bufferInfo->owner != BufferOwner::OWNED_BY_USER) {
558         HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(bufferInfo->owner));
559         ReplyErrorCode(msg.id, IC_ERR_INVALID_VAL);
560         return;
561     }
562     bufferInfo->imgCodecBuffer->GetBufferCirculateInfo(bufferInfo->omxBuffer->pts,
563                                                        bufferInfo->omxBuffer->flag,
564                                                        bufferInfo->omxBuffer->filledLen,
565                                                        bufferInfo->omxBuffer->offset);
566     ChangeOwner(*bufferInfo, BufferOwner::OWNED_BY_US);
567     ReplyErrorCode(msg.id, IC_ERR_OK);
568     OnQueueInputBuffer(mode, bufferInfo);
569 }
570 
OnQueueInputBuffer(BufferOperationMode mode,BufferInfo * info)571 void ImageCodec::OnQueueInputBuffer(BufferOperationMode mode, BufferInfo* info)
572 {
573     switch (mode) {
574         case KEEP_BUFFER: {
575             return;
576         }
577         case RESUBMIT_BUFFER: {
578             if (inputPortEos_) {
579                 HLOGI("input already eos, keep this buffer");
580                 return;
581             }
582             bool eos = (info->omxBuffer->flag & OMX_BUFFERFLAG_EOS);
583             if (!eos && info->omxBuffer->filledLen == 0) {
584                 HLOGI("this is not a eos buffer but not filled, ask user to re-fill it");
585                 NotifyUserToFillThisInBuffer(*info);
586                 return;
587             }
588             if (eos) {
589                 inputPortEos_ = true;
590             }
591             int32_t ret = NotifyOmxToEmptyThisInBuffer(*info);
592             if (ret != IC_ERR_OK) {
593                 SignalError(IC_ERR_UNKNOWN);
594             }
595             return;
596         }
597         default: {
598             HLOGE("SHOULD NEVER BE HERE");
599             return;
600         }
601     }
602 }
603 
NotifyOmxToEmptyThisInBuffer(BufferInfo & info)604 int32_t ImageCodec::NotifyOmxToEmptyThisInBuffer(BufferInfo& info)
605 {
606     info.Dump(compUniqueStr_, dumpMode_);
607     info.EndCpuAccess();
608     int32_t ret = compNode_->EmptyThisBuffer(*(info.omxBuffer));
609     if (ret != HDF_SUCCESS) {
610         HLOGE("EmptyThisBuffer failed");
611         return IC_ERR_UNKNOWN;
612     }
613     ChangeOwner(info, BufferOwner::OWNED_BY_OMX);
614     return IC_ERR_OK;
615 }
616 
NotifyOmxToFillThisOutBuffer(BufferInfo & info)617 int32_t ImageCodec::NotifyOmxToFillThisOutBuffer(BufferInfo& info)
618 {
619     info.omxBuffer->flag = 0;
620     int32_t ret = compNode_->FillThisBuffer(*(info.omxBuffer));
621     if (ret != HDF_SUCCESS) {
622         HLOGE("outBufId = %{public}u failed", info.bufferId);
623         return IC_ERR_UNKNOWN;
624     }
625     ChangeOwner(info, BufferOwner::OWNED_BY_OMX);
626     return IC_ERR_OK;
627 }
628 
OnOMXFillBufferDone(const OmxCodecBuffer & omxBuffer,BufferOperationMode mode)629 void ImageCodec::OnOMXFillBufferDone(const OmxCodecBuffer& omxBuffer, BufferOperationMode mode)
630 {
631     optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, omxBuffer.bufferId);
632     if (!idx.has_value()) {
633         return;
634     }
635     BufferInfo& info = outputBufferPool_[idx.value()];
636     if (info.owner != BufferOwner::OWNED_BY_OMX) {
637         HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", info.bufferId, ToString(info.owner));
638         return;
639     }
640     info.omxBuffer->offset = omxBuffer.offset;
641     info.omxBuffer->filledLen = omxBuffer.filledLen;
642     info.omxBuffer->pts = omxBuffer.pts;
643     info.omxBuffer->flag = omxBuffer.flag;
644     ChangeOwner(info, BufferOwner::OWNED_BY_US);
645     OnOMXFillBufferDone(mode, info, idx.value());
646 }
647 
OnOMXFillBufferDone(BufferOperationMode mode,BufferInfo & info,size_t bufferIdx)648 void ImageCodec::OnOMXFillBufferDone(BufferOperationMode mode, BufferInfo& info, size_t bufferIdx)
649 {
650     switch (mode) {
651         case KEEP_BUFFER:
652             return;
653         case RESUBMIT_BUFFER: {
654             if (outputPortEos_) {
655                 HLOGI("output eos, keep this buffer");
656                 return;
657             }
658             bool eos = (info.omxBuffer->flag & OMX_BUFFERFLAG_EOS);
659             if (!eos && info.omxBuffer->filledLen == 0) {
660                 HLOGD("it's not a eos buffer but not filled, ask omx to re-fill it");
661                 NotifyOmxToFillThisOutBuffer(info);
662                 return;
663             }
664             NotifyUserOutBufferAvaliable(info);
665             if (eos) {
666                 outputPortEos_ = true;
667             }
668             return;
669         }
670         case FREE_BUFFER:
671             EraseBufferFromPool(OMX_DirOutput, bufferIdx);
672             return;
673         default:
674             HLOGE("SHOULD NEVER BE HERE");
675             return;
676     }
677 }
678 
NotifyUserOutBufferAvaliable(BufferInfo & info)679 void ImageCodec::NotifyUserOutBufferAvaliable(BufferInfo &info)
680 {
681     info.BeginCpuAccess();
682     info.Dump(compUniqueStr_, dumpMode_);
683     shared_ptr<OmxCodecBuffer> omxBuffer = info.omxBuffer;
684     info.imgCodecBuffer->SetBufferCirculateInfo(omxBuffer->pts, omxBuffer->flag,
685                                                 omxBuffer->filledLen, omxBuffer->offset);
686     callback_->OnOutputBufferAvailable(info.bufferId, info.imgCodecBuffer);
687     ChangeOwner(info, BufferOwner::OWNED_BY_USER);
688 }
689 
OnReleaseOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)690 void ImageCodec::OnReleaseOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
691 {
692     uint32_t bufferId;
693     (void)msg.param->GetValue(BUFFER_ID, bufferId);
694     optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
695     if (!idx.has_value()) {
696         ReplyErrorCode(msg.id, IC_ERR_INVALID_VAL);
697         return;
698     }
699     BufferInfo& info = outputBufferPool_[idx.value()];
700     if (info.owner != BufferOwner::OWNED_BY_USER) {
701         HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info.owner));
702         ReplyErrorCode(msg.id, IC_ERR_INVALID_VAL);
703         return;
704     }
705     HLOGD("outBufId = %{public}u", bufferId);
706     ChangeOwner(info, BufferOwner::OWNED_BY_US);
707     ReplyErrorCode(msg.id, IC_ERR_OK);
708 
709     switch (mode) {
710         case KEEP_BUFFER: {
711             return;
712         }
713         case RESUBMIT_BUFFER: {
714             if (outputPortEos_) {
715                 HLOGI("output eos, keep this buffer");
716                 return;
717             }
718             int32_t ret = NotifyOmxToFillThisOutBuffer(info);
719             if (ret != IC_ERR_OK) {
720                 SignalError(IC_ERR_UNKNOWN);
721             }
722             return;
723         }
724         case FREE_BUFFER: {
725             EraseBufferFromPool(OMX_DirOutput, idx.value());
726             return;
727         }
728         default: {
729             HLOGE("SHOULD NEVER BE HERE");
730             return;
731         }
732     }
733 }
734 
ReclaimBuffer(OMX_DIRTYPE portIndex,BufferOwner owner,bool erase)735 void ImageCodec::ReclaimBuffer(OMX_DIRTYPE portIndex, BufferOwner owner, bool erase)
736 {
737     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
738     for (size_t i = pool.size(); i > 0;) {
739         i--;
740         BufferInfo& info = pool[i];
741         if (info.owner == owner) {
742             ChangeOwner(info, BufferOwner::OWNED_BY_US);
743             if (erase) {
744                 EraseBufferFromPool(portIndex, i);
745             }
746         }
747     }
748 }
749 
IsAllBufferOwnedByUs(OMX_DIRTYPE portIndex)750 bool ImageCodec::IsAllBufferOwnedByUs(OMX_DIRTYPE portIndex)
751 {
752     const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
753     for (const BufferInfo& info : pool) {
754         if (info.owner != BufferOwner::OWNED_BY_US) {
755             return false;
756         }
757     }
758     return true;
759 }
760 
IsAllBufferOwnedByUs()761 bool ImageCodec::IsAllBufferOwnedByUs()
762 {
763     return IsAllBufferOwnedByUs(OMX_DirInput) && IsAllBufferOwnedByUs(OMX_DirOutput);
764 }
765 
EraseOutBuffersOwnedByUs()766 void ImageCodec::EraseOutBuffersOwnedByUs()
767 {
768     // traverse index in reverse order because we need to erase index from vector
769     for (size_t i = outputBufferPool_.size(); i > 0;) {
770         i--;
771         const BufferInfo& info = outputBufferPool_[i];
772         if (info.owner == BufferOwner::OWNED_BY_US) {
773             EraseBufferFromPool(OMX_DirOutput, i);
774         }
775     }
776 }
777 
ClearBufferPool(OMX_DIRTYPE portIndex)778 void ImageCodec::ClearBufferPool(OMX_DIRTYPE portIndex)
779 {
780     const vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
781     for (size_t i = pool.size(); i > 0;) {
782         i--;
783         EraseBufferFromPool(portIndex, i);
784     }
785 }
786 
FreeOmxBuffer(OMX_DIRTYPE portIndex,const BufferInfo & info)787 void ImageCodec::FreeOmxBuffer(OMX_DIRTYPE portIndex, const BufferInfo& info)
788 {
789     if (compNode_ && info.omxBuffer) {
790         int32_t omxRet = compNode_->FreeBuffer(portIndex, *(info.omxBuffer));
791         if (omxRet != HDF_SUCCESS) {
792             HLOGW("notify omx to free buffer failed");
793         }
794     }
795 }
796 
DoSyncCall(MsgWhat msgType,function<void (ParamSP)> oper)797 int32_t ImageCodec::DoSyncCall(MsgWhat msgType, function<void(ParamSP)> oper)
798 {
799     ParamSP reply;
800     return DoSyncCallAndGetReply(msgType, oper, reply);
801 }
802 
DoSyncCallAndGetReply(MsgWhat msgType,function<void (ParamSP)> oper,ParamSP & reply)803 int32_t ImageCodec::DoSyncCallAndGetReply(MsgWhat msgType, function<void(ParamSP)> oper, ParamSP &reply)
804 {
805     ParamSP msg = make_shared<ParamBundle>();
806     IF_TRUE_RETURN_VAL_WITH_MSG(msg == nullptr, IC_ERR_NO_MEMORY, "out of memory");
807     if (oper) {
808         oper(msg);
809     }
810     bool ret = MsgHandleLoop::SendSyncMsg(msgType, msg, reply);
811     IF_TRUE_RETURN_VAL_WITH_MSG(!ret, IC_ERR_UNKNOWN, "wait msg %{public}d time out", msgType);
812     int32_t err;
813     IF_TRUE_RETURN_VAL_WITH_MSG(reply == nullptr || !reply->GetValue("err", err),
814         IC_ERR_UNKNOWN, "error code of msg %{public}d not replied", msgType);
815     return err;
816 }
817 
ChangeOmxToTargetState(CodecStateType & state,CodecStateType targetState)818 void ImageCodec::ChangeOmxToTargetState(CodecStateType &state, CodecStateType targetState)
819 {
820     int32_t ret = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, targetState, {});
821     if (ret != HDF_SUCCESS) {
822         HLOGE("failed to change omx state, ret=%{public}d", ret);
823         return;
824     }
825 
826     int tryCnt = 0;
827     do {
828         if (tryCnt++ > 10) { // try up to 10 times
829             HLOGE("failed to change to state(%{public}d), abort", targetState);
830             state = CODEC_STATE_INVALID;
831             break;
832         }
833         this_thread::sleep_for(10ms); // wait 10ms
834         ret = compNode_->GetState(state);
835         if (ret != HDF_SUCCESS) {
836             HLOGE("failed to get omx state, ret=%{public}d", ret);
837         }
838     } while (ret == HDF_SUCCESS && state != targetState && state != CODEC_STATE_INVALID);
839 }
840 
RollOmxBackToLoaded()841 bool ImageCodec::RollOmxBackToLoaded()
842 {
843     CodecStateType state;
844     int32_t ret = compNode_->GetState(state);
845     if (ret != HDF_SUCCESS) {
846         HLOGE("failed to get omx node status(ret=%{public}d), can not perform state rollback", ret);
847         return false;
848     }
849     HLOGI("current omx state (%{public}d)", state);
850     switch (state) {
851         case CODEC_STATE_EXECUTING: {
852             ChangeOmxToTargetState(state, CODEC_STATE_IDLE);
853             [[fallthrough]];
854         }
855         case CODEC_STATE_IDLE: {
856             ChangeOmxToTargetState(state, CODEC_STATE_LOADED);
857             [[fallthrough]];
858         }
859         case CODEC_STATE_LOADED:
860         case CODEC_STATE_INVALID: {
861             return true;
862         }
863         default: {
864             HLOGE("invalid omx state: %{public}d", state);
865             return false;
866         }
867     }
868 }
869 
CleanUpOmxNode()870 void ImageCodec::CleanUpOmxNode()
871 {
872     if (compNode_ == nullptr) {
873         return;
874     }
875 
876     if (RollOmxBackToLoaded()) {
877         for (const BufferInfo& info : inputBufferPool_) {
878             FreeOmxBuffer(OMX_DirInput, info);
879         }
880         for (const BufferInfo& info : outputBufferPool_) {
881             FreeOmxBuffer(OMX_DirOutput, info);
882         }
883     }
884 }
885 
ReleaseComponent()886 void ImageCodec::ReleaseComponent()
887 {
888     CleanUpOmxNode();
889     if (compMgr_ != nullptr) {
890         compMgr_->DestroyComponent(componentId_);
891     }
892     compNode_ = nullptr;
893     compCb_ = nullptr;
894     compMgr_ = nullptr;
895     componentId_ = 0;
896     componentName_.clear();
897 }
898 
ForceShutdown(int32_t generation)899 int32_t ImageCodec::ForceShutdown(int32_t generation)
900 {
901     if (generation != stateGeneration_) {
902         HLOGE("ignoring stale force shutdown message: #%{public}d (now #%{public}d)",
903             generation, stateGeneration_);
904         return IC_ERR_OK;
905     }
906     HLOGI("force to shutdown");
907     isShutDownFromRunning_ = true;
908     notifyCallerAfterShutdownComplete_ = false;
909     auto err = compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
910     if (err == HDF_SUCCESS) {
911         ChangeStateTo(stoppingState_);
912     }
913     return IC_ERR_OK;
914 }
915 
SignalError(ImageCodecError err)916 void ImageCodec::SignalError(ImageCodecError err)
917 {
918     HLOGE("fatal error happened: errCode=%{public}d", err);
919     hasFatalError_ = true;
920     callback_->OnError(err);
921 }
922 
DeferMessage(const MsgInfo & info)923 void ImageCodec::DeferMessage(const MsgInfo &info)
924 {
925     deferredQueue_.push_back(info);
926 }
927 
ProcessDeferredMessages()928 void ImageCodec::ProcessDeferredMessages()
929 {
930     for (const MsgInfo &info : deferredQueue_) {
931         StateMachine::OnMsgReceived(info);
932     }
933     deferredQueue_.clear();
934 }
935 
ReplyToSyncMsgLater(const MsgInfo & msg)936 void ImageCodec::ReplyToSyncMsgLater(const MsgInfo& msg)
937 {
938     syncMsgToReply_[msg.type].push(make_pair(msg.id, msg.param));
939 }
940 
GetFirstSyncMsgToReply(MsgInfo & msg)941 bool ImageCodec::GetFirstSyncMsgToReply(MsgInfo& msg)
942 {
943     auto iter = syncMsgToReply_.find(msg.type);
944     if (iter == syncMsgToReply_.end()) {
945         return false;
946     }
947     tie(msg.id, msg.param) = iter->second.front();
948     iter->second.pop();
949     return true;
950 }
951 
952 /**************************** HdiCallback functions begin ****************************/
EventHandler(CodecEventType event,const EventInfo & info)953 int32_t ImageCodec::HdiCallback::EventHandler(CodecEventType event, const EventInfo &info)
954 {
955     LOGD("event = %{public}d, data1 = %{public}u, data2 = %{public}u", event, info.data1, info.data2);
956     ParamSP msg = make_shared<ParamBundle>();
957     msg->SetValue("event", event);
958     msg->SetValue("data1", info.data1);
959     msg->SetValue("data2", info.data2);
960     codec_->SendAsyncMsg(MsgWhat::CODEC_EVENT, msg);
961     return HDF_SUCCESS;
962 }
963 
EmptyBufferDone(int64_t appData,const OmxCodecBuffer & buffer)964 int32_t ImageCodec::HdiCallback::EmptyBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
965 {
966     ParamSP msg = make_shared<ParamBundle>();
967     msg->SetValue(BUFFER_ID, buffer.bufferId);
968     codec_->SendAsyncMsg(MsgWhat::OMX_EMPTY_BUFFER_DONE, msg);
969     return HDF_SUCCESS;
970 }
971 
FillBufferDone(int64_t appData,const OmxCodecBuffer & buffer)972 int32_t ImageCodec::HdiCallback::FillBufferDone(int64_t appData, const OmxCodecBuffer& buffer)
973 {
974     ParamSP msg = make_shared<ParamBundle>();
975     msg->SetValue("omxBuffer", buffer);
976     codec_->SendAsyncMsg(MsgWhat::OMX_FILL_BUFFER_DONE, msg);
977     return HDF_SUCCESS;
978 }
979 /**************************** HdiCallback functions begin ****************************/
980 
981 /**************************** BufferInfo functions begin ****************************/
CleanUpUnusedInfo()982 void ImageCodec::BufferInfo::CleanUpUnusedInfo()
983 {
984     if (omxBuffer == nullptr || omxBuffer->fd < 0) {
985         return;
986     }
987     if (omxBuffer->fd == 0) {
988         LOGW("fd of omxbuffer should never be 0");
989     }
990     close(omxBuffer->fd);
991     omxBuffer->fd = -1;
992 }
993 
BeginCpuAccess()994 void ImageCodec::BufferInfo::BeginCpuAccess()
995 {
996     if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
997         GSError err = surfaceBuffer->InvalidateCache();
998         if (err != GSERROR_OK) {
999             LOGW("InvalidateCache failed, GSError=%{public}d", err);
1000         }
1001     }
1002 }
1003 
EndCpuAccess()1004 void ImageCodec::BufferInfo::EndCpuAccess()
1005 {
1006     if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
1007         GSError err = surfaceBuffer->Map();
1008         if (err != GSERROR_OK) {
1009             LOGW("Map failed, GSError=%{public}d", err);
1010             return;
1011         }
1012         err = surfaceBuffer->FlushCache();
1013         if (err != GSERROR_OK) {
1014             LOGW("FlushCache failed, GSError=%{public}d", err);
1015         }
1016     }
1017 }
1018 /**************************** BufferInfo functions end ****************************/
1019 } // namespace OHOS::ImagePlugin