waylandsink : apply keeping camera preview
[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     /* for internal window */
198     window->shell_surface = wl_shell_get_shell_surface (display->shell,
199         window->area_surface);
200   } else if (display->use_parent_wl_surface) {
201 #ifdef GST_WLSINK_ENHANCEMENT
202     GST_INFO ("call tizen_policy_get_subsurface");
203     if (display->wl_surface_id && parent == NULL) {
204       window->area_subsurface =
205           tizen_policy_get_subsurface (display->tizen_policy,
206           window->area_surface, display->wl_surface_id);
207       wl_subsurface_set_desync (window->area_subsurface);
208       wl_surface_commit (window->area_surface);
209     } else {
210       GST_INFO (" wl_surface %p", parent);
211       window->area_subsurface =
212           wl_subcompositor_get_subsurface (display->subcompositor,
213           window->area_surface, parent);
214       wl_subsurface_set_desync (window->area_subsurface);
215     }
216 #else
217     window->area_subsurface =
218         wl_subcompositor_get_subsurface (display->subcompositor,
219         window->area_surface, parent);
220     wl_subsurface_set_desync (window->area_subsurface);
221 #endif
222   }
223 #endif
224
225   /* embed video_surface in area_surface */
226   window->video_subsurface =
227       wl_subcompositor_get_subsurface (display->subcompositor,
228       window->video_surface, window->area_surface);
229   wl_subsurface_set_desync (window->video_subsurface);
230   wl_surface_commit (window->video_surface);
231
232   window->area_viewport = wl_scaler_get_viewport (display->scaler,
233       window->area_surface);
234   window->video_viewport = wl_scaler_get_viewport (display->scaler,
235       window->video_surface);
236
237   /* draw the area_subsurface */
238   gst_video_info_set_format (&info,
239       /* we want WL_SHM_FORMAT_XRGB8888 */
240 #if G_BYTE_ORDER == G_BIG_ENDIAN
241       GST_VIDEO_FORMAT_xRGB,
242 #else
243       GST_VIDEO_FORMAT_BGRx,
244 #endif
245       1, 1);
246
247 #ifdef GST_WLSINK_ENHANCEMENT
248   if (window->display->USE_TBM) {
249     /* Inform enlightenment of surface which render video */
250     window->video_object =
251         tizen_video_get_object (display->tizen_video, window->video_surface);
252
253     /* to use shm memory for mapping sub-surface, set FALSE to USE_TBM */
254     window->display->USE_TBM = FALSE;
255     gst_wl_window_map_sub_surface (display, window, &info);
256     /*restore USE_TBM */
257     window->display->USE_TBM = TRUE;
258   } else {
259     gst_wl_window_map_sub_surface (display, window, &info);
260   }
261 #else /* open source */
262   buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info.size, NULL);
263   gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
264   *((guint32 *) mapinfo.data) = 0;      /* paint it black */
265   gst_buffer_unmap (buf, &mapinfo);
266   wlbuf =
267       gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
268       display, &info);
269   gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
270   gst_wl_buffer_attach (gwlbuf, window->area_surface);
271
272   /* at this point, the GstWlBuffer keeps the buffer
273    * alive and will free it on wl_buffer::release */
274   gst_buffer_unref (buf);
275 #endif
276
277   /* do not accept input */
278   region = wl_compositor_create_region (display->compositor);
279   wl_surface_set_input_region (window->area_surface, region);
280   wl_region_destroy (region);
281
282   region = wl_compositor_create_region (display->compositor);
283   wl_surface_set_input_region (window->video_surface, region);
284   wl_region_destroy (region);
285
286   return window;
287 }
288
289 GstWlWindow *
290 gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info)
291 {
292   GstWlWindow *window;
293   gint width;
294   FUNCTION;
295
296 /* not create shell_surface here for enlightenment */
297 #ifdef GST_WLSINK_ENHANCEMENT
298   display->need_shell_surface = TRUE;
299
300   window = gst_wl_window_new_internal (display, NULL);
301
302 #if 0                           //GST_WLSINK_ENHANCEMENT
303   /* go toplevel */
304   window->shell_surface = wl_shell_get_shell_surface (display->shell,
305       window->area_surface);
306 #endif
307 #endif
308   if (window->shell_surface) {
309     wl_shell_surface_add_listener (window->shell_surface,
310         &shell_surface_listener, window);
311     wl_shell_surface_set_toplevel (window->shell_surface);
312   } else {
313     GST_ERROR ("Unable to get wl_shell_surface");
314
315     g_object_unref (window);
316     return NULL;
317   }
318
319   /* set the initial size to be the same as the reported video size */
320   width =
321       gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
322   gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
323
324   return window;
325 }
326
327 GstWlWindow *
328 gst_wl_window_new_in_surface (GstWlDisplay * display,
329     struct wl_surface * parent)
330 {
331   GstWlWindow *window;
332   FUNCTION;
333
334   display->use_parent_wl_surface = TRUE;
335 #ifdef GST_WLSINK_ENHANCEMENT
336   if (parent) {                 /*use wl_surface */
337     window = gst_wl_window_new_internal (display, parent);
338   } else {                      /* use wl_surface id */
339     window = gst_wl_window_new_internal (display, NULL);
340   }
341 #else
342   window = gst_wl_window_new_internal (display, parent);
343 #endif
344
345 #if 0                           /*for enlightment */
346   /* embed in parent */
347   window->area_subsurface =
348       wl_subcompositor_get_subsurface (display->subcompositor,
349       window->area_surface, parent);
350   wl_subsurface_set_desync (window->area_subsurface);
351 #endif
352
353 #ifdef GST_WLSINK_ENHANCEMENT
354   /*Area surface from App need to be under parent surface */
355   if (display->tizen_policy) {
356     GST_INFO (" call tizen_policy_place_subsurface_below_parent ");
357     tizen_policy_place_subsurface_below_parent (display->tizen_policy,
358         window->area_subsurface);
359     tizen_policy_place_subsurface_below_parent (display->tizen_policy,
360         window->video_subsurface);
361   }
362 #else
363   wl_surface_commit (parent);
364 #endif
365   return window;
366 }
367
368 GstWlDisplay *
369 gst_wl_window_get_display (GstWlWindow * window)
370 {
371   FUNCTION;
372   g_return_val_if_fail (window != NULL, NULL);
373
374   return g_object_ref (window->display);
375 }
376
377 struct wl_surface *
378 gst_wl_window_get_wl_surface (GstWlWindow * window)
379 {
380   FUNCTION;
381   g_return_val_if_fail (window != NULL, NULL);
382
383   return window->video_surface;
384 }
385
386 gboolean
387 gst_wl_window_is_toplevel (GstWlWindow * window)
388 {
389   FUNCTION;
390   g_return_val_if_fail (window != NULL, FALSE);
391
392   return (window->shell_surface != NULL);
393 }
394
395 #ifdef GST_WLSINK_ENHANCEMENT
396 static gint
397 gst_wl_window_find_transform (guint rotate_angle, guint flip)
398 {
399   gint transform;
400   guint combine = rotate_angle * 10 + flip;
401   FUNCTION;
402   GST_DEBUG ("rotate %d, flip %d, combine %d", rotate_angle, flip, combine);
403   switch (combine) {
404     case ROTATE_0_FLIP_NONE:
405       transform = WL_OUTPUT_TRANSFORM_NORMAL;
406       break;
407     case ROTATE_0_FLIP_HORIZONTAL:
408       transform = WL_OUTPUT_TRANSFORM_FLIPPED;
409       break;
410     case ROTATE_0_FLIP_VERTICAL:
411       transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
412       break;
413     case ROTATE_0_FLIP_BOTH:
414       transform = WL_OUTPUT_TRANSFORM_180;
415       break;
416     case ROTATE_90_FLIP_NONE:
417       transform = WL_OUTPUT_TRANSFORM_90;
418       break;
419     case ROTATE_90_FLIP_HORIZONTAL:
420       transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
421       break;
422     case ROTATE_90_FLIP_VERTICAL:
423       transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
424       break;
425     case ROTATE_90_FLIP_BOTH:
426       transform = WL_OUTPUT_TRANSFORM_270;
427       break;
428     case ROTATE_180_FLIP_NONE:
429       transform = WL_OUTPUT_TRANSFORM_180;
430       break;
431     case ROTATE_180_FLIP_HORIZONTAL:
432       transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
433       break;
434     case ROTATE_180_FLIP_VERTICAL:
435       transform = WL_OUTPUT_TRANSFORM_FLIPPED;
436       break;
437     case ROTATE_180_FLIP_BOTH:
438       transform = WL_OUTPUT_TRANSFORM_NORMAL;
439       break;
440     case ROTATE_270_FLIP_NONE:
441       transform = WL_OUTPUT_TRANSFORM_270;
442       break;
443     case ROTATE_270_FLIP_HORIZONTAL:
444       transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
445       break;
446     case ROTATE_270_FLIP_VERTICAL:
447       transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
448       break;
449     case ROTATE_270_FLIP_BOTH:
450       transform = WL_OUTPUT_TRANSFORM_90;
451       break;
452   }
453
454   return transform;
455 }
456
457 #endif
458 static void
459 gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit)
460 {
461   GstVideoRectangle src = { 0, };
462   GstVideoRectangle res;
463 #ifdef GST_WLSINK_ENHANCEMENT   // need to change ifndef to ifdef
464   GstVideoRectangle src_origin = { 0, 0, 0, 0 };
465   GstVideoRectangle src_input = { 0, 0, 0, 0 };
466   GstVideoRectangle dst = { 0, 0, 0, 0 };
467   int temp = 0;
468   gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
469 #endif
470   FUNCTION;
471
472   /* center the video_subsurface inside area_subsurface */
473   src.w = window->video_width;
474   src.h = window->video_height;
475
476 #ifdef GST_WLSINK_ENHANCEMENT   // need to change ifndef to ifdef
477   src.x = src.y = 0;
478   src_input.w = src_origin.w = window->video_width;
479   src_input.h = src_origin.h = window->video_height;
480   GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
481   GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
482       src_input.h);
483   GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
484       src_origin.w, src_origin.h);
485
486   if (window->rotate_angle == DEGREE_0 || window->rotate_angle == DEGREE_180) {
487     src.w = window->video_width;        //video_width
488     src.h = window->video_height;       //video_height
489   } else {
490     src.w = window->video_height;
491     src.h = window->video_width;
492   }
493   GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
494
495   /*default res.w and res.h */
496   dst.w = window->render_rectangle.w;
497   dst.h = window->render_rectangle.h;
498   dst.x = window->render_rectangle.x;
499   dst.y = window->render_rectangle.y;
500
501   GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
502   GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
503       window->render_rectangle.x, window->render_rectangle.y,
504       window->render_rectangle.w, window->render_rectangle.h);
505   switch (window->disp_geo_method) {
506     case DISP_GEO_METHOD_LETTER_BOX:
507       GST_INFO ("DISP_GEO_METHOD_LETTER_BOX");
508       gst_video_sink_center_rect (src, dst, &res, TRUE);
509       break;
510     case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
511       if (src.w > dst.w || src.h > dst.h) {
512         /*LETTER BOX */
513         GST_INFO
514             ("DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX -> set LETTER BOX");
515         gst_video_sink_center_rect (src, dst, &res, TRUE);
516       } else {
517         /*ORIGIN SIZE */
518         GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
519         gst_video_sink_center_rect (src, dst, &res, FALSE);
520         gst_video_sink_center_rect (dst, src, &src_input, FALSE);
521       }
522       break;
523     case DISP_GEO_METHOD_ORIGIN_SIZE:  //is working
524       GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
525       gst_video_sink_center_rect (src, dst, &res, FALSE);
526       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
527       break;
528     case DISP_GEO_METHOD_FULL_SCREEN:  //is working
529       GST_INFO ("DISP_GEO_METHOD_FULL_SCREEN");
530       res.x = res.y = 0;
531       res.w = window->render_rectangle.w;
532       res.h = window->render_rectangle.h;
533       break;
534     case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
535       GST_INFO ("DISP_GEO_METHOD_CROPPED_FULL_SCREEN");
536       gst_video_sink_center_rect (src, dst, &res, FALSE);
537       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
538       res.x = res.y = 0;
539       res.w = dst.w;
540       res.h = dst.h;
541       break;
542     default:
543       break;
544   }
545
546   transform = gst_wl_window_find_transform (window->rotate_angle, window->flip);
547
548   GST_INFO
549       ("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]",
550       window->render_rectangle.w, window->render_rectangle.h,
551       src.x, src.y, src.w, src.h,
552       dst.x, dst.y, dst.w, dst.h,
553       src_input.x, src_input.y, src_input.w, src_input.h,
554       res.x, res.y, res.w, res.h);
555
556   GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
557   GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
558       src_input.h);
559   GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
560       src_origin.w, src_origin.h);
561   GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
562   GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
563   GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
564       window->render_rectangle.x, window->render_rectangle.y,
565       window->render_rectangle.w, window->render_rectangle.h);
566   GST_INFO ("res(%d, %d, %d x %d)", res.x, res.y, res.w, res.h);
567
568   if (window->video_subsurface) {
569     GST_INFO ("have window->subsurface");
570     wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
571     GST_INFO ("wl_subsurface_set_position(%d,%d)", res.x, res.y);
572   }
573   wl_viewport_set_destination (window->video_viewport, res.w, res.h);
574   GST_INFO ("wl_viewport_set_destination(%d,%d)", res.w, res.h);
575
576   /*need to swap */
577   if (transform % 2 == 1) {     /*1, 3, 5, 7 */
578     temp = src_input.w;
579     src_input.w = src_input.h;
580     src_input.h = temp;
581   }
582   wl_viewport_set_source (window->video_viewport,
583       wl_fixed_from_int (src_input.x), wl_fixed_from_int (src_input.y),
584       wl_fixed_from_int (src_input.w), wl_fixed_from_int (src_input.h));
585   GST_INFO ("wl_viewport_set_source(%d,%d, %d x %d)", src_input.x, src_input.y,
586       src_input.w, src_input.h);
587
588   wl_surface_set_buffer_transform (window->video_surface, transform);
589   GST_INFO ("wl_surface_set_buffer_transform (%d)", transform);
590 #else
591   gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE);
592
593   wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
594   wl_viewport_set_destination (window->video_viewport, res.w, res.h);
595 #endif
596   if (commit) {
597     wl_surface_damage (window->video_surface, 0, 0, res.w, res.h);
598     wl_surface_commit (window->video_surface);
599   }
600
601   if (gst_wl_window_is_toplevel (window)) {
602     struct wl_region *region;
603
604     region = wl_compositor_create_region (window->display->compositor);
605     wl_region_add (region, 0, 0, window->render_rectangle.w,
606         window->render_rectangle.h);
607     wl_surface_set_input_region (window->area_surface, region);
608     wl_region_destroy (region);
609   }
610
611   /* this is saved for use in wl_surface_damage */
612   window->surface_width = res.w;
613   window->surface_height = res.h;
614 }
615
616 void
617 gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer,
618     const GstVideoInfo * info)
619 {
620   FUNCTION;
621   if (G_UNLIKELY (info)) {
622     window->video_width =
623         gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
624     window->video_height = info->height;
625
626     wl_subsurface_set_sync (window->video_subsurface);
627     gst_wl_window_resize_video_surface (window, FALSE);
628   }
629   GST_INFO ("GstWlBuffer(%p)", buffer);
630   if (G_LIKELY (buffer))
631     gst_wl_buffer_attach (buffer, window->video_surface);
632   else
633     wl_surface_attach (window->video_surface, NULL, 0, 0);
634
635   /*Wayland-compositor will try to render damage area which need  to be updated */
636   wl_surface_damage (window->video_surface, 0, 0, window->surface_width,
637       window->surface_height);
638 #ifdef GST_WLSINK_ENHANCEMENT
639   GST_LOG ("update area width %d, height %d", window->surface_width,
640       window->surface_height);
641 #endif
642   /* wl_surface_commit change surface state, if wl_buffer is not attached newly,  then surface is not changed */
643   wl_surface_commit (window->video_surface);
644
645   if (G_UNLIKELY (info)) {
646     /* commit also the parent (area_surface) in order to change
647      * the position of the video_subsurface */
648 #ifdef GST_WLSINK_ENHANCEMENT
649     GST_DEBUG ("render_rectangle %d*%d", window->render_rectangle.w,
650         window->render_rectangle.h);
651 #endif
652     wl_surface_damage (window->area_surface, 0, 0, window->render_rectangle.w,
653         window->render_rectangle.h);
654     wl_surface_commit (window->area_surface);
655     wl_subsurface_set_desync (window->video_subsurface);
656   }
657
658   wl_display_flush (window->display->display);
659 }
660
661 void
662 gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
663     gint w, gint h)
664 {
665   FUNCTION;
666   g_return_if_fail (window != NULL);
667 #ifdef GST_WLSINK_ENHANCEMENT
668   if (window->render_rectangle.x == x && window->render_rectangle.y == y
669       && window->render_rectangle.w == w && window->render_rectangle.h == h) {
670     GST_DEBUG ("but the values are same. skip");
671     return;
672   }
673 #endif
674   window->render_rectangle.x = x;
675   window->render_rectangle.y = y;
676   window->render_rectangle.w = w;
677   window->render_rectangle.h = h;
678
679   /* position the area inside the parent - needs a parent commit to apply */
680   if (window->area_subsurface)
681     wl_subsurface_set_position (window->area_subsurface, x, y);
682
683   /* change the size of the area */
684   wl_viewport_set_destination (window->area_viewport, w, h);
685
686   if (window->video_width != 0) {
687     wl_subsurface_set_sync (window->video_subsurface);
688     gst_wl_window_resize_video_surface (window, TRUE);
689   }
690
691   wl_surface_damage (window->area_surface, 0, 0, w, h);
692   wl_surface_commit (window->area_surface);
693
694   if (window->video_width != 0)
695     wl_subsurface_set_desync (window->video_subsurface);
696 }
697
698 #ifdef GST_WLSINK_ENHANCEMENT
699 void
700 gst_wl_window_set_video_info (GstWlWindow * window, const GstVideoInfo * info)
701 {
702   FUNCTION;
703   g_return_if_fail (window != NULL);
704
705   window->video_width =
706       gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
707   window->video_height = info->height;
708
709   if (window->render_rectangle.w != 0)
710     gst_wl_window_resize_video_surface (window, FALSE);
711 }
712
713 void
714 gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle)
715 {
716   FUNCTION;
717   g_return_if_fail (window != NULL);
718   window->rotate_angle = rotate_angle;
719   GST_INFO ("rotate_angle value is (%d)", window->rotate_angle);
720 }
721
722 void
723 gst_wl_window_set_disp_geo_method (GstWlWindow * window, guint disp_geo_method)
724 {
725   FUNCTION;
726   g_return_if_fail (window != NULL);
727   window->disp_geo_method = disp_geo_method;
728   GST_INFO ("disp_geo_method value is (%d)", window->disp_geo_method);
729 }
730
731 void
732 gst_wl_window_set_orientation (GstWlWindow * window, guint orientation)
733 {
734   FUNCTION;
735   g_return_if_fail (window != NULL);
736   window->orientation = orientation;
737   GST_INFO ("orientation value is (%d)", window->orientation);
738 }
739
740 void
741 gst_wl_window_set_flip (GstWlWindow * window, guint flip)
742 {
743   FUNCTION;
744   g_return_if_fail (window != NULL);
745   window->flip = flip;
746   GST_INFO ("flip value is (%d)", window->flip);
747 }
748 #endif