blob: 1c6fae98a86bb6dd1ce37afa067f2e340d0a1f60 [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
fei.dengb9a1a572023-09-13 01:33:57 +000026WaylandPlugin::WaylandPlugin(int logCatgory)
27 : mRenderLock("renderlock"),
28 mLogCategory(logCatgory)
fei.dengf7a0cd32023-08-29 09:36:37 +000029{
fei.dengb9a1a572023-09-13 01:33:57 +000030 mDisplay = new WaylandDisplay(this, logCatgory);
fei.dengf7a0cd32023-08-29 09:36:37 +000031 mQueue = new Tls::Queue();
32 mPaused = false;
33 mImmediatelyOutput = false;
34}
35
36WaylandPlugin::~WaylandPlugin()
37{
38 if (mDisplay) {
39 delete mDisplay;
40 }
41 if (mQueue) {
42 mQueue->flush();
43 delete mQueue;
44 mQueue = NULL;
45 }
fei.dengb9a1a572023-09-13 01:33:57 +000046 TRACE(mLogCategory,"desconstruct");
fei.dengf7a0cd32023-08-29 09:36:37 +000047}
48
49void WaylandPlugin::init()
50{
fei.dengb9a1a572023-09-13 01:33:57 +000051 INFO(mLogCategory,"\n--------------------------------\n"
fei.dengf7a0cd32023-08-29 09:36:37 +000052 "plugin : weston\n"
53 "ARCH : %s\n"
54 "branch name : %s\n"
55 "git version : %s\n"
56 "change id : %s \n"
57 "ID : %s \n"
58 "last changed: %s\n"
59 "build-time : %s\n"
60 "build-name : %s\n"
61 "--------------------------------\n",
62#if defined(__aarch64__)
63 "arm64",
64#else
65 "arm",
66#endif
67 BRANCH_NAME,
68 GIT_VERSION,
69 COMMIT_CHANGEID,
70 COMMIT_PD,
71 LAST_CHANGED,
72 BUILD_TIME,
73 BUILD_NAME
74 );
75}
76
77void WaylandPlugin::release()
78{
79}
80
81void WaylandPlugin::setCallback(void *userData, PluginCallback *callback)
82{
83 mUserData = userData;
84 mCallback = callback;
85}
86
87int WaylandPlugin::openDisplay()
88{
89 int ret;
90
fei.dengb9a1a572023-09-13 01:33:57 +000091 Tls::Mutex::Autolock _l(mRenderLock);
92 DEBUG(mLogCategory,"openDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +000093 ret = mDisplay->openDisplay();
fei.dengb9a1a572023-09-13 01:33:57 +000094 if (ret != NO_ERROR) {
95 ERROR(mLogCategory,"Error open display");
96 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +000097 }
fei.dengb9a1a572023-09-13 01:33:57 +000098 DEBUG(mLogCategory,"openDisplay end");
99 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +0000100}
101
102int WaylandPlugin::openWindow()
103{
fei.dengb9a1a572023-09-13 01:33:57 +0000104 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000105 /* if weston can't support pts feature,
106 * we should create a post buffer thread to
107 * send buffer by mono time
108 */
fei.deng640c3c92024-04-12 08:31:19 +0000109 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
110 if (!amlconfig->enableSetPts) {
fei.dengdd910ef2024-06-07 10:25:30 +0800111 DEBUG(mLogCategory,"run frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000112 setThreadPriority(50);
113 run("waylandPostThread");
114 }
fei.dengb9a1a572023-09-13 01:33:57 +0000115 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000116}
117
118int WaylandPlugin::prepareFrame(RenderBuffer *buffer)
119{
120 mDisplay->prepareFrameBuffer(buffer);
fei.dengb9a1a572023-09-13 01:33:57 +0000121 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000122}
123
124int WaylandPlugin::displayFrame(RenderBuffer *buffer, int64_t displayTime)
125{
126 /* if weston can't support pts feature,
127 * push buffer to queue, the buffer will send to
128 * weston in post thread
129 */
fei.deng640c3c92024-04-12 08:31:19 +0000130 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
131 if (!amlconfig->enableSetPts) {
fei.dengf7a0cd32023-08-29 09:36:37 +0000132 buffer->time = displayTime;
133 mQueue->push(buffer);
fei.dengdd910ef2024-06-07 10:25:30 +0800134 DEBUG(mLogCategory,"queue size:%d,pts:%lld us",mQueue->getCnt(),buffer->pts/1000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000135 } else {
fei.dengae8c90a2024-06-27 13:39:53 +0800136 buffer->time = displayTime;
fei.dengf7a0cd32023-08-29 09:36:37 +0000137 mDisplay->displayFrameBuffer(buffer, displayTime);
138 }
fei.dengb9a1a572023-09-13 01:33:57 +0000139 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000140}
141
142void WaylandPlugin::queueFlushCallback(void *userdata,void *data)
143{
144 WaylandPlugin* plugin = static_cast<WaylandPlugin *>(userdata);
145 plugin->handleFrameDropped((RenderBuffer *)data);
146 plugin->handleBufferRelease((RenderBuffer *)data);
147}
148
149int WaylandPlugin::flush()
150{
151 RenderBuffer *entity;
152 mQueue->flushAndCallback(this, WaylandPlugin::queueFlushCallback);
153 mDisplay->flushBuffers();
fei.dengb9a1a572023-09-13 01:33:57 +0000154 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000155}
156
157int WaylandPlugin::pause()
158{
fei.deng19b48692024-08-13 14:17:55 +0800159 /*pause and resume can cause frame dropped.
160 those frames ready to send to weston in queue will drop
161 when resume*/
162 //mPaused = true;
fei.deng649b0e22024-09-03 18:57:13 +0800163 mDisplay->pause();
fei.dengb9a1a572023-09-13 01:33:57 +0000164 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000165}
166int WaylandPlugin::resume()
167{
fei.deng19b48692024-08-13 14:17:55 +0800168 //mPaused = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000169 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000170}
171
172int WaylandPlugin::closeDisplay()
173{
174 RenderBuffer *entity;
fei.dengb9a1a572023-09-13 01:33:57 +0000175 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000176 mDisplay->closeDisplay();
fei.dengf7a0cd32023-08-29 09:36:37 +0000177
fei.dengb9a1a572023-09-13 01:33:57 +0000178 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000179}
180
181int WaylandPlugin::closeWindow()
182{
fei.dengb9a1a572023-09-13 01:33:57 +0000183 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000184 if (isRunning()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000185 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000186 requestExitAndWait();
187 }
fei.dengdd910ef2024-06-07 10:25:30 +0800188 mQueue->flushAndCallback(this, WaylandPlugin::queueFlushCallback);
fei.dengb9a1a572023-09-13 01:33:57 +0000189 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000190}
191
192
193int WaylandPlugin::getValue(PluginKey key, void *value)
194{
195 switch (key) {
196 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
197 *(int *)(value) = mDisplay->getDisplayOutput();
fei.dengb9a1a572023-09-13 01:33:57 +0000198 TRACE(mLogCategory,"get select display output:%d",*(int *)value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000199 } break;
fei.dengf1f5fc32023-12-06 06:22:20 +0000200 case PLUGIN_KEY_CURRENT_OUTPUT: {
201 *(int *)(value) = mDisplay->getCurrentOutputCrtcIndex();
202 //DEBUG(mLogCategory,"get current crtc output index:%d",*(int *)value);
203 } break;
fei.deng1c94a342024-08-05 19:33:28 +0800204 case PLUGIN_KEY_ZORDER: {
205 *(int *)(value) = mDisplay->getVideoPlaneZorder();
206 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000207 }
fei.dengb9a1a572023-09-13 01:33:57 +0000208 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000209}
210
211int WaylandPlugin::setValue(PluginKey key, void *value)
212{
213 switch (key) {
214 case PLUGIN_KEY_WINDOW_SIZE: {
215 RenderRect* rect = static_cast<RenderRect*>(value);
216 if (mDisplay) {
217 mDisplay->setWindowSize(rect->x, rect->y, rect->w, rect->h);
218 }
219 } break;
220 case PLUGIN_KEY_FRAME_SIZE: {
221 RenderFrameSize * frameSize = static_cast<RenderFrameSize * >(value);
222 if (mDisplay) {
223 mDisplay->setFrameSize(frameSize->width, frameSize->height);
224 }
225 } break;
226 case PLUGIN_KEY_VIDEO_FORMAT: {
227 int videoFormat = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000228 DEBUG(mLogCategory,"Set video format :%d",videoFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000229 mDisplay->setVideoBufferFormat((RenderVideoFormat)videoFormat);
230 } break;
231 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
232 int outputIndex = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000233 DEBUG(mLogCategory,"Set select display output :%d",outputIndex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000234 mDisplay->setDisplayOutput(outputIndex);
235 } break;
236 case PLUGIN_KEY_VIDEO_PIP: {
237 int pip = *(int *) (value);
238 pip = pip > 0? 1: 0;
239 mDisplay->setPip(pip);
240 } break;
241 case PLUGIN_KEY_IMMEDIATELY_OUTPUT: {
242 bool mImmediatelyOutput = (*(int *)(value)) > 0? true: false;
fei.dengb9a1a572023-09-13 01:33:57 +0000243 DEBUG(mLogCategory, "Set immediately output:%d",mImmediatelyOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +0000244 } break;
fei.deng640c3c92024-04-12 08:31:19 +0000245 case PLUGIN_KEY_KEEP_LAST_FRAME: {
246 int keep = *(int *) (value);
247 DEBUG(mLogCategory, "Set keep last frame:%d",keep);
248 mDisplay->setKeepLastFrame(keep);
249 } break;
fei.denga4abbd52024-07-11 19:17:50 +0800250 case PLUGIN_KEY_FORCE_ASPECT_RATIO: {
251 int forceAspectRatio = *(int *)(value);
252 DEBUG(mLogCategory, "force aspect ratio:%d, TODO ",forceAspectRatio);
253 } break;
254 case PLUGIN_KEY_PIXEL_ASPECT_RATIO: {
255 double ratio = *(double *)(value);
256 INFO(mLogCategory,"pixel aspect ratio :%f",ratio);
257 mDisplay->setPixelAspectRatio((double)ratio);
258 } break;
fei.deng6c425232024-07-19 16:15:31 +0800259 case PLUGIN_KEY_VIDEO_FRAME_RATE: {
260 RenderFraction * fraction = static_cast<RenderFraction*>(value);
261 INFO(mLogCategory,"frame rate,num:%d,denom:%d",fraction->num,fraction->denom);
262 mDisplay->setFrameRate(fraction->num, fraction->denom);
263 } break;
fei.deng1c94a342024-08-05 19:33:28 +0800264 case PLUGIN_KEY_ZORDER: {
265 int zorder = *(int *)(value);
266 INFO(mLogCategory,"set video plane zorder:%d",zorder);
267 mDisplay->setVideoPlaneZorder(zorder);
268 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000269 }
270 return 0;
271}
272
273void WaylandPlugin::handleBufferRelease(RenderBuffer *buffer)
274{
275 if (mCallback) {
276 mCallback->doBufferReleaseCallback(mUserData, (void *)buffer);
277 }
278}
279
280void WaylandPlugin::handleFrameDisplayed(RenderBuffer *buffer)
281{
282 if (mCallback) {
283 mCallback->doBufferDisplayedCallback(mUserData, (void *)buffer);
284 }
285}
286
287void WaylandPlugin::handleFrameDropped(RenderBuffer *buffer)
288{
289 if (mCallback) {
290 mCallback->doBufferDropedCallback(mUserData, (void *)buffer);
291 }
292}
293
fei.deng3287c082024-04-23 09:29:22 +0000294void WaylandPlugin::handleMsgNotify(int type, void *detail)
295{
296 if (mCallback) {
297 mCallback->doMsgCallback(mUserData, type, detail);
298 }
299}
300
fei.dengf7a0cd32023-08-29 09:36:37 +0000301void WaylandPlugin::readyToRun()
302{
303}
304
305bool WaylandPlugin::threadLoop()
306{
307 RenderBuffer *curFrameEntity = NULL;
308 RenderBuffer *expiredFrameEntity = NULL;
309 int64_t nowMonotime = Tls::Times::getSystemTimeUs();
310
311 //if queue is empty or paused, loop next
312 if (mQueue->isEmpty() || mPaused) {
313 goto tag_next;
314 }
315
316 //if weston obtains a buffer rendering,we can't send buffer to weston
317 if (mDisplay->isRedrawingPending()) {
318 goto tag_next;
319 }
320
321 //we output video frame asap
322 if (mImmediatelyOutput) {
323 //pop the peeked frame
324 mQueue->pop((void **)&expiredFrameEntity);
325 goto tag_post;
326 }
327
328 while (mQueue->peek((void **)&curFrameEntity, 0) == Q_OK)
329 {
330 //no frame expired,loop next
331 if (nowMonotime < curFrameEntity->time) {
332 break;
333 }
334
335 //pop the peeked frame
336 mQueue->pop((void **)&curFrameEntity);
337
338 //drop last expired frame,got a new expired frame
339 if (expiredFrameEntity) {
fei.dengb9a1a572023-09-13 01:33:57 +0000340 WARNING(mLogCategory,"drop,now:%lld,display:%lld(pts:%lld ms),n-d:%lld ms",
fei.dengf7a0cd32023-08-29 09:36:37 +0000341 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
342 (nowMonotime - expiredFrameEntity->time)/1000);
343 handleFrameDropped(expiredFrameEntity);
344 handleBufferRelease(expiredFrameEntity);
345 expiredFrameEntity = NULL;
346 }
347
348 expiredFrameEntity = curFrameEntity;
349 }
350
351tag_post:
352 if (!expiredFrameEntity) {
353 //TRACE(mLogCategory,"no frame expire");
354 goto tag_next;
355 }
356
357 if (mDisplay) {
fei.dengdd910ef2024-06-07 10:25:30 +0800358 TRACE(mLogCategory,"post,now:%lld,display:%lld(pts:%lld ms),n-d::%lld ms, size:%d",
fei.dengf7a0cd32023-08-29 09:36:37 +0000359 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
fei.dengdd910ef2024-06-07 10:25:30 +0800360 (nowMonotime - expiredFrameEntity->time)/1000,mQueue->getCnt());
fei.dengf7a0cd32023-08-29 09:36:37 +0000361 mDisplay->displayFrameBuffer(expiredFrameEntity, expiredFrameEntity->time);
362 }
363
364tag_next:
365 usleep(4*1000);
366 return true;
367}
368
369void *makePluginInstance(int id)
370{
fei.dengdd910ef2024-06-07 10:25:30 +0800371 int fd= -1;
372 const char *levelPath = "/run/rlib_plugin_level";
373
fei.dengb9a1a572023-09-13 01:33:57 +0000374 int category =Logger_init(id);
fei.dengc4677852023-10-09 07:21:04 +0000375 char *env = getenv("VIDEO_RENDER_PLUGIN_LOG_LEVEL");
fei.dengf7a0cd32023-08-29 09:36:37 +0000376 if (env) {
377 int level = atoi(env);
378 Logger_set_level(level);
fei.dengdd910ef2024-06-07 10:25:30 +0800379 INFO(category,"env set VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",level);
fei.dengf7a0cd32023-08-29 09:36:37 +0000380 }
fei.dengdd910ef2024-06-07 10:25:30 +0800381
382 //get log level from /run/rlib_plugin_level
383 fd= open(levelPath, O_RDONLY|O_CLOEXEC);
384 if ( fd >= 0 )
385 {
386 char valstr[64];
387 uint32_t val= 0;
388 int nRead;
389
390 memset(valstr, 0, sizeof(valstr));
391 nRead = read(fd, valstr, sizeof(valstr) - 1);
392 valstr[strlen(valstr)] = '\0';
393 if (sscanf(valstr, "%u", &val) > 0)
394 {
395 Logger_set_level(val);
396 INFO(category,"set VIDEO_RENDER_LOG_LEVEL=%d",val);
397 }
398 close(fd);
399 fd = -1;
400 }
fei.dengdd910ef2024-06-07 10:25:30 +0800401
fei.dengb9a1a572023-09-13 01:33:57 +0000402 WaylandPlugin *pluginInstance = new WaylandPlugin(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000403 return static_cast<void *>(pluginInstance);
404}
405
406void destroyPluginInstance(void * plugin)
407{
fei.dengb9a1a572023-09-13 01:33:57 +0000408 int category;
409
fei.dengf7a0cd32023-08-29 09:36:37 +0000410 WaylandPlugin *pluginInstance = static_cast<WaylandPlugin *>(plugin);
fei.dengb9a1a572023-09-13 01:33:57 +0000411 category = pluginInstance->getLogCategory();
fei.dengf7a0cd32023-08-29 09:36:37 +0000412 delete pluginInstance;
fei.dengb9a1a572023-09-13 01:33:57 +0000413 Logger_exit(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000414}