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