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