3fdea334f90bafc364fbf72fdb136e8f53c30826
[platform/upstream/gstreamer.git] / ext / wayland / wlwindow.c
1 /* GStreamer Wayland video sink
2  *
3  * Copyright (C) 2011 Intel Corporation
4  * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
5  * Copyright (C) 2014 Collabora Ltd.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301 USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #ifdef GST_WLSINK_ENHANCEMENT
27 #include "gstwaylandsink.h"
28 #else
29 #include "wlwindow.h"
30 #endif
31 #include "wlshmallocator.h"
32 #include "wlbuffer.h"
33
34 enum
35 {
36   ROTATE_0_FLIP_NONE,
37   ROTATE_0_FLIP_HORIZONTAL,
38   ROTATE_0_FLIP_VERTICAL,
39   ROTATE_0_FLIP_BOTH,
40   ROTATE_90_FLIP_NONE = 10,
41   ROTATE_90_FLIP_HORIZONTAL,
42   ROTATE_90_FLIP_VERTICAL,
43   ROTATE_90_FLIP_BOTH,
44   ROTATE_180_FLIP_NONE = 20,
45   ROTATE_180_FLIP_HORIZONTAL,
46   ROTATE_180_FLIP_VERTICAL,
47   ROTATE_180_FLIP_BOTH,
48   ROTATE_270_FLIP_NONE = 30,
49   ROTATE_270_FLIP_HORIZONTAL,
50   ROTATE_270_FLIP_VERTICAL,
51   ROTATE_270_FLIP_BOTH,
52   ROTATE_NUM,
53 };
54
55 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
56 #define GST_CAT_DEFAULT gstwayland_debug
57
58 G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT);
59
60 static void gst_wl_window_finalize (GObject * gobject);
61
62 static void
63 handle_ping (void *data, struct wl_shell_surface *shell_surface,
64     uint32_t serial)
65 {
66   wl_shell_surface_pong (shell_surface, serial);
67 }
68
69 static void
70 handle_configure (void *data, struct wl_shell_surface *shell_surface,
71     uint32_t edges, int32_t width, int32_t height)
72 {
73 }
74
75 static void
76 handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
77 {
78 }
79
80 static const struct wl_shell_surface_listener shell_surface_listener = {
81   handle_ping,
82   handle_configure,
83   handle_popup_done
84 };
85
86 static void
87 gst_wl_window_class_init (GstWlWindowClass * klass)
88 {
89   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
90   FUNCTION;
91   gobject_class->finalize = gst_wl_window_finalize;
92 }
93
94 static void
95 gst_wl_window_init (GstWlWindow * self)
96 {
97 }
98
99 static void
100 gst_wl_window_finalize (GObject * gobject)
101 {
102   GstWlWindow *self = GST_WL_WINDOW (gobject);
103   FUNCTION;
104
105 #ifdef GST_WLSINK_ENHANCEMENT
106   if (self->video_object)
107     tizen_video_object_destroy (self->video_object);
108 #endif
109
110   if (self->shell_surface) {
111     wl_shell_surface_destroy (self->shell_surface);
112   }
113
114   wl_viewport_destroy (self->video_viewport);
115   wl_subsurface_destroy (self->video_subsurface);
116   wl_surface_destroy (self->video_surface);
117
118   if (self->area_subsurface) {
119     wl_subsurface_destroy (self->area_subsurface);
120   }
121   wl_viewport_destroy (self->area_viewport);
122   wl_surface_destroy (self->area_surface);
123
124   g_clear_object (&self->display);
125
126   G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject);
127 }
128
129 #ifdef GST_WLSINK_ENHANCEMENT
130 static void
131 gst_wl_window_map_sub_surface (GstWlDisplay * display, GstWlWindow * window,
132     GstVideoInfo * info)
133 {
134   /* A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
135    * and the parent surface is mapped */
136   GstBuffer *buf;
137   GstMapInfo mapinfo;
138   struct wl_buffer *wlbuf;
139   GstWlBuffer *gwlbuf;
140   GstWlShmAllocator *self = NULL;
141   FUNCTION;
142   g_return_val_if_fail (display, NULL);
143   g_return_val_if_fail (window, NULL);
144   g_return_val_if_fail (info, NULL);
145
146   self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
147   self->display = display;
148
149   buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info->size, NULL);
150   gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
151   *((guint32 *) mapinfo.data) = 0;      /* paint it black */
152   gst_buffer_unmap (buf, &mapinfo);
153   wlbuf =
154       gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
155       display, info);
156
157   gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
158   gst_wl_buffer_attach (gwlbuf, window->area_surface);
159
160   /* at this point, the GstWlBuffer keeps the buffer
161    * alive and will free it on wl_buffer::release */
162   gst_buffer_unref (buf);
163 }
164 #endif
165
166 static GstWlWindow *
167 #ifdef GST_WLSINK_ENHANCEMENT
168 gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *parent)
169 #else
170 gst_wl_window_new_internal (GstWlDisplay * display)
171 #endif
172 {
173   GstWlWindow *window;
174   GstVideoInfo info;
175 #ifndef GST_WLSINK_ENHANCEMENT
176   GstBuffer *buf;
177   GstMapInfo mapinfo;
178   struct wl_buffer *wlbuf;
179   GstWlBuffer *gwlbuf;
180 #endif
181   struct wl_region *region;
182   FUNCTION;
183
184   window = g_object_new (GST_TYPE_WL_WINDOW, NULL);
185   window->display = g_object_ref (display);
186
187   window->area_surface = wl_compositor_create_surface (display->compositor);
188   window->video_surface = wl_compositor_create_surface (display->compositor);
189
190   wl_proxy_set_queue ((struct wl_proxy *) window->area_surface, display->queue);
191   wl_proxy_set_queue ((struct wl_proxy *) window->video_surface,
192       display->queue);
193
194 #if 1                           /* create shell_surface here for enlightenment */
195   /* go toplevel */
196   if (display->need_shell_surface) {
197     window->shell_surface = wl_shell_get_shell_surface (display->shell,
198         window->area_surface);
199   } else if (display->use_parent_wl_surface) {
200 #ifdef GST_WLSINK_ENHANCEMENT
201     GST_INFO ("call tizen_policy_get_subsurface");
202     if (display->wl_surface_id && parent == NULL) {
203       window->area_subsurface =
204           tizen_policy_get_subsurface (display->tizen_policy,
205           window->area_surface, display->wl_surface_id);
206       wl_subsurface_set_desync (window->area_subsurface);
207       wl_surface_commit (window->area_surface);
208     } else {
209       GST_INFO (" wl_surface %p", parent);
210       window->area_subsurface =
211           wl_subcompositor_get_subsurface (display->subcompositor,
212           window->area_surface, parent);
213       wl_subsurface_set_desync (window->area_subsurface);
214     }
215 #else
216     window->area_subsurface =
217         wl_subcompositor_get_subsurface (display->subcompositor,
218         window->area_surface, parent);
219     wl_subsurface_set_desync (window->area_subsurface);
220 #endif
221   }
222 #endif
223
224   /* embed video_surface in area_surface */
225   window->video_subsurface =
226       wl_subcompositor_get_subsurface (display->subcompositor,
227       window->video_surface, window->area_surface);
228   wl_subsurface_set_desync (window->video_subsurface);
229   wl_surface_commit (window->video_surface);
230
231   window->area_viewport = wl_scaler_get_viewport (display->scaler,
232       window->area_surface);
233   window->video_viewport = wl_scaler_get_viewport (display->scaler,
234       window->video_surface);
235
236   /* draw the area_subsurface */
237   gst_video_info_set_format (&info,
238       /* we want WL_SHM_FORMAT_XRGB8888 */
239 #if G_BYTE_ORDER == G_BIG_ENDIAN
240       GST_VIDEO_FORMAT_xRGB,
241 #else
242       GST_VIDEO_FORMAT_BGRx,
243 #endif
244       1, 1);
245
246 #ifdef GST_WLSINK_ENHANCEMENT
247   if (window->display->USE_TBM) {
248     /* Inform enlightenment of surface which render video */
249     window->video_object =
250         tizen_video_get_object (display->tizen_video, window->video_surface);
251
252     /* to use shm memory for mapping sub-surface, set FALSE to USE_TBM*/
253     window->display->USE_TBM = FALSE;
254     gst_wl_window_map_sub_surface (display, window, &info);
255     /*restore USE_TBM*/
256     window->display->USE_TBM = TRUE;
257   } else {
258     gst_wl_window_map_sub_surface (display, window, &info);
259   }
260 #else /* open source */
261   buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info.size, NULL);
262   gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
263   *((guint32 *) mapinfo.data) = 0;      /* paint it black */
264   gst_buffer_unmap (buf, &mapinfo);
265   wlbuf =
266       gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
267       display, &info);
268   gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
269   gst_wl_buffer_attach (gwlbuf, window->area_surface);
270
271   /* at this point, the GstWlBuffer keeps the buffer
272    * alive and will free it on wl_buffer::release */
273   gst_buffer_unref (buf);
274 #endif
275
276   /* do not accept input */
277   region = wl_compositor_create_region (display->compositor);
278   wl_surface_set_input_region (window->area_surface, region);
279   wl_region_destroy (region);
280
281   region = wl_compositor_create_region (display->compositor);
282   wl_surface_set_input_region (window->video_surface, region);
283   wl_region_destroy (region);
284
285   return window;
286 }
287
288 GstWlWindow *
289 gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info)
290 {
291   GstWlWindow *window;
292   gint width;
293   FUNCTION;
294
295 /* not create shell_surface here for enlightenment */
296 #ifdef GST_WLSINK_ENHANCEMENT
297   display->need_shell_surface = TRUE;
298
299   window = gst_wl_window_new_internal (display, NULL);
300
301 #if 0                           //GST_WLSINK_ENHANCEMENT
302   /* go toplevel */
303   window->shell_surface = wl_shell_get_shell_surface (display->shell,
304       window->area_surface);
305 #endif
306 #endif
307   if (window->shell_surface) {
308     wl_shell_surface_add_listener (window->shell_surface,
309         &shell_surface_listener, window);
310     wl_shell_surface_set_toplevel (window->shell_surface);
311   } else {
312     GST_ERROR ("Unable to get wl_shell_surface");
313
314     g_object_unref (window);
315     return NULL;
316   }
317
318   /* set the initial size to be the same as the reported video size */
319   width =
320       gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
321   gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
322
323   return window;
324 }
325
326 GstWlWindow *
327 gst_wl_window_new_in_surface (GstWlDisplay * display,
328     struct wl_surface * parent)
329 {
330   GstWlWindow *window;
331   FUNCTION;
332
333   display->use_parent_wl_surface = TRUE;
334 #ifdef GST_WLSINK_ENHANCEMENT
335   if (parent) {                 /*use wl_surface */
336     window = gst_wl_window_new_internal (display, parent);
337   } else {                      /* use wl_surface id */
338     window = gst_wl_window_new_internal (display, NULL);
339   }
340 #else
341   window = gst_wl_window_new_internal (display, parent);
342 #endif
343
344 #if 0                           /*for enlightment */
345   /* embed in parent */
346   window->area_subsurface =
347       wl_subcompositor_get_subsurface (display->subcompositor,
348       window->area_surface, parent);
349   wl_subsurface_set_desync (window->area_subsurface);
350 #endif
351
352 #ifdef GST_WLSINK_ENHANCEMENT
353   /*Area surface from App need to be under parent surface */
354   if (display->tizen_policy) {
355     GST_INFO (" call tizen_policy_place_subsurface_below_parent ");
356     tizen_policy_place_subsurface_below_parent (display->tizen_policy,
357         window->area_subsurface);
358     tizen_policy_place_subsurface_below_parent (display->tizen_policy,
359         window->video_subsurface);
360   }
361 #else
362   wl_surface_commit (parent);
363 #endif
364   return window;
365 }
366
367 GstWlDisplay *
368 gst_wl_window_get_display (GstWlWindow * window)
369 {
370   FUNCTION;
371   g_return_val_if_fail (window != NULL, NULL);
372
373   return g_object_ref (window->display);
374 }
375
376 struct wl_surface *
377 gst_wl_window_get_wl_surface (GstWlWindow * window)
378 {
379   FUNCTION;
380   g_return_val_if_fail (window != NULL, NULL);
381
382   return window->video_surface;
383 }
384
385 gboolean
386 gst_wl_window_is_toplevel (GstWlWindow * window)
387 {
388   FUNCTION;
389   g_return_val_if_fail (window != NULL, FALSE);
390
391   return (window->shell_surface != NULL);
392 }
393
394 #ifdef GST_WLSINK_ENHANCEMENT
395 static gint
396 gst_wl_window_find_transform (guint rotate_angle, guint flip)
397 {
398   gint transform;
399   guint combine = rotate_angle * 10 + flip;
400   FUNCTION;
401   GST_DEBUG ("rotate %d, flip %d, combine %d", rotate_angle, flip, combine);
402   switch (combine) {
403     case ROTATE_0_FLIP_NONE:
404       transform = WL_OUTPUT_TRANSFORM_NORMAL;
405       break;
406     case ROTATE_0_FLIP_HORIZONTAL:
407       transform = WL_OUTPUT_TRANSFORM_FLIPPED;
408       break;
409     case ROTATE_0_FLIP_VERTICAL:
410       transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
411       break;
412     case ROTATE_0_FLIP_BOTH:
413       transform = WL_OUTPUT_TRANSFORM_180;
414       break;
415     case ROTATE_90_FLIP_NONE:
416       transform = WL_OUTPUT_TRANSFORM_90;
417       break;
418     case ROTATE_90_FLIP_HORIZONTAL:
419       transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
420       break;
421     case ROTATE_90_FLIP_VERTICAL:
422       transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
423       break;
424     case ROTATE_90_FLIP_BOTH:
425       transform = WL_OUTPUT_TRANSFORM_270;
426       break;
427     case ROTATE_180_FLIP_NONE:
428       transform = WL_OUTPUT_TRANSFORM_180;
429       break;
430     case ROTATE_180_FLIP_HORIZONTAL:
431       transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
432       break;
433     case ROTATE_180_FLIP_VERTICAL:
434       transform = WL_OUTPUT_TRANSFORM_FLIPPED;
435       break;
436     case ROTATE_180_FLIP_BOTH:
437       transform = WL_OUTPUT_TRANSFORM_NORMAL;
438       break;
439     case ROTATE_270_FLIP_NONE:
440       transform = WL_OUTPUT_TRANSFORM_270;
441       break;
442     case ROTATE_270_FLIP_HORIZONTAL:
443       transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
444       break;
445     case ROTATE_270_FLIP_VERTICAL:
446       transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
447       break;
448     case ROTATE_270_FLIP_BOTH:
449       transform = WL_OUTPUT_TRANSFORM_90;
450       break;
451   }
452
453   return transform;
454 }
455
456 #endif
457 static void
458 gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit)
459 {
460   GstVideoRectangle src = { 0, };
461   GstVideoRectangle res;
462 #ifdef GST_WLSINK_ENHANCEMENT   // need to change ifndef to ifdef
463   GstVideoRectangle src_origin = { 0, 0, 0, 0 };
464   GstVideoRectangle src_input = { 0, 0, 0, 0 };
465   GstVideoRectangle dst = { 0, 0, 0, 0 };
466   int temp = 0;
467   gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
468 #endif
469   FUNCTION;
470
471   /* center the video_subsurface inside area_subsurface */
472   src.w = window->video_width;
473   src.h = window->video_height;
474
475 #ifdef GST_WLSINK_ENHANCEMENT   // need to change ifndef to ifdef
476   src.x = src.y = 0;
477   src_input.w = src_origin.w = window->video_width;
478   src_input.h = src_origin.h = window->video_height;
479   GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
480   GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
481       src_input.h);
482   GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
483       src_origin.w, src_origin.h);
484
485   if (window->rotate_angle == DEGREE_0 || window->rotate_angle == DEGREE_180) {
486     src.w = window->video_width;        //video_width
487     src.h = window->video_height;       //video_height
488   } else {
489     src.w = window->video_height;
490     src.h = window->video_width;
491   }
492   GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
493
494   /*default res.w and res.h */
495   dst.w = window->render_rectangle.w;
496   dst.h = window->render_rectangle.h;
497   dst.x = window->render_rectangle.x;
498   dst.y = window->render_rectangle.y;
499
500   GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
501   GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
502       window->render_rectangle.x, window->render_rectangle.y,
503       window->render_rectangle.w, window->render_rectangle.h);
504   switch (window->disp_geo_method) {
505     case DISP_GEO_METHOD_LETTER_BOX:
506       GST_INFO ("DISP_GEO_METHOD_LETTER_BOX");
507       gst_video_sink_center_rect (src, dst, &res, TRUE);
508       break;
509     case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
510       if (src.w > dst.w || src.h > dst.h) {
511         /*LETTER BOX */
512         GST_INFO
513             ("DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX -> set LETTER BOX");
514         gst_video_sink_center_rect (src, dst, &res, TRUE);
515       } else {
516         /*ORIGIN SIZE */
517         GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
518         gst_video_sink_center_rect (src, dst, &res, FALSE);
519         gst_video_sink_center_rect (dst, src, &src_input, FALSE);
520       }
521       break;
522     case DISP_GEO_METHOD_ORIGIN_SIZE:  //is working
523       GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
524       gst_video_sink_center_rect (src, dst, &res, FALSE);
525       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
526       break;
527     case DISP_GEO_METHOD_FULL_SCREEN:  //is working
528       GST_INFO ("DISP_GEO_METHOD_FULL_SCREEN");
529       res.x = res.y = 0;
530       res.w = window->render_rectangle.w;
531       res.h = window->render_rectangle.h;
532       break;
533     case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
534       GST_INFO ("DISP_GEO_METHOD_CROPPED_FULL_SCREEN");
535       gst_video_sink_center_rect (src, dst, &res, FALSE);
536       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
537       res.x = res.y = 0;
538       res.w = dst.w;
539       res.h = dst.h;
540       break;
541     default:
542       break;
543   }
544
545   transform = gst_wl_window_find_transform (window->rotate_angle, window->flip);
546
547   GST_INFO
548       ("window[%d x %d] src[%d,%d,%d x %d],dst[%d,%d,%d x %d],input[%d,%d,%d x %d],result[%d,%d,%d x %d]",
549       window->render_rectangle.w, window->render_rectangle.h,
550       src.x, src.y, src.w, src.h,
551       dst.x, dst.y, dst.w, dst.h,
552       src_input.x, src_input.y, src_input.w, src_input.h,
553       res.x, res.y, res.w, res.h);
554
555   GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
556   GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
557       src_input.h);
558   GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
559       src_origin.w, src_origin.h);
560   GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
561   GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
562   GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
563       window->render_rectangle.x, window->render_rectangle.y,
564       window->render_rectangle.w, window->render_rectangle.h);
565   GST_INFO ("res(%d, %d, %d x %d)", res.x, res.y, res.w, res.h);
566
567   if (window->video_subsurface) {
568     GST_INFO ("have window->subsurface");
569     wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
570     GST_INFO ("wl_subsurface_set_position(%d,%d)", res.x, res.y);
571   }
572   wl_viewport_set_destination (window->video_viewport, res.w, res.h);
573   GST_INFO ("wl_viewport_set_destination(%d,%d)", res.w, res.h);
574
575   /*need to swap */
576   if (transform % 2 == 1) {     /*1, 3, 5, 7 */
577     temp = src_input.w;
578     src_input.w = src_input.h;
579     src_input.h = temp;
580   }
581   wl_viewport_set_source (window->video_viewport,
582       wl_fixed_from_int (src_input.x), wl_fixed_from_int (src_input.y),
583       wl_fixed_from_int (src_input.w), wl_fixed_from_int (src_input.h));
584   GST_INFO ("wl_viewport_set_source(%d,%d, %d x %d)", src_input.x, src_input.y,
585       src_input.w, src_input.h);
586
587   wl_surface_set_buffer_transform (window->video_surface, transform);
588   GST_INFO ("wl_surface_set_buffer_transform (%d)", transform);
589 #else
590   gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE);
591
592   wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
593   wl_viewport_set_destination (window->video_viewport, res.w, res.h);
594 #endif
595   if (commit) {
596     wl_surface_damage (window->video_surface, 0, 0, res.w, res.h);
597     wl_surface_commit (window->video_surface);
598   }
599
600   if (gst_wl_window_is_toplevel (window)) {
601     struct wl_region *region;
602
603     region = wl_compositor_create_region (window->display->compositor);
604     wl_region_add (region, 0, 0, window->render_rectangle.w,
605         window->render_rectangle.h);
606     wl_surface_set_input_region (window->area_surface, region);
607     wl_region_destroy (region);
608   }
609
610   /* this is saved for use in wl_surface_damage */
611   window->surface_width = res.w;
612   window->surface_height = res.h;
613 }
614
615 void
616 gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer,
617     const GstVideoInfo * info)
618 {
619   FUNCTION;
620   if (G_UNLIKELY (info)) {
621     window->video_width =
622         gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
623     window->video_height = info->height;
624
625     wl_subsurface_set_sync (window->video_subsurface);
626     gst_wl_window_resize_video_surface (window, FALSE);
627   }
628   GST_INFO ("GstWlBuffer(%p)", buffer);
629   if (G_LIKELY (buffer))
630     gst_wl_buffer_attach (buffer, window->video_surface);
631   else
632     wl_surface_attach (window->video_surface, NULL, 0, 0);
633
634   /*Wayland-compositor will try to render damage area which need  to be updated */
635   wl_surface_damage (window->video_surface, 0, 0, window->surface_width,
636       window->surface_height);
637 #ifdef GST_WLSINK_ENHANCEMENT
638   GST_LOG ("update area width %d, height %d", window->surface_width,
639       window->surface_height);
640 #endif
641   /* wl_surface_commit change surface state, if wl_buffer is not attached newly,  then surface is not changed */
642   wl_surface_commit (window->video_surface);
643
644   if (G_UNLIKELY (info)) {
645     /* commit also the parent (area_surface) in order to change
646      * the position of the video_subsurface */
647 #ifdef GST_WLSINK_ENHANCEMENT
648     GST_DEBUG ("render_rectangle %d*%d", window->render_rectangle.w,
649         window->render_rectangle.h);
650 #endif
651     wl_surface_damage (window->area_surface, 0, 0, window->render_rectangle.w,
652         window->render_rectangle.h);
653     wl_surface_commit (window->area_surface);
654     wl_subsurface_set_desync (window->video_subsurface);
655   }
656
657   wl_display_flush (window->display->display);
658 }
659
660 void
661 gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
662     gint w, gint h)
663 {
664   FUNCTION;
665   g_return_if_fail (window != NULL);
666 #ifdef GST_WLSINK_ENHANCEMENT
667   if (window->render_rectangle.x == x && window->render_rectangle.y == y
668       && window->render_rectangle.w == w && window->render_rectangle.h == h) {
669     GST_DEBUG ("but the values are same. skip");
670     return;
671   }
672 #endif
673   window->render_rectangle.x = x;
674   window->render_rectangle.y = y;
675   window->render_rectangle.w = w;
676   window->render_rectangle.h = h;
677
678   /* position the area inside the parent - needs a parent commit to apply */
679   if (window->area_subsurface)
680     wl_subsurface_set_position (window->area_subsurface, x, y);
681
682   /* change the size of the area */
683   wl_viewport_set_destination (window->area_viewport, w, h);
684
685   if (window->video_width != 0) {
686     wl_subsurface_set_sync (window->video_subsurface);
687     gst_wl_window_resize_video_surface (window, TRUE);
688   }
689
690   wl_surface_damage (window->area_surface, 0, 0, w, h);
691   wl_surface_commit (window->area_surface);
692
693   if (window->video_width != 0)
694     wl_subsurface_set_desync (window->video_subsurface);
695 }
696
697 #ifdef GST_WLSINK_ENHANCEMENT
698 void
699 gst_wl_window_set_video_info (GstWlWindow * window, const GstVideoInfo * info)
700 {
701   FUNCTION;
702   g_return_if_fail (window != NULL);
703
704   window->video_width =
705       gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
706   window->video_height = info->height;
707
708   if (window->render_rectangle.w != 0)
709     gst_wl_window_resize_video_surface (window, FALSE);
710 }
711
712 void
713 gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle)
714 {
715   FUNCTION;
716   g_return_if_fail (window != NULL);
717   window->rotate_angle = rotate_angle;
718   GST_INFO ("rotate_angle value is (%d)", window->rotate_angle);
719 }
720
721 void
722 gst_wl_window_set_disp_geo_method (GstWlWindow * window, guint disp_geo_method)
723 {
724   FUNCTION;
725   g_return_if_fail (window != NULL);
726   window->disp_geo_method = disp_geo_method;
727   GST_INFO ("disp_geo_method value is (%d)", window->disp_geo_method);
728 }
729
730 void
731 gst_wl_window_set_orientation (GstWlWindow * window, guint orientation)
732 {
733   FUNCTION;
734   g_return_if_fail (window != NULL);
735   window->orientation = orientation;
736   GST_INFO ("orientation value is (%d)", window->orientation);
737 }
738
739 void
740 gst_wl_window_set_flip (GstWlWindow * window, guint flip)
741 {
742   FUNCTION;
743   g_return_if_fail (window != NULL);
744   window->flip = flip;
745   GST_INFO ("flip value is (%d)", window->flip);
746 }
747 #endif