blob: d8c0a7051bc73e86396a486945dff74ad2b68f3c [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 */
fei.dengdd910ef2024-06-07 10:25:30 +080016#include <fcntl.h>
17#include <string.h>
fei.dengf7a0cd32023-08-29 09:36:37 +000018#include "wayland_plugin.h"
19#include "wayland_display.h"
20#include "Logger.h"
21#include "Times.h"
fei.dengb9a1a572023-09-13 01:33:57 +000022#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000023
24#define TAG "rlib:wayland_plugin"
25
le.handb98beb2024-09-09 08:39:09 +000026#define UNDER_FLOW_EXPIRED_TIME_MS 83
27
fei.dengb9a1a572023-09-13 01:33:57 +000028WaylandPlugin::WaylandPlugin(int logCatgory)
29 : mRenderLock("renderlock"),
30 mLogCategory(logCatgory)
fei.dengf7a0cd32023-08-29 09:36:37 +000031{
fei.dengb9a1a572023-09-13 01:33:57 +000032 mDisplay = new WaylandDisplay(this, logCatgory);
fei.dengf7a0cd32023-08-29 09:36:37 +000033 mQueue = new Tls::Queue();
34 mPaused = false;
35 mImmediatelyOutput = false;
le.handb98beb2024-09-09 08:39:09 +000036 mUnderFlowDetect = false;
fei.dengf7a0cd32023-08-29 09:36:37 +000037}
38
39WaylandPlugin::~WaylandPlugin()
40{
41 if (mDisplay) {
42 delete mDisplay;
43 }
44 if (mQueue) {
45 mQueue->flush();
46 delete mQueue;
47 mQueue = NULL;
48 }
fei.dengb9a1a572023-09-13 01:33:57 +000049 TRACE(mLogCategory,"desconstruct");
fei.dengf7a0cd32023-08-29 09:36:37 +000050}
51
52void WaylandPlugin::init()
53{
fei.dengb9a1a572023-09-13 01:33:57 +000054 INFO(mLogCategory,"\n--------------------------------\n"
fei.dengf7a0cd32023-08-29 09:36:37 +000055 "plugin : weston\n"
56 "ARCH : %s\n"
57 "branch name : %s\n"
58 "git version : %s\n"
59 "change id : %s \n"
60 "ID : %s \n"
61 "last changed: %s\n"
62 "build-time : %s\n"
63 "build-name : %s\n"
64 "--------------------------------\n",
65#if defined(__aarch64__)
66 "arm64",
67#else
68 "arm",
69#endif
70 BRANCH_NAME,
71 GIT_VERSION,
72 COMMIT_CHANGEID,
73 COMMIT_PD,
74 LAST_CHANGED,
75 BUILD_TIME,
76 BUILD_NAME
77 );
78}
79
80void WaylandPlugin::release()
81{
82}
83
84void WaylandPlugin::setCallback(void *userData, PluginCallback *callback)
85{
86 mUserData = userData;
87 mCallback = callback;
88}
89
90int WaylandPlugin::openDisplay()
91{
92 int ret;
93
fei.dengb9a1a572023-09-13 01:33:57 +000094 Tls::Mutex::Autolock _l(mRenderLock);
95 DEBUG(mLogCategory,"openDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +000096 ret = mDisplay->openDisplay();
fei.dengb9a1a572023-09-13 01:33:57 +000097 if (ret != NO_ERROR) {
98 ERROR(mLogCategory,"Error open display");
99 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +0000100 }
fei.dengb9a1a572023-09-13 01:33:57 +0000101 DEBUG(mLogCategory,"openDisplay end");
102 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +0000103}
104
105int WaylandPlugin::openWindow()
106{
fei.dengb9a1a572023-09-13 01:33:57 +0000107 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000108 /* if weston can't support pts feature,
109 * we should create a post buffer thread to
110 * send buffer by mono time
111 */
fei.deng640c3c92024-04-12 08:31:19 +0000112 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
113 if (!amlconfig->enableSetPts) {
fei.dengdd910ef2024-06-07 10:25:30 +0800114 DEBUG(mLogCategory,"run frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000115 setThreadPriority(50);
116 run("waylandPostThread");
117 }
fei.dengb9a1a572023-09-13 01:33:57 +0000118 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000119}
120
121int WaylandPlugin::prepareFrame(RenderBuffer *buffer)
122{
123 mDisplay->prepareFrameBuffer(buffer);
fei.dengb9a1a572023-09-13 01:33:57 +0000124 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000125}
126
127int WaylandPlugin::displayFrame(RenderBuffer *buffer, int64_t displayTime)
128{
129 /* if weston can't support pts feature,
130 * push buffer to queue, the buffer will send to
131 * weston in post thread
132 */
fei.deng640c3c92024-04-12 08:31:19 +0000133 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
134 if (!amlconfig->enableSetPts) {
le.handb98beb2024-09-09 08:39:09 +0000135 if (mUnderFlowDetect) {
136 mUnderFlowDetect = false;
137 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000138 buffer->time = displayTime;
139 mQueue->push(buffer);
fei.dengdd910ef2024-06-07 10:25:30 +0800140 DEBUG(mLogCategory,"queue size:%d,pts:%lld us",mQueue->getCnt(),buffer->pts/1000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000141 } else {
fei.dengae8c90a2024-06-27 13:39:53 +0800142 buffer->time = displayTime;
fei.dengf7a0cd32023-08-29 09:36:37 +0000143 mDisplay->displayFrameBuffer(buffer, displayTime);
144 }
fei.dengb9a1a572023-09-13 01:33:57 +0000145 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000146}
147
148void WaylandPlugin::queueFlushCallback(void *userdata,void *data)
149{
150 WaylandPlugin* plugin = static_cast<WaylandPlugin *>(userdata);
151 plugin->handleFrameDropped((RenderBuffer *)data);
152 plugin->handleBufferRelease((RenderBuffer *)data);
153}
154
155int WaylandPlugin::flush()
156{
157 RenderBuffer *entity;
158 mQueue->flushAndCallback(this, WaylandPlugin::queueFlushCallback);
159 mDisplay->flushBuffers();
fei.dengb9a1a572023-09-13 01:33:57 +0000160 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000161}
162
163int WaylandPlugin::pause()
164{
fei.deng19b48692024-08-13 14:17:55 +0800165 /*pause and resume can cause frame dropped.
166 those frames ready to send to weston in queue will drop
167 when resume*/
168 //mPaused = true;
fei.deng649b0e22024-09-03 18:57:13 +0800169 mDisplay->pause();
fei.dengb9a1a572023-09-13 01:33:57 +0000170 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000171}
172int WaylandPlugin::resume()
173{
fei.deng19b48692024-08-13 14:17:55 +0800174 //mPaused = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000175 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000176}
177
178int WaylandPlugin::closeDisplay()
179{
180 RenderBuffer *entity;
fei.dengb9a1a572023-09-13 01:33:57 +0000181 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000182 mDisplay->closeDisplay();
fei.dengf7a0cd32023-08-29 09:36:37 +0000183
fei.dengb9a1a572023-09-13 01:33:57 +0000184 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000185}
186
187int WaylandPlugin::closeWindow()
188{
fei.dengb9a1a572023-09-13 01:33:57 +0000189 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000190 if (isRunning()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000191 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000192 requestExitAndWait();
193 }
fei.dengdd910ef2024-06-07 10:25:30 +0800194 mQueue->flushAndCallback(this, WaylandPlugin::queueFlushCallback);
fei.dengb9a1a572023-09-13 01:33:57 +0000195 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000196}
197
198
199int WaylandPlugin::getValue(PluginKey key, void *value)
200{
201 switch (key) {
202 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
203 *(int *)(value) = mDisplay->getDisplayOutput();
fei.dengb9a1a572023-09-13 01:33:57 +0000204 TRACE(mLogCategory,"get select display output:%d",*(int *)value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000205 } break;
fei.dengf1f5fc32023-12-06 06:22:20 +0000206 case PLUGIN_KEY_CURRENT_OUTPUT: {
207 *(int *)(value) = mDisplay->getCurrentOutputCrtcIndex();
208 //DEBUG(mLogCategory,"get current crtc output index:%d",*(int *)value);
209 } break;
fei.deng1c94a342024-08-05 19:33:28 +0800210 case PLUGIN_KEY_ZORDER: {
211 *(int *)(value) = mDisplay->getVideoPlaneZorder();
212 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000213 }
fei.dengb9a1a572023-09-13 01:33:57 +0000214 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000215}
216
217int WaylandPlugin::setValue(PluginKey key, void *value)
218{
219 switch (key) {
220 case PLUGIN_KEY_WINDOW_SIZE: {
221 RenderRect* rect = static_cast<RenderRect*>(value);
222 if (mDisplay) {
223 mDisplay->setWindowSize(rect->x, rect->y, rect->w, rect->h);
224 }
225 } break;
226 case PLUGIN_KEY_FRAME_SIZE: {
227 RenderFrameSize * frameSize = static_cast<RenderFrameSize * >(value);
228 if (mDisplay) {
229 mDisplay->setFrameSize(frameSize->width, frameSize->height);
230 }
231 } break;
232 case PLUGIN_KEY_VIDEO_FORMAT: {
233 int videoFormat = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000234 DEBUG(mLogCategory,"Set video format :%d",videoFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000235 mDisplay->setVideoBufferFormat((RenderVideoFormat)videoFormat);
236 } break;
237 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
238 int outputIndex = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000239 DEBUG(mLogCategory,"Set select display output :%d",outputIndex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000240 mDisplay->setDisplayOutput(outputIndex);
241 } break;
242 case PLUGIN_KEY_VIDEO_PIP: {
243 int pip = *(int *) (value);
244 pip = pip > 0? 1: 0;
245 mDisplay->setPip(pip);
246 } break;
247 case PLUGIN_KEY_IMMEDIATELY_OUTPUT: {
fei.deng234e5f62024-09-30 15:27:48 +0800248 int enableImmediately = (*(int *)(value));
249 mImmediatelyOutput = enableImmediately > 0? true: false;
250 mDisplay->setImmediatelyOutput(enableImmediately);
fei.dengb9a1a572023-09-13 01:33:57 +0000251 DEBUG(mLogCategory, "Set immediately output:%d",mImmediatelyOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +0000252 } break;
fei.deng640c3c92024-04-12 08:31:19 +0000253 case PLUGIN_KEY_KEEP_LAST_FRAME: {
254 int keep = *(int *) (value);
255 DEBUG(mLogCategory, "Set keep last frame:%d",keep);
256 mDisplay->setKeepLastFrame(keep);
257 } break;
le.hane8c8fdd2024-09-19 09:28:50 +0000258 case PLUGIN_KEY_KEEP_LAST_FRAME_ON_FLUSH: {
259 int keepOnFlush = *(int *) (value);
260 DEBUG(mLogCategory, "Set keep last frame on flush:%d",keepOnFlush);
261 mDisplay->setKeepLastFrameOnFlush(keepOnFlush);
262 } break;
fei.denga4abbd52024-07-11 19:17:50 +0800263 case PLUGIN_KEY_FORCE_ASPECT_RATIO: {
264 int forceAspectRatio = *(int *)(value);
265 DEBUG(mLogCategory, "force aspect ratio:%d, TODO ",forceAspectRatio);
266 } break;
267 case PLUGIN_KEY_PIXEL_ASPECT_RATIO: {
268 double ratio = *(double *)(value);
269 INFO(mLogCategory,"pixel aspect ratio :%f",ratio);
270 mDisplay->setPixelAspectRatio((double)ratio);
271 } break;
fei.deng6c425232024-07-19 16:15:31 +0800272 case PLUGIN_KEY_VIDEO_FRAME_RATE: {
273 RenderFraction * fraction = static_cast<RenderFraction*>(value);
274 INFO(mLogCategory,"frame rate,num:%d,denom:%d",fraction->num,fraction->denom);
275 mDisplay->setFrameRate(fraction->num, fraction->denom);
276 } break;
fei.deng1c94a342024-08-05 19:33:28 +0800277 case PLUGIN_KEY_ZORDER: {
278 int zorder = *(int *)(value);
279 INFO(mLogCategory,"set video plane zorder:%d",zorder);
280 mDisplay->setVideoPlaneZorder(zorder);
281 } break;
fei.deng96aa7f72024-09-29 15:46:52 +0800282 case PLUGIN_KEY_ROTATE_VIDEO: {
283 int degree = *(int *)(value);
284 INFO(mLogCategory,"set rotate video to:%d",degree);
285 mDisplay->setRotateVideo(degree);
286 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000287 }
288 return 0;
289}
290
291void WaylandPlugin::handleBufferRelease(RenderBuffer *buffer)
292{
293 if (mCallback) {
294 mCallback->doBufferReleaseCallback(mUserData, (void *)buffer);
295 }
296}
297
298void WaylandPlugin::handleFrameDisplayed(RenderBuffer *buffer)
299{
300 if (mCallback) {
301 mCallback->doBufferDisplayedCallback(mUserData, (void *)buffer);
302 }
303}
304
305void WaylandPlugin::handleFrameDropped(RenderBuffer *buffer)
306{
307 if (mCallback) {
308 mCallback->doBufferDropedCallback(mUserData, (void *)buffer);
309 }
310}
311
fei.deng3287c082024-04-23 09:29:22 +0000312void WaylandPlugin::handleMsgNotify(int type, void *detail)
313{
314 if (mCallback) {
315 mCallback->doMsgCallback(mUserData, type, detail);
316 }
317}
318
fei.dengf7a0cd32023-08-29 09:36:37 +0000319void WaylandPlugin::readyToRun()
320{
321}
322
323bool WaylandPlugin::threadLoop()
324{
325 RenderBuffer *curFrameEntity = NULL;
326 RenderBuffer *expiredFrameEntity = NULL;
327 int64_t nowMonotime = Tls::Times::getSystemTimeUs();
328
329 //if queue is empty or paused, loop next
330 if (mQueue->isEmpty() || mPaused) {
le.handb98beb2024-09-09 08:39:09 +0000331 if (mQueue->isEmpty() &&
332 Tls::Times::getSystemTimeMs() - mLastDisplayTime > UNDER_FLOW_EXPIRED_TIME_MS &&
333 !mUnderFlowDetect) {
334 mUnderFlowDetect = true;
335 handleMsgNotify(MSG_UNDER_FLOW, NULL);
336 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000337 goto tag_next;
338 }
339
340 //if weston obtains a buffer rendering,we can't send buffer to weston
341 if (mDisplay->isRedrawingPending()) {
342 goto tag_next;
343 }
344
345 //we output video frame asap
346 if (mImmediatelyOutput) {
347 //pop the peeked frame
348 mQueue->pop((void **)&expiredFrameEntity);
349 goto tag_post;
350 }
351
352 while (mQueue->peek((void **)&curFrameEntity, 0) == Q_OK)
353 {
354 //no frame expired,loop next
355 if (nowMonotime < curFrameEntity->time) {
356 break;
357 }
358
359 //pop the peeked frame
360 mQueue->pop((void **)&curFrameEntity);
361
362 //drop last expired frame,got a new expired frame
363 if (expiredFrameEntity) {
fei.dengb9a1a572023-09-13 01:33:57 +0000364 WARNING(mLogCategory,"drop,now:%lld,display:%lld(pts:%lld ms),n-d:%lld ms",
fei.dengf7a0cd32023-08-29 09:36:37 +0000365 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
366 (nowMonotime - expiredFrameEntity->time)/1000);
367 handleFrameDropped(expiredFrameEntity);
368 handleBufferRelease(expiredFrameEntity);
369 expiredFrameEntity = NULL;
370 }
371
372 expiredFrameEntity = curFrameEntity;
373 }
374
375tag_post:
376 if (!expiredFrameEntity) {
377 //TRACE(mLogCategory,"no frame expire");
378 goto tag_next;
379 }
380
381 if (mDisplay) {
le.handb98beb2024-09-09 08:39:09 +0000382 mLastDisplayTime = Tls::Times::getSystemTimeMs();
fei.dengdd910ef2024-06-07 10:25:30 +0800383 TRACE(mLogCategory,"post,now:%lld,display:%lld(pts:%lld ms),n-d::%lld ms, size:%d",
fei.dengf7a0cd32023-08-29 09:36:37 +0000384 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
fei.dengdd910ef2024-06-07 10:25:30 +0800385 (nowMonotime - expiredFrameEntity->time)/1000,mQueue->getCnt());
fei.dengf7a0cd32023-08-29 09:36:37 +0000386 mDisplay->displayFrameBuffer(expiredFrameEntity, expiredFrameEntity->time);
387 }
388
389tag_next:
390 usleep(4*1000);
391 return true;
392}
393
394void *makePluginInstance(int id)
395{
fei.dengdd910ef2024-06-07 10:25:30 +0800396 int fd= -1;
397 const char *levelPath = "/run/rlib_plugin_level";
398
fei.dengb9a1a572023-09-13 01:33:57 +0000399 int category =Logger_init(id);
fei.dengc4677852023-10-09 07:21:04 +0000400 char *env = getenv("VIDEO_RENDER_PLUGIN_LOG_LEVEL");
fei.dengf7a0cd32023-08-29 09:36:37 +0000401 if (env) {
402 int level = atoi(env);
403 Logger_set_level(level);
fei.dengdd910ef2024-06-07 10:25:30 +0800404 INFO(category,"env set VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",level);
fei.dengf7a0cd32023-08-29 09:36:37 +0000405 }
fei.dengdd910ef2024-06-07 10:25:30 +0800406
407 //get log level from /run/rlib_plugin_level
408 fd= open(levelPath, O_RDONLY|O_CLOEXEC);
409 if ( fd >= 0 )
410 {
411 char valstr[64];
412 uint32_t val= 0;
413 int nRead;
414
415 memset(valstr, 0, sizeof(valstr));
416 nRead = read(fd, valstr, sizeof(valstr) - 1);
417 valstr[strlen(valstr)] = '\0';
418 if (sscanf(valstr, "%u", &val) > 0)
419 {
420 Logger_set_level(val);
421 INFO(category,"set VIDEO_RENDER_LOG_LEVEL=%d",val);
422 }
423 close(fd);
424 fd = -1;
425 }
fei.dengdd910ef2024-06-07 10:25:30 +0800426
fei.dengb9a1a572023-09-13 01:33:57 +0000427 WaylandPlugin *pluginInstance = new WaylandPlugin(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000428 return static_cast<void *>(pluginInstance);
429}
430
431void destroyPluginInstance(void * plugin)
432{
fei.dengb9a1a572023-09-13 01:33:57 +0000433 int category;
434
fei.dengf7a0cd32023-08-29 09:36:37 +0000435 WaylandPlugin *pluginInstance = static_cast<WaylandPlugin *>(plugin);
fei.dengb9a1a572023-09-13 01:33:57 +0000436 category = pluginInstance->getLogCategory();
fei.dengf7a0cd32023-08-29 09:36:37 +0000437 delete pluginInstance;
fei.dengb9a1a572023-09-13 01:33:57 +0000438 Logger_exit(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000439}