blob: c567961eef7e6b1d6b1b63bf633fc1aa93bd9a56 [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 <linux/videodev2.h>
17#include "wstclient_wayland.h"
18#include "wstclient_plugin.h"
19#include "Logger.h"
fei.dengb9a1a572023-09-13 01:33:57 +000020#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000021
22#define TAG "rlib:wstClient_plugin"
23#define DEFAULT_VIDEO_SERVER "video"
24
fei.dengb9a1a572023-09-13 01:33:57 +000025WstClientPlugin::WstClientPlugin(int logCategory)
26 : mFullscreen(true),
27 mLogCategory(logCategory)
fei.dengf7a0cd32023-08-29 09:36:37 +000028{
29 mIsVideoPip = false;
30 mBufferFormat = VIDEO_FORMAT_UNKNOWN;
31 mNumDroppedFrames = 0;
32 mCommitFrameCnt = 0;
33 mReadyDisplayFrameCnt = 0;
fei.dengb9a1a572023-09-13 01:33:57 +000034 mWayland = new WstClientWayland(this, logCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000035 mWstClientSocket = NULL;
36 mKeepLastFrame.isSet = false;
37 mKeepLastFrame.value = 0;
38 mHideVideo.isSet = false;
39 mHideVideo.value = 0;
40 mFirstFramePts = -1;
41 mImmediatelyOutput = false;
42 mSetCropFrameRect = false;
fei.deng7ac1aeb2023-12-05 01:38:57 +000043 mFrameRateFractionNum = 0;
44 mFrameRateFractionDenom = 0;
45 mFrameRateChanged = false;
fei.dengb9a1a572023-09-13 01:33:57 +000046 mWstEssRMgrOps = new WstEssRMgrOps(this,logCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000047}
48
49WstClientPlugin::~WstClientPlugin()
50{
51 if (mWayland) {
52 delete mWayland;
53 mWayland = NULL;
54 }
55 if (mWstEssRMgrOps) {
56 delete mWstEssRMgrOps;
57 mWstEssRMgrOps = NULL;
58 }
59
fei.dengb9a1a572023-09-13 01:33:57 +000060 TRACE(mLogCategory,"deconstruct");
fei.dengf7a0cd32023-08-29 09:36:37 +000061}
62
63void WstClientPlugin::init()
64{
fei.dengb9a1a572023-09-13 01:33:57 +000065 INFO(mLogCategory,"\n--------------------------------\n"
fei.dengf7a0cd32023-08-29 09:36:37 +000066 "plugin : westeros\n"
67 "ARCH : %s\n"
68 "branch name : %s\n"
69 "git version : %s\n"
70 "change id : %s \n"
71 "ID : %s \n"
72 "last changed: %s\n"
73 "build-time : %s\n"
74 "build-name : %s\n"
75 "--------------------------------\n",
76#if defined(__aarch64__)
77 "arm64",
78#else
79 "arm",
80#endif
81 BRANCH_NAME,
82 GIT_VERSION,
83 COMMIT_CHANGEID,
84 COMMIT_PD,
85 LAST_CHANGED,
86 BUILD_TIME,
87 BUILD_NAME
88 );
89}
90
91void WstClientPlugin::release()
92{
fei.dengb9a1a572023-09-13 01:33:57 +000093 DEBUG(mLogCategory,"release");
fei.dengf7a0cd32023-08-29 09:36:37 +000094}
95
96void WstClientPlugin::setCallback(void *userData, PluginCallback *callback)
97{
98 mUserData = userData;
99 mCallback = callback;
100}
101
102int WstClientPlugin::openDisplay()
103{
104 int ret = 0;
105
fei.dengb9a1a572023-09-13 01:33:57 +0000106 DEBUG(mLogCategory,"openDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +0000107
108 mWstEssRMgrOps->resMgrInit();
109 mWstEssRMgrOps->resMgrRequestDecoder(mIsVideoPip);
110
111 //connect video server first
112 if (!mWstClientSocket) {
113 bool rc;
fei.dengb9a1a572023-09-13 01:33:57 +0000114 mWstClientSocket = new WstClientSocket(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +0000115 rc = mWstClientSocket->connectToSocket(DEFAULT_VIDEO_SERVER);
116 if (!rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000117 ERROR(mLogCategory,"Error connect to video server fail");
fei.dengf7a0cd32023-08-29 09:36:37 +0000118 delete mWstClientSocket;
119 mWstClientSocket = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +0000120 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000121 }
122 }
123
124 if (mWstClientSocket) {
125 mWstClientSocket->sendLayerVideoClientConnection(mIsVideoPip);
126 mWstClientSocket->sendResourceVideoClientConnection(mIsVideoPip);
127 }
128
129 ret = mWayland->connectToWayland();
fei.dengb9a1a572023-09-13 01:33:57 +0000130 if (ret != NO_ERROR) {
131 ERROR(mLogCategory,"Error open display");
fei.dengf7a0cd32023-08-29 09:36:37 +0000132 } else {
133 //run wl display queue dispatch
fei.dengb9a1a572023-09-13 01:33:57 +0000134 DEBUG(mLogCategory,"To run wl display dispatch queue");
fei.dengf7a0cd32023-08-29 09:36:37 +0000135 mWayland->run("display queue");
136 }
137
fei.dengb9a1a572023-09-13 01:33:57 +0000138 DEBUG(mLogCategory,"openDisplay end");
139 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000140}
141
142int WstClientPlugin::openWindow()
143{
144 int ret;
145
fei.dengb9a1a572023-09-13 01:33:57 +0000146 DEBUG(mLogCategory,"openWindow");
fei.dengf7a0cd32023-08-29 09:36:37 +0000147 mCommitFrameCnt = 0;
148 mNumDroppedFrames = 0;
149 mReadyDisplayFrameCnt = 0;
150 /*send session info to server
151 we use mediasync to sync a/v,so select AV_SYNC_MODE_VIDEO_MONO as av clock*/
152 if (mWstClientSocket) {
153 if (mImmediatelyOutput) {
154 mWstClientSocket->sendSessionInfoVideoClientConnection(INVALID_SESSION_ID, SYNC_IMMEDIATE);
155 } else {
156 mWstClientSocket->sendSessionInfoVideoClientConnection(AV_SYNC_SESSION_V_MONO, AV_SYNC_MODE_VIDEO_MONO);
157 }
158 }
159
160 //send hide video
161 if (mWstClientSocket && mHideVideo.isSet) {
162 mWstClientSocket->sendHideVideoClientConnection(mHideVideo.value);
163 }
164
165 //send keep last video frame
166 if (mWstClientSocket && mKeepLastFrame.isSet) {
167 mWstClientSocket->sendKeepLastFrameVideoClientConnection(mKeepLastFrame.value);
168 }
169
170 //send crop frame size if set before window opened
171 if (mSetCropFrameRect) {
172 setCropFrameRect();
173 }
174
fei.dengb9a1a572023-09-13 01:33:57 +0000175 DEBUG(mLogCategory,"openWindow,end");
fei.dengf7a0cd32023-08-29 09:36:37 +0000176 return ret;
177}
178
179int WstClientPlugin::prepareFrame(RenderBuffer *buffer)
180{
fei.dengb9a1a572023-09-13 01:33:57 +0000181 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000182}
183
184int WstClientPlugin::displayFrame(RenderBuffer *buffer, int64_t displayTime)
185{
186 bool ret;
187 WstBufferInfo wstBufferInfo;
188 WstRect wstRect;
189 int x,y,w,h;
190
fei.deng7ac1aeb2023-12-05 01:38:57 +0000191 if (mWstClientSocket && mFrameRateChanged) {
192 mFrameRateChanged = false;
193 mWstClientSocket->sendRateVideoClientConnection(mFrameRateFractionNum, mFrameRateFractionDenom);
194 }
195
fei.dengf7a0cd32023-08-29 09:36:37 +0000196 mWayland->getVideoBounds(&x, &y, &w, &h);
197
198 //init wstBufferInfo,must set fd to -1 value
199 memset(&wstBufferInfo, 0, sizeof(WstBufferInfo));
200 for (int i = 0; i < WST_MAX_PLANES; i++) {
201 wstBufferInfo.planeInfo[0].fd = -1;
202 wstBufferInfo.planeInfo[1].fd = -1;
203 wstBufferInfo.planeInfo[2].fd = -1;
204 }
205
206 wstBufferInfo.bufferId = buffer->id;
207 wstBufferInfo.planeCount = buffer->dma.planeCnt;
fei.dengb9a1a572023-09-13 01:33:57 +0000208 TRACE(mLogCategory,"buffer width:%d,height:%d",buffer->dma.width,buffer->dma.height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000209 for (int i = 0; i < buffer->dma.planeCnt; i++) {
210 wstBufferInfo.planeInfo[i].fd = buffer->dma.fd[i];
211 wstBufferInfo.planeInfo[i].stride = buffer->dma.stride[i];
212 wstBufferInfo.planeInfo[i].offset = buffer->dma.offset[i];
fei.dengb9a1a572023-09-13 01:33:57 +0000213 DEBUG(mLogCategory,"buffer id:%d,plane[%d],fd:%d,stride:%d,offset:%d",buffer->id,i,buffer->dma.fd[i],buffer->dma.stride[i],buffer->dma.offset[i]);
fei.dengf7a0cd32023-08-29 09:36:37 +0000214 }
215
216 wstBufferInfo.frameWidth = buffer->dma.width;
217 wstBufferInfo.frameHeight = buffer->dma.height;
218 wstBufferInfo.frameTime = displayTime;
219
220 //change render lib video format to v4l2 support format
221 if (mBufferFormat == VIDEO_FORMAT_NV12) {
222 wstBufferInfo.pixelFormat = V4L2_PIX_FMT_NV12;
223 } else if (mBufferFormat == VIDEO_FORMAT_NV21) {
224 wstBufferInfo.pixelFormat = V4L2_PIX_FMT_NV21;
225 } else {
fei.dengb9a1a572023-09-13 01:33:57 +0000226 ERROR(mLogCategory,"unknown video buffer format:%d",mBufferFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000227 }
228
229 wstRect.x = x;
230 wstRect.y = y;
231 wstRect.w = w;
232 wstRect.h = h;
233
234 if (mWstClientSocket) {
235 ret = mWstClientSocket->sendFrameVideoClientConnection(&wstBufferInfo, &wstRect);
236 if (!ret) {
fei.dengb9a1a572023-09-13 01:33:57 +0000237 ERROR(mLogCategory,"send video frame to server fail");
fei.dengf7a0cd32023-08-29 09:36:37 +0000238 handleFrameDropped(buffer);
239 handleBufferRelease(buffer);
fei.dengb9a1a572023-09-13 01:33:57 +0000240 return ERROR_FAILED_TRANSACTION;
fei.dengf7a0cd32023-08-29 09:36:37 +0000241 }
242 }
243
244 //storage render buffer to manager
245 std::lock_guard<std::mutex> lck(mRenderLock);
246 std::pair<int, RenderBuffer *> item(buffer->id, buffer);
247 mRenderBuffersMap.insert(item);
248 ++mCommitFrameCnt;
249 ++mReadyDisplayFrameCnt;
fei.dengb9a1a572023-09-13 01:33:57 +0000250 TRACE(mLogCategory,"committed to westeros cnt:%d,readyDisplayFramesCnt:%d",mCommitFrameCnt,mReadyDisplayFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000251
252 //storage displayed render buffer
253 std::pair<int, int64_t> displayitem(buffer->id, displayTime);
254 mDisplayedFrameMap.insert(displayitem);
255 if (mFirstFramePts == -1) {
256 mFirstFramePts = buffer->pts;
257 }
258
fei.dengb9a1a572023-09-13 01:33:57 +0000259 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000260}
261
262int WstClientPlugin::flush()
263{
264 int ret;
fei.dengb9a1a572023-09-13 01:33:57 +0000265 INFO(mLogCategory,"flush");
fei.dengf7a0cd32023-08-29 09:36:37 +0000266 if (mWstClientSocket) {
267 mWstClientSocket->sendFlushVideoClientConnection();
268 }
269 //drop frames those had committed to westeros
270 std::lock_guard<std::mutex> lck(mRenderLock);
271 for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); ) {
272 int bufferid = (int)item->first;
273 auto bufItem = mRenderBuffersMap.find(bufferid);
274 if (bufItem == mRenderBuffersMap.end()) {
275 continue;
276 }
277 mDisplayedFrameMap.erase(item++);
278 RenderBuffer *renderbuffer = (RenderBuffer*) bufItem->second;
279 if (renderbuffer) {
280 handleFrameDropped(renderbuffer);
281 }
282 }
283
fei.dengb9a1a572023-09-13 01:33:57 +0000284 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000285}
286
287int WstClientPlugin::pause()
288{
289 int ret;
fei.dengb9a1a572023-09-13 01:33:57 +0000290 INFO(mLogCategory,"pause");
fei.dengf7a0cd32023-08-29 09:36:37 +0000291 if (mWstClientSocket) {
292 int waitCnt = 20; //we wait about 10 vsync duration
293 while (mReadyDisplayFrameCnt != 0 && waitCnt > 0) {
294 usleep(8000);
295 --waitCnt;
296 }
297 std::lock_guard<std::mutex> lck(mRenderLock);
298 if (mReadyDisplayFrameCnt == 0) { //send pause cmd immediatialy if no frame displays
299 mWstClientSocket->sendPauseVideoClientConnection(true);
300 }
301 }
302 mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_paused);
fei.dengb9a1a572023-09-13 01:33:57 +0000303 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000304}
305
306int WstClientPlugin::resume()
307{
308 int ret;
fei.dengb9a1a572023-09-13 01:33:57 +0000309 INFO(mLogCategory,"resume");
fei.dengf7a0cd32023-08-29 09:36:37 +0000310 std::lock_guard<std::mutex> lck(mRenderLock);
311 if (mWstClientSocket) {
312 mWstClientSocket->sendPauseVideoClientConnection(false);
313 }
314 mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_active);
fei.dengb9a1a572023-09-13 01:33:57 +0000315 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000316}
317
318int WstClientPlugin::closeDisplay()
319{
fei.dengb9a1a572023-09-13 01:33:57 +0000320 INFO(mLogCategory,"closeDisplay, in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000321 mWayland->disconnectFromWayland();
322 mWstEssRMgrOps->resMgrReleaseDecoder();
323 mWstEssRMgrOps->resMgrTerm();
fei.dengb9a1a572023-09-13 01:33:57 +0000324 INFO(mLogCategory,"closeDisplay, out");
325 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000326}
327
328int WstClientPlugin::closeWindow()
329{
fei.dengb9a1a572023-09-13 01:33:57 +0000330 DEBUG(mLogCategory,"closeWindow, in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000331 if (mWstClientSocket) {
332 mWstClientSocket->disconnectFromSocket();
333 delete mWstClientSocket;
334 mWstClientSocket = NULL;
335 }
336
337 std::lock_guard<std::mutex> lck(mRenderLock);
338 //drop all frames those don't displayed
339 for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); ) {
340 int bufferid = (int)item->first;
341 auto bufItem = mRenderBuffersMap.find(bufferid);
342 if (bufItem == mRenderBuffersMap.end()) {
343 continue;
344 }
345 mDisplayedFrameMap.erase(item++);
346 RenderBuffer *renderbuffer = (RenderBuffer*) bufItem->second;
347 if (renderbuffer) {
348 handleFrameDropped(renderbuffer);
349 }
350 }
351 //release all frames those had committed to westeros server
352 for (auto item = mRenderBuffersMap.begin(); item != mRenderBuffersMap.end();) {
353 RenderBuffer *renderbuffer = (RenderBuffer*) item->second;
354 mRenderBuffersMap.erase(item++);
355 if (renderbuffer) {
356 handleBufferRelease(renderbuffer);
357 }
358 }
359 mWstEssRMgrOps->resMgrUpdateState(EssRMgrRes_idle);
360 mRenderBuffersMap.clear();
361 mDisplayedFrameMap.clear();
362 mCommitFrameCnt = 0;
363 mNumDroppedFrames = 0;
364 mReadyDisplayFrameCnt = 0;
365 mImmediatelyOutput = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000366 DEBUG(mLogCategory,"out");
367 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000368}
369
370int WstClientPlugin::getValue(PluginKey key, void *value)
371{
372 switch (key) {
373 case PLUGIN_KEY_KEEP_LAST_FRAME: {
374 *(int *)value = mKeepLastFrame.value;
fei.dengb9a1a572023-09-13 01:33:57 +0000375 TRACE(mLogCategory,"get keep last frame:%d",*(int *)value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000376 } break;
377 case PLUGIN_KEY_HIDE_VIDEO: {
378 *(int *)value = mHideVideo.value;
fei.dengb9a1a572023-09-13 01:33:57 +0000379 TRACE(mLogCategory,"get hide video:%d",*(int *)value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000380 } break;
381 case PLUGIN_KEY_CROP_FRAME_SIZE: {
382 RenderRect* rect = static_cast<RenderRect*>(value);
383 rect->x = mCropFrameRect.x;
384 rect->y = mCropFrameRect.y;
385 rect->w = mCropFrameRect.w;
386 rect->h = mCropFrameRect.h;
387 } break;
388 }
fei.dengb9a1a572023-09-13 01:33:57 +0000389 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000390}
391
392int WstClientPlugin::setValue(PluginKey key, void *value)
393{
394 switch (key) {
395 case PLUGIN_KEY_WINDOW_SIZE: {
396 RenderRect* rect = static_cast<RenderRect*>(value);
397 if (mWayland) {
398 mWayland->setWindowSize(rect->x, rect->y, rect->w, rect->h);
399 }
400 } break;
401 case PLUGIN_KEY_FRAME_SIZE: {
402 RenderFrameSize * frameSize = static_cast<RenderFrameSize * >(value);
403 if (mWayland) {
404 mWayland->setFrameSize(frameSize->width, frameSize->height);
405 }
406 //if set crop property before set frame size,we set crop params now, because
407 //crop property dependent frame size
408 if (mSetCropFrameRect) {
409 setCropFrameRect();
410 }
411 } break;
412 case PLUGIN_KEY_VIDEO_FORMAT: {
413 int format = *(int *)(value);
414 mBufferFormat = (RenderVideoFormat) format;
fei.dengb9a1a572023-09-13 01:33:57 +0000415 DEBUG(mLogCategory,"Set video format :%d",mBufferFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000416 } break;
417 case PLUGIN_KEY_VIDEO_PIP: {
418 int pip = *(int *) (value);
419 mIsVideoPip = pip > 0? true:false;
fei.deng76493fa2023-11-09 11:13:34 +0000420 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000421 case PLUGIN_KEY_KEEP_LAST_FRAME: {
422 int keep = *(int *) (value);
423 mKeepLastFrame.value = keep > 0? true:false;
424 mKeepLastFrame.isSet = true;
fei.dengb9a1a572023-09-13 01:33:57 +0000425 DEBUG(mLogCategory, "Set keep last frame :%d",mKeepLastFrame.value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000426 if (mWstClientSocket) {
427 mWstClientSocket->sendKeepLastFrameVideoClientConnection(mKeepLastFrame.value);
428 }
429 } break;
430 case PLUGIN_KEY_HIDE_VIDEO: {
431 int hide = *(int *)(value);
432 mHideVideo.value = hide > 0? true:false;
433 mHideVideo.isSet = true;
fei.dengb9a1a572023-09-13 01:33:57 +0000434 DEBUG(mLogCategory, "Set hide video:%d",mHideVideo.value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000435 if (mWstClientSocket) {
436 mWstClientSocket->sendHideVideoClientConnection(mHideVideo.value);
437 }
438 } break;
439 case PLUGIN_KEY_FORCE_ASPECT_RATIO: {
440 int forceAspectRatio = *(int *)(value);
441 if (mWayland) {
442 mWayland->setForceAspectRatio(forceAspectRatio > 0? true:false);
443 }
444 } break;
445 case PLUGIN_KEY_IMMEDIATELY_OUTPUT: {
446 int immediately = *(int *)(value);
447 mImmediatelyOutput = immediately > 0? true: false;
fei.dengb9a1a572023-09-13 01:33:57 +0000448 DEBUG(mLogCategory,"Set immediately output:%d",mImmediatelyOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +0000449 if (mImmediatelyOutput && mWstClientSocket) {
450 mWstClientSocket->sendSessionInfoVideoClientConnection(INVALID_SESSION_ID, SYNC_IMMEDIATE);
451 }
452 } break;
453 case PLUGIN_KEY_CROP_FRAME_SIZE: {
454 RenderRect* rect = static_cast<RenderRect*>(value);
455 mCropFrameRect.x = rect->x;
456 mCropFrameRect.y = rect->y;
457 mCropFrameRect.w = rect->w;
458 mCropFrameRect.h = rect->h;
459 mSetCropFrameRect = true;
fei.dengb9a1a572023-09-13 01:33:57 +0000460 INFO(mLogCategory,"crop params (%d,%d,%d,%d)",rect->x,rect->y,rect->w,rect->h);
fei.dengf7a0cd32023-08-29 09:36:37 +0000461 setCropFrameRect();
462 } break;
463 case PLUGIN_KEY_PIXEL_ASPECT_RATIO: {
464 double ratio = *(double *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000465 INFO(mLogCategory,"pixel aspect ratio :%f",ratio);
fei.dengf7a0cd32023-08-29 09:36:37 +0000466 if (mWayland) {
467 mWayland->setPixelAspectRatio((double)ratio);
468 }
469 } break;
fei.deng7ac1aeb2023-12-05 01:38:57 +0000470 case PLUGIN_KEY_VIDEO_FRAME_RATE: {
471 RenderFraction * fraction = static_cast<RenderFraction*>(value);
472 INFO(mLogCategory,"frame rate,num:%d,denom:%d",fraction->num,fraction->denom);
473 if (fraction->num != mFrameRateFractionNum ||
474 fraction->denom != mFrameRateFractionDenom) {
475 mFrameRateFractionNum = fraction->num;
476 mFrameRateFractionDenom = fraction->denom;
477 if (mFrameRateFractionDenom == 0) {
478 mFrameRateFractionDenom = 1;
479 }
480 mFrameRateChanged = true;
481 }
482 if (mWstClientSocket && mFrameRateChanged) {
483 mFrameRateChanged = false;
484 mWstClientSocket->sendRateVideoClientConnection(mFrameRateFractionNum, mFrameRateFractionDenom);
485 }
486 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000487 }
fei.dengb9a1a572023-09-13 01:33:57 +0000488 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000489}
490
491void WstClientPlugin::handleBufferRelease(RenderBuffer *buffer)
492{
493 if (mCallback) {
494 mCallback->doBufferReleaseCallback(mUserData, (void *)buffer);
495 }
496}
497
498void WstClientPlugin::handleFrameDisplayed(RenderBuffer *buffer)
499{
500 if (mCallback) {
501 mCallback->doBufferDisplayedCallback(mUserData, (void *)buffer);
502 }
503}
504
505void WstClientPlugin::handleFrameDropped(RenderBuffer *buffer)
506{
507 if (mCallback) {
508 mCallback->doBufferDropedCallback(mUserData, (void *)buffer);
509 }
510}
511
512void WstClientPlugin::handleMsgNotify(int type, void *detail)
513{
514 if (mCallback) {
515 mCallback->doMsgCallback(mUserData, type, detail);
516 }
517}
518
519void WstClientPlugin::setVideoRect(int videoX, int videoY, int videoWidth, int videoHeight)
520{
521 if (mWstClientSocket) {
522 mWstClientSocket->sendRectVideoClientConnection(videoX, videoY, videoWidth, videoHeight);
523 }
524}
525
526void WstClientPlugin::onWstSocketEvent(WstEvent *event)
527{
fei.dengb9a1a572023-09-13 01:33:57 +0000528 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000529 switch (event->event)
530 {
531 case WST_REFRESH_RATE: {
532 int rate = event->param;
fei.dengb9a1a572023-09-13 01:33:57 +0000533 INFO(mLogCategory,"refresh rate:%d",rate);
fei.dengf7a0cd32023-08-29 09:36:37 +0000534 } break;
535 case WST_BUFFER_RELEASE: {
536 int bufferid = event->param;
fei.dengb9a1a572023-09-13 01:33:57 +0000537 TRACE(mLogCategory,"Buffer release id:%d",bufferid);
fei.dengf7a0cd32023-08-29 09:36:37 +0000538 RenderBuffer *renderbuffer = NULL;
539 bool isDropped = false;
540 int64_t displaytime = 0;
541 {
542 std::lock_guard<std::mutex> lck(mRenderLock);
543 auto renderBufferItem = mRenderBuffersMap.find(bufferid);
544 if (renderBufferItem == mRenderBuffersMap.end()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000545 WARNING(mLogCategory,"can't find map Renderbuffer");
fei.dengf7a0cd32023-08-29 09:36:37 +0000546 return ;
547 }
548 --mCommitFrameCnt;
549 renderbuffer = (RenderBuffer*) renderBufferItem->second;
550 //remove had release render buffer
551 mRenderBuffersMap.erase(bufferid);
552 auto displayFrameItem = mDisplayedFrameMap.find(bufferid);
553 if (displayFrameItem != mDisplayedFrameMap.end()) {
554 mDisplayedFrameMap.erase(bufferid);
555 --mReadyDisplayFrameCnt;
556 isDropped = true;
557 displaytime = (int64_t)displayFrameItem->second;
558 }
559 }
560
561 if (renderbuffer) {
562 /*if we can find item in mDisplayedFrameMap,
563 this buffer is dropped by westeros server,so we
564 must call displayed callback*/
565 if (isDropped) {
fei.dengb9a1a572023-09-13 01:33:57 +0000566 WARNING(mLogCategory,"Frame droped,pts:%lld us,displaytime:%lld,readyDisplayFramesCnt:%d",\
fei.dengf7a0cd32023-08-29 09:36:37 +0000567 renderbuffer->pts/1000,displaytime,mReadyDisplayFrameCnt);
568 handleFrameDropped(renderbuffer);
569 }
570 handleBufferRelease(renderbuffer);
571 }
fei.dengb9a1a572023-09-13 01:33:57 +0000572 TRACE(mLogCategory,"remain on westeros cnt:%d",mCommitFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000573 } break;
574 case WST_STATUS: {
575 int dropframes = event->param;
576 int64_t frameTime = event->lparam;
fei.dengb9a1a572023-09-13 01:33:57 +0000577 TRACE(mLogCategory,"WST_STATUS,dropframes:%d,frameTime:%lld",dropframes,frameTime);
fei.dengf7a0cd32023-08-29 09:36:37 +0000578 RenderBuffer *renderbuffer = NULL;
579 if (mNumDroppedFrames != event->param) {
580 mNumDroppedFrames = event->param;
fei.dengb9a1a572023-09-13 01:33:57 +0000581 WARNING(mLogCategory,"frame dropped cnt:%d",mNumDroppedFrames);
fei.dengf7a0cd32023-08-29 09:36:37 +0000582 }
583 //update status,if frameTime isn't equal -1LL
584 //this buffer had displayed
585 if (frameTime != -1LL) {
586 std::lock_guard<std::mutex> lck(mRenderLock);
587 --mReadyDisplayFrameCnt;
fei.dengb9a1a572023-09-13 01:33:57 +0000588 TRACE(mLogCategory,"displayed frame time:%lld,readyDisplayFramesCnt:%d",frameTime,mReadyDisplayFrameCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +0000589 int bufferId = getDisplayFrameBufferId(frameTime);
590 if (bufferId < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000591 WARNING(mLogCategory,"can't find map displayed frame:%lld",frameTime);
fei.dengf7a0cd32023-08-29 09:36:37 +0000592 return ;
593 }
594 auto displayItem = mDisplayedFrameMap.find(bufferId);
595 if (displayItem != mDisplayedFrameMap.end()) {
596 mDisplayedFrameMap.erase(bufferId);
597 }
598 auto item = mRenderBuffersMap.find(bufferId);
599 if (item != mRenderBuffersMap.end()) {
600 renderbuffer = (RenderBuffer*) item->second;
601 }
602 }
603 if (renderbuffer) {
604 //first frame signal
605 if (renderbuffer->pts == mFirstFramePts) {
606 handleMsgNotify(MSG_FIRST_FRAME,(void*)&renderbuffer->pts);
607 }
608 handleFrameDisplayed(renderbuffer);
609 }
610 } break;
611 case WST_UNDERFLOW: {
612 uint64_t frameTime = event->lparam;
fei.dengb9a1a572023-09-13 01:33:57 +0000613 TRACE(mLogCategory,"under flow frametime:%lld",frameTime);
fei.dengf7a0cd32023-08-29 09:36:37 +0000614 //under flow event sended must be after sending first frame to westeros
615 if (mFirstFramePts != -1) {
616 handleMsgNotify(MSG_UNDER_FLOW, NULL);
617 }
618 } break;
619 case WST_ZOOM_MODE: {
620 int mode = event->param;
621 bool globalZoomActive = event->param1 > 0? true:false;
622 bool allow4kZoom = event->param2 > 0? true:false;;
623 mWayland->setZoomMode(mode, globalZoomActive, allow4kZoom);
624 } break;
625 case WST_DEBUG_LEVEL: {
626 /* code */
627 } break;
628 default:
629 break;
630 }
631}
632
633int WstClientPlugin::getDisplayFrameBufferId(int64_t displayTime)
634{
635 int bufId = -1;
636 for (auto item = mDisplayedFrameMap.begin(); item != mDisplayedFrameMap.end(); item++) {
637 int64_t time = (int64_t)item->second;
638 if (time == displayTime) {
639 bufId = (int)item->first;
640 break;
641 }
642 }
643 return bufId;
644}
645
646bool WstClientPlugin::setCropFrameRect()
647{
648 if (mWayland) {
649 int frameWidth,frameHeight;
650 mWayland->getFrameSize(&frameWidth, &frameHeight);
651 if (frameWidth <= 0 || frameHeight <= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000652 WARNING(mLogCategory, "no set video frame size,set crop params later");
fei.dengf7a0cd32023-08-29 09:36:37 +0000653 goto bad_param;
654 }
655
656 //correct crop rect if needed
657 if (frameWidth > 0 && (mCropFrameRect.x + mCropFrameRect.w) > frameWidth) {
658 if (mCropFrameRect.x < frameWidth) {
659 int oriX = mCropFrameRect.x;
660 int oriW = mCropFrameRect.w;
661 mCropFrameRect.w = frameWidth - mCropFrameRect.x;
fei.dengb9a1a572023-09-13 01:33:57 +0000662 WARNING(mLogCategory, "correct crop x:%d, w:%d to x:%d, w:%d", \
fei.dengf7a0cd32023-08-29 09:36:37 +0000663 oriX,oriW,mCropFrameRect.x,mCropFrameRect.w);
664 } else {
fei.dengb9a1a572023-09-13 01:33:57 +0000665 ERROR(mLogCategory, "Error crop params (%d,%d,%d,%d) frame(%d,%d)", \
fei.dengf7a0cd32023-08-29 09:36:37 +0000666 mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h,frameWidth,frameHeight);
667 goto bad_param;
668 }
669 }
670 if (frameHeight > 0 && (mCropFrameRect.y + mCropFrameRect.h) > frameHeight) {
671 if (mCropFrameRect.y < frameHeight) {
672 int oriY = mCropFrameRect.x;
673 int oriH = mCropFrameRect.w;
674 mCropFrameRect.h = frameHeight - mCropFrameRect.y;
fei.dengb9a1a572023-09-13 01:33:57 +0000675 WARNING(mLogCategory, "correct crop y:%d, h:%d to y:%d, h:%d", \
fei.dengf7a0cd32023-08-29 09:36:37 +0000676 oriY,oriH,mCropFrameRect.y,mCropFrameRect.h);
677 } else {
fei.dengb9a1a572023-09-13 01:33:57 +0000678 ERROR(mLogCategory, "Error crop params (%d,%d,%d,%d) frame(%d,%d)", \
fei.dengf7a0cd32023-08-29 09:36:37 +0000679 mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h,frameWidth,frameHeight);
680 goto bad_param;
681 }
682 }
fei.dengb9a1a572023-09-13 01:33:57 +0000683 INFO(mLogCategory, "crop (%d,%d,%d,%d)", \
fei.dengf7a0cd32023-08-29 09:36:37 +0000684 mCropFrameRect.x,mCropFrameRect.y,mCropFrameRect.w,mCropFrameRect.h);
685 }
686 if (mWstClientSocket && mSetCropFrameRect) {
687 mWstClientSocket->sendCropFrameSizeClientConnection(mCropFrameRect.x, mCropFrameRect.y, mCropFrameRect.w, mCropFrameRect.h);
688 mSetCropFrameRect = false;
689 }
690 return true;
691bad_param:
692 return false;
693}
694
695void *makePluginInstance(int id)
696{
fei.dengb9a1a572023-09-13 01:33:57 +0000697 int category =Logger_init(id);
fei.dengc4677852023-10-09 07:21:04 +0000698 char *env = getenv("VIDEO_RENDER_PLUGIN_LOG_LEVEL");
fei.dengf7a0cd32023-08-29 09:36:37 +0000699 if (env) {
700 int level = atoi(env);
701 Logger_set_level(level);
fei.dengc4677852023-10-09 07:21:04 +0000702 INFO(category,"VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",level);
fei.dengf7a0cd32023-08-29 09:36:37 +0000703 }
fei.dengb9a1a572023-09-13 01:33:57 +0000704 WstClientPlugin *pluginInstance = new WstClientPlugin(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000705 return static_cast<void *>(pluginInstance);
706}
707
708void destroyPluginInstance(void * plugin)
709{
fei.dengb9a1a572023-09-13 01:33:57 +0000710 int category;
711
fei.dengf7a0cd32023-08-29 09:36:37 +0000712 WstClientPlugin *pluginInstance = static_cast<WstClientPlugin *>(plugin);
fei.dengb9a1a572023-09-13 01:33:57 +0000713 category = pluginInstance->getLogCategory();
fei.dengf7a0cd32023-08-29 09:36:37 +0000714 delete pluginInstance;
fei.dengb9a1a572023-09-13 01:33:57 +0000715 Logger_exit(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000716}