• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <vector>
17 #include <algorithm>
18 #include <thread>
19 #include <fcntl.h>
20 #include <string>
21 #include <sys/ioctl.h>
22 #include <sys/mman.h>
23 #include "codec_omx_ext.h"
24 #include "hcodec_list.h"
25 #include "hencoder.h"
26 #include "hdecoder.h"
27 #include "hitrace_meter.h"
28 #include "hcodec_log.h"
29 #include "hcodec_dfx.h"
30 #include "hcodec_utils.h"
31 
32 namespace OHOS::MediaAVCodec {
33 using namespace std;
34 using namespace CodecHDI;
35 using namespace Media;
36 
37 #define DMA_DEVICE_FILE "/dev/dma_reclaim"
38 #define DMA_BUF_RECLAIM_IOC_MAGIC 'd'
39 #define  DMA_BUF_RECLAIM_FD \
40     _IOWR(DMA_BUF_RECLAIM_IOC_MAGIC, 0x07, int)
41 #define  DMA_BUF_RESUME_FD \
42     _IOWR(DMA_BUF_RECLAIM_IOC_MAGIC, 0x08, int)
43 
44 struct DmaBufIoctlSwPara {
45     pid_t pid;
46     unsigned long ino;
47     unsigned int fd;
48 };
49 
50 class DmaSwaper {
51 public:
SwapOutDma(pid_t pid,int bufFd)52     int32_t SwapOutDma(pid_t pid, int bufFd)
53     {
54         if (reclaimDriverFd_ <= 0) {
55             return AVCS_ERR_UNKNOWN;
56         }
57         DmaBufIoctlSwPara param {
58             .pid = pid,
59             .ino = 0,
60             .fd = bufFd
61         };
62         return ioctl(reclaimDriverFd_, DMA_BUF_RECLAIM_FD, &param);
63     }
64 
SwapInDma(pid_t pid,int bufFd)65     int32_t SwapInDma(pid_t pid, int bufFd)
66     {
67         if (reclaimDriverFd_ <= 0) {
68             return AVCS_ERR_UNKNOWN;
69         }
70         DmaBufIoctlSwPara param {
71             .pid = pid,
72             .ino = 0,
73             .fd = bufFd
74         };
75         return ioctl(reclaimDriverFd_, DMA_BUF_RESUME_FD, &param);
76     }
77 
GetInstance()78     static DmaSwaper& GetInstance()
79     {
80         static DmaSwaper swaper;
81         return swaper;
82     }
83 private:
DmaSwaper()84     DmaSwaper()
85     {
86         if (reclaimDriverFd_ > 0) {
87             LOGE("already initialized!");
88             return;
89         }
90         reclaimDriverFd_ = open(DMA_DEVICE_FILE, O_RDWR | O_CLOEXEC | O_NONBLOCK);
91         if (reclaimDriverFd_ <= 0) {
92             LOGE("fail to open device");
93         }
94     }
95 
~DmaSwaper()96     ~DmaSwaper()
97     {
98         if (reclaimDriverFd_ <= 0) {
99             LOGE("invalid fd!");
100             return;
101         }
102         close(reclaimDriverFd_);
103         reclaimDriverFd_ = -1;
104     }
105 
106     DmaSwaper(const DmaSwaper &dmaSwaper) = delete;
107     const DmaSwaper &operator=(const DmaSwaper &dmaSwaper) = delete;
108     int reclaimDriverFd_ = -1;
109 };
110 
111 
NotifyMemoryRecycle()112 int32_t HCodec::NotifyMemoryRecycle()
113 {
114     SCOPED_TRACE();
115     FUNC_TRACKER();
116     return DoSyncCall(MsgWhat::FREEZE, nullptr);
117 }
118 
NotifyMemoryWriteBack()119 int32_t HCodec::NotifyMemoryWriteBack()
120 {
121     SCOPED_TRACE();
122     FUNC_TRACKER();
123     return DoSyncCall(MsgWhat::ACTIVE, nullptr);
124 }
125 
RecordBufferStatus(OMX_DIRTYPE portIndex,uint32_t bufferId,BufferOwner nextOwner)126 void HCodec::RecordBufferStatus(OMX_DIRTYPE portIndex, uint32_t bufferId, BufferOwner nextOwner)
127 {
128     auto bufferInfo = FindBufferInfoByID(portIndex, bufferId);
129     HLOGI("port[%d] buffer[%u] next owner[%s]", portIndex, bufferId, ToString(nextOwner));
130     if (bufferInfo != nullptr) {
131         bufferInfo->nextStepOwner = nextOwner;
132     }
133 }
134 
SwapOutBufferByPortIndex(OMX_DIRTYPE portIndex)135 int32_t HDecoder::SwapOutBufferByPortIndex(OMX_DIRTYPE portIndex)
136 {
137     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
138 
139     for (BufferInfo& info : pool) {
140         if (CanSwapOut(portIndex, info) == false) {
141             HLOGD("buf[%u] can't freeze owner[%d] swaped out[%d]", info.bufferId, info.owner, info.hasSwapedOut);
142             continue;
143         }
144         int fd = (portIndex == OMX_DirInput) ? info.avBuffer->memory_->GetFileDescriptor() :
145                  info.surfaceBuffer->GetFileDescriptor();
146         if (DmaSwaper::GetInstance().SwapOutDma(pid_, fd) != AVCS_ERR_OK) {
147             HLOGE("prot[%d] bufferId[%d], fd[%d] freeze failed", portIndex, info.bufferId, fd);
148             return ActiveBuffers();
149         }
150         info.hasSwapedOut = true;
151     }
152     return AVCS_ERR_OK;
153 }
154 
SwapInBufferByPortIndex(OMX_DIRTYPE portIndex)155 int32_t HDecoder::SwapInBufferByPortIndex(OMX_DIRTYPE portIndex)
156 {
157     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
158 
159     for (BufferInfo& info : pool) {
160         if (info.hasSwapedOut == true) {
161             int fd = (portIndex == OMX_DirInput) ? info.avBuffer->memory_->GetFileDescriptor() :
162                      info.surfaceBuffer->GetFileDescriptor();
163             if (DmaSwaper::GetInstance().SwapInDma(pid_, fd) != AVCS_ERR_OK) {
164                 HLOGE("buffer fd[%d] swap in error", fd);
165                 return AVCS_ERR_UNKNOWN;
166             }
167             info.hasSwapedOut = false;
168         }
169     }
170     return AVCS_ERR_OK;
171 }
172 
CanSwapOut(OMX_DIRTYPE portIndex,BufferInfo & info)173 bool HDecoder::CanSwapOut(OMX_DIRTYPE portIndex, BufferInfo& info)
174 {
175     if (portIndex == OMX_DirInput) {
176         if (info.owner == BufferOwner::OWNED_BY_USER || info.hasSwapedOut) {
177             return false;
178         }
179     }
180     if (portIndex == OMX_DirOutput) {
181         if (currSurface_.surface_) {
182             return !(info.owner == BufferOwner::OWNED_BY_SURFACE ||
183                      info.hasSwapedOut || info.surfaceBuffer == nullptr);
184         } else {
185             return !(info.owner == BufferOwner::OWNED_BY_SURFACE || info.surfaceBuffer == nullptr ||
186                      info.owner == BufferOwner::OWNED_BY_USER || info.hasSwapedOut);
187         }
188     }
189     return true;
190 }
191 
FreezeBuffers()192 int32_t HDecoder::FreezeBuffers()
193 {
194     if (isSecure_) {
195         return AVCS_ERR_OK;
196     }
197     OMX_CONFIG_BOOLEANTYPE param {};
198     InitOMXParam(param);
199     param.bEnabled = OMX_TRUE;
200     if (!SetParameter(OMX_IndexParamSwitchGround, param)) {
201         HLOGE("failed to set decoder to background");
202         return AVCS_ERR_UNKNOWN;
203     }
204     if (SwapOutBufferByPortIndex(OMX_DirInput) != AVCS_ERR_OK) {
205         return AVCS_ERR_UNKNOWN;
206     }
207     if (SwapOutBufferByPortIndex(OMX_DirOutput) != AVCS_ERR_OK) {
208         return AVCS_ERR_UNKNOWN;
209     }
210     HLOGI("freeze buffers success");
211     return AVCS_ERR_OK;
212 }
213 
ActiveBuffers()214 int32_t HDecoder::ActiveBuffers()
215 {
216     if (SwapInBufferByPortIndex(OMX_DirInput) != AVCS_ERR_OK) {
217         return AVCS_ERR_UNKNOWN;
218     }
219     if (SwapInBufferByPortIndex(OMX_DirOutput) != AVCS_ERR_OK) {
220         return AVCS_ERR_UNKNOWN;
221     }
222     OMX_CONFIG_BOOLEANTYPE param {};
223     InitOMXParam(param);
224     param.bEnabled = OMX_FALSE;
225     if (!SetParameter(OMX_IndexParamSwitchGround, param)) {
226         HLOGE("failed to set OMX_IndexParamSwitchGround");
227         return AVCS_ERR_UNKNOWN;
228     }
229     HLOGI("buffers active success");
230     return AVCS_ERR_OK;
231 }
232 
SubmitBuffersToNextOwner()233 void HDecoder::SubmitBuffersToNextOwner()
234 {
235     for (BufferInfo& info : inputBufferPool_) {
236         if (info.nextStepOwner == BufferOwner::OWNED_BY_OMX) {
237             HLOGI("bufferId = %d, input buffer next owner is omx", info.bufferId);
238             OnQueueInputBuffer(RESUBMIT_BUFFER, &info);
239         } else if (info.nextStepOwner == BufferOwner::OWNED_BY_USER) {
240             HLOGI("bufferId = %d, input buffer next owner is user", info.bufferId);
241             if (!inputPortEos_) {
242                 NotifyUserToFillThisInBuffer(info);
243             }
244         }
245         info.nextStepOwner = BufferOwner::OWNER_CNT;
246     }
247 
248     for (BufferInfo& info : outputBufferPool_) {
249         if (info.nextStepOwner == BufferOwner::OWNED_BY_OMX) {
250             NotifyOmxToFillThisOutBuffer(info);
251             HLOGI("bufferId = %d, output buffer next owner is omx", info.bufferId);
252         } else if (info.nextStepOwner == BufferOwner::OWNED_BY_USER) {
253             optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, info.bufferId);
254             if (!idx.has_value()) {
255                 return;
256             }
257             HLOGI("bufferId = %d, output buffer next owner is user", info.bufferId);
258             OnOMXFillBufferDone(RESUBMIT_BUFFER, info, idx.value());
259         } else if (info.nextStepOwner == BufferOwner::OWNED_BY_SURFACE) {
260             if (info.omxBuffer->filledLen != 0) {
261                 NotifySurfaceToRenderOutputBuffer(info);
262             }
263             SurfaceModeSubmitBuffer();
264         }
265         info.nextStepOwner = BufferOwner::OWNER_CNT;
266     }
267 }
268 
OnFreeze(const MsgInfo & info)269 void HCodec::RunningState::OnFreeze(const MsgInfo &info)
270 {
271     if (codec_->disableDmaSwap_) {
272         SLOGI("hcodec dma swap has been disabled!");
273         ReplyErrorCode(info.id, AVCS_ERR_OK);
274         return;
275     }
276     SLOGI("begin to freeze this codec");
277     int32_t errCode = codec_->FreezeBuffers();
278     if (errCode == AVCS_ERR_OK) {
279         codec_->ChangeStateTo(codec_->frozenState_);
280     }
281     ReplyErrorCode(info.id, errCode);
282 }
283 
284 /**************************** FrozenState Start ********************************/
OnMsgReceived(const MsgInfo & info)285 void HCodec::FrozenState::OnMsgReceived(const MsgInfo &info)
286 {
287     switch (info.type) {
288         case MsgWhat::FORCE_SHUTDOWN: {
289             codec_->ChangeStateTo(codec_->stoppingState_);
290             return;
291         }
292         case MsgWhat::SET_PARAMETERS:
293             OnSetParameters(info);
294             return;
295         case MsgWhat::QUEUE_INPUT_BUFFER: {
296             uint32_t bufferId = 0;
297             (void)info.param->GetValue(BUFFER_ID, bufferId);
298             codec_->OnQueueInputBuffer(info, inputMode_);
299             codec_->RecordBufferStatus(OMX_DirInput, bufferId, OWNED_BY_OMX);
300             return;
301         }
302         case MsgWhat::RENDER_OUTPUT_BUFFER: {
303             uint32_t bufferId = 0;
304             (void)info.param->GetValue(BUFFER_ID, bufferId);
305             codec_->OnRenderOutputBuffer(info, outputMode_);
306             codec_->RecordBufferStatus(OMX_DirOutput, bufferId, OWNED_BY_OMX);
307             return;
308         }
309         case MsgWhat::RELEASE_OUTPUT_BUFFER: {
310             uint32_t bufferId = 0;
311             (void)info.param->GetValue(BUFFER_ID, bufferId);
312             codec_->OnReleaseOutputBuffer(info, outputMode_);
313             codec_->RecordBufferStatus(OMX_DirOutput, bufferId, OWNED_BY_OMX);
314             return;
315         }
316         case MsgWhat::OMX_EMPTY_BUFFER_DONE: {
317             uint32_t bufferId = 0;
318             (void)info.param->GetValue(BUFFER_ID, bufferId);
319             codec_->OnOMXEmptyBufferDone(bufferId, inputMode_);
320             codec_->RecordBufferStatus(OMX_DirInput, bufferId, OWNED_BY_USER);
321             return;
322         }
323         case MsgWhat::OMX_FILL_BUFFER_DONE: {
324             OmxCodecBuffer omxBuffer;
325             (void)info.param->GetValue("omxBuffer", omxBuffer);
326             codec_->OnOMXFillBufferDone(omxBuffer, outputMode_);
327             codec_->RecordBufferStatus(OMX_DirOutput, omxBuffer.bufferId, OWNED_BY_OMX);
328             return;
329         }
330         case MsgWhat::ACTIVE: {
331             OnActive(info);
332             return;
333         }
334         case MsgWhat::GET_BUFFER_FROM_SURFACE: {
335             SLOGD("defer GET_BUFFER_FROM_SURFACE");
336             codec_->DeferMessage(info);
337             return;
338         }
339         case MsgWhat::CODEC_EVENT: {
340             codec_->DeferMessage(info);
341             SLOGI("deferring codec event");
342             return;
343         }
344         default: {
345             BaseState::OnMsgReceived(info);
346         }
347     }
348 }
349 
OnActive(const MsgInfo & info)350 void HCodec::FrozenState::OnActive(const MsgInfo &info)
351 {
352     SLOGI("begin to active this codec");
353     int32_t errCode = codec_->ActiveBuffers();
354     if (errCode == AVCS_ERR_OK) {
355         codec_->SubmitBuffersToNextOwner();
356         codec_->ChangeStateTo(codec_->runningState_);
357     }
358     ReplyErrorCode(info.id, errCode);
359 }
360 
OnShutDown(const MsgInfo & info)361 void HCodec::FrozenState::OnShutDown(const MsgInfo &info)
362 {
363     codec_->isShutDownFromRunning_ = true;
364     codec_->notifyCallerAfterShutdownComplete_ = true;
365     codec_->keepComponentAllocated_ = (info.type == MsgWhat::STOP);
366     codec_->isBufferCirculating_ = false;
367     codec_->PrintAllBufferInfo();
368     SLOGI("receive %s msg, begin to set omx to idle", info.type == MsgWhat::RELEASE ? "release" : "stop");
369     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
370     if (ret == HDF_SUCCESS) {
371         codec_->ReplyToSyncMsgLater(info);
372         codec_->ChangeStateTo(codec_->stoppingState_);
373     } else {
374         SLOGE("set omx to idle failed, ret=%d", ret);
375         ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
376     }
377 }
378 
379 /**************************** FrozenState End ********************************/
380 }