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 #include "hdi_codec.h"
16 #include "avcodec_log.h"
17 #include <unistd.h>
18
19 namespace {
20 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-HdiCodec"};
21 constexpr int TIMEOUT_MS = 1000;
22 using namespace OHOS::HDI::Codec::V4_0;
23 } // namespace
24
25 namespace OHOS {
26 namespace Media {
27 namespace Plugins {
28 namespace Hdi {
HdiCodec()29 HdiCodec::HdiCodec()
30 : componentId_(0),
31 componentName_(""),
32 compCb_(nullptr),
33 compNode_(nullptr),
34 compMgr_(nullptr),
35 outputOmxBuffer_(nullptr),
36 omxInBufferInfo_(std::make_shared<OmxBufferInfo>()),
37 omxOutBufferInfo_(std::make_shared<OmxBufferInfo>()),
38 event_(CODEC_EVENT_ERROR)
39 {
40 }
41
InitComponent(const std::string & name)42 Status HdiCodec::InitComponent(const std::string &name)
43 {
44 compMgr_ = GetComponentManager();
45 CHECK_AND_RETURN_RET_LOG(compMgr_ != nullptr, Status::ERROR_NULL_POINTER, "GetCodecComponentManager failed!");
46
47 componentName_ = name;
48 compCb_ = new HdiCodec::HdiCallback(shared_from_this());
49 int32_t ret = compMgr_->CreateComponent(compNode_, componentId_, componentName_, 0, compCb_);
50 if (ret != HDF_SUCCESS || compNode_ == nullptr) {
51 if (compCb_ != nullptr) {
52 compCb_ = nullptr;
53 }
54 compMgr_ = nullptr;
55 AVCODEC_LOGE("CreateComponent failed, ret=%{public}d", ret);
56 return Status::ERROR_NULL_POINTER;
57 }
58 return Status::OK;
59 }
60
GetComponentManager()61 sptr<ICodecComponentManager> HdiCodec::GetComponentManager()
62 {
63 sptr<ICodecComponentManager> compMgr = ICodecComponentManager::Get(false); // false: ipc
64 return compMgr;
65 }
66
GetCapabilityList()67 std::vector<CodecCompCapability> HdiCodec::GetCapabilityList()
68 {
69 CHECK_AND_RETURN_RET_LOG(compMgr_ != nullptr, {}, "compMgr is nullptr!");
70 int32_t compCount = 0;
71 int32_t ret = compMgr_->GetComponentNum(compCount);
72 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, {}, "GetComponentNum failed, ret=%{public}d", ret);
73 CHECK_AND_RETURN_RET_LOG(compCount > 0, {}, "GetComponentNum failed, compCount=%{public}d", compCount);
74
75 std::vector<CodecCompCapability> capabilityList(compCount);
76 ret = compMgr_->GetComponentCapabilityList(capabilityList, compCount);
77 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, {}, "GetComponentCapabilityList failed, ret=%{public}d", ret);
78
79 return capabilityList;
80 }
81
IsSupportCodecType(const std::string & name,MediaAVCodec::CapabilityData * audioCapability)82 bool HdiCodec::IsSupportCodecType(const std::string &name, MediaAVCodec::CapabilityData *audioCapability)
83 {
84 if (compMgr_ == nullptr) {
85 compMgr_ = GetComponentManager();
86 CHECK_AND_RETURN_RET_LOG(compMgr_ != nullptr, false, "compMgr_ is null");
87 }
88
89 std::vector<CodecCompCapability> capabilityList = GetCapabilityList();
90 CHECK_AND_RETURN_RET_LOG(!capabilityList.empty(), false, "Hdi capabilityList is empty!");
91
92 bool checkName = std::any_of(std::begin(capabilityList),
93 std::end(capabilityList), [name, audioCapability](CodecCompCapability capability) {
94 if (capability.compName == name) {
95 audioCapability->bitrate = MediaAVCodec::Range(capability.bitRate.min, capability.bitRate.max);
96 audioCapability->sampleRate.push_back(capability.port.audio.sampleRate[0]); //set first number so far
97 audioCapability->maxInstance = capability.maxInst;
98 audioCapability->profiles.push_back(capability.supportProfiles[0]);
99 audioCapability->channels = MediaAVCodec::Range(1, capability.port.audio.channelCount[0]);
100 }
101
102 return capability.compName == name;
103 });
104 return checkName;
105 }
106
InitParameter(AudioCodecOmxParam & param)107 void HdiCodec::InitParameter(AudioCodecOmxParam ¶m)
108 {
109 (void)memset_s(¶m, sizeof(param), 0x0, sizeof(param));
110 param.size = sizeof(param);
111 param.version.s.nVersionMajor = 1;
112 }
113
GetParameter(uint32_t index,AudioCodecOmxParam & param)114 Status HdiCodec::GetParameter(uint32_t index, AudioCodecOmxParam ¶m)
115 {
116 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
117 int8_t *p = reinterpret_cast<int8_t *>(¶m);
118 std::vector<int8_t> inParamVec(p, p + sizeof(param));
119 std::vector<int8_t> outParamVec;
120 int32_t ret = compNode_->GetParameter(index, inParamVec, outParamVec);
121 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_PARAMETER, "GetParameter failed!");
122 CHECK_AND_RETURN_RET_LOG(outParamVec.size() == sizeof(param), Status::ERROR_INVALID_PARAMETER,
123 "param size is invalid!");
124
125 errno_t rc = memcpy_s(¶m, sizeof(param), outParamVec.data(), outParamVec.size());
126 CHECK_AND_RETURN_RET_LOG(rc == EOK, Status::ERROR_INVALID_DATA, "memory copy failed!");
127 return Status::OK;
128 }
129
SetParameter(uint32_t index,const std::vector<int8_t> & paramVec)130 Status HdiCodec::SetParameter(uint32_t index, const std::vector<int8_t> ¶mVec)
131 {
132 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
133 int32_t ret = compNode_->SetParameter(index, paramVec);
134 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_PARAMETER, "SetParameter failed!");
135 return Status::OK;
136 }
137
InitBuffers(uint32_t bufferSize)138 Status HdiCodec::InitBuffers(uint32_t bufferSize)
139 {
140 Status ret;
141
142 ret = InitBuffersByPort(PortIndex::INPUT_PORT, bufferSize);
143 CHECK_AND_RETURN_RET_LOG(ret == Status::OK, ret, "Init Input Buffers failed, ret=%{public}d", ret);
144 ret = InitBuffersByPort(PortIndex::OUTPUT_PORT, bufferSize);
145 CHECK_AND_RETURN_RET_LOG(ret == Status::OK, ret, "Init Output Buffers failed, ret=%{public}d", ret);
146
147 return Status::OK;
148 }
149
InitBuffersByPort(PortIndex portIndex,uint32_t bufferSize)150 Status HdiCodec::InitBuffersByPort(PortIndex portIndex, uint32_t bufferSize)
151 {
152 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
153 auto avAllocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
154 std::shared_ptr<AVBuffer> avBuffer = AVBuffer::CreateAVBuffer(avAllocator, bufferSize);
155 if (avBuffer == nullptr) {
156 AVCODEC_LOGE("Create avBuffer failed!");
157 return Status::ERROR_NO_MEMORY;
158 }
159 std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
160 omxBuffer->size = sizeof(OmxCodecBuffer);
161 omxBuffer->version.version.majorVersion = 1;
162 omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
163 omxBuffer->fd = avBuffer->memory_->GetFileDescriptor();
164 omxBuffer->bufferhandle = nullptr;
165 omxBuffer->allocLen = bufferSize;
166 omxBuffer->fenceFd = -1;
167 omxBuffer->pts = 0;
168 omxBuffer->flag = 0;
169
170 if (portIndex == PortIndex::INPUT_PORT) {
171 omxBuffer->type = READ_ONLY_TYPE;
172 } else {
173 omxBuffer->type = READ_WRITE_TYPE;
174 }
175
176 OmxCodecBuffer outBuffer;
177 int32_t ret = compNode_->UseBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get(), outBuffer);
178 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_NO_MEMORY,
179 "InitBuffers failed, ret=%{public}d", ret);
180
181 omxBuffer->bufferId = outBuffer.bufferId;
182 if (portIndex == PortIndex::INPUT_PORT) {
183 std::unique_lock lock(inMutex_);
184 omxInBufferInfo_->omxBuffer = omxBuffer;
185 omxInBufferInfo_->avBuffer = avBuffer;
186 } else if (portIndex == PortIndex::OUTPUT_PORT) {
187 std::unique_lock lock(outMutex_);
188 omxOutBufferInfo_->omxBuffer = omxBuffer;
189 omxOutBufferInfo_->avBuffer = avBuffer;
190 }
191
192 return Status::OK;
193 }
194
SendCommand(CodecCommandType cmd,uint32_t param)195 Status HdiCodec::SendCommand(CodecCommandType cmd, uint32_t param)
196 {
197 std::unique_lock lock(inMutex_);
198 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
199 event_ = CODEC_EVENT_ERROR;
200 int32_t ret = compNode_->SendCommand(cmd, param, {});
201 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_DATA, "SendCommand failed");
202
203 condition_.wait_for(lock, std::chrono::milliseconds(TIMEOUT_MS),
204 [this] { return event_ == CODEC_EVENT_CMD_COMPLETE; });
205 CHECK_AND_RETURN_RET_LOG(event_ == CODEC_EVENT_CMD_COMPLETE, Status::ERROR_INVALID_PARAMETER,
206 "SendCommand timeout!");
207
208 return Status::OK;
209 }
210
EmptyThisBuffer(const std::shared_ptr<AVBuffer> & buffer)211 Status HdiCodec::EmptyThisBuffer(const std::shared_ptr<AVBuffer> &buffer)
212 {
213 std::unique_lock lock(inMutex_);
214 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
215 omxInBufferInfo_->omxBuffer->filledLen = static_cast<uint32_t>(buffer->memory_->GetSize());
216 omxInBufferInfo_->omxBuffer->offset = static_cast<uint32_t>(buffer->memory_->GetOffset());
217 omxInBufferInfo_->omxBuffer->pts = buffer->pts_;
218 omxInBufferInfo_->omxBuffer->flag = buffer->flag_;
219
220 errno_t rc = memcpy_s(omxInBufferInfo_->avBuffer->memory_->GetAddr(), omxInBufferInfo_->omxBuffer->filledLen,
221 buffer->memory_->GetAddr(), omxInBufferInfo_->omxBuffer->filledLen);
222 CHECK_AND_RETURN_RET_LOG(rc == EOK, Status::ERROR_INVALID_DATA, "memory copy failed!");
223
224 int32_t ret = compNode_->EmptyThisBuffer(*omxInBufferInfo_->omxBuffer.get());
225 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_DATA,
226 "EmptyThisBuffer failed, ret=%{public}d", ret);
227
228 AVCODEC_LOGD("EmptyThisBuffer OK");
229 return Status::OK;
230 }
231
FillThisBuffer(std::shared_ptr<AVBuffer> & buffer)232 Status HdiCodec::FillThisBuffer(std::shared_ptr<AVBuffer> &buffer)
233 {
234 std::unique_lock lock(outMutex_);
235 CHECK_AND_RETURN_RET_LOG(compNode_ != nullptr, Status::ERROR_NULL_POINTER, "compNode is nullptr!");
236 outputOmxBuffer_ = nullptr;
237 int32_t ret = compNode_->FillThisBuffer(*omxOutBufferInfo_->omxBuffer.get());
238 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_DATA, "FillThisBuffer failed!");
239
240 condition_.wait_for(lock, std::chrono::milliseconds(TIMEOUT_MS), [this] { return outputOmxBuffer_ != nullptr; });
241 CHECK_AND_RETURN_RET_LOG(outputOmxBuffer_ != nullptr, Status::ERROR_INVALID_PARAMETER, "FillThisBuffer timeout!");
242
243 errno_t rc = memcpy_s(buffer->memory_->GetAddr(), outputOmxBuffer_->filledLen,
244 omxOutBufferInfo_->avBuffer->memory_->GetAddr(), outputOmxBuffer_->filledLen);
245 CHECK_AND_RETURN_RET_LOG(rc == EOK, Status::ERROR_INVALID_DATA, "memory copy failed!");
246
247 buffer->memory_->SetSize(outputOmxBuffer_->filledLen);
248 buffer->memory_->SetOffset(outputOmxBuffer_->offset);
249 buffer->pts_ = outputOmxBuffer_->pts;
250 buffer->flag_ = outputOmxBuffer_->flag;
251
252 AVCODEC_LOGD("FillThisBuffer OK");
253 return Status::OK;
254 }
255
FreeBuffer(PortIndex portIndex,const std::shared_ptr<OmxCodecBuffer> & omxBuffer)256 Status HdiCodec::FreeBuffer(PortIndex portIndex, const std::shared_ptr<OmxCodecBuffer> &omxBuffer)
257 {
258 if (omxBuffer != nullptr) {
259 int32_t ret = compNode_->FreeBuffer(static_cast<uint32_t>(portIndex), *omxBuffer.get());
260 CHECK_AND_RETURN_RET_LOG(ret == HDF_SUCCESS, Status::ERROR_INVALID_DATA,
261 "Free buffer fail, portIndex=%{public}d, ret=%{public}d", portIndex, ret);
262 }
263
264 AVCODEC_LOGD("FreeBuffer OK");
265 return Status::OK;
266 }
267
OnEventHandler(CodecEventType event,const EventInfo & info)268 Status HdiCodec::OnEventHandler(CodecEventType event, const EventInfo &info)
269 {
270 std::unique_lock lock(inMutex_);
271 event_ = event;
272 condition_.notify_all();
273 return Status::OK;
274 }
275
OnEmptyBufferDone(const OmxCodecBuffer & buffer)276 Status HdiCodec::OnEmptyBufferDone(const OmxCodecBuffer &buffer)
277 {
278 return Status::OK;
279 }
280
OnFillBufferDone(const OmxCodecBuffer & buffer)281 Status HdiCodec::OnFillBufferDone(const OmxCodecBuffer &buffer)
282 {
283 std::unique_lock lock(outMutex_);
284 outputOmxBuffer_ = std::make_shared<OmxCodecBuffer>(buffer);
285 condition_.notify_all();
286 return Status::OK;
287 }
288
Reset()289 Status HdiCodec::Reset()
290 {
291 {
292 std::unique_lock lock(inMutex_);
293 FreeBuffer(PortIndex::INPUT_PORT, omxInBufferInfo_->omxBuffer);
294 omxInBufferInfo_->Reset();
295 }
296 {
297 std::unique_lock lock(outMutex_);
298 FreeBuffer(PortIndex::OUTPUT_PORT, omxOutBufferInfo_->omxBuffer);
299 omxOutBufferInfo_->Reset();
300 }
301 return Status::OK;
302 }
303
Release()304 void HdiCodec::Release()
305 {
306 {
307 std::unique_lock lock(inMutex_);
308 FreeBuffer(PortIndex::INPUT_PORT, omxInBufferInfo_->omxBuffer);
309 omxInBufferInfo_->Reset();
310 }
311 {
312 std::unique_lock lock(outMutex_);
313 FreeBuffer(PortIndex::OUTPUT_PORT, omxOutBufferInfo_->omxBuffer);
314 omxOutBufferInfo_->Reset();
315 }
316
317 if (compMgr_ != nullptr && componentId_ > 0) {
318 compMgr_->DestroyComponent(componentId_);
319 }
320 compNode_ = nullptr;
321 if (compCb_ != nullptr) {
322 compCb_ = nullptr;
323 }
324 compMgr_ = nullptr;
325 }
326
HdiCallback(std::shared_ptr<HdiCodec> hdiCodec)327 HdiCodec::HdiCallback::HdiCallback(std::shared_ptr<HdiCodec> hdiCodec) : hdiCodec_(hdiCodec)
328 {
329 }
330
EventHandler(CodecEventType event,const EventInfo & info)331 int32_t HdiCodec::HdiCallback::EventHandler(CodecEventType event, const EventInfo &info)
332 {
333 AVCODEC_LOGD("OnEventHandler");
334 if (hdiCodec_) {
335 hdiCodec_->OnEventHandler(event, info);
336 }
337 return HDF_SUCCESS;
338 }
339
EmptyBufferDone(int64_t appData,const OmxCodecBuffer & buffer)340 int32_t HdiCodec::HdiCallback::EmptyBufferDone(int64_t appData, const OmxCodecBuffer &buffer)
341 {
342 if (hdiCodec_) {
343 hdiCodec_->OnEmptyBufferDone(buffer);
344 }
345 if (buffer.fd >= 0) {
346 close(buffer.fd);
347 }
348 return HDF_SUCCESS;
349 }
350
FillBufferDone(int64_t appData,const OmxCodecBuffer & buffer)351 int32_t HdiCodec::HdiCallback::FillBufferDone(int64_t appData, const OmxCodecBuffer &buffer)
352 {
353 AVCODEC_LOGD("FillBufferDone");
354 if (hdiCodec_) {
355 hdiCodec_->OnFillBufferDone(buffer);
356 }
357 if (buffer.fd >= 0) {
358 close(buffer.fd);
359 }
360 return HDF_SUCCESS;
361 }
362 } // namespace Hdi
363 } // namespace Plugins
364 } // namespace Media
365 } // namespace OHOS
366