blob: d9f89766bb5020c0c435b692cdd81d6003b284d7 [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 <cstring>
17#include "wstclient_wayland.h"
18#include "wstclient_plugin.h"
19#include "Logger.h"
20
21#define TAG "rlib:wstclient_wayland"
22
23#ifndef MAX
24# define MAX(a,b) ((a) > (b)? (a) : (b))
25# define MIN(a,b) ((a) < (b)? (a) : (b))
26#endif
27
28#define WESTEROS_UNUSED(x) ((void)(x))
29
30#define DEFAULT_WINDOW_X (0)
31#define DEFAULT_WINDOW_Y (0)
32#define DEFAULT_WINDOW_WIDTH (1920)
33#define DEFAULT_WINDOW_HEIGHT (1080)
34//discuss with display team,outpu resolution is a fixed value(1920x1080)
35#define DEFAULT_OUTPUT_WIDTH (1920)
36#define DEFAULT_OUTPUT_HEIGHT (1080)
37
38#define AV_SYNC_SESSION_V_MONO 64
39
40enum
41{
42 ZOOM_NONE,
43 ZOOM_DIRECT,
44 ZOOM_NORMAL,
45 ZOOM_16_9_STRETCH,
46 ZOOM_4_3_PILLARBOX,
47 ZOOM_ZOOM,
48 ZOOM_GLOBAL
49};
50
51#define needBounds() (mForceAspectRatio || (mZoomMode != ZOOM_NONE))
52
53void WstClientWayland::shellSurfaceId(void *data,
54 struct wl_simple_shell *wl_simple_shell,
55 struct wl_surface *surface,
56 uint32_t surfaceId)
57{
58 WstClientWayland *self = static_cast<WstClientWayland *>(data);
59 self->mWlShellSurfaceId = surfaceId;
60 char name[32];
61 wl_fixed_t z, op;
62 WESTEROS_UNUSED(wl_simple_shell);
63 WESTEROS_UNUSED(surface);
64
65 sprintf( name, "westeros-surface-%x", surfaceId );
66 wl_simple_shell_set_name(self->mWlShell, surfaceId, name);
67 if ( (self->mWindowWidth == 0) || (self->mWindowHeight == 0) )
68 {
69 wl_simple_shell_set_visible(self->mWlShell, self->mWlShellSurfaceId, false);
70 }
71 else
72 {
73 wl_simple_shell_set_visible(self->mWlShell, self->mWlShellSurfaceId, true);
74 if (!self->mWlVpc)
75 {
76 wl_simple_shell_set_geometry(self->mWlShell, self->mWlShellSurfaceId, self->mWindowX, self->mWindowY, self->mWindowWidth, self->mWindowHeight );
77 }
78 }
79
80 z = wl_fixed_from_double(self->mZorder);
81 wl_simple_shell_set_zorder(self->mWlShell, self->mWlShellSurfaceId, z);
82 op = wl_fixed_from_double(self->mOpacity);
83 wl_simple_shell_set_opacity(self->mWlShell, self->mWlShellSurfaceId, op);
84 wl_simple_shell_get_status(self->mWlShell, self->mWlShellSurfaceId);
85
86 wl_display_flush(self->mWlDisplay);
87}
88
89void WstClientWayland::shellSurfaceCreated(void *data,
90 struct wl_simple_shell *wl_simple_shell,
91 uint32_t surfaceId,
92 const char *name)
93{
94 WESTEROS_UNUSED(data);
95 WESTEROS_UNUSED(wl_simple_shell);
96 WESTEROS_UNUSED(surfaceId);
97 WESTEROS_UNUSED(name);
98}
99
100void WstClientWayland::shellSurfaceDestroyed(void *data,
101 struct wl_simple_shell *wl_simple_shell,
102 uint32_t surfaceId,
103 const char *name)
104{
105 WESTEROS_UNUSED(data);
106 WESTEROS_UNUSED(wl_simple_shell);
107 WESTEROS_UNUSED(surfaceId);
108 WESTEROS_UNUSED(name);
109}
110
111void WstClientWayland::shellSurfaceStatus(void *data,
112 struct wl_simple_shell *wl_simple_shell,
113 uint32_t surfaceId,
114 const char *name,
115 uint32_t visible,
116 int32_t x,
117 int32_t y,
118 int32_t width,
119 int32_t height,
120 wl_fixed_t opacity,
121 wl_fixed_t zorder)
122{
123 WstClientWayland *self = static_cast<WstClientWayland *>(data);
124 WESTEROS_UNUSED(wl_simple_shell);
125 WESTEROS_UNUSED(surfaceId);
126 WESTEROS_UNUSED(name);
127 WESTEROS_UNUSED(x);
128 WESTEROS_UNUSED(y);
129 WESTEROS_UNUSED(width);
130 WESTEROS_UNUSED(height);
131
132 INFO("opacity: %d,zorder:%d", opacity,zorder);
133 self->mWindowChange = true;
134 self->mOpacity = opacity;
135 self->mZorder = zorder;
136}
137
138void WstClientWayland::shellGetSurfacesDone(void *data, struct wl_simple_shell *wl_simple_shell)
139{
140 WESTEROS_UNUSED(data);
141 WESTEROS_UNUSED(wl_simple_shell);
142}
143
144static const struct wl_simple_shell_listener shellListener =
145{
146 WstClientWayland::shellSurfaceId,
147 WstClientWayland::shellSurfaceCreated,
148 WstClientWayland::shellSurfaceDestroyed,
149 WstClientWayland::shellSurfaceStatus,
150 WstClientWayland::shellGetSurfacesDone
151};
152
153void WstClientWayland::vpcVideoPathChange(void *data,
154 struct wl_vpc_surface *wl_vpc_surface,
155 uint32_t new_pathway )
156{
157 WESTEROS_UNUSED(wl_vpc_surface);
158 WstClientWayland *self = static_cast<WstClientWayland *>(data);
159
160 INFO("new pathway: %d\n", new_pathway);
161 self->setVideoPath(new_pathway == WL_VPC_SURFACE_PATHWAY_GRAPHICS);
162}
163
164void WstClientWayland::vpcVideoXformChange(void *data,
165 struct wl_vpc_surface *wl_vpc_surface,
166 int32_t x_translation,
167 int32_t y_translation,
168 uint32_t x_scale_num,
169 uint32_t x_scale_denom,
170 uint32_t y_scale_num,
171 uint32_t y_scale_denom,
172 uint32_t output_width,
173 uint32_t output_height)
174{
175 WESTEROS_UNUSED(wl_vpc_surface);
176 WstClientWayland *self = static_cast<WstClientWayland *>(data);
177
178 TRACE("x_trans:%d,y_trans:%d,x_scale_num:%d,x_scale_denom:%d,y_scale_num:%d,y_scale_denom:%d",\
179 x_translation,y_translation,x_scale_num,x_scale_denom,y_scale_num,y_scale_denom);
180 TRACE("output_width:%d,output_height:%d",output_width,output_height);
181 self->mTransX= x_translation;
182 self->mTransY= y_translation;
183 if ( x_scale_denom )
184 {
185 self->mScaleXNum= x_scale_num;
186 self->mScaleXDenom= x_scale_denom;
187 }
188 if ( y_scale_denom )
189 {
190 self->mScaleYNum = y_scale_num;
191 self->mScaleYDenom = y_scale_denom;
192 }
193 self->mOutputWidth= (int)output_width;
194 self->mOutputHeight= (int)output_height;
195
196 std::lock_guard<std::mutex> lck(self->mMutex);
197 self->updateVideoPosition();
198}
199
200static const struct wl_vpc_surface_listener vpcListener= {
201 WstClientWayland::vpcVideoPathChange,
202 WstClientWayland::vpcVideoXformChange
203};
204
205void WstClientWayland::outputHandleGeometry( void *data,
206 struct wl_output *output,
207 int x,
208 int y,
209 int mmWidth,
210 int mmHeight,
211 int subPixel,
212 const char *make,
213 const char *model,
214 int transform )
215{
216 WESTEROS_UNUSED(data);
217 WESTEROS_UNUSED(output);
218 WESTEROS_UNUSED(x);
219 WESTEROS_UNUSED(y);
220 WESTEROS_UNUSED(mmWidth);
221 WESTEROS_UNUSED(mmHeight);
222 WESTEROS_UNUSED(subPixel);
223 WESTEROS_UNUSED(make);
224 WESTEROS_UNUSED(model);
225 WESTEROS_UNUSED(transform);
226}
227
228void WstClientWayland::outputHandleMode( void *data,
229 struct wl_output *output,
230 uint32_t flags,
231 int width,
232 int height,
233 int refreshRate )
234{
235 WstClientWayland *self = static_cast<WstClientWayland *>(data);
236
237 if ( flags & WL_OUTPUT_MODE_CURRENT )
238 {
239 //output resolution is a fixed value(1920x1080)
240 width = DEFAULT_OUTPUT_WIDTH;
241 height = DEFAULT_OUTPUT_HEIGHT;
242 std::lock_guard<std::mutex> lck(self->mMutex);
243 self->mDisplayWidth = width;
244 self->mDisplayHeight = height;
245 DEBUG("compositor sets window to (%dx%d)\n", width, height);
246 if (!self->mWindowSet)
247 {
248 self->mWindowWidth = width;
249 self->mWindowHeight = height;
250 if (self->mWlVpcSurface)
251 {
252 TRACE("set window geometry:x:%d,y:%d,w:%d,h:%d",self->mWindowX,self->mWindowY,self->mWindowWidth,self->mWindowHeight);
253 wl_vpc_surface_set_geometry(self->mWlVpcSurface, self->mWindowX, self->mWindowY, self->mWindowWidth, self->mWindowHeight);
254 }
255 }
256 }
257}
258
259void WstClientWayland::outputHandleDone( void *data,
260 struct wl_output *output )
261{
262 WESTEROS_UNUSED(data);
263 WESTEROS_UNUSED(output);
264}
265
266void WstClientWayland::outputHandleScale( void *data,
267 struct wl_output *output,
268 int32_t scale )
269{
270 WESTEROS_UNUSED(data);
271 WESTEROS_UNUSED(output);
272 WESTEROS_UNUSED(scale);
273}
274
275static const struct wl_output_listener outputListener = {
276 WstClientWayland::outputHandleGeometry,
277 WstClientWayland::outputHandleMode,
278 WstClientWayland::outputHandleDone,
279 WstClientWayland::outputHandleScale
280};
281
282void WstClientWayland::sbFormat(void *data, struct wl_sb *wl_sb, uint32_t format)
283{
284 WstClientWayland *self = static_cast<WstClientWayland *>(data);
285 WESTEROS_UNUSED(wl_sb);
286 WESTEROS_UNUSED(data);
287 TRACE("registry: sbFormat: %X\n", format);
288}
289
290static const struct wl_sb_listener sbListener = {
291 WstClientWayland::sbFormat
292};
293
294void
295WstClientWayland::registryHandleGlobal (void *data, struct wl_registry *registry,
296 uint32_t id, const char *interface, uint32_t version)
297{
298 WstClientWayland *self = static_cast<WstClientWayland *>(data);
299 TRACE("registryHandleGlobal,interface:%s,version:%d",interface,version);
300
301 if (strcmp (interface, "wl_compositor") == 0) {
302 self->mWlCompositor = (struct wl_compositor *)wl_registry_bind (registry, id, &wl_compositor_interface, 1/*MIN (version, 3)*/);
303 wl_proxy_set_queue((struct wl_proxy*)self->mWlCompositor, self->mWlQueue);
304 TRACE("registry: compositor %p\n", (void*)self->mWlCompositor);
305 } else if (strcmp (interface, "wl_simple_shell") == 0) {
306 self->mWlShell = (struct wl_simple_shell*)wl_registry_bind(registry, id, &wl_simple_shell_interface, 1);
307 wl_proxy_set_queue((struct wl_proxy*)self->mWlShell, self->mWlQueue);
308 wl_simple_shell_add_listener(self->mWlShell, &shellListener, (void *)self);
309 TRACE("registry: simple shell %p\n", (void*)self->mWlShell);
310 } else if (strcmp (interface, "wl_vpc") == 0) {
311 self->mWlVpc = (struct wl_vpc*)wl_registry_bind(registry, id, &wl_vpc_interface, 1);
312 wl_proxy_set_queue((struct wl_proxy*)self->mWlVpc, self->mWlQueue);
313 TRACE("registry: vpc %p\n", (void*)self->mWlVpc);
314 } else if (strcmp (interface, "wl_output") == 0) {
315 self->mWlOutput = (struct wl_output*)wl_registry_bind(registry, id, &wl_output_interface, 2);
316 wl_proxy_set_queue((struct wl_proxy*)self->mWlOutput, self->mWlQueue);
317 wl_output_add_listener(self->mWlOutput, &outputListener, (void *)self);
318 TRACE("registry: output %p\n", (void*)self->mWlOutput);
319 } else if (strcmp (interface, "wl_sb") == 0) {
320 self->mWlSb = (struct wl_sb*)wl_registry_bind(registry, id, &wl_sb_interface, version);
321 wl_proxy_set_queue((struct wl_proxy*)self->mWlSb, self->mWlQueue);
322 wl_sb_add_listener(self->mWlSb, &sbListener, (void *)self);
323 TRACE("registry: sb %p\n", (void*)self->mWlSb);
324 }
325}
326
327void
328WstClientWayland::registryHandleGlobalRemove (void *data, struct wl_registry *registry, uint32_t name)
329{
330 WstClientWayland *self = static_cast<WstClientWayland *>(data);
331 /* temporarily do nothing */
332 DEBUG("wayland display remove registry handle global");
333}
334
335static const struct wl_registry_listener registry_listener = {
336 WstClientWayland::registryHandleGlobal,
337 WstClientWayland::registryHandleGlobalRemove
338};
339
340WstClientWayland::WstClientWayland(WstClientPlugin *plugin)
341 :mPlugin(plugin)
342{
343 TRACE("construct WstClientWayland");
344 mWlDisplay = NULL;
345 mWlQueue = NULL;
346 mWlRegistry = NULL;
347 mWlCompositor = NULL;
348 mWlSurface = NULL;
349 mWlVpc = NULL;
350 mWlVpcSurface = NULL;
351 mWlOutput = NULL;
352 mWlShell = NULL;
353 mWlSb = NULL;
354 mDisplayWidth = DEFAULT_OUTPUT_WIDTH;
355 mDisplayHeight = DEFAULT_OUTPUT_HEIGHT;
356 mWindowX = DEFAULT_WINDOW_X;
357 mWindowY = DEFAULT_WINDOW_Y;
358 mWindowWidth = DEFAULT_WINDOW_WIDTH;
359 mWindowHeight = DEFAULT_WINDOW_HEIGHT;
360 mVideoX = mWindowX;
361 mVideoY = mWindowY;
362 mVideoWidth = mWindowWidth;
363 mVideoHeight = mWindowHeight;
364 mWlShellSurfaceId = 0;
365 mWindowChange = false;
366 mWindowSet = false;
367 mWindowSizeOverride = false;
368 mZoomMode = ZOOM_NONE;
369 mZoomModeGlobal = false;
370 mAllow4kZoom = false;
371 mFrameWidth = 0;
372 mFrameHeight = 0;
373 mForceAspectRatio = false;
374 mPixelAspectRatio = 1.0;
375 mScaleXDenom = 0;
376 mScaleYDenom = 0;
377 mForceFullScreen = false;
378}
379
380WstClientWayland::~WstClientWayland()
381{
382 TRACE("deconstruct WstClientWayland");
383}
384
385int WstClientWayland::connectToWayland()
386{
387 const char *xdgEnv = NULL;
388 const char *displayEnv = NULL;
389 const char *displayName = "rlib-display";
390 const char *fullScreenEnV = NULL;
391 DEBUG("in");
392 xdgEnv = getenv("XDG_RUNTIME_DIR");
393 INFO("XDG_RUNTIME_DIR:%s",xdgEnv != NULL?xdgEnv:"NULL");
394 if (!xdgEnv) {
395 xdgEnv = "/run";
396 ERROR("XDG_RUNTIME_DIR is not set,set default %s",xdgEnv);
397 }
398 displayEnv= getenv("WAYLAND_DISPLAY");
399 INFO("WAYLAND_DISPLAY:%s",displayEnv != NULL?displayEnv:"NULL");
400
401 fullScreenEnV= getenv("VIDEO_RENDER_FORCE_FULLSCREEN");
402 INFO("VIDEO_RENDER_FORCE_FULLSCREEN:%s",fullScreenEnV != NULL?fullScreenEnV:"NULL");
403 if (fullScreenEnV) {
404 int force = atoi(fullScreenEnV);
405 mForceFullScreen = force != 0? true: false;
406 INFO("VIDEO_RENDER_FORCE_FULLSCREEN:%d",mForceFullScreen);
407 }
408
409 mWlDisplay = wl_display_connect(NULL);
410 if (!mWlDisplay) {
411 char waylandDisplay[64];
412 ERROR("Failed connect to default wayland display");
413 memset(waylandDisplay, 0, 64);
414 strcpy(waylandDisplay, xdgEnv);
415 strcat(waylandDisplay, "/" );
416 strcat(waylandDisplay, displayName);
417 INFO("detect rlib wayland display %s",waylandDisplay);
418 if (access(waylandDisplay,F_OK) == 0) {
419 INFO("try to connect to %s",waylandDisplay);
420 mWlDisplay = wl_display_connect(displayName);
421 }
422 /*try to create wayland display my self*/
423 if (!mWlDisplay && xdgEnv) {
424 WARNING("try to create and connect rlib-display display");
425 std::string cmdCreateDisplay = R"(curl 'http://127.0.0.1:9998/jsonrpc' -d '{"jsonrpc": "2.0","id": 4,"method":
426 "org.rdk.RDKShell.1.createDisplay","params": { "client": "rlib-display", "displayName": "rlib-display" }}';echo)";
427 std::string cmdMoveDisplay = R"(curl 'http://127.0.0.1:9998/jsonrpc' -d '{"jsonrpc": "2.0","id": 4,"method":
428 "org.rdk.RDKShell.1.moveToBack", "params": { "client": "rlib-display" }}';echo)";
429
430 executeCmd(cmdCreateDisplay.c_str());
431 executeCmd(cmdMoveDisplay.c_str());
432 //try to connect again
433 mWlDisplay = wl_display_connect(displayName);
434 }
435
436 if (!mWlDisplay) {
437 ERROR( "wayland connect rlib-display fail");
438 return -1;
439 }
440 INFO("wayland connected to rlib-display");
441 }
442
443 mWlQueue = wl_display_create_queue (mWlDisplay);
444 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplay, mWlQueue);
445
446 mWlRegistry = wl_display_get_registry (mWlDisplay);
447 wl_registry_add_listener (mWlRegistry, &registry_listener, (void *)this);
448
449 /* we need exactly 2 roundtrips to discover global objects and their state */
450 for (int i = 0; i < 2; i++) {
451 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
452 ERROR("Error communicating with the wayland display");
453 return -1;
454 }
455 }
456
457 //create surface from compositor
458 if (mWlCompositor) {
459 mWlSurface = wl_compositor_create_surface(mWlCompositor);
460 wl_proxy_set_queue((struct wl_proxy*)mWlSurface, mWlQueue);
461 wl_display_flush( mWlDisplay );
462 }
463
464 if (mWlVpc && mWlSurface) {
465 mWlVpcSurface = wl_vpc_get_vpc_surface( mWlVpc, mWlSurface );
466 if (mWlVpcSurface) {
467 wl_vpc_surface_add_listener( mWlVpcSurface, &vpcListener, (void *)this);
468 wl_proxy_set_queue((struct wl_proxy*)mWlVpcSurface, mWlQueue);
469 wl_vpc_surface_set_geometry( mWlVpcSurface, mWindowX, mWindowY, mWindowWidth, mWindowHeight);
470 wl_display_flush(mWlDisplay);
471 }
472 }
473
474 DEBUG("out");
475 return 0;
476}
477
478void WstClientWayland::disconnectFromWayland()
479{
480 DEBUG("in");
481
482 if (isRunning()) {
483 TRACE("try stop dispatch thread");
484 requestExitAndWait();
485 }
486
487 if (mWlShell) {
488 wl_simple_shell_destroy(mWlShell);
489 mWlShell = NULL;
490 }
491
492 if (mWlVpcSurface) {
493 wl_vpc_surface_destroy(mWlVpcSurface);
494 mWlVpcSurface = NULL;
495 }
496
497 if (mWlVpc) {
498 wl_vpc_destroy(mWlVpc);
499 mWlVpc = NULL;
500 }
501
502 if (mWlSurface) {
503 wl_surface_destroy(mWlSurface);
504 mWlSurface = NULL;
505 }
506
507 if (mWlOutput) {
508 wl_output_destroy(mWlOutput);
509 mWlOutput = NULL;
510 }
511
512 if (mWlSb) {
513 wl_sb_destroy(mWlSb);
514 mWlSb = NULL;
515 }
516
517 if (mWlCompositor) {
518 wl_compositor_destroy (mWlCompositor);
519 mWlCompositor = NULL;
520 }
521
522 if (mWlRegistry) {
523 wl_registry_destroy (mWlRegistry);
524 mWlRegistry= NULL;
525 }
526
527 if (mWlQueue) {
528 wl_event_queue_destroy (mWlQueue);
529 mWlQueue = NULL;
530 }
531
532 if (mWlDisplay) {
533 wl_display_flush (mWlDisplay);
534 wl_display_disconnect (mWlDisplay);
535 mWlDisplay = NULL;
536 }
537
538 DEBUG("out");
539}
540
541void WstClientWayland::setWindowSize(int x, int y, int w, int h)
542{
543 if (x == 0 && y == 0 && w == 0 && h == 0) {
544 WARNING( "set full screen? %dx%dx%dx%d",x,y,w,h);
545 return;
546 }
547 mWindowX = x;
548 mWindowY = y;
549 mWindowWidth = w;
550 mWindowHeight = h;
551 mWindowChange = true;
552 mWindowSet = true;
553 mWindowSizeOverride = true;
554 DEBUG("set window size:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
555 if (mWlVpcSurface) {
556 DEBUG( "wl_vpc_surface_set_geometry(%d,%d,%d,%d)",mWindowX,mWindowY,mWindowWidth,mWindowHeight);
557 wl_vpc_surface_set_geometry(mWlVpcSurface, mWindowX, mWindowY, mWindowWidth, mWindowHeight);
558 }
559 //if window size is updated, update video position
560 if (mWlVpcSurface && mWindowChange && mScaleXDenom != 0 && mScaleYDenom != 0) {
561 mWindowChange = false;
562 updateVideoPosition();
563 }
564}
565
566void WstClientWayland::setFrameSize(int frameWidth, int frameHeight) {
567 mFrameWidth = frameWidth;
568 mFrameHeight = frameHeight;
569 DEBUG( "set frame size:%dx%d",mFrameWidth, mFrameHeight);
570}
571
572void WstClientWayland::setZoomMode(int zoomMode, bool globalZoomActive, bool allow4kZoom) {
573 DEBUG( "zoomMode:%d, globalZoomActive:%d, allow4kZoom:%d",zoomMode,globalZoomActive,allow4kZoom);
574 mZoomModeGlobal = globalZoomActive;
575 if ( !globalZoomActive )
576 {
577 mZoomMode = ZOOM_NONE;
578 }
579 mAllow4kZoom= allow4kZoom;
580 if ( mZoomModeGlobal == true )
581 {
582 if ( (zoomMode >= ZOOM_NONE) && (zoomMode <= ZOOM_ZOOM) )
583 {
584 mZoomMode = zoomMode;
585 mPixelAspectRatioChanged = true;
586 }
587 } else {
588 DEBUG( "global zoom disabled: ignore server value");
589 }
590}
591
592void WstClientWayland::getVideoBounds(int *x, int *y, int *w, int *h)
593{
594 int vx, vy, vw, vh;
595 int frameWidth, frameHeight;
596 int zoomMode;
597 double contentWidth, contentHeight;
598 double roix, roiy, roiw, roih;
599 double arf, ard;
600 double hfactor= 1.0, vfactor= 1.0;
601
602 //if wayland open fail,use the default window size
603 if (!mWlDisplay) {
604 *x = mWindowX;
605 *y = mWindowY;
606 *w = mWindowWidth;
607 *h = mWindowHeight;
608 TRACE( "no wldisplay, %d,%d,%d,%d",mVideoX,mVideoY,mVideoWidth,mVideoHeight);
609 return;
610 }
611
612 //if window size is updated, update video position
613 if (mWlVpcSurface && mWindowChange) {
614 mWindowChange = false;
615 updateVideoPosition();
616 }
617
618 vx = mVideoX;
619 vy = mVideoY;
620 vw = mVideoWidth;
621 vh = mVideoHeight;
622
623 TRACE( "videoX:%d,videoY:%d,videoW:%d,videoH:%d",mVideoX,mVideoY,mVideoWidth,mVideoHeight);
624 //if the window size is smaller than display size,we scall video to map window size
625 if (mWindowWidth != mDisplayWidth || mWindowHeight != mDisplayHeight) {
626 *x= vx;
627 *y= vy;
628 *w= vw;
629 *h= vh;
630 TRACE("small window vrect %d, %d, %d, %d", vx, vy, vw, vh);
631 return;
632 }
633 if (mForceFullScreen) {
634 *x= vx;
635 *y= vy;
636 *w= vw;
637 *h= vh;
638 TRACE("force window vrect %d, %d, %d, %d", vx, vy, vw, vh);
639 return;
640 }
641
642 frameWidth = mFrameWidth;
643 frameHeight = mFrameHeight;
644 contentWidth = frameWidth * mPixelAspectRatio;
645 contentHeight = frameHeight;
646
647 if (mPixelAspectRatioChanged)
648 DEBUG("pixelAspectRatio: %f zoom-mode %d", mPixelAspectRatio, mZoomMode);
649
650 ard = (double)mVideoWidth/(double)mVideoHeight;
651 arf = (double)contentWidth/(double)contentHeight;
652
653 TRACE( "frameWidth:%d,frameHeight:%d,contentWidth:%f,contentHeight:%f",frameWidth,frameHeight,contentWidth,contentHeight);
654
655 /* Establish region of interest */
656 roix = 0;
657 roiy = 0;
658 roiw = contentWidth;
659 roih = contentHeight;
660
661 zoomMode = mZoomMode;
662 if ((mFrameWidth > 1920) || (mFrameHeight > 1080))
663 {
664 zoomMode= ZOOM_NORMAL;
665 }
666 //if (mPixelAspectRatioChanged )
667 TRACE("ard %f arf %f", ard, arf);
668 switch ( zoomMode )
669 {
670 case ZOOM_NORMAL:
671 {
672 if ( arf >= ard )
673 {
674 vw = mVideoWidth * (1.0);
675 vh = (roih * vw) / roiw;
676 vx = vx+(mVideoWidth-vw)/2;
677 vy = vy+(mVideoHeight-vh)/2;
678 }
679 else
680 {
681 vh = mVideoHeight * (1.0);
682 vw = (roiw * vh) / roih;
683 vx = vx+(mVideoWidth-vw)/2;
684 vy = vy+(mVideoHeight-vh)/2;
685 }
686 }
687 break;
688 case ZOOM_NONE:
689 case ZOOM_DIRECT:
690 {
691 if ( arf >= ard )
692 {
693 vh = (contentHeight * mVideoWidth) / contentWidth;
694 vy = vy+(mVideoHeight-vh)/2;
695 }
696 else
697 {
698 vw = (contentWidth * mVideoHeight) / contentHeight;
699 vx = vx+(mVideoWidth-vw)/2;
700 }
701 }
702 break;
703 case ZOOM_16_9_STRETCH:
704 {
705 if ( approxEqual(arf, ard) && approxEqual(arf, 1.777) )
706 {
707 /* For 16:9 content on a 16:9 display, stretch as though 4:3 */
708 hfactor= 4.0/3.0;
709 if (mPixelAspectRatioChanged )
710 DEBUG("stretch apply vfactor %f hfactor %f", vfactor, hfactor);
711 }
712 vh = mVideoHeight * (1.0);
713 vw = vh*hfactor*16/9;
714 vx = vx+(mVideoWidth-vw)/2;
715 vy = vy+(mVideoHeight-vh)/2;
716 }
717 break;
718 case ZOOM_4_3_PILLARBOX:
719 {
720 vh = mVideoHeight * (1.0);
721 vw = vh*4/3;
722 vx = vx+(mVideoWidth-vw)/2;
723 vy = vy+(mVideoHeight-vh)/2;
724 }
725 break;
726 case ZOOM_ZOOM:
727 {
728 if ( arf >= ard )
729 {
730 if (approxEqual(arf, ard) && approxEqual( arf, 1.777) )
731 {
732 /* For 16:9 content on a 16:9 display, enlarge as though 4:3 */
733 vfactor= 4.0/3.0;
734 hfactor= 1.0;
735 if (mPixelAspectRatioChanged )
736 DEBUG("zoom apply vfactor %f hfactor %f", vfactor, hfactor);
737 }
738 vh = mVideoHeight * vfactor * (1.0);
739 vw = (roiw * vh) * hfactor / roih;
740 vx = vx+(mVideoWidth-vw)/2;
741 vy = vy+(mVideoHeight-vh)/2;
742 }
743 else
744 {
745 vw = mVideoWidth * (1.0);
746 vh = (roih * vw) / roiw;
747 vx = vx+(mVideoWidth-vw)/2;
748 vy = vy+(mVideoHeight-vh)/2;
749 }
750 }
751 break;
752 }
753 if (mPixelAspectRatioChanged) DEBUG("vrect %d, %d, %d, %d", vx, vy, vw, vh);
754 if (mPixelAspectRatioChanged)
755 {
756 if (mWlDisplay && mWlVpcSurface )
757 {
758 wl_vpc_surface_set_geometry(mWlVpcSurface, mWindowX, mWindowY, mWindowWidth, mWindowHeight);
759 wl_display_flush(mWlDisplay);
760 }
761 }
762 mPixelAspectRatioChanged = false;
763 *x= vx;
764 *y= vy;
765 *w= vw;
766 *h= vh;
767 TRACE("vrect %d, %d, %d, %d", vx, vy, vw, vh);
768}
769
770void WstClientWayland::setTextureCrop(int vx, int vy, int vw, int vh)
771{
772 DEBUG("vx %d vy %d vw %d vh %d window(%d, %d, %d, %d) display(%dx%d)", \
773 vx, vy, vw, vh, mWindowX, mWindowY, mWindowWidth, mWindowHeight, mDisplayWidth, mDisplayHeight);
774 if ( (mDisplayWidth != -1) && (mDisplayHeight != -1) &&
775 ( (vx < 0) || (vx+vw > mDisplayWidth) ||
776 (vy < 0) || (vy+vh > mDisplayHeight) ) )
777 {
778 int cropx, cropy, cropw, croph;
779 int wx1, wx2, wy1, wy2;
780 cropx= 0;
781 cropw= mWindowWidth;
782 cropy= 0;
783 croph= mWindowHeight;
784 if ( (vx < mWindowX) || (vx+vw > mWindowX+mWindowWidth) )
785 {
786 cropx= (mWindowX-vx)*mWindowWidth/vw;
787 cropw= (mWindowX+mWindowWidth-vx)*mWindowWidth/vw - cropx;
788 }
789 else if ( vx < 0 )
790 {
791 cropx= -vx*mWindowWidth/vw;
792 cropw= (vw+vx)*mWindowWidth/vw;
793 }
794 else if ( vx+vw > mWindowWidth )
795 {
796 cropx= 0;
797 cropw= (mWindowWidth-vx)*mWindowWidth/vw;
798 }
799
800 if ( (vy < mWindowY) || (vy+vh > mWindowY+mWindowHeight) )
801 {
802 cropy= (mWindowY-vy)*mWindowHeight/vh;
803 croph= (mWindowY+mWindowHeight-vy)*mWindowHeight/vh - cropy;
804 }
805 else if ( vy < 0 )
806 {
807 cropy= -vy*mWindowHeight/vh;
808 croph= (vh+vy)*mWindowHeight/vh;
809 }
810 else if ( vy+vh > mWindowHeight )
811 {
812 cropy= 0;
813 croph= (mWindowHeight-vy)*mWindowHeight/vh;
814 }
815
816 wx1 = vx;
817 wx2 = vx+vw;
818 wy1 = vy;
819 wy2 = vy+vh;
820 vx = mWindowX;
821 vy = mWindowY;
822 vw = mWindowWidth;
823 vh = mWindowHeight;
824 if ( (wx1 > vx) && (wx1 > 0) )
825 {
826 vx= wx1;
827 }
828 else if ( (wx1 >= vx) && (wx1 < 0) )
829 {
830 vw += wx1;
831 vx= 0;
832 }
833 else if ( wx2 < vx+vw )
834 {
835 vw= wx2-vx;
836 }
837 if ( (wx1 >= 0) && (wx2 > vw) )
838 {
839 vw= vw-wx1;
840 }
841 else if ( wx2 < vx+vw )
842 {
843 vw= wx2-vx;
844 }
845
846 if ( (wy1 > vy) && (wy1 > 0) )
847 {
848 vy= wy1;
849 }
850 else if ( (wy1 >= vy) && (wy1 < 0) )
851 {
852 vy= 0;
853 }
854 else if ( (wy1 < vy) && (wy1 > 0) )
855 {
856 vh -= wy1;
857 }
858 if ( (wy1 >= 0) && (wy2 > vh) )
859 {
860 vh= vh-wy1;
861 }
862 else if ( wy2 < vy+vh )
863 {
864 vh= wy2-vy;
865 }
866 if ( vw < 0 ) vw= 0;
867 if ( vh < 0 ) vh= 0;
868 cropx= (cropx*WL_VPC_SURFACE_CROP_DENOM)/mWindowWidth;
869 cropy= (cropy*WL_VPC_SURFACE_CROP_DENOM)/mWindowHeight;
870 cropw= (cropw*WL_VPC_SURFACE_CROP_DENOM)/mWindowWidth;
871 croph= (croph*WL_VPC_SURFACE_CROP_DENOM)/mWindowHeight;
872 DEBUG("%d, %d, %d, %d - %d, %d, %d, %d", vx, vy, vw, vh, cropx, cropy, cropw, croph);
873 if (mWlVpcSurface) {
874 wl_vpc_surface_set_geometry_with_crop(mWlVpcSurface, vx, vy, vw, vh, cropx, cropy, cropw, croph );
875 }
876 }
877 else
878 {
879 if (mWlVpcSurface) {
880 wl_vpc_surface_set_geometry(mWlVpcSurface, mWindowX, mWindowY, mWindowWidth, mWindowHeight);
881 }
882 }
883}
884
885void WstClientWayland::setForceAspectRatio(bool force)
886{
887 DEBUG( "force aspect ratio:%d",force);
888 mForceAspectRatio = force;
889}
890
891void WstClientWayland::setPixelAspectRatio(double ratio)
892{
893 mPixelAspectRatio = ratio;
894 mPixelAspectRatioChanged = true;
895 INFO( "set aspect ratio:%f",ratio);
896}
897
898void WstClientWayland::updateVideoPosition()
899{
900 bool needUpdate= true;
901 int vx, vy, vw, vh;
902 vx= mVideoX;
903 vy= mVideoY;
904 vw= mVideoWidth;
905 vh= mVideoHeight;
906
907 if (mWindowSizeOverride)
908 {
909 mVideoX= ((mWindowX*mScaleXNum)/mScaleXDenom) + mTransX;
910 mVideoY= ((mWindowY*mScaleYNum)/mScaleYDenom) + mTransY;
911 mVideoWidth= (mWindowWidth*mScaleXNum)/mScaleXDenom;
912 mVideoHeight= (mWindowHeight*mScaleYNum)/mScaleYDenom;
913 DEBUG( "window override video rectangle(%d,%d,%d,%d)",mVideoX,mVideoY,mVideoWidth,mVideoHeight);
914 }
915 else
916 {
917 mVideoX = mTransX;
918 mVideoY = mTransY;
919 mVideoWidth = (mOutputWidth*mScaleXNum)/mScaleXDenom;
920 mVideoHeight = (mOutputHeight*mScaleYNum)/mScaleYDenom;
921 DEBUG( "video rectangle(%d,%d,%d,%d)",mVideoX,mVideoY,mVideoWidth,mVideoHeight);
922 }
923
924 if (vx == mVideoX && vy == mVideoY && vw == mVideoWidth && vh == mVideoHeight) {
925 needUpdate = false;
926 }
927
928 if (needUpdate) {
929 /* Send a buffer to compositor to update hole punch geometry */
930 if (mWlSb)
931 {
932 struct wl_buffer *buff;
933
934 buff = wl_sb_create_buffer( mWlSb,
935 0,
936 mWindowWidth,
937 mWindowHeight,
938 mWindowWidth*4,
939 WL_SB_FORMAT_ARGB8888 );
940 wl_surface_attach(mWlSurface, buff, mWindowX, mWindowY);
941 wl_surface_damage(mWlSurface, 0, 0, mWindowWidth, mWindowHeight);
942 wl_surface_commit(mWlSurface);
943 }
944 if (mVideoPaused && mPlugin)
945 {
946 mPlugin->setVideoRect(mVideoX, mVideoY, mVideoWidth, mVideoHeight);
947 }
948 }
949}
950
951void WstClientWayland::setVideoPath(bool useGfxPath )
952{
953 INFO("useGfxPath:%d",useGfxPath);
954 if ( needBounds() && mWlVpcSurface )
955 {
956 /* Use nominal display size provided to us by
957 * the compositor to calculate the video bounds
958 * we should use when we transition to graphics path.
959 * Save and restore current HW video rectangle. */
960 int vx, vy, vw, vh;
961 int tx, ty, tw, th;
962 tx = mVideoX;
963 ty = mVideoY;
964 tw = mVideoWidth;
965 th = mVideoHeight;
966 mVideoX = mWindowX;
967 mVideoY = mWindowY;
968 mVideoWidth = mWindowWidth;
969 mVideoHeight = mWindowHeight;
970
971 DEBUG( "video rect (%d,%d,%d,%d)",mVideoX,mVideoY,mVideoWidth,mVideoHeight);
972
973 if (mFrameWidth > 0 && mFrameHeight > 0) {
974 getVideoBounds(&vx, &vy, &vw, &vh);
975 setTextureCrop(vx, vy, vw, vh);
976 }
977
978 mVideoX = tx;
979 mVideoY = ty;
980 mVideoWidth = tw;
981 mVideoHeight = th;
982 }
983}
984
985bool WstClientWayland::approxEqual( double v1, double v2 )
986{
987 bool result= false;
988 if ( v1 >= v2 )
989 {
990 if ( (v1-v2) < 0.001 )
991 {
992 result= true;
993 }
994 }
995 else
996 {
997 if ( (v2-v1) < 0.001 )
998 {
999 result= true;
1000 }
1001 }
1002 return result;
1003}
1004
1005void WstClientWayland::readyToRun()
1006{
1007 mFd = wl_display_get_fd (mWlDisplay);
1008}
1009
1010bool WstClientWayland::threadLoop()
1011{
1012 struct pollfd pfd;
1013 int ret;
1014
1015 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1016 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1017 }
1018
1019 pfd.fd = mFd;
1020 pfd.events = POLLERR | POLLNVAL | POLLHUP |POLLIN | POLLPRI | POLLRDNORM;
1021 pfd.revents = 0;
1022
1023 wl_display_flush (mWlDisplay);
1024
1025 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed*/
1026 ret = poll(&pfd, 1, 500);
1027 if (ret < 0) { //poll error
1028 WARNING("poll error");
1029 wl_display_cancel_read(mWlDisplay);
1030 return false;
1031 } else if (ret == 0) { //poll time out
1032 return true; //run loop
1033 }
1034
1035 if (wl_display_read_events (mWlDisplay) == -1) {
1036 goto tag_error;
1037 }
1038
1039 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1040 return true;
1041tag_error:
1042 ERROR("Error communicating with the wayland server");
1043 return false;
1044}
1045
1046void WstClientWayland::executeCmd(const char *cmd) {
1047 INFO("%s", cmd);
1048 FILE* pFile = popen(cmd, "r");
1049 char buf[128];
1050 char* retStr = fgets(buf, sizeof(buf), pFile);
1051 INFO("ret= %s", retStr);
1052 pclose(pFile);
1053}