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