blob: 2fc6b6cf421b88a692b52314af0501dc538d3ec0 [file] [log] [blame]
fei.dengf7a0cd32023-08-29 09:36:37 +00001/*
2 * Copyright (C) 2021 Amlogic Corporation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <errno.h>
17#include <poll.h>
18#include "videotunnel_plugin.h"
19#include "videotunnel_impl.h"
20#include "Logger.h"
21#include "Times.h"
22#include "video_tunnel.h"
23#include "videotunnel.h"
24
25using namespace Tls;
26
27#define TAG "rlib:videotunnel_impl"
28
29#define UNDER_FLOW_EXPIRED_TIME_MS 83
30
31
fei.dengb9a1a572023-09-13 01:33:57 +000032VideoTunnelImpl::VideoTunnelImpl(VideoTunnelPlugin *plugin, int logcategory)
33 : mPlugin(plugin),
34 mLogCategory(logcategory)
fei.dengf7a0cd32023-08-29 09:36:37 +000035{
36 mFd = -1;
37 mInstanceId = 0;
38 mIsVideoTunnelConnected = false;
39 mQueueFrameCnt = 0;
40 mStarted = false;
41 mRequestStop = false;
42 mVideotunnelLib = NULL;
43 mFrameWidth = 0;
44 mFrameHeight = 0;
45 mUnderFlowDetect = false;
fei.dengb9a1a572023-09-13 01:33:57 +000046 mPoll = new Tls::Poll(true);
fei.dengf7a0cd32023-08-29 09:36:37 +000047}
48
49VideoTunnelImpl::~VideoTunnelImpl()
50{
fei.dengb9a1a572023-09-13 01:33:57 +000051 if (mPoll) {
52 delete mPoll;
53 mPoll = NULL;
54 }
fei.dengf7a0cd32023-08-29 09:36:37 +000055}
56
57bool VideoTunnelImpl::init()
58{
fei.dengb9a1a572023-09-13 01:33:57 +000059 mVideotunnelLib = videotunnelLoadLib(mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000060 if (!mVideotunnelLib) {
fei.dengb9a1a572023-09-13 01:33:57 +000061 ERROR(mLogCategory,"videotunnelLoadLib load symbol fail");
fei.dengf7a0cd32023-08-29 09:36:37 +000062 return false;
63 }
64 return true;
65}
66
67bool VideoTunnelImpl::release()
68{
69 if (mVideotunnelLib) {
fei.dengb9a1a572023-09-13 01:33:57 +000070 videotunnelUnloadLib(mLogCategory, mVideotunnelLib);
fei.dengf7a0cd32023-08-29 09:36:37 +000071 mVideotunnelLib = NULL;
72 }
73 return true;
74}
75
76bool VideoTunnelImpl::connect()
77{
78 int ret;
fei.dengb9a1a572023-09-13 01:33:57 +000079 DEBUG(mLogCategory,"in");
fei.dengf7a0cd32023-08-29 09:36:37 +000080 mRequestStop = false;
81 mSignalFirstFrameDiplayed = false;
82 if (mVideotunnelLib && mVideotunnelLib->vtOpen) {
83 mFd = mVideotunnelLib->vtOpen();
84 }
85 if (mFd > 0) {
86 //ret = meson_vt_alloc_id(mFd, &mInstanceId);
87 }
88 if (mFd > 0 && mInstanceId >= 0) {
89 if (mVideotunnelLib && mVideotunnelLib->vtConnect) {
90 ret = mVideotunnelLib->vtConnect(mFd, mInstanceId, VT_ROLE_PRODUCER);
91 }
92 mIsVideoTunnelConnected = true;
93 } else {
fei.dengb9a1a572023-09-13 01:33:57 +000094 ERROR(mLogCategory,"open videotunnel fail or alloc id fail");
fei.dengf7a0cd32023-08-29 09:36:37 +000095 return false;
96 }
fei.dengb9a1a572023-09-13 01:33:57 +000097 INFO(mLogCategory,"vt fd:%d, instance id:%d",mFd,mInstanceId);
98 DEBUG(mLogCategory,"out");
fei.dengf7a0cd32023-08-29 09:36:37 +000099 return true;
100}
101
102bool VideoTunnelImpl::disconnect()
103{
104 mRequestStop = true;
fei.dengb9a1a572023-09-13 01:33:57 +0000105 DEBUG(mLogCategory,"in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000106 if (isRunning()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000107 if (mPoll) {
108 mPoll->setFlushing(true);
109 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000110 requestExitAndWait();
111 mStarted = false;
112 }
113
114 if (mFd > 0) {
115 if (mIsVideoTunnelConnected) {
fei.dengb9a1a572023-09-13 01:33:57 +0000116 INFO(mLogCategory,"instance id:%d",mInstanceId);
fei.dengf7a0cd32023-08-29 09:36:37 +0000117 if (mVideotunnelLib && mVideotunnelLib->vtDisconnect) {
118 mVideotunnelLib->vtDisconnect(mFd, mInstanceId, VT_ROLE_PRODUCER);
119 }
120 mIsVideoTunnelConnected = false;
121 }
122 if (mInstanceId >= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000123 INFO(mLogCategory,"free instance id:%d",mInstanceId);
fei.dengf7a0cd32023-08-29 09:36:37 +0000124 //meson_vt_free_id(mFd, mInstanceId);
125 }
fei.dengb9a1a572023-09-13 01:33:57 +0000126 INFO(mLogCategory,"close vt fd:%d",mFd);
fei.dengf7a0cd32023-08-29 09:36:37 +0000127 if (mVideotunnelLib && mVideotunnelLib->vtClose) {
128 mVideotunnelLib->vtClose(mFd);
129 }
130 mFd = -1;
131 }
132
133 //flush all buffer those do not displayed
fei.dengb9a1a572023-09-13 01:33:57 +0000134 DEBUG(mLogCategory,"release all posted to videotunnel buffers");
135 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000136 for (auto item = mQueueRenderBufferMap.begin(); item != mQueueRenderBufferMap.end(); ) {
137 RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
138 mQueueRenderBufferMap.erase(item++);
139 mPlugin->handleFrameDropped(renderbuffer);
140 mPlugin->handleBufferRelease(renderbuffer);
141 }
fei.dengb9a1a572023-09-13 01:33:57 +0000142 DEBUG(mLogCategory,"out");
fei.dengf7a0cd32023-08-29 09:36:37 +0000143 return true;
144}
145
146bool VideoTunnelImpl::displayFrame(RenderBuffer *buf, int64_t displayTime)
147{
148 int ret;
149 if (mStarted == false) {
fei.dengb9a1a572023-09-13 01:33:57 +0000150 DEBUG(mLogCategory,"to run VideoTunnelImpl");
fei.dengf7a0cd32023-08-29 09:36:37 +0000151 run("VideoTunnelImpl");
152 mStarted = true;
153 mSignalFirstFrameDiplayed = true;
154 }
155
156 int fd0 = buf->dma.fd[0];
157 //leng.fang suggest fence id set -1
158 if (mVideotunnelLib && mVideotunnelLib->vtQueueBuffer) {
159 ret = mVideotunnelLib->vtQueueBuffer(mFd, mInstanceId, fd0, -1 /*fence_fd*/, displayTime);
160 if (mUnderFlowDetect) {
161 mUnderFlowDetect = false;
162 }
163 }
164
fei.dengb9a1a572023-09-13 01:33:57 +0000165 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000166 std::pair<int, RenderBuffer *> item(fd0, buf);
167 mQueueRenderBufferMap.insert(item);
168 ++mQueueFrameCnt;
fei.dengb9a1a572023-09-13 01:33:57 +0000169 TRACE(mLogCategory,"***fd:%d,w:%d,h:%d,displaytime:%lld,commitCnt:%d",buf->dma.fd[0],buf->dma.width,buf->dma.height,displayTime,mQueueFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000170 mPlugin->handleFrameDisplayed(buf);
171 mLastDisplayTime = Tls::Times::getSystemTimeMs();
172 return true;
173}
174
175void VideoTunnelImpl::flush()
176{
fei.dengb9a1a572023-09-13 01:33:57 +0000177 DEBUG(mLogCategory,"flush");
178 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000179 if (mVideotunnelLib && mVideotunnelLib->vtCancelBuffer) {
180 mVideotunnelLib->vtCancelBuffer(mFd, mInstanceId);
181 }
182 for (auto item = mQueueRenderBufferMap.begin(); item != mQueueRenderBufferMap.end(); ) {
183 RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
184 mQueueRenderBufferMap.erase(item++);
185 mPlugin->handleFrameDropped(renderbuffer);
186 mPlugin->handleBufferRelease(renderbuffer);
187 }
188 mQueueFrameCnt = 0;
fei.dengb9a1a572023-09-13 01:33:57 +0000189 DEBUG(mLogCategory,"after flush,commitCnt:%d",mQueueFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000190}
191
192void VideoTunnelImpl::setFrameSize(int width, int height)
193{
194 mFrameWidth = width;
195 mFrameHeight = height;
fei.dengb9a1a572023-09-13 01:33:57 +0000196 DEBUG(mLogCategory, "set frame size, width:%d, height:%d",mFrameWidth,mFrameHeight);
fei.dengf7a0cd32023-08-29 09:36:37 +0000197}
198
199void VideoTunnelImpl::setVideotunnelId(int id)
200{
201 mInstanceId = id;
202}
203
204void VideoTunnelImpl::waitFence(int fence) {
205 if (fence > 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000206 mPoll->addFd(fence);
207 mPoll->setFdReadable(fence, true);
fei.dengf7a0cd32023-08-29 09:36:37 +0000208
209 for ( ; ; ) {
fei.dengb9a1a572023-09-13 01:33:57 +0000210 int rc = mPoll->wait(3000); //3 sec
fei.dengf7a0cd32023-08-29 09:36:37 +0000211 if ((rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) {
212 continue;
213 } else if (rc <= 0) {
214 if (rc == 0) errno = ETIME;
215 }
216 break;
217 }
fei.dengb9a1a572023-09-13 01:33:57 +0000218 mPoll->removeFd(fence);
fei.dengf7a0cd32023-08-29 09:36:37 +0000219 close(fence);
220 fence = -1;
221 }
222}
223
224void VideoTunnelImpl::readyToRun()
225{
226 struct vt_rect rect;
227
228 if (mFrameWidth > 0 && mFrameHeight > 0) {
229 rect.left = 0;
230 rect.top = 0;
231 rect.right = mFrameWidth;
232 rect.bottom = mFrameHeight;
233 if (mVideotunnelLib && mVideotunnelLib->vtSetSourceCrop) {
234 mVideotunnelLib->vtSetSourceCrop(mFd, mInstanceId, rect);
235 }
236 }
237}
238
239bool VideoTunnelImpl::threadLoop()
240{
241 int ret;
242 int bufferId = 0;
243 int fenceId;
244 RenderBuffer *buffer = NULL;
245
246 if (mRequestStop) {
fei.dengb9a1a572023-09-13 01:33:57 +0000247 DEBUG(mLogCategory,"request stop");
fei.dengf7a0cd32023-08-29 09:36:37 +0000248 return false;
249 }
250 //if last frame expired,and not send frame to compositor for under flow expired time
251 //we need to send under flow msg
252 if (mQueueFrameCnt < 1 &&
253 Tls::Times::getSystemTimeMs() - mLastDisplayTime > UNDER_FLOW_EXPIRED_TIME_MS &&
254 !mUnderFlowDetect) {
255 mUnderFlowDetect = true;
256 mPlugin->handleMsgNotify(MSG_UNDER_FLOW, NULL);
257 }
258
259 if (mVideotunnelLib && mVideotunnelLib->vtDequeueBuffer) {
260 ret = mVideotunnelLib->vtDequeueBuffer(mFd, mInstanceId, &bufferId, &fenceId);
261 }
262
263 if (ret != 0) {
264 if (mRequestStop) {
fei.dengb9a1a572023-09-13 01:33:57 +0000265 DEBUG(mLogCategory,"request stop");
fei.dengf7a0cd32023-08-29 09:36:37 +0000266 return false;
267 }
268 return true;
269 }
270 if (mRequestStop) {
fei.dengb9a1a572023-09-13 01:33:57 +0000271 DEBUG(mLogCategory,"request stop");
fei.dengf7a0cd32023-08-29 09:36:37 +0000272 return false;
273 }
274
275 //send uvm fd to driver after getted fence
276 waitFence(fenceId);
277
278 {
fei.dengb9a1a572023-09-13 01:33:57 +0000279 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000280 auto item = mQueueRenderBufferMap.find(bufferId);
281 if (item == mQueueRenderBufferMap.end()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000282 ERROR(mLogCategory,"Not found in mQueueRenderBufferMap bufferId:%d",bufferId);
fei.dengf7a0cd32023-08-29 09:36:37 +0000283 return true;
284 }
285 // try locking when removing item from mQueueRenderBufferMap
286 buffer = (RenderBuffer*) item->second;
287 mQueueRenderBufferMap.erase(bufferId);
288 --mQueueFrameCnt;
fei.dengb9a1a572023-09-13 01:33:57 +0000289 TRACE(mLogCategory,"***dq buffer fd:%d,commitCnt:%d",bufferId,mQueueFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000290 }
291 //send first frame displayed msg
292 if (mSignalFirstFrameDiplayed) {
293 mSignalFirstFrameDiplayed = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000294 INFO(mLogCategory,"send first frame displayed msg");
fei.dengf7a0cd32023-08-29 09:36:37 +0000295 mPlugin->handleMsgNotify(MSG_FIRST_FRAME,(void*)&buffer->pts);
296 }
297 mPlugin->handleBufferRelease(buffer);
298 return true;
299}