[evaspixmapsink] Fix bug to re-create pixmaps for new evas image object
[framework/multimedia/gst-plugins-ext0.10.git] / evaspixmapsink / evaspixmapsink.c
1 /*
2  * EvasPixmapSink
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
8  * This library is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the
10  * Free Software Foundation; either version 2.1 of the License, or (at your option)
11  * any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software Foundation, Inc., 51
20  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 /* Our interfaces */
29 #include <gst/interfaces/navigation.h>
30 #include <gst/interfaces/colorbalance.h>
31 #include <gst/interfaces/propertyprobe.h>
32 /* Helper functions */
33 #include <gst/video/video.h>
34
35 /* Object header */
36 #include "evaspixmapsink.h"
37
38 #include <time.h>
39
40 /* Samsung extension headers */
41 /* For xv extension header for buffer transfer (output) */
42 #include "xv_types.h"
43
44 /* headers for drm */
45 #include <sys/stat.h>
46 #include <sys/ioctl.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <X11/Xmd.h>
50 #include <dri2/dri2.h>
51 #include <libdrm/drm.h>
52
53 typedef enum {
54         BUF_SHARE_METHOD_PADDR = 0,
55         BUF_SHARE_METHOD_FD
56 } buf_share_method_t;
57
58 /* max channel count *********************************************************/
59 #define SCMN_IMGB_MAX_PLANE         (4)
60
61 /* image buffer definition ***************************************************
62
63     +------------------------------------------+ ---
64     |                                          |  ^
65     |     a[], p[]                             |  |
66     |     +---------------------------+ ---    |  |
67     |     |                           |  ^     |  |
68     |     |<---------- w[] ---------->|  |     |  |
69     |     |                           |  |     |  |
70     |     |                           |        |
71     |     |                           |  h[]   |  e[]
72     |     |                           |        |
73     |     |                           |  |     |  |
74     |     |                           |  |     |  |
75     |     |                           |  v     |  |
76     |     +---------------------------+ ---    |  |
77     |                                          |  v
78     +------------------------------------------+ ---
79
80     |<----------------- s[] ------------------>|
81 */
82
83 typedef struct
84 {
85         /* width of each image plane */
86         int      w[SCMN_IMGB_MAX_PLANE];
87         /* height of each image plane */
88         int      h[SCMN_IMGB_MAX_PLANE];
89         /* stride of each image plane */
90         int      s[SCMN_IMGB_MAX_PLANE];
91         /* elevation of each image plane */
92         int      e[SCMN_IMGB_MAX_PLANE];
93         /* user space address of each image plane */
94         void   * a[SCMN_IMGB_MAX_PLANE];
95         /* physical address of each image plane, if needs */
96         void   * p[SCMN_IMGB_MAX_PLANE];
97         /* color space type of image */
98         int      cs;
99         /* left postion, if needs */
100         int      x;
101         /* top position, if needs */
102         int      y;
103         /* to align memory */
104         int      __dummy2;
105         /* arbitrary data */
106         int      data[16];
107         /* dma buf fd */
108         int dma_buf_fd[SCMN_IMGB_MAX_PLANE];
109         /* buffer share method */
110         int buf_share_method;
111 } SCMN_IMGB;
112
113 /* Debugging category */
114 #include <gst/gstinfo.h>
115 GST_DEBUG_CATEGORY_STATIC (gst_debug_evaspixmapsink);
116 #define GST_CAT_DEFAULT gst_debug_evaspixmapsink
117 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
118
119 enum {
120     DEGREE_0,
121     DEGREE_90,
122     DEGREE_180,
123     DEGREE_270,
124     DEGREE_NUM,
125 };
126
127 enum {
128     DISP_GEO_METHOD_LETTER_BOX = 0,
129     DISP_GEO_METHOD_ORIGIN_SIZE,
130     DISP_GEO_METHOD_FULL_SCREEN,
131     DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
132     DISP_GEO_METHOD_CUSTOM_ROI,
133     DISP_GEO_METHOD_NUM,
134 };
135
136 enum {
137     FLIP_NONE = 0,
138     FLIP_HORIZONTAL,
139     FLIP_VERTICAL,
140     FLIP_BOTH,
141     FLIP_NUM,
142 };
143
144 #define DEF_DISPLAY_GEOMETRY_METHOD                     DISP_GEO_METHOD_LETTER_BOX
145 #define DEF_DISPLAY_FLIP                                FLIP_NONE
146 #define GST_TYPE_EVASPIXMAPSINK_FLIP                    (gst_evaspixmapsink_flip_get_type())
147 #define GST_TYPE_EVASPIXMAPSINK_ROTATE_ANGLE            (gst_evaspixmapsink_rotate_angle_get_type())
148 #define GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD (gst_evaspixmapsink_display_geometry_method_get_type())
149
150 static GType
151 gst_evaspixmapsink_flip_get_type(void)
152 {
153         static GType evaspixmapsink_flip_type = 0;
154         static const GEnumValue flip_type[] = {
155                 { FLIP_NONE,       "Flip NONE", "FLIP_NONE"},
156                 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
157                 { FLIP_VERTICAL,   "Flip VERTICAL", "FLIP_VERTICAL"},
158                 { FLIP_BOTH,       "Flip BOTH", "FLIP_BOTH"},
159                 { FLIP_NUM, NULL, NULL},
160         };
161
162         if (!evaspixmapsink_flip_type) {
163                 evaspixmapsink_flip_type = g_enum_register_static("GstEvasPixmapSinkFlipType", flip_type);
164         }
165
166         return evaspixmapsink_flip_type;
167 }
168
169 static GType
170 gst_evaspixmapsink_rotate_angle_get_type(void)
171 {
172         static GType evaspixmapsink_rotate_angle_type = 0;
173         static const GEnumValue rotate_angle_type[] = {
174                 { 0, "No rotate", "DEGREE_0"},
175                 { 1, "Rotate 90 degree", "DEGREE_90"},
176                 { 2, "Rotate 180 degree", "DEGREE_180"},
177                 { 3, "Rotate 270 degree", "DEGREE_270"},
178                 { 4, NULL, NULL},
179         };
180
181         if (!evaspixmapsink_rotate_angle_type) {
182                 evaspixmapsink_rotate_angle_type = g_enum_register_static("GstEvasPixmapSinkRotateAngleType", rotate_angle_type);
183         }
184
185         return evaspixmapsink_rotate_angle_type;
186 }
187
188 static GType
189 gst_evaspixmapsink_display_geometry_method_get_type(void)
190 {
191         static GType evaspixmapsink_display_geometry_method_type = 0;
192         static const GEnumValue display_geometry_method_type[] = {
193                 { 0, "Letter box", "LETTER_BOX"},
194                 { 1, "Origin size", "ORIGIN_SIZE"},
195                 { 2, "Full-screen", "FULL_SCREEN"},
196                 { 3, "Cropped Full-screen", "CROPPED_FULL_SCREEN"},
197                 { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
198                 { 5, NULL, NULL},
199         };
200
201         if (!evaspixmapsink_display_geometry_method_type) {
202                 evaspixmapsink_display_geometry_method_type = g_enum_register_static("GstEvasPixmapSinkDisplayGeometryMethodType", display_geometry_method_type);
203         }
204
205         return evaspixmapsink_display_geometry_method_type;
206 }
207
208 typedef struct
209 {
210   unsigned long flags;
211   unsigned long functions;
212   unsigned long decorations;
213   long input_mode;
214   unsigned long status;
215 }
216 MotifWmHints, MwmHints;
217
218 #define MWM_HINTS_DECORATIONS   (1L << 1)
219
220 static void gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink);
221 static GstBufferClass *evaspixmap_buffer_parent_class = NULL;
222 static void gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf);
223 static void gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink);
224 static void gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
225 static void gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink, int idx);
226 static gboolean gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf);
227 static gboolean gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink);
228 static void gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
229 static gint gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps);
230 static void drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle);
231
232 /* Default template - initiated with class struct to allow gst-register to work
233    without X running */
234 static GstStaticPadTemplate gst_evaspixmapsink_sink_template_factory =
235     GST_STATIC_PAD_TEMPLATE ("sink",
236     GST_PAD_SINK,
237     GST_PAD_ALWAYS,
238     GST_STATIC_CAPS ("video/x-raw-rgb, "
239         "framerate = (fraction) [ 0, MAX ], "
240         "width = (int) [ 1, MAX ], "
241         "height = (int) [ 1, MAX ]; "
242         "video/x-raw-yuv, "
243         "framerate = (fraction) [ 0, MAX ], "
244         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
245     );
246
247 enum
248 {
249   PROP_0,
250   PROP_CONTRAST,
251   PROP_BRIGHTNESS,
252   PROP_HUE,
253   PROP_SATURATION,
254   PROP_DISPLAY,
255   PROP_SYNCHRONOUS,
256   PROP_PIXEL_ASPECT_RATIO,
257   PROP_DEVICE,
258   PROP_DEVICE_NAME,
259   PROP_DOUBLE_BUFFER,
260   PROP_AUTOPAINT_COLORKEY,
261   PROP_COLORKEY,
262   PROP_PIXMAP_WIDTH,
263   PROP_PIXMAP_HEIGHT,
264   PROP_FLIP,
265   PROP_ROTATE_ANGLE,
266   PROP_DISPLAY_GEOMETRY_METHOD,
267   PROP_ZOOM,
268   PROP_DST_ROI_X,
269   PROP_DST_ROI_Y,
270   PROP_DST_ROI_W,
271   PROP_DST_ROI_H,
272   PROP_STOP_VIDEO,
273   PROP_EVAS_OBJECT,
274   PROP_VISIBLE,
275   PROP_ORIGIN_SIZE,
276 };
277
278 static GstVideoSinkClass *parent_class = NULL;
279
280 /* ============================================================= */
281 /*                                                               */
282 /*                       Private Methods                         */
283 /*                                                               */
284 /* ============================================================= */
285
286 /* evaspixmap buffers */
287
288 #define GST_TYPE_EVASPIXMAP_BUFFER (gst_evaspixmap_buffer_get_type())
289
290 #define GST_IS_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVASPIXMAP_BUFFER))
291 #define GST_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVASPIXMAP_BUFFER, GstEvasPixmapBuffer))
292
293 static int get_millis_time()
294 {
295     struct timespec tp;
296     clock_gettime(CLOCK_MONOTONIC, &tp);
297     return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
298 }
299
300 static void
301 ecore_pipe_callback_handler (void *data, void *buffer, unsigned int nbyte)
302 {
303         GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink*)data;
304         GST_DEBUG_OBJECT (evaspixmapsink,"[START] Evas_Object(0x%x)", evaspixmapsink->eo);
305         MMTA_ACUM_ITEM_BEGIN("evaspixmapsink - ecore thread cb : TOTAL", FALSE);
306         int i = 0;
307         guint idx = 0;
308         GstXPixmap *xpixmap = NULL;
309
310         if (!data ) {
311                 GST_WARNING_OBJECT (evaspixmapsink,"data is NULL..");
312                 return;
313         }
314         if (!evaspixmapsink->eo) {
315                 GST_WARNING_OBJECT (evaspixmapsink,"evas object is NULL..");
316                 return;
317         }
318
319         g_mutex_lock (evaspixmapsink->pixmap_ref_lock);
320
321         /* mapping evas object with xpixmap */
322         if (evaspixmapsink->do_link) {
323                 GST_DEBUG_OBJECT (evaspixmapsink,"do link");
324                 evas_object_image_size_set(evaspixmapsink->eo, evaspixmapsink->w, evaspixmapsink->h);
325                 if (evaspixmapsink->xpixmap[idx]->pixmap) {
326                         Evas_Native_Surface surf;
327                         surf.version = EVAS_NATIVE_SURFACE_VERSION;
328                         surf.type = EVAS_NATIVE_SURFACE_X11;
329                         surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get());
330                         surf.data.x11.pixmap = evaspixmapsink->xpixmap[idx]->pixmap;
331                         __ta__("evaspixmapsink - ecore thread cb : _native_surface_set(LINK)", evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); );
332                         evaspixmapsink->do_link = FALSE;
333                         evaspixmapsink->last_updated_idx = -1;
334                 } else {
335                         GST_WARNING_OBJECT (evaspixmapsink,"pixmap is NULL..");
336                         g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
337                         return;
338                 }
339         } else {
340                 GST_DEBUG_OBJECT (evaspixmapsink,"update");
341                 /* update evas image object size */
342                 if (evaspixmapsink->use_origin_size) {
343                         evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evaspixmapsink->w, &evaspixmapsink->h);
344                 }
345
346                 /* find a oldest damaged pixmap */
347                 int temp_time = 0;
348                 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
349                         if (evaspixmapsink->last_updated_idx == i) {
350                                 continue;
351                         } else {
352                                 xpixmap = evaspixmapsink->xpixmap[i];
353                                 if (xpixmap->ref > 0 && xpixmap->damaged_time) {
354                                         if (temp_time == 0) {
355                                                 temp_time = xpixmap->damaged_time;
356                                                 idx = i;
357                                         } else {
358                                                 if (temp_time > xpixmap->damaged_time) {
359                                                         temp_time = xpixmap->damaged_time;
360                                                         idx = i;
361                                                 }
362                                         }
363                                 }
364                         }
365                 }
366
367                 xpixmap = evaspixmapsink->xpixmap[idx];
368                 if (xpixmap->pixmap) {
369                         if (evaspixmapsink->last_updated_idx != idx) {
370                                 Evas_Native_Surface surf;
371                                 surf.version = EVAS_NATIVE_SURFACE_VERSION;
372                                 surf.type = EVAS_NATIVE_SURFACE_X11;
373                                 surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get());
374                                 surf.data.x11.pixmap = xpixmap->pixmap;
375                                 if (evaspixmapsink->eo) {
376                                         evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
377                                 }
378                                 __ta__("evaspixmapsink - ecore thread cb : _native_surface_set", evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); );
379                                 GST_LOG_OBJECT (evaspixmapsink,"update, native_surface_set of xpixmap[%d]",idx);
380                                 if (evaspixmapsink->last_updated_idx == -1) {
381                                         xpixmap->damaged_time = 0;
382                                         GST_INFO_OBJECT (evaspixmapsink,"this is the first time to request to update : pixmap(%d), refcount(%d), damaged_time(%d), idx(%d)",
383                                                                                                                         xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time, idx);
384                                 } else {
385                                         xpixmap = evaspixmapsink->xpixmap[evaspixmapsink->last_updated_idx];
386                                         xpixmap->ref--;
387                                         xpixmap->damaged_time = 0;
388                                         GST_INFO_OBJECT (evaspixmapsink,"pixmap ref-count DECREASED : pixmap(%d), refcount(%d), damaged_time(%d), idx(%d)",
389                                                                                         xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time, evaspixmapsink->last_updated_idx);
390                                 }
391                                 evaspixmapsink->last_updated_idx = idx;
392                         }
393
394                         MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evas_object_image update", FALSE);
395                         evas_object_image_pixels_dirty_set (evaspixmapsink->eo, 1);
396                         evas_object_image_fill_set(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
397                         evas_object_image_data_update_add(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
398                         MMTA_ACUM_ITEM_END("evaspixmapsink evas_object_image update", FALSE);
399
400                         //GST_LOG_OBJECT (evaspixmapsink,"request to update : pixmap idx(%d), ref(%d)", idx, xpixmap->ref);
401                 } else {
402                         GST_ERROR_OBJECT (evaspixmapsink,"pixmap is NULL..");
403                         g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
404                         return;
405                 }
406         }
407         g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
408
409         MMTA_ACUM_ITEM_END("evaspixmapsink - ecore thread cb : TOTAL", FALSE);
410
411         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
412 }
413
414 static void
415 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
416 {
417         int w = 0;
418         int h = 0;
419         float former_ratio = 0;
420         float ratio = 0;
421         float abs_margin = 0;
422         int i = 0;
423
424         GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink *)data;
425         GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
426
427         evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &w, &h);
428         GST_DEBUG_OBJECT (evaspixmapsink,"resized : w(%d), h(%d)", w, h);
429         if (!evaspixmapsink->use_origin_size &&
430                         (evaspixmapsink->w != w || evaspixmapsink->h != h)) {
431                 former_ratio = (float)evaspixmapsink->w / evaspixmapsink->h;
432                 ratio = (float)w / h;
433                 evaspixmapsink->w = w;
434                 evaspixmapsink->h = h;
435
436 #ifdef COMPARE_RATIO
437                 GST_DEBUG_OBJECT (evaspixmapsink,"resized : ratio(%.3f=>%.3f)", former_ratio, ratio);
438                 if ( former_ratio >= ratio ) {
439                         abs_margin = former_ratio - ratio;
440                 } else {
441                         abs_margin = ratio - former_ratio;
442                 }
443                 /* re-link_pixmap can only be set when ratio is changed */
444                 if ( abs_margin >= MARGIN_OF_ERROR ) {
445 #endif
446                         if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
447                                 GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
448                                 return;
449                         }
450 #ifdef COMPARE_RATIO
451                 }
452 #endif
453         }
454
455         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
456                 if (evaspixmapsink->xpixmap[i]->ref == 0) {
457                         break;
458                 }
459         }
460         if (GST_STATE(evaspixmapsink) == GST_STATE_PAUSED && i < evaspixmapsink->num_of_pixmaps) {
461                 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
462         }
463
464         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
465 }
466
467 static inline gboolean
468 is_evas_image_object (Evas_Object *obj)
469 {
470         const char *type;
471         if (!obj) {
472                 return FALSE;
473         }
474         type = evas_object_type_get (obj);
475         if (!type) {
476                 return FALSE;
477         }
478         if (strcmp (type, "image") == 0) {
479                 return TRUE;
480         }
481         return FALSE;
482 }
483
484 static void
485 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
486 {
487         GstEvasPixmapSink *evaspixmapsink = data;
488         if (!evaspixmapsink) {
489                 GST_WARNING ("evaspixmapsink is NULL..");
490                 return;
491         }
492         GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
493
494         evas_object_event_callback_del(evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
495         if (evaspixmapsink->eo) {
496                 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
497                 evaspixmapsink->eo = NULL;
498         }
499
500         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
501 }
502
503 /* X11 stuff */
504 static gboolean error_caught = FALSE;
505
506 static int
507 gst_evaspixmapsink_handle_xerror (Display * display, XErrorEvent * xevent)
508 {
509   char error_msg[1024];
510
511   XGetErrorText (display, xevent->error_code, error_msg, 1024);
512   GST_DEBUG ("evaspixmapsink triggered an XError. error: %s", error_msg);
513   error_caught = TRUE;
514   return 0;
515 }
516
517 #ifdef HAVE_XSHM
518 /* This function checks that it is actually really possible to create an image
519    using XShm */
520 static gboolean
521 gst_evaspixmapsink_check_xshm_calls (GstXContext * xcontext)
522 {
523   XvImage *xvimage;
524   XShmSegmentInfo SHMInfo;
525   gint size;
526   int (*handler) (Display *, XErrorEvent *);
527   gboolean result = FALSE;
528   gboolean did_attach = FALSE;
529
530   g_return_val_if_fail (xcontext != NULL, FALSE);
531
532   /* Sync to ensure any older errors are already processed */
533   XSync (xcontext->disp, FALSE);
534
535   /* Set defaults so we don't free these later unnecessarily */
536   SHMInfo.shmaddr = ((void *) -1);
537   SHMInfo.shmid = -1;
538
539   /* Setting an error handler to catch failure */
540   error_caught = FALSE;
541   handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
542
543   /* Trying to create a 1x1 picture */
544   GST_DEBUG ("XvShmCreateImage of 1x1");
545   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
546       xcontext->im_format, NULL, 1, 1, &SHMInfo);
547
548   /* Might cause an error, sync to ensure it is noticed */
549   XSync (xcontext->disp, FALSE);
550   if (!xvimage || error_caught) {
551     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
552     goto beach;
553   }
554   size = xvimage->data_size;
555
556   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
557   if (SHMInfo.shmid == -1) {
558     GST_WARNING ("could not get shared memory of %d bytes", size);
559     goto beach;
560   }
561
562   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
563   if (SHMInfo.shmaddr == ((void *) -1)) {
564     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
565     /* Clean up the shared memory segment */
566     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
567     goto beach;
568   }
569
570   xvimage->data = SHMInfo.shmaddr;
571   SHMInfo.readOnly = FALSE;
572
573   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
574     GST_WARNING ("Failed to XShmAttach");
575     /* Clean up the shared memory segment */
576     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
577     goto beach;
578   }
579
580   /* Sync to ensure we see any errors we caused */
581   XSync (xcontext->disp, FALSE);
582
583   /* Delete the shared memory segment as soon as everyone is attached.
584    * This way, it will be deleted as soon as we detach later, and not
585    * leaked if we crash. */
586   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
587
588   if (!error_caught) {
589     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
590         SHMInfo.shmseg);
591
592     did_attach = TRUE;
593     /* store whether we succeeded in result */
594     result = TRUE;
595   } else {
596     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
597         "Not using shared memory.");
598   }
599
600 beach:
601   /* Sync to ensure we swallow any errors we caused and reset error_caught */
602   XSync (xcontext->disp, FALSE);
603
604   error_caught = FALSE;
605   XSetErrorHandler (handler);
606
607   if (did_attach) {
608     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
609         SHMInfo.shmid, SHMInfo.shmseg);
610     XShmDetach (xcontext->disp, &SHMInfo);
611     XSync (xcontext->disp, FALSE);
612   }
613   if (SHMInfo.shmaddr != ((void *) -1))
614     shmdt (SHMInfo.shmaddr);
615   if (xvimage)
616     XFree (xvimage);
617   return result;
618 }
619 #endif /* HAVE_XSHM */
620
621 /* This function destroys a GstEvasPixmap handling XShm availability */
622 static void
623 gst_evaspixmap_buffer_destroy (GstEvasPixmapBuffer *evaspixmapbuf)
624 {
625         GstEvasPixmapSink *evaspixmapsink;
626
627         evaspixmapsink = evaspixmapbuf->evaspixmapsink;
628         if (G_UNLIKELY (evaspixmapsink == NULL)) {
629                 goto no_sink;
630         }
631         GST_DEBUG_OBJECT (evaspixmapsink, "Destroying buffer");
632
633         g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
634
635         GST_OBJECT_LOCK (evaspixmapsink);
636
637         /* We might have some buffers destroyed after changing state to NULL */
638         if (evaspixmapsink->xcontext == NULL) {
639                 GST_DEBUG_OBJECT (evaspixmapsink,"Destroying XvImage after Xcontext");
640 #ifdef HAVE_XSHM
641                 /* Need to free the shared memory segment even if the x context
642                 * was already cleaned up */
643                 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
644                         shmdt (evaspixmapbuf->SHMInfo.shmaddr);
645                 }
646 #endif
647                 goto beach;
648         }
649         g_mutex_lock (evaspixmapsink->x_lock);
650
651 #ifdef HAVE_XSHM
652         if (evaspixmapsink->xcontext->use_xshm) {
653                 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
654                         GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmDetaching from 0x%x id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
655                         XShmDetach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo);
656                         XSync (evaspixmapsink->xcontext->disp, FALSE);
657                         shmdt (evaspixmapbuf->SHMInfo.shmaddr);
658                 }
659                 if (evaspixmapbuf->xvimage)
660                 XFree (evaspixmapbuf->xvimage);
661         } else
662 #endif /* HAVE_XSHM */
663         {
664                 if (evaspixmapbuf->xvimage) {
665                         if (evaspixmapbuf->xvimage->data) {
666                                 g_free (evaspixmapbuf->xvimage->data);
667                         }
668                         XFree (evaspixmapbuf->xvimage);
669                 }
670         }
671
672         XSync (evaspixmapsink->xcontext->disp, FALSE);
673
674         g_mutex_unlock (evaspixmapsink->x_lock);
675
676 beach:
677         GST_OBJECT_UNLOCK (evaspixmapsink);
678         evaspixmapbuf->evaspixmapsink = NULL;
679         gst_object_unref (evaspixmapsink);
680
681         GST_MINI_OBJECT_CLASS (evaspixmap_buffer_parent_class)->finalize (GST_MINI_OBJECT(evaspixmapbuf));
682
683         return;
684
685         no_sink:
686         {
687                 GST_WARNING ("no sink found");
688                 return;
689         }
690 }
691
692 static void
693 gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf)
694 {
695         GstEvasPixmapSink *evaspixmapsink;
696
697         evaspixmapsink = evaspixmapbuf->evaspixmapsink;
698         if (G_UNLIKELY (evaspixmapsink == NULL)) {
699                 GST_WARNING_OBJECT (evaspixmapsink,"no sink found");
700                 return;
701         }
702         g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
703
704          /* If our geometry changed we can't reuse that image. */
705         GST_LOG_OBJECT (evaspixmapsink,"destroy image as sink is shutting down");
706         gst_evaspixmap_buffer_destroy (evaspixmapbuf);
707 }
708
709 static void
710 gst_evaspixmap_buffer_free (GstEvasPixmapBuffer *evaspixmapbuf)
711 {
712   /* make sure it is not recycled */
713   evaspixmapbuf->width = -1;
714   evaspixmapbuf->height = -1;
715   gst_buffer_unref (GST_BUFFER (evaspixmapbuf));
716 }
717
718 static void
719 gst_evaspixmap_buffer_init (GstEvasPixmapBuffer *evaspixmapbuf, gpointer g_class)
720 {
721 #ifdef HAVE_XSHM
722   evaspixmapbuf->SHMInfo.shmaddr = ((void *) -1);
723   evaspixmapbuf->SHMInfo.shmid = -1;
724 #endif
725 }
726
727 static void
728 gst_evaspixmap_buffer_class_init (gpointer g_class, gpointer class_data)
729 {
730   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
731
732   evaspixmap_buffer_parent_class = g_type_class_peek_parent (g_class);
733
734   mini_object_class->finalize = (GstMiniObjectFinalizeFunction) gst_evaspixmap_buffer_finalize;
735 }
736
737 static GType
738 gst_evaspixmap_buffer_get_type (void)
739 {
740   static GType _gst_evaspixmap_buffer_type;
741
742   if (G_UNLIKELY (_gst_evaspixmap_buffer_type == 0)) {
743     static const GTypeInfo evaspixmap_buffer_info = {
744       sizeof (GstBufferClass),
745       NULL,
746       NULL,
747       gst_evaspixmap_buffer_class_init,
748       NULL,
749       NULL,
750       sizeof (GstEvasPixmapBuffer),
751       0,
752       (GInstanceInitFunc) gst_evaspixmap_buffer_init,
753       NULL
754     };
755     _gst_evaspixmap_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
756         "GstEvasPixmapBuffer", &evaspixmap_buffer_info, 0);
757   }
758   return _gst_evaspixmap_buffer_type;
759 }
760
761 /* This function handles GstEvasPixmapBuffer creation depending on XShm availability */
762 static GstEvasPixmapBuffer*
763 gst_evaspixmap_buffer_new (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
764 {
765         GstEvasPixmapBuffer *evaspixmapbuf = NULL;
766         GstStructure *structure = NULL;
767         gboolean succeeded = FALSE;
768         int (*handler) (Display *, XErrorEvent *);
769
770         g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
771
772         if (caps == NULL) {
773                 return NULL;
774         }
775
776         evaspixmapbuf = (GstEvasPixmapBuffer*) gst_mini_object_new (GST_TYPE_EVASPIXMAP_BUFFER);
777         GST_DEBUG_OBJECT (evaspixmapsink,"Creating new EvasPixmapBuffer");
778
779         structure = gst_caps_get_structure (caps, 0);
780
781         if (!gst_structure_get_int (structure, "width", &evaspixmapbuf->width) || !gst_structure_get_int (structure, "height", &evaspixmapbuf->height)) {
782                 GST_WARNING_OBJECT (evaspixmapsink,"failed getting geometry from caps %" GST_PTR_FORMAT, caps);
783         }
784
785         GST_LOG_OBJECT (evaspixmapsink,"creating %dx%d", evaspixmapbuf->width, evaspixmapbuf->height);
786
787         GST_LOG_OBJECT (evaspixmapsink,"aligned size %dx%d", evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
788         if (evaspixmapsink->aligned_width == 0 || evaspixmapsink->aligned_height == 0) {
789                 GST_INFO_OBJECT (evaspixmapsink,"aligned size is zero. set size of caps.");
790                 evaspixmapsink->aligned_width = evaspixmapbuf->width;
791                 evaspixmapsink->aligned_height = evaspixmapbuf->height;
792         }
793
794         evaspixmapbuf->im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
795         if (evaspixmapbuf->im_format == -1) {
796                 GST_WARNING_OBJECT (evaspixmapsink,"failed to get format from caps %"GST_PTR_FORMAT, caps);
797                 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",
798                                    evaspixmapbuf->width, evaspixmapbuf->height), ("Invalid input caps"));
799                 goto beach_unlocked;
800         }
801         evaspixmapbuf->evaspixmapsink = gst_object_ref (evaspixmapsink);
802
803         g_mutex_lock (evaspixmapsink->x_lock);
804
805         /* Setting an error handler to catch failure */
806         error_caught = FALSE;
807         handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
808
809 #ifdef HAVE_XSHM
810         if (evaspixmapsink->xcontext->use_xshm) {
811                 int expected_size;
812                 evaspixmapbuf->xvimage = XvShmCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, evaspixmapbuf->im_format, NULL,
813                 evaspixmapsink->aligned_width, evaspixmapsink->aligned_height, &evaspixmapbuf->SHMInfo);
814                 if(!evaspixmapbuf->xvimage) {
815                         GST_ERROR_OBJECT (evaspixmapsink,"XvShmCreateImage() failed");
816                 }
817
818                 if (!evaspixmapbuf->xvimage || error_caught) {
819                         if (error_caught) {
820                                 GST_ERROR_OBJECT (evaspixmapsink,"error_caught!");
821                         }
822                         g_mutex_unlock (evaspixmapsink->x_lock);
823                         /* Reset error handler */
824                         error_caught = FALSE;
825                         XSetErrorHandler (handler);
826                         /* Push an error */
827                         GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",evaspixmapbuf->width,
828                                    evaspixmapbuf->height),("could not XvShmCreateImage a %dx%d image",evaspixmapbuf->width, evaspixmapbuf->height));
829                         goto beach_unlocked;
830                 }
831
832                 /* we have to use the returned data_size for our shm size */
833                 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
834                 GST_LOG_OBJECT (evaspixmapsink,"XShm image size is %" G_GSIZE_FORMAT, evaspixmapbuf->size);
835
836                 /* calculate the expected size.  This is only for sanity checking the
837                 * number we get from X. */
838                 switch (evaspixmapbuf->im_format) {
839                 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
840                 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
841                 {
842                         gint pitches[3];
843                         gint offsets[3];
844                         guint plane;
845
846                         offsets[0] = 0;
847                         pitches[0] = GST_ROUND_UP_4 (evaspixmapbuf->width);
848                         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (evaspixmapbuf->height);
849                         pitches[1] = GST_ROUND_UP_8 (evaspixmapbuf->width) / 2;
850                         offsets[2] =
851                         offsets[1] + pitches[1] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
852                         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
853
854                         expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
855
856                         for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
857                                 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a expected pitch of %d bytes, " "offset of %d",
858                                                 plane, pitches[plane], offsets[plane]);
859                         }
860                         break;
861                 }
862                 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
863                 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
864                         expected_size = evaspixmapbuf->height * GST_ROUND_UP_4 (evaspixmapbuf->width * 2);
865                         break;
866                 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
867                 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
868                 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
869                 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
870                 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
871                 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
872                         expected_size = sizeof(SCMN_IMGB);
873                         break;
874                 default:
875                         expected_size = 0;
876                         break;
877                 }
878                 if (expected_size != 0 && evaspixmapbuf->size != expected_size) {
879                         GST_WARNING_OBJECT (evaspixmapsink,"unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", evaspixmapbuf->size, expected_size);
880                 }
881
882                 /* Be verbose about our XvImage stride */
883                 {
884                         guint plane;
885                         for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
886                                 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a pitch of %d bytes, ""offset of %d", plane,
887                                                 evaspixmapbuf->xvimage->pitches[plane], evaspixmapbuf->xvimage->offsets[plane]);
888                         }
889                 }
890
891                 evaspixmapbuf->SHMInfo.shmid = shmget (IPC_PRIVATE, evaspixmapbuf->size,IPC_CREAT | 0777);
892                 if (evaspixmapbuf->SHMInfo.shmid == -1) {
893                         g_mutex_unlock (evaspixmapsink->x_lock);
894                         GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
895                                 ("Failed to create output image buffer of %dx%d pixels", evaspixmapbuf->width, evaspixmapbuf->height),
896                                 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",evaspixmapbuf->size));
897                         goto beach_unlocked;
898                 }
899
900                 evaspixmapbuf->SHMInfo.shmaddr = shmat (evaspixmapbuf->SHMInfo.shmid, NULL, 0);
901                 if (evaspixmapbuf->SHMInfo.shmaddr == ((void *) -1)) {
902                         g_mutex_unlock (evaspixmapsink->x_lock);
903                         GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
904                                 ("Failed to create output image buffer of %dx%d pixels",
905                                 evaspixmapbuf->width, evaspixmapbuf->height),
906                                 ("Failed to shmat: %s", g_strerror (errno)));
907                         /* Clean up the shared memory segment */
908                         shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
909                         goto beach_unlocked;
910                 }
911
912                 evaspixmapbuf->xvimage->data = evaspixmapbuf->SHMInfo.shmaddr;
913                 evaspixmapbuf->SHMInfo.readOnly = FALSE;
914
915                 if (XShmAttach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo) == 0) {
916                 /* Clean up the shared memory segment */
917                 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
918
919                 g_mutex_unlock (evaspixmapsink->x_lock);
920                 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
921                         ("Failed to create output image buffer of %dx%d pixels",
922                         evaspixmapbuf->width, evaspixmapbuf->height), ("Failed to XShmAttach"));
923                 goto beach_unlocked;
924                 }
925
926                 XSync (evaspixmapsink->xcontext->disp, FALSE);
927
928                 /* Delete the shared memory segment as soon as we everyone is attached.
929                 * This way, it will be deleted as soon as we detach later, and not
930                 * leaked if we crash. */
931                 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
932
933                 GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmAttached to 0x%x, id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
934         } else
935 #endif /* HAVE_XSHM */
936         {
937                 evaspixmapbuf->xvimage = XvCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id,
938                 evaspixmapbuf->im_format, NULL, evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
939                 if (!evaspixmapbuf->xvimage || error_caught) {
940                         g_mutex_unlock (evaspixmapsink->x_lock);
941                         /* Reset error handler */
942                         error_caught = FALSE;
943                         XSetErrorHandler (handler);
944                         /* Push an error */
945                         GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
946                                 ("Failed to create outputimage buffer of %dx%d pixels",
947                                 evaspixmapbuf->width, evaspixmapbuf->height),
948                                 ("could not XvCreateImage a %dx%d image",
949                                 evaspixmapbuf->width, evaspixmapbuf->height));
950                         goto beach_unlocked;
951                 }
952
953                 /* we have to use the returned data_size for our image size */
954                 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
955                 evaspixmapbuf->xvimage->data = g_malloc (evaspixmapbuf->size);
956
957                 XSync (evaspixmapsink->xcontext->disp, FALSE);
958         }
959
960         /* Reset error handler */
961         error_caught = FALSE;
962         XSetErrorHandler (handler);
963
964         succeeded = TRUE;
965
966         GST_BUFFER_DATA (evaspixmapbuf) = (guchar *) evaspixmapbuf->xvimage->data;
967         GST_BUFFER_SIZE (evaspixmapbuf) = evaspixmapbuf->size;
968
969         g_mutex_unlock (evaspixmapsink->x_lock);
970
971 beach_unlocked:
972         if (!succeeded) {
973                 gst_evaspixmap_buffer_free (evaspixmapbuf);
974                 evaspixmapbuf = NULL;
975         }
976
977         return evaspixmapbuf;
978 }
979
980 /* This function puts a GstEvasPixmapBuffer on a GstEvasPixmapSink's pixmap. Returns FALSE
981  * if no pixmap was available  */
982 static gboolean
983 gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf)
984 {
985         GstVideoRectangle result;
986
987         GstVideoRectangle src_origin = { 0, 0, 0, 0};
988         GstVideoRectangle src_input  = { 0, 0, 0, 0};
989         GstVideoRectangle src = { 0, 0, 0, 0};
990         GstVideoRectangle dst = { 0, 0, 0, 0};
991         int rotate = 0;
992         int ret = 0;
993         int idx = 0;
994         GstXPixmap *xpixmap = NULL;
995
996         MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evaspixmap_buffer_put()", FALSE);
997
998         /* We take the flow_lock. If expose is in there we don't want to run
999         concurrently from the data flow thread */
1000         g_mutex_lock (evaspixmapsink->flow_lock);
1001
1002         if (G_UNLIKELY (evaspixmapsink->xpixmap[idx] == NULL)) {
1003                 GST_WARNING_OBJECT (evaspixmapsink, "xpixmap is NULL. Skip buffer_put." );
1004                 g_mutex_unlock(evaspixmapsink->flow_lock);
1005                 return FALSE;
1006         }
1007         if (evaspixmapsink->visible == FALSE) {
1008                 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. Skip buffer_put." );
1009                 g_mutex_unlock(evaspixmapsink->flow_lock);
1010                 return TRUE;
1011         }
1012         if (!evaspixmapbuf) {
1013                 GST_WARNING_OBJECT (evaspixmapsink, "evaspixmapbuf is NULL. Skip buffer_put." );
1014                 g_mutex_unlock(evaspixmapsink->flow_lock);
1015                 return TRUE;
1016         }
1017
1018         for (idx = 0; idx < evaspixmapsink->num_of_pixmaps; idx++) {
1019                 g_mutex_lock (evaspixmapsink->pixmap_ref_lock);
1020                 if (idx == evaspixmapsink->last_updated_idx) {
1021                         g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1022                         continue;
1023                 } else {
1024                         xpixmap = evaspixmapsink->xpixmap[idx];
1025                         if (xpixmap->ref == 0 && xpixmap->damaged_time == 0) {
1026                                 xpixmap->ref++;
1027                                 GST_LOG_OBJECT (evaspixmapsink, "found an available pixmap(%d) : xpixmap[%d]", xpixmap->pixmap, idx);
1028                                 GST_INFO_OBJECT (evaspixmapsink,"pixmap ref-count INCREASED : pixmap(%d), refcount(%d)", xpixmap->pixmap, xpixmap->ref);
1029                                 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1030                                 break;
1031                         }
1032                         g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1033                 }
1034         }
1035         if (idx == evaspixmapsink->num_of_pixmaps) {
1036                 GST_LOG_OBJECT (evaspixmapsink, "Could not find a pixmap with idle state, skip buffer_put." );
1037                 g_mutex_unlock(evaspixmapsink->flow_lock);
1038                 return TRUE;
1039         }
1040
1041         gst_evaspixmapsink_xpixmap_update_geometry(evaspixmapsink, idx);
1042
1043         src.x = src.y = 0;
1044         src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1045         src_input.w = src_origin.w = evaspixmapsink->video_width;
1046         src_input.h = src_origin.h = evaspixmapsink->video_height;
1047         if (evaspixmapsink->use_origin_size ||
1048                 (evaspixmapsink->rotate_angle == DEGREE_0 ||
1049                 evaspixmapsink->rotate_angle == DEGREE_180)) {
1050                 src.w = src_origin.w;
1051                 src.h = src_origin.h;
1052         } else {
1053                 src.w = src_origin.h;
1054                 src.h = src_origin.w;
1055         }
1056
1057         dst.w = evaspixmapsink->render_rect.w; /* pixmap width */
1058         dst.h = evaspixmapsink->render_rect.h; /* pixmap height */
1059
1060         if (!evaspixmapsink->use_origin_size) {
1061                 static Atom atom_rotation = None;
1062                 static Atom atom_hflip = None;
1063                 static Atom atom_vflip = None;
1064                 gboolean set_hflip = FALSE;
1065                 gboolean set_vflip = FALSE;
1066
1067                 /* compensation of size information (between evas image object's and pixmap's) */
1068                 if (evaspixmapsink->sizediff_width > 1) {
1069                         if (evaspixmapsink->sizediff_height > 1) {
1070                                 dst.w -= (evaspixmapsink->sizediff_width >> 1) << 1;
1071                                 dst.h -= (evaspixmapsink->sizediff_height >> 1) << 1;
1072                         } else {
1073                                 dst.w -= (evaspixmapsink->sizediff_width >> 1) << 1;
1074                         }
1075                 } else if (evaspixmapsink->sizediff_height > 1) {
1076                         dst.h -= (evaspixmapsink->sizediff_height >> 1) << 1;
1077                 }
1078
1079                 switch (evaspixmapsink->display_geometry_method) {
1080                 case DISP_GEO_METHOD_LETTER_BOX:
1081                         gst_video_sink_center_rect (src, dst, &result, TRUE);
1082                         result.x += evaspixmapsink->render_rect.x;
1083                         result.y += evaspixmapsink->render_rect.y;
1084                         GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : letter box");
1085                         break;
1086                 case DISP_GEO_METHOD_ORIGIN_SIZE:
1087                         gst_video_sink_center_rect (src, dst, &result, FALSE);
1088                         gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1089                         GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : origin size");
1090                         if (evaspixmapsink->rotate_angle == DEGREE_90 ||
1091                                 evaspixmapsink->rotate_angle == DEGREE_270) {
1092                                 src_input.x = src_input.x ^ src_input.y;
1093                                 src_input.y = src_input.x ^ src_input.y;
1094                                 src_input.x = src_input.x ^ src_input.y;
1095                                 src_input.w = src_input.w ^ src_input.h;
1096                                 src_input.h = src_input.w ^ src_input.h;
1097                                 src_input.w = src_input.w ^ src_input.h;
1098                         }
1099                         break;
1100                 case DISP_GEO_METHOD_FULL_SCREEN:
1101                         result.x = result.y = 0;
1102                         result.w = evaspixmapsink->xpixmap[idx]->width;
1103                         result.h = evaspixmapsink->xpixmap[idx]->height;
1104                         GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : full screen");
1105                         break;
1106                 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1107                         GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : cropped full screen");
1108                         gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1109                         result.x = result.y = 0;
1110                         result.w = dst.w;
1111                         result.h = dst.h;
1112                         if (evaspixmapsink->rotate_angle == DEGREE_90 ||
1113                                 evaspixmapsink->rotate_angle == DEGREE_270) {
1114                                 src_input.x = src_input.x ^ src_input.y;
1115                                 src_input.y = src_input.x ^ src_input.y;
1116                                 src_input.x = src_input.x ^ src_input.y;
1117                                 src_input.w = src_input.w ^ src_input.h;
1118                                 src_input.h = src_input.w ^ src_input.h;
1119                                 src_input.w = src_input.w ^ src_input.h;
1120                         }
1121                         break;
1122                 case DISP_GEO_METHOD_CUSTOM_ROI:
1123                         switch (evaspixmapsink->rotate_angle) {
1124                         case DEGREE_90:
1125                                 result.w = evaspixmapsink->dst_roi.h;
1126                                 result.h = evaspixmapsink->dst_roi.w;
1127                                 result.x = evaspixmapsink->dst_roi.y;
1128                                 result.y = evaspixmapsink->xpixmap[idx]->height - evaspixmapsink->dst_roi.x - evaspixmapsink->dst_roi.w;
1129                                 break;
1130                         case DEGREE_180:
1131                                 result.w = evaspixmapsink->dst_roi.w;
1132                                 result.h = evaspixmapsink->dst_roi.h;
1133                                 result.x = evaspixmapsink->xpixmap[idx]->width - result.w - evaspixmapsink->dst_roi.x;
1134                                 result.y = evaspixmapsink->xpixmap[idx]->height - result.h - evaspixmapsink->dst_roi.y;
1135                                 break;
1136                         case DEGREE_270:
1137                                 result.w = evaspixmapsink->dst_roi.h;
1138                                 result.h = evaspixmapsink->dst_roi.w;
1139                                 result.x = evaspixmapsink->xpixmap[idx]->width - evaspixmapsink->dst_roi.y - evaspixmapsink->dst_roi.h;
1140                                 result.y = evaspixmapsink->dst_roi.x;
1141                                 break;
1142                         default:
1143                                 result.x = evaspixmapsink->dst_roi.x;
1144                                 result.y = evaspixmapsink->dst_roi.y;
1145                                 result.w = evaspixmapsink->dst_roi.w;
1146                                 result.h = evaspixmapsink->dst_roi.h;
1147                                 break;
1148                         }
1149                         GST_LOG_OBJECT(evaspixmapsink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1150                                         evaspixmapsink->rotate_angle,
1151                                         evaspixmapsink->dst_roi.x, evaspixmapsink->dst_roi.y, evaspixmapsink->dst_roi.w, evaspixmapsink->dst_roi.h,
1152                                         result.x, result.y, result.w, result.h);
1153                         break;
1154                 default:
1155                         break;
1156                 }
1157                 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : src(%dx%d), dst(%dx%d), result(%dx%d), result_x(%d), result_y(%d)",
1158                                 src.w,src.h,dst.w,dst.h,result.w,result.h,result.x,result.y);
1159
1160                 switch( evaspixmapsink->rotate_angle ) {
1161                         case DEGREE_0:
1162                         break;
1163                         case DEGREE_90:
1164                         rotate = 270;
1165                         break;
1166                         case DEGREE_180:
1167                         rotate = 180;
1168                         break;
1169                         case DEGREE_270:
1170                         rotate = 90;
1171                         break;
1172                         default:
1173                         GST_WARNING_OBJECT( evaspixmapsink, "Unsupported rotation [%d]... set DEGREE 0.",
1174                                         evaspixmapsink->rotate_angle );
1175                         break;
1176                 }
1177
1178                 /* set display rotation */
1179                 if (atom_rotation == None) {
1180                         atom_rotation = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1181                 }
1182
1183                 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate);
1184                 if (ret != Success) {
1185                         GST_ERROR_OBJECT( evaspixmapsink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1186                                         ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate );
1187                         return FALSE;
1188                 }
1189
1190                 /* set display flip */
1191                 if (atom_hflip == None) {
1192                         atom_hflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1193                 }
1194                 if (atom_vflip == None) {
1195                         atom_vflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1196                 }
1197
1198                 switch (evaspixmapsink->flip) {
1199                 case FLIP_HORIZONTAL:
1200                         set_hflip = TRUE;
1201                         set_vflip = FALSE;
1202                         break;
1203                 case FLIP_VERTICAL:
1204                         set_hflip = FALSE;
1205                         set_vflip = TRUE;
1206                         break;
1207                 case FLIP_BOTH:
1208                         set_hflip = TRUE;
1209                         set_vflip = TRUE;
1210                         break;
1211                 case FLIP_NONE:
1212                 default:
1213                         set_hflip = FALSE;
1214                         set_vflip = FALSE;
1215                         break;
1216                 }
1217                 GST_INFO_OBJECT(evaspixmapsink, "set rotate %d HFLIP %d, VFLIP %d", rotate, set_hflip, set_vflip);
1218
1219                 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1220                 if (ret != Success) {
1221                         GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1222                                         ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1223                 }
1224                 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1225                 if (ret != Success) {
1226                         GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1227                                         ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1228                 }
1229
1230         } else {
1231                 result.x = result.y = 0;
1232                 result.w = evaspixmapsink->xpixmap[idx]->width;
1233                 result.h = evaspixmapsink->xpixmap[idx]->height;
1234                 GST_INFO_OBJECT (evaspixmapsink, "USE ORIGIN SIZE, no geometry method, no rotation/flip" );
1235         }
1236
1237         g_mutex_lock (evaspixmapsink->x_lock);
1238
1239   /* We scale to the pixmap's geometry */
1240 #ifdef HAVE_XSHM
1241         if (evaspixmapsink->xcontext->use_xshm) {
1242                 GST_LOG_OBJECT (evaspixmapsink,"XvShmPutImage with image %dx%d and pixmap %dx%d, from xvimage %"
1243                                 GST_PTR_FORMAT,
1244                                 evaspixmapbuf->width, evaspixmapbuf->height,
1245                                 evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h, evaspixmapbuf);
1246
1247         /* Trim as proper size */
1248         if (src_input.w % 2 == 1) {
1249                 src_input.w += 1;
1250         }
1251         if (src_input.h % 2 == 1) {
1252                 src_input.h += 1;
1253         }
1254
1255         GST_LOG_OBJECT (evaspixmapsink, "screen[%dx%d],pixmap[%d,%d,%dx%d],method[%d],rotate[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1256                 evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1257                 evaspixmapsink->xpixmap[idx]->x, evaspixmapsink->xpixmap[idx]->y, evaspixmapsink->xpixmap[idx]->width, evaspixmapsink->xpixmap[idx]->height,
1258                 evaspixmapsink->display_geometry_method, rotate,
1259                 src_origin.w, src_origin.h,
1260                 dst.x, dst.y, dst.w, dst.h,
1261                 src_input.x, src_input.y, src_input.w, src_input.h,
1262                 result.x, result.y, result.w, result.h );
1263
1264         if (evaspixmapsink->visible) {
1265                 ret = XvShmPutImage (evaspixmapsink->xcontext->disp,
1266                         evaspixmapsink->xcontext->xv_port_id,
1267                         evaspixmapsink->xpixmap[idx]->pixmap,
1268                         evaspixmapsink->xpixmap[idx]->gc, evaspixmapbuf->xvimage,
1269                         src_input.x, src_input.y, src_input.w, src_input.h,
1270                         result.x, result.y, result.w, result.h, FALSE);
1271                 GST_LOG_OBJECT (evaspixmapsink, "XvShmPutImage return value [%d]", ret );
1272
1273         } else {
1274                 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1275         }
1276   } else
1277 #endif /* HAVE_XSHM */
1278         {
1279                 if (evaspixmapsink->visible) {
1280                 XvPutImage (evaspixmapsink->xcontext->disp,
1281                         evaspixmapsink->xcontext->xv_port_id,
1282                         evaspixmapsink->xpixmap[idx]->pixmap,
1283                         evaspixmapsink->xpixmap[idx]->gc, evaspixmapbuf->xvimage,
1284                         evaspixmapsink->disp_x, evaspixmapsink->disp_y,
1285                         evaspixmapsink->disp_width, evaspixmapsink->disp_height,
1286                         result.x, result.y, result.w, result.h);
1287                 } else {
1288                         GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1289                 }
1290         }
1291         XSync (evaspixmapsink->xcontext->disp, FALSE);
1292
1293         g_mutex_unlock (evaspixmapsink->x_lock);
1294         g_mutex_unlock (evaspixmapsink->flow_lock);
1295
1296         MMTA_ACUM_ITEM_END("evaspixmapsink evaspixmap_buffer_put()", FALSE);
1297
1298         return TRUE;
1299 }
1300
1301 static int
1302 drm_init(GstEvasPixmapSink *evaspixmapsink)
1303 {
1304         Display *dpy;
1305         int i = 0;
1306         int eventBase = 0;
1307         int errorBase = 0;
1308         int dri2Major = 0;
1309         int dri2Minor = 0;
1310         char *driverName = NULL;
1311         char *deviceName = NULL;
1312         struct drm_auth auth_arg = {0};
1313
1314         evaspixmapsink->drm_fd = -1;
1315
1316         dpy = XOpenDisplay(0);
1317
1318         /* DRI2 */
1319         if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
1320                 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryExtension()");
1321                 goto ERROR_CASE;
1322         }
1323
1324         if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
1325                 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryVersion");
1326                 goto ERROR_CASE;
1327         }
1328
1329         if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
1330                 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2Connect");
1331                 goto ERROR_CASE;
1332         }
1333
1334         if (!driverName || !deviceName) {
1335                 GST_ERROR_OBJECT (evaspixmapsink,"driverName or deviceName is not valid");
1336                 goto ERROR_CASE;
1337         }
1338
1339         GST_INFO_OBJECT (evaspixmapsink,"Open drm device : %s", deviceName);
1340
1341         /* get the drm_fd though opening the deviceName */
1342         evaspixmapsink->drm_fd = open(deviceName, O_RDWR);
1343         if (evaspixmapsink->drm_fd < 0) {
1344                 GST_ERROR_OBJECT (evaspixmapsink,"cannot open drm device (%s)", deviceName);
1345                 goto ERROR_CASE;
1346         }
1347
1348         /* get magic from drm to authentication */
1349         if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
1350                 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm auth magic");
1351                 close(evaspixmapsink->drm_fd);
1352                 evaspixmapsink->drm_fd = -1;
1353                 goto ERROR_CASE;
1354         }
1355
1356         if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
1357                 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm authentication from X");
1358                 close(evaspixmapsink->drm_fd);
1359                 evaspixmapsink->drm_fd = -1;
1360                 goto ERROR_CASE;
1361         }
1362
1363         /* init gem handle */
1364         for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1365                 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1366                 evaspixmapsink->gem_info[i].gem_handle = 0;
1367                 evaspixmapsink->gem_info[i].gem_name = 0;
1368         }
1369
1370         XCloseDisplay(dpy);
1371         free(driverName);
1372         free(deviceName);
1373
1374         return 0;
1375
1376 ERROR_CASE:
1377         XCloseDisplay(dpy);
1378         if (driverName) {
1379                 free(driverName);
1380         }
1381         if (deviceName) {
1382                 free(deviceName);
1383         }
1384
1385         return -1;
1386 }
1387
1388 static void
1389 drm_fini(GstEvasPixmapSink *evaspixmapsink)
1390 {
1391         if (evaspixmapsink->drm_fd >= 0) {
1392                 GST_INFO_OBJECT (evaspixmapsink,"close drm_fd(%d)", evaspixmapsink->drm_fd);
1393                 close(evaspixmapsink->drm_fd);
1394                 evaspixmapsink->drm_fd = -1;
1395         }
1396 }
1397
1398 static unsigned int
1399 drm_init_convert_dmabuf_gemname(GstEvasPixmapSink *evaspixmapsink, int dmabuf_fd)
1400 {
1401         struct drm_prime_handle prime_arg = {0,};
1402         struct drm_gem_flink flink_arg = {0,};
1403         int i = 0;
1404
1405         if (evaspixmapsink->drm_fd < 0) {
1406                 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1407                 return 0;
1408         }
1409
1410         if (dmabuf_fd <= 0) {
1411                 GST_DEBUG_OBJECT (evaspixmapsink,"Ignore wrong dmabuf fd(%d)", dmabuf_fd);              /* temporarily change log level to DEBUG for reducing WARNING level log */
1412                 return 0;
1413         }
1414
1415         /* check duplicated dmabuf fd */
1416         for (i = 0 ; i < MAX_GEM_BUFFER_NUM ; i++) {
1417                 if (evaspixmapsink->gem_info[i].dmabuf_fd == dmabuf_fd) {
1418                         GST_LOG_OBJECT (evaspixmapsink,"already got fd(%u) with name(%u)", dmabuf_fd, evaspixmapsink->gem_info[i].gem_name);
1419                         return evaspixmapsink->gem_info[i].gem_name;
1420                 }
1421
1422                 if (evaspixmapsink->gem_info[i].dmabuf_fd == 0) {
1423                         GST_LOG_OBJECT (evaspixmapsink,"empty gem_info[%d] found", i);
1424                         break;
1425                 }
1426         }
1427
1428         if (i == MAX_GEM_BUFFER_NUM) {
1429                 GST_WARNING_OBJECT (evaspixmapsink,"too many buffers[dmabuf_fd(%d). skip it]", dmabuf_fd);
1430                 return 0;
1431         }
1432
1433         evaspixmapsink->gem_info[i].dmabuf_fd = dmabuf_fd;
1434         prime_arg.fd = dmabuf_fd;
1435         if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg)) {
1436                 GST_ERROR_OBJECT (evaspixmapsink,"non dmabuf fd(%d)", dmabuf_fd);
1437                 return 0;
1438         }
1439
1440         evaspixmapsink->gem_info[i].gem_handle = prime_arg.handle;
1441         GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_handle = %u", i, prime_arg.handle);
1442
1443         flink_arg.handle = prime_arg.handle;
1444         if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg)) {
1445                 GST_ERROR_OBJECT (evaspixmapsink,"cannot convert drm handle to name");
1446                 return 0;
1447         }
1448
1449         evaspixmapsink->gem_info[i].gem_name = flink_arg.name;
1450         GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_name = %u", i, flink_arg.name);
1451
1452         return flink_arg.name;
1453 }
1454
1455 static void
1456 drm_fini_close_gem_handle(GstEvasPixmapSink *evaspixmapsink)
1457 {
1458         int i = 0;
1459         if (evaspixmapsink->drm_fd >= 0) {
1460                 for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1461                         if (evaspixmapsink->gem_info[i].dmabuf_fd > 0) {
1462                                 GST_INFO_OBJECT (evaspixmapsink,"close gem_handle(%u)", evaspixmapsink->gem_info[i].gem_handle);
1463                                 drm_close_gem(evaspixmapsink, evaspixmapsink->gem_info[i].gem_handle);
1464                                 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1465                                 evaspixmapsink->gem_info[i].gem_handle = 0;
1466                                 evaspixmapsink->gem_info[i].gem_name = 0;
1467                         } else {
1468                                 break;
1469                         }
1470                 }
1471         }
1472 }
1473
1474 static void
1475 drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle)
1476 {
1477         struct drm_gem_close close_arg = {0,};
1478
1479         if (evaspixmapsink->drm_fd < 0) {
1480                 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1481                 return;
1482         }
1483
1484         if (gem_handle == 0) {
1485                 GST_ERROR_OBJECT (evaspixmapsink,"invalid gem_handle(%d)",gem_handle);
1486                 return;
1487         }
1488
1489         close_arg.handle = gem_handle;
1490         if (gem_handle > 0 && ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
1491                 GST_ERROR_OBJECT (evaspixmapsink,"cannot close drm gem handle(%d)", gem_handle);
1492                 return;
1493         }
1494
1495         return;
1496 }
1497
1498 /* This function destroys a GstXPixmap */
1499 static void
1500 gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1501 {
1502         g_return_if_fail (xpixmap != NULL);
1503         g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1504
1505         g_mutex_lock (evaspixmapsink->x_lock);
1506
1507         if(xpixmap->pixmap) {
1508                 GST_LOG_OBJECT (evaspixmapsink,"Free pixmap(%d)", xpixmap->pixmap);
1509                 XFreePixmap(evaspixmapsink->xcontext->disp, xpixmap->pixmap);
1510                 xpixmap->pixmap = 0;
1511         }
1512
1513         if (xpixmap->gc) {
1514                 XFreeGC (evaspixmapsink->xcontext->disp, xpixmap->gc);
1515         }
1516
1517         XSync (evaspixmapsink->xcontext->disp, FALSE);
1518
1519         g_mutex_unlock (evaspixmapsink->x_lock);
1520
1521         g_free (xpixmap);
1522 }
1523
1524 static void
1525 gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink, int idx)
1526 {
1527         Window root_window;
1528         XWindowAttributes root_attr;
1529
1530         int cur_pixmap_x = 0;
1531         int cur_pixmap_y = 0;
1532         unsigned int cur_pixmap_width = 0;
1533         unsigned int cur_pixmap_height = 0;
1534         unsigned int cur_pixmap_border_width = 0;
1535         unsigned int cur_pixmap_depth = 0;
1536
1537         g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1538
1539         /* Update the window geometry */
1540         g_mutex_lock (evaspixmapsink->x_lock);
1541         if (G_UNLIKELY (evaspixmapsink->xpixmap[idx] == NULL)) {
1542                 g_mutex_unlock (evaspixmapsink->x_lock);
1543                 return;
1544         }
1545
1546         /* Get root window and size of current pixmap */
1547         XGetGeometry( evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap[idx]->pixmap, &root_window,
1548                         &cur_pixmap_x, &cur_pixmap_y, /* relative x, y, for pixmap these are alway 0 */
1549                         &cur_pixmap_width, &cur_pixmap_height,
1550                         &cur_pixmap_border_width, &cur_pixmap_depth ); /* cur_pixmap_border_width, cur_pixmap_depth are not used */
1551
1552         evaspixmapsink->xpixmap[idx]->width = cur_pixmap_width;
1553         evaspixmapsink->xpixmap[idx]->height = cur_pixmap_height;
1554
1555         evaspixmapsink->xpixmap[idx]->x = cur_pixmap_x;
1556         evaspixmapsink->xpixmap[idx]->y = cur_pixmap_y;
1557
1558         /* Get size of root window == size of screen */
1559         XGetWindowAttributes(evaspixmapsink->xcontext->disp, root_window, &root_attr);
1560
1561         evaspixmapsink->scr_w = root_attr.width;
1562         evaspixmapsink->scr_h = root_attr.height;
1563
1564         if (!evaspixmapsink->have_render_rect) {
1565                 evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = 0;
1566                 evaspixmapsink->render_rect.w = cur_pixmap_width;
1567                 evaspixmapsink->render_rect.h = cur_pixmap_height;
1568         }
1569
1570         GST_LOG_OBJECT (evaspixmapsink,"screen size %dx%d, current pixmap geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
1571                         evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1572                         evaspixmapsink->xpixmap[idx]->x, evaspixmapsink->xpixmap[idx]->y,
1573                         evaspixmapsink->xpixmap[idx]->width, evaspixmapsink->xpixmap[idx]->height,
1574                         evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y,
1575                         evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1576
1577         g_mutex_unlock (evaspixmapsink->x_lock);
1578 }
1579
1580 static void
1581 gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1582 {
1583         g_return_if_fail (xpixmap != NULL);
1584         g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1585
1586         if (!xpixmap->pixmap) {
1587                 GST_WARNING_OBJECT (evaspixmapsink,"pixmap was not created..");
1588                 return;
1589         }
1590
1591         g_mutex_lock (evaspixmapsink->x_lock);
1592
1593         if (!evaspixmapsink->xcontext) {
1594                 GST_WARNING_OBJECT (evaspixmapsink,"xcontext is null..");
1595                 g_mutex_unlock (evaspixmapsink->x_lock);
1596                 return;
1597         }
1598
1599         if (evaspixmapsink->stop_video) {
1600                 XvStopVideo (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, xpixmap->pixmap);
1601         }
1602         XSetForeground (evaspixmapsink->xcontext->disp, xpixmap->gc, evaspixmapsink->xcontext->black);
1603         XFillRectangle (evaspixmapsink->xcontext->disp, xpixmap->pixmap, xpixmap->gc,
1604                 evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y, evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1605
1606         XSync (evaspixmapsink->xcontext->disp, FALSE);
1607
1608         g_mutex_unlock (evaspixmapsink->x_lock);
1609 }
1610
1611 /* This function commits our internal colorbalance settings to our grabbed Xv
1612    port. If the xcontext is not initialized yet it simply returns */
1613 static void
1614 gst_evaspixmapsink_update_colorbalance (GstEvasPixmapSink *evaspixmapsink)
1615 {
1616   GList *channels = NULL;
1617
1618   g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1619
1620   /* If we haven't initialized the X context we can't update anything */
1621   if (evaspixmapsink->xcontext == NULL)
1622     return;
1623
1624   /* Don't set the attributes if they haven't been changed, to avoid
1625    * rounding errors changing the values */
1626   if (!evaspixmapsink->cb_changed)
1627     return;
1628
1629   /* For each channel of the colorbalance we calculate the correct value
1630      doing range conversion and then set the Xv port attribute to match our
1631      values. */
1632   channels = evaspixmapsink->xcontext->channels_list;
1633
1634   while (channels) {
1635     if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
1636       GstColorBalanceChannel *channel = NULL;
1637       Atom prop_atom;
1638       gint value = 0;
1639       gdouble convert_coef;
1640
1641       channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
1642       g_object_ref (channel);
1643
1644       /* Our range conversion coef */
1645       convert_coef = (channel->max_value - channel->min_value) / 2000.0;
1646
1647       if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
1648         value = evaspixmapsink->hue;
1649       } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
1650         value = evaspixmapsink->saturation;
1651       } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
1652         value = evaspixmapsink->contrast;
1653       } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
1654         value = evaspixmapsink->brightness;
1655       } else {
1656         g_warning ("got an unknown channel %s", channel->label);
1657         g_object_unref (channel);
1658         return;
1659       }
1660
1661       /* Committing to Xv port */
1662       g_mutex_lock (evaspixmapsink->x_lock);
1663       prop_atom =
1664           XInternAtom (evaspixmapsink->xcontext->disp, channel->label, True);
1665       if (prop_atom != None) {
1666         int xv_value;
1667         xv_value =
1668             floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
1669         XvSetPortAttribute (evaspixmapsink->xcontext->disp,
1670             evaspixmapsink->xcontext->xv_port_id, prop_atom, xv_value);
1671       }
1672       g_mutex_unlock (evaspixmapsink->x_lock);
1673
1674       g_object_unref (channel);
1675     }
1676     channels = g_list_next (channels);
1677   }
1678 }
1679
1680 static void
1681 gst_lookup_xv_port_from_adaptor (GstXContext *xcontext, XvAdaptorInfo *adaptors, int adaptor_no)
1682 {
1683   gint j;
1684   gint res;
1685
1686   /* Do we support XvImageMask ? */
1687   if (!(adaptors[adaptor_no].type & XvImageMask)) {
1688     GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", adaptors[adaptor_no].name);
1689     return;
1690   }
1691
1692   /* We found such an adaptor, looking for an available port */
1693   for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
1694     /* We try to grab the port */
1695     res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
1696     if (Success == res) {
1697       xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
1698       GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, adaptors[adaptor_no].num_ports);
1699     } else {
1700       GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, adaptors[adaptor_no].name, res);
1701     }
1702   }
1703 }
1704
1705 /* This function generates a caps with all supported format by the first
1706    Xv grabable port we find. We store each one of the supported formats in a
1707    format list and append the format to a newly created caps that we return
1708    If this function does not return NULL because of an error, it also grabs
1709    the port via XvGrabPort */
1710 static GstCaps*
1711 gst_evaspixmapsink_get_xv_support (GstEvasPixmapSink *evaspixmapsink, GstXContext *xcontext)
1712 {
1713   gint i;
1714   XvAdaptorInfo *adaptors;
1715   gint nb_formats;
1716   XvImageFormatValues *formats = NULL;
1717   guint nb_encodings;
1718   XvEncodingInfo *encodings = NULL;
1719   gulong max_w = G_MAXINT, max_h = G_MAXINT;
1720   GstCaps *caps = NULL;
1721   GstCaps *rgb_caps = NULL;
1722
1723   g_return_val_if_fail (xcontext != NULL, NULL);
1724
1725   /* First let's check that XVideo extension is available */
1726   if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
1727     GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1728         ("Could not initialise Xv output"),
1729         ("XVideo extension is not available"));
1730     return NULL;
1731   }
1732
1733   /* Then we get adaptors list */
1734   if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
1735           &xcontext->nb_adaptors, &adaptors)) {
1736     GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1737         ("Could not initialise Xv output"),
1738         ("Failed getting XV adaptors list"));
1739     return NULL;
1740   }
1741
1742   xcontext->xv_port_id = 0;
1743
1744   GST_DEBUG_OBJECT (evaspixmapsink,"Found %u XV adaptor(s)", xcontext->nb_adaptors);
1745
1746   xcontext->adaptors =
1747       (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
1748
1749   /* Now fill up our adaptor name array */
1750   for (i = 0; i < xcontext->nb_adaptors; i++) {
1751     xcontext->adaptors[i] = g_strdup (adaptors[i].name);
1752   }
1753
1754   if (evaspixmapsink->adaptor_no < xcontext->nb_adaptors) {
1755     /* Find xv port from user defined adaptor */
1756     gst_lookup_xv_port_from_adaptor (xcontext, adaptors, evaspixmapsink->adaptor_no);
1757   }
1758
1759   if (!xcontext->xv_port_id) {
1760     /* Now search for an adaptor that supports XvImageMask */
1761     for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
1762       gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
1763       evaspixmapsink->adaptor_no = i;
1764     }
1765   }
1766
1767   XvFreeAdaptorInfo (adaptors);
1768
1769   if (!xcontext->xv_port_id) {
1770     evaspixmapsink->adaptor_no = -1;
1771     GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, BUSY,
1772         ("Could not initialise Xv output"), ("No port available"));
1773     return NULL;
1774   }
1775
1776   /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
1777   {
1778     int count, todo = 3;
1779     XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
1780         xcontext->xv_port_id, &count);
1781     static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
1782     static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
1783     static const char colorkey[] = "XV_COLORKEY";
1784
1785     GST_DEBUG_OBJECT (evaspixmapsink,"Checking %d Xv port attributes", count);
1786
1787     evaspixmapsink->have_autopaint_colorkey = FALSE;
1788     evaspixmapsink->have_double_buffer = FALSE;
1789     evaspixmapsink->have_colorkey = FALSE;
1790
1791     for (i = 0; ((i < count) && todo); i++)
1792       if (!strcmp (attr[i].name, autopaint)) {
1793         const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
1794
1795         /* turn on autopaint colorkey */
1796         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1797             (evaspixmapsink->autopaint_colorkey ? 1 : 0));
1798         todo--;
1799         evaspixmapsink->have_autopaint_colorkey = TRUE;
1800       } else if (!strcmp (attr[i].name, dbl_buffer)) {
1801         const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
1802
1803         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1804             (evaspixmapsink->double_buffer ? 1 : 0));
1805         todo--;
1806         evaspixmapsink->have_double_buffer = TRUE;
1807       } else if (!strcmp (attr[i].name, colorkey)) {
1808         /* Set the colorkey, default is something that is dark but hopefully
1809          * won't randomly appear on the screen elsewhere (ie not black or greys)
1810          * can be overridden by setting "colorkey" property
1811          */
1812         const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
1813         guint32 ckey = 0;
1814         gboolean set_attr = TRUE;
1815         guint cr, cg, cb;
1816
1817         /* set a colorkey in the right format RGB565/RGB888
1818          * We only handle these 2 cases, because they're the only types of
1819          * devices we've encountered. If we don't recognise it, leave it alone
1820          */
1821         cr = (evaspixmapsink->colorkey >> 16);
1822         cg = (evaspixmapsink->colorkey >> 8) & 0xFF;
1823         cb = (evaspixmapsink->colorkey) & 0xFF;
1824         switch (xcontext->depth) {
1825           case 16:             /* RGB 565 */
1826             cr >>= 3;
1827             cg >>= 2;
1828             cb >>= 3;
1829             ckey = (cr << 11) | (cg << 5) | cb;
1830             break;
1831           case 24:
1832           case 32:             /* RGB 888 / ARGB 8888 */
1833             ckey = (cr << 16) | (cg << 8) | cb;
1834             break;
1835           default:
1836             GST_DEBUG_OBJECT (evaspixmapsink,"Unknown bit depth %d for Xv Colorkey - not adjusting", xcontext->depth);
1837             set_attr = FALSE;
1838             break;
1839         }
1840
1841         if (set_attr) {
1842           ckey = CLAMP (ckey, (guint32) attr[i].min_value,
1843               (guint32) attr[i].max_value);
1844           GST_LOG_OBJECT (evaspixmapsink,"Setting color key for display depth %d to 0x%x", xcontext->depth, ckey);
1845
1846           XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1847               (gint) ckey);
1848         }
1849         todo--;
1850         evaspixmapsink->have_colorkey = TRUE;
1851       }
1852
1853     XFree (attr);
1854   }
1855
1856   /* Get the list of encodings supported by the adapter and look for the
1857    * XV_IMAGE encoding so we can determine the maximum width and height
1858    * supported */
1859   XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
1860       &encodings);
1861
1862   for (i = 0; i < nb_encodings; i++) {
1863     GST_LOG_OBJECT (evaspixmapsink,
1864         "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
1865         i, encodings[i].name, encodings[i].width, encodings[i].height,
1866         encodings[i].rate.numerator, encodings[i].rate.denominator);
1867     if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
1868       max_w = encodings[i].width;
1869       max_h = encodings[i].height;
1870       evaspixmapsink->scr_w = max_w;
1871       evaspixmapsink->scr_h = max_h;
1872     }
1873   }
1874
1875   XvFreeEncodingInfo (encodings);
1876
1877   /* We get all image formats supported by our port */
1878   formats = XvListImageFormats (xcontext->disp,
1879       xcontext->xv_port_id, &nb_formats);
1880   caps = gst_caps_new_empty ();
1881   for (i = 0; i < nb_formats; i++) {
1882     GstCaps *format_caps = NULL;
1883     gboolean is_rgb_format = FALSE;
1884
1885     /* We set the image format of the xcontext to an existing one. This
1886        is just some valid image format for making our xshm calls check before
1887        caps negotiation really happens. */
1888     xcontext->im_format = formats[i].id;
1889
1890     switch (formats[i].type) {
1891       case XvRGB:
1892       {
1893         XvImageFormatValues *fmt = &(formats[i]);
1894         gint endianness = G_BIG_ENDIAN;
1895
1896         if (fmt->byte_order == LSBFirst) {
1897           /* our caps system handles 24/32bpp RGB as big-endian. */
1898           if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
1899             fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
1900             fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
1901             fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
1902
1903             if (fmt->bits_per_pixel == 24) {
1904               fmt->red_mask >>= 8;
1905               fmt->green_mask >>= 8;
1906               fmt->blue_mask >>= 8;
1907             }
1908           } else
1909             endianness = G_LITTLE_ENDIAN;
1910         }
1911
1912         format_caps = gst_caps_new_simple ("video/x-raw-rgb",
1913             "endianness", G_TYPE_INT, endianness,
1914             "depth", G_TYPE_INT, fmt->depth,
1915             "bpp", G_TYPE_INT, fmt->bits_per_pixel,
1916             "red_mask", G_TYPE_INT, fmt->red_mask,
1917             "green_mask", G_TYPE_INT, fmt->green_mask,
1918             "blue_mask", G_TYPE_INT, fmt->blue_mask,
1919             "width", GST_TYPE_INT_RANGE, 1, max_w,
1920             "height", GST_TYPE_INT_RANGE, 1, max_h,
1921             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1922
1923         is_rgb_format = TRUE;
1924         break;
1925       }
1926       case XvYUV:
1927         format_caps = gst_caps_new_simple ("video/x-raw-yuv",
1928             "format", GST_TYPE_FOURCC, formats[i].id,
1929             "width", GST_TYPE_INT_RANGE, 1, max_w,
1930             "height", GST_TYPE_INT_RANGE, 1, max_h,
1931             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1932         break;
1933       default:
1934         g_assert_not_reached ();
1935         break;
1936     }
1937
1938     if (format_caps) {
1939       GstEvasPixmapFormat *format = NULL;
1940
1941       format = g_new0 (GstEvasPixmapFormat, 1);
1942       if (format) {
1943         format->format = formats[i].id;
1944         format->caps = gst_caps_copy (format_caps);
1945         xcontext->formats_list = g_list_append (xcontext->formats_list, format);
1946       }
1947
1948       if (is_rgb_format) {
1949         if (rgb_caps == NULL)
1950           rgb_caps = format_caps;
1951         else
1952           gst_caps_append (rgb_caps, format_caps);
1953       } else
1954         gst_caps_append (caps, format_caps);
1955     }
1956   }
1957
1958   /* Collected all caps into either the caps or rgb_caps structures.
1959    * Append rgb_caps on the end of YUV, so that YUV is always preferred */
1960   if (rgb_caps)
1961     gst_caps_append (caps, rgb_caps);
1962
1963   if (formats)
1964     XFree (formats);
1965
1966   GST_DEBUG_OBJECT (evaspixmapsink,"Generated the following caps: %" GST_PTR_FORMAT, caps);
1967
1968   if (gst_caps_is_empty (caps)) {
1969     gst_caps_unref (caps);
1970     XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
1971     GST_ELEMENT_ERROR (evaspixmapsink, STREAM, WRONG_TYPE, (NULL),
1972         ("No supported format found"));
1973     return NULL;
1974   }
1975
1976   return caps;
1977 }
1978
1979 static gpointer
1980 gst_evaspixmapsink_event_thread (GstEvasPixmapSink * evaspixmapsink)
1981 {
1982         g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
1983         int damage_base = 0;
1984         int damage_err_base = 0;
1985         int damage_case = 0;
1986         XEvent e;
1987         int i = 0;
1988         Display *disp = NULL;
1989
1990         GST_OBJECT_LOCK (evaspixmapsink);
1991
1992         if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->disp) {
1993                 disp = evaspixmapsink->xcontext->disp;
1994         } else {
1995                 GST_ERROR_OBJECT (evaspixmapsink,"evaspixmapsink->xcontext(->disp) is not ready");
1996                 return NULL;
1997         }
1998
1999         if (!XDamageQueryExtension(evaspixmapsink->xcontext->disp, &damage_base, &damage_err_base)) {
2000                 GST_ERROR_OBJECT (evaspixmapsink,"XDamageQueryExtension() failed");
2001                 return NULL;
2002         }
2003         damage_case = (int)damage_base + XDamageNotify;
2004
2005         while (evaspixmapsink->running) {
2006                 GST_OBJECT_UNLOCK (evaspixmapsink);
2007
2008                 g_mutex_lock (evaspixmapsink->x_lock);
2009                 while (XPending (disp)) {
2010                         XNextEvent (disp, &e);
2011                         if (e.type == damage_case ) {
2012                                 XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&e;
2013                                 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
2014                                         GstXPixmap *xpixmap = evaspixmapsink->xpixmap[i];
2015                                         if (xpixmap && damage_ev->drawable == xpixmap->pixmap) {
2016                                                 g_mutex_lock(evaspixmapsink->pixmap_ref_lock);
2017                                                 if (xpixmap->ref) {
2018                                                         /* set it only if damage event comes from _buffer_put() */
2019                                                         xpixmap->damaged_time = (gint)get_millis_time();
2020                                                 }
2021                                                 GST_LOG_OBJECT (evaspixmapsink,"event_handler : got a damage event for pixmap(%d), refcount(%d), damaged_time(%d)",
2022                                                                                                 xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time);
2023                                                 g_mutex_unlock(evaspixmapsink->pixmap_ref_lock);
2024
2025                                                 __ta__("evaspixmapsink ecore_pipe_write", ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink)););
2026                                                 GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : after call ecore_pipe_write() for pixmap(%d)", xpixmap->pixmap);
2027                                                 XDamageSubtract (evaspixmapsink->xcontext->disp, evaspixmapsink->damage[i], None, None );
2028
2029                                                 break;
2030                                         }
2031                                 }
2032                                 if (i == evaspixmapsink->num_of_pixmaps) {
2033                                         GST_WARNING_OBJECT (evaspixmapsink,"event_handler : could not find corresponding pixmap with this damage event(%d)", damage_ev->drawable);
2034                                 }
2035                         } else {
2036                                 GST_LOG_OBJECT (evaspixmapsink,"event_handler : unidentified event(%d)", e.type);
2037                                 continue;
2038                         }
2039                 }
2040                 //XSync (disp, FALSE);
2041                 g_mutex_unlock (evaspixmapsink->x_lock);
2042
2043                 g_usleep (G_USEC_PER_SEC / 40);
2044                 GST_OBJECT_LOCK (evaspixmapsink);
2045         }
2046         GST_OBJECT_UNLOCK (evaspixmapsink);
2047         return NULL;
2048 }
2049
2050 static void
2051 gst_evaspixmapsink_manage_event_thread (GstEvasPixmapSink *evaspixmapsink)
2052 {
2053         /* don't start the thread too early */
2054         if (evaspixmapsink->xcontext == NULL) {
2055                 GST_ERROR_OBJECT (evaspixmapsink,"xcontext is NULL..");
2056                 return;
2057         }
2058
2059         GST_OBJECT_LOCK (evaspixmapsink);
2060
2061         if (!evaspixmapsink->event_thread) {
2062                 /* Setup our event listening thread */
2063                 GST_DEBUG_OBJECT (evaspixmapsink,"run xevent thread");
2064                 evaspixmapsink->running = TRUE;
2065                 evaspixmapsink->event_thread = g_thread_create ( (GThreadFunc) gst_evaspixmapsink_event_thread, evaspixmapsink, TRUE, NULL);
2066         } else {
2067                 GST_WARNING_OBJECT (evaspixmapsink,"there already existed the event_thread.. keep going");
2068                 /* Do not finalize the thread in here, Only finalize the thread by calling gst_evaspixmapsink_reset() */
2069         }
2070
2071         GST_OBJECT_UNLOCK (evaspixmapsink);
2072 }
2073
2074
2075 /* This function calculates the pixel aspect ratio based on the properties
2076  * in the xcontext structure and stores it there. */
2077 static void
2078 gst_evaspixmapsink_calculate_pixel_aspect_ratio (GstXContext *xcontext)
2079 {
2080   static const gint par[][2] = {
2081     {1, 1},                     /* regular screen */
2082     {16, 15},                   /* PAL TV */
2083     {11, 10},                   /* 525 line Rec.601 video */
2084     {54, 59},                   /* 625 line Rec.601 video */
2085     {64, 45},                   /* 1280x1024 on 16:9 display */
2086     {5, 3},                     /* 1280x1024 on 4:3 display */
2087     {4, 3}                      /*  800x600 on 16:9 display */
2088   };
2089   gint i;
2090   gint index;
2091   gdouble ratio;
2092   gdouble delta;
2093
2094 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
2095
2096   /* first calculate the "real" ratio based on the X values;
2097    * which is the "physical" w/h divided by the w/h in pixels of the display */
2098   ratio = (gdouble) (xcontext->widthmm * xcontext->height)
2099       / (xcontext->heightmm * xcontext->width);
2100
2101   /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
2102    * override here */
2103   if (xcontext->width == 720 && xcontext->height == 576) {
2104     ratio = 4.0 * 576 / (3.0 * 720);
2105   }
2106   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
2107   /* now find the one from par[][2] with the lowest delta to the real one */
2108   delta = DELTA (0);
2109   index = 0;
2110
2111   for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
2112     gdouble this_delta = DELTA (i);
2113
2114     if (this_delta < delta) {
2115       index = i;
2116       delta = this_delta;
2117     }
2118   }
2119
2120   GST_DEBUG ("Decided on index %d (%d/%d)", index,
2121       par[index][0], par[index][1]);
2122
2123   g_free (xcontext->par);
2124   xcontext->par = g_new0 (GValue, 1);
2125   g_value_init (xcontext->par, GST_TYPE_FRACTION);
2126   gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
2127   GST_DEBUG ("set xcontext PAR to %d/%d",
2128       gst_value_get_fraction_numerator (xcontext->par),
2129       gst_value_get_fraction_denominator (xcontext->par));
2130 }
2131
2132 /* This function gets the X Display and global info about it. Everything is
2133    stored in our object and will be cleaned when the object is disposed. Note
2134    here that caps for supported format are generated without any window or
2135    image creation */
2136 static GstXContext*
2137 gst_evaspixmapsink_xcontext_get (GstEvasPixmapSink *evaspixmapsink)
2138 {
2139         GstXContext *xcontext = NULL;
2140         XPixmapFormatValues *px_formats = NULL;
2141         gint nb_formats = 0, i, j, N_attr;
2142         XvAttribute *xv_attr;
2143         Atom prop_atom;
2144         const char *channels[4] = { "XV_HUE", "XV_SATURATION", "XV_BRIGHTNESS", "XV_CONTRAST"};
2145
2146         g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
2147
2148         xcontext = g_new0 (GstXContext, 1);
2149         xcontext->im_format = 0;
2150
2151         g_mutex_lock (evaspixmapsink->x_lock);
2152
2153         xcontext->disp = XOpenDisplay (evaspixmapsink->display_name);
2154
2155         if (!xcontext->disp) {
2156                 g_mutex_unlock (evaspixmapsink->x_lock);
2157                 g_free (xcontext);
2158                 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Could not initialise Xv output"), ("Could not open display"));
2159                 return NULL;
2160         }
2161
2162         xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
2163         xcontext->screen_num = DefaultScreen (xcontext->disp);
2164         xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
2165         xcontext->root = DefaultRootWindow (xcontext->disp);
2166         xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
2167         xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
2168         xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
2169
2170         xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
2171         xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
2172         xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
2173         xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
2174
2175         GST_DEBUG_OBJECT (evaspixmapsink,"X reports %dx%d pixels and %d mm x %d mm", xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
2176
2177         gst_evaspixmapsink_calculate_pixel_aspect_ratio (xcontext);
2178         /* We get supported pixmap formats at supported depth */
2179         px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
2180
2181         if (!px_formats) {
2182                 XCloseDisplay (xcontext->disp);
2183                 g_mutex_unlock (evaspixmapsink->x_lock);
2184                 g_free (xcontext->par);
2185                 g_free (xcontext);
2186                 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
2187                 ("Could not initialise Xv output"), ("Could not get pixel formats"));
2188                 return NULL;
2189         }
2190
2191         /* We get bpp value corresponding to our running depth */
2192         for (i = 0; i < nb_formats; i++) {
2193                 if (px_formats[i].depth == xcontext->depth)
2194                 xcontext->bpp = px_formats[i].bits_per_pixel;
2195         }
2196
2197         XFree (px_formats);
2198
2199         xcontext->endianness = (ImageByteOrder (xcontext->disp) == LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
2200
2201         /* our caps system handles 24/32bpp RGB as big-endian. */
2202         if ((xcontext->bpp == 24 || xcontext->bpp == 32) && xcontext->endianness == G_LITTLE_ENDIAN) {
2203                 xcontext->endianness = G_BIG_ENDIAN;
2204                 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
2205                 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
2206                 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
2207                 if (xcontext->bpp == 24) {
2208                         xcontext->visual->red_mask >>= 8;
2209                         xcontext->visual->green_mask >>= 8;
2210                         xcontext->visual->blue_mask >>= 8;
2211                 }
2212         }
2213
2214         xcontext->caps = gst_evaspixmapsink_get_xv_support (evaspixmapsink, xcontext);
2215
2216         if (!xcontext->caps) {
2217                 XCloseDisplay (xcontext->disp);
2218                 g_mutex_unlock (evaspixmapsink->x_lock);
2219                 g_free (xcontext->par);
2220                 g_free (xcontext);
2221                 /* GST_ELEMENT_ERROR is thrown by gst_evaspixmapsink_get_xv_support */
2222                 return NULL;
2223         }
2224 #ifdef HAVE_XSHM
2225         /* Search for XShm extension support */
2226         if (XShmQueryExtension (xcontext->disp) && gst_evaspixmapsink_check_xshm_calls (xcontext)) {
2227                 xcontext->use_xshm = TRUE;
2228                 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is using XShm extension");
2229         } else
2230 #endif /* HAVE_XSHM */
2231         {
2232                 xcontext->use_xshm = FALSE;
2233                 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is not using XShm extension");
2234         }
2235
2236         xv_attr = XvQueryPortAttributes (xcontext->disp, xcontext->xv_port_id, &N_attr);
2237
2238         /* Generate the channels list */
2239         for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
2240                 XvAttribute *matching_attr = NULL;
2241
2242                 /* Retrieve the property atom if it exists. If it doesn't exist,
2243                 * the attribute itself must not either, so we can skip */
2244                 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
2245                 if (prop_atom == None) {
2246                         continue;
2247                 }
2248
2249                 if (xv_attr != NULL) {
2250                         for (j = 0; j < N_attr && matching_attr == NULL; ++j) {
2251                                 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) {
2252                                         matching_attr = xv_attr + j;
2253                                 }
2254                         }
2255                 }
2256
2257                 if (matching_attr) {
2258                         GstColorBalanceChannel *channel;
2259                         channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
2260                         channel->label = g_strdup (channels[i]);
2261                         channel->min_value = matching_attr->min_value;
2262                         channel->max_value = matching_attr->max_value;
2263
2264                         xcontext->channels_list = g_list_append (xcontext->channels_list, channel);
2265
2266                         /* If the colorbalance settings have not been touched we get Xv values
2267                                 as defaults and update our internal variables */
2268                         if (!evaspixmapsink->cb_changed) {
2269                                 gint val;
2270                                 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, prop_atom, &val);
2271                                 /* Normalize val to [-1000, 1000] */
2272                                 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /  (double) (channel->max_value - channel->min_value));
2273
2274                                 if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) {
2275                                         evaspixmapsink->hue = val;
2276                                 } else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) {
2277                                         evaspixmapsink->saturation = val;
2278                                 } else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) {
2279                                         evaspixmapsink->brightness = val;
2280                                 } else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) {
2281                                         evaspixmapsink->contrast = val;
2282                                 }
2283                         }
2284                 }
2285         }
2286
2287         if (xv_attr) {
2288                 XFree (xv_attr);
2289         }
2290
2291         g_mutex_unlock (evaspixmapsink->x_lock);
2292
2293         return xcontext;
2294 }
2295
2296 /* This function cleans the X context. Closing the Display, releasing the XV
2297    port and unrefing the caps for supported formats. */
2298 static void
2299 gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink)
2300 {
2301   GList *formats_list, *channels_list;
2302   GstXContext *xcontext;
2303   gint i = 0;
2304
2305   g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2306
2307   GST_OBJECT_LOCK (evaspixmapsink);
2308   if (evaspixmapsink->xcontext == NULL) {
2309     GST_OBJECT_UNLOCK (evaspixmapsink);
2310     return;
2311   }
2312
2313   /* Take the XContext from the sink and clean it up */
2314   xcontext = evaspixmapsink->xcontext;
2315   evaspixmapsink->xcontext = NULL;
2316
2317   GST_OBJECT_UNLOCK (evaspixmapsink);
2318
2319   formats_list = xcontext->formats_list;
2320
2321   while (formats_list) {
2322     GstEvasPixmapFormat *format = formats_list->data;
2323
2324     gst_caps_unref (format->caps);
2325     g_free (format);
2326     formats_list = g_list_next (formats_list);
2327   }
2328
2329   if (xcontext->formats_list)
2330     g_list_free (xcontext->formats_list);
2331
2332   channels_list = xcontext->channels_list;
2333
2334   while (channels_list) {
2335     GstColorBalanceChannel *channel = channels_list->data;
2336
2337     g_object_unref (channel);
2338     channels_list = g_list_next (channels_list);
2339   }
2340
2341   if (xcontext->channels_list)
2342     g_list_free (xcontext->channels_list);
2343
2344   gst_caps_unref (xcontext->caps);
2345
2346   for (i = 0; i < xcontext->nb_adaptors; i++) {
2347     g_free (xcontext->adaptors[i]);
2348   }
2349
2350   g_free (xcontext->adaptors);
2351
2352   g_free (xcontext->par);
2353
2354   g_mutex_lock (evaspixmapsink->x_lock);
2355
2356   GST_DEBUG_OBJECT (evaspixmapsink,"Closing display and freeing X Context");
2357
2358   XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2359
2360   XCloseDisplay (xcontext->disp);
2361
2362   g_mutex_unlock (evaspixmapsink->x_lock);
2363
2364   g_free (xcontext);
2365 }
2366
2367 /* Element stuff */
2368
2369 /* This function tries to get a format matching with a given caps in the
2370    supported list of formats we generated in gst_evaspixmapsink_get_xv_support */
2371 static gint
2372 gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
2373 {
2374   GList *list = NULL;
2375
2376   g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2377
2378   list = evaspixmapsink->xcontext->formats_list;
2379
2380   while (list) {
2381     GstEvasPixmapFormat *format = list->data;
2382
2383     if (format) {
2384       if (gst_caps_can_intersect (caps, format->caps)) {
2385         return format->format;
2386       }
2387     }
2388     list = g_list_next (list);
2389   }
2390
2391   return -1;
2392 }
2393
2394 static GstCaps *
2395 gst_evaspixmapsink_getcaps (GstBaseSink *bsink)
2396 {
2397   GstEvasPixmapSink *evaspixmapsink;
2398
2399   evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2400
2401   if (evaspixmapsink->xcontext)
2402     return gst_caps_ref (evaspixmapsink->xcontext->caps);
2403
2404   return
2405       gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
2406           (evaspixmapsink)));
2407 }
2408
2409 static gboolean
2410 gst_evaspixmapsink_setcaps (GstBaseSink *bsink, GstCaps *caps)
2411 {
2412         GstEvasPixmapSink *evaspixmapsink;
2413         GstStructure *structure;
2414         guint32 im_format = 0;
2415         gboolean ret;
2416         gint video_width, video_height;
2417         gint disp_x, disp_y;
2418         gint disp_width, disp_height;
2419         gint video_par_n, video_par_d;        /* video's PAR */
2420         gint display_par_n, display_par_d;    /* display's PAR */
2421         const GValue *caps_par;
2422         const GValue *caps_disp_reg;
2423         const GValue *fps;
2424         guint num, den;
2425         gboolean enable_last_buffer;
2426
2427         evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2428
2429         GST_DEBUG_OBJECT (evaspixmapsink,"In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" GST_PTR_FORMAT, evaspixmapsink->xcontext->caps, caps);
2430
2431         if (!gst_caps_can_intersect (evaspixmapsink->xcontext->caps, caps)) {
2432                 goto incompatible_caps;
2433         }
2434
2435         structure = gst_caps_get_structure (caps, 0);
2436         ret = gst_structure_get_int (structure, "width", &video_width);
2437         ret &= gst_structure_get_int (structure, "height", &video_height);
2438         fps = gst_structure_get_value (structure, "framerate");
2439         ret &= (fps != NULL);
2440
2441         if (!ret) {
2442                 goto incomplete_caps;
2443         }
2444
2445         evaspixmapsink->aligned_width = video_width;
2446         evaspixmapsink->aligned_height = video_height;
2447
2448         /* get enable-last-buffer */
2449         g_object_get(G_OBJECT(evaspixmapsink), "enable-last-buffer", &enable_last_buffer, NULL);
2450         GST_INFO_OBJECT (evaspixmapsink,"current enable-last-buffer : %d", enable_last_buffer);
2451         /* flush if enable-last-buffer is TRUE */
2452         if (enable_last_buffer) {
2453                 GST_INFO_OBJECT (evaspixmapsink,"flush last-buffer");
2454                 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", FALSE, NULL);
2455                 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", TRUE, NULL);
2456         }
2457
2458         evaspixmapsink->fps_n = gst_value_get_fraction_numerator (fps);
2459         evaspixmapsink->fps_d = gst_value_get_fraction_denominator (fps);
2460
2461         evaspixmapsink->video_width = video_width;
2462         evaspixmapsink->video_height = video_height;
2463
2464         im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
2465         if (im_format == -1) {
2466                 goto invalid_format;
2467         }
2468
2469         /* get aspect ratio from caps if it's present, and
2470         * convert video width and height to a display width and height
2471         * using wd / hd = wv / hv * PARv / PARd */
2472
2473         /* get video's PAR */
2474         caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
2475         if (caps_par) {
2476                 video_par_n = gst_value_get_fraction_numerator (caps_par);
2477                 video_par_d = gst_value_get_fraction_denominator (caps_par);
2478         } else {
2479                 video_par_n = 1;
2480                 video_par_d = 1;
2481         }
2482         /* get display's PAR */
2483         if (evaspixmapsink->par) {
2484                 display_par_n = gst_value_get_fraction_numerator (evaspixmapsink->par);
2485                 display_par_d = gst_value_get_fraction_denominator (evaspixmapsink->par);
2486         } else {
2487                 display_par_n = 1;
2488                 display_par_d = 1;
2489         }
2490
2491         /* get the display region */
2492         caps_disp_reg = gst_structure_get_value (structure, "display-region");
2493         if (caps_disp_reg) {
2494                 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
2495                 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
2496                 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
2497                 disp_height = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
2498         } else {
2499                 disp_x = disp_y = 0;
2500                 disp_width = video_width;
2501                 disp_height = video_height;
2502         }
2503
2504         if (!gst_video_calculate_display_ratio (&num, &den, video_width, video_height, video_par_n, video_par_d, display_par_n, display_par_d)) {
2505                 goto no_disp_ratio;
2506         }
2507
2508         evaspixmapsink->disp_x = disp_x;
2509         evaspixmapsink->disp_y = disp_y;
2510         evaspixmapsink->disp_width = disp_width;
2511         evaspixmapsink->disp_height = disp_height;
2512
2513         GST_DEBUG_OBJECT (evaspixmapsink,"video width/height: %dx%d, calculated display ratio: %d/%d",  video_width, video_height, num, den);
2514
2515         /* now find a width x height that respects this display ratio.
2516         * prefer those that have one of w/h the same as the incoming video
2517         * using wd / hd = num / den */
2518
2519         /* start with same height, because of interlaced video */
2520         /* check hd / den is an integer scale factor, and scale wd with the PAR */
2521         if (video_height % den == 0) {
2522                 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video height");
2523                 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2524                 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2525         } else if (video_width % num == 0) {
2526                 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video width");
2527                 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = video_width;
2528                 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_width, den, num);
2529         } else {
2530                 GST_DEBUG_OBJECT (evaspixmapsink,"approximating while keeping video height");
2531                 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2532                 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2533         }
2534         GST_DEBUG_OBJECT (evaspixmapsink,"scaling to %dx%d", GST_VIDEO_SINK_WIDTH (evaspixmapsink), GST_VIDEO_SINK_HEIGHT (evaspixmapsink));
2535
2536         /* Creating our window and our image with the display size in pixels */
2537         if (GST_VIDEO_SINK_WIDTH (evaspixmapsink) <= 0 || GST_VIDEO_SINK_HEIGHT (evaspixmapsink) <= 0) {
2538                 goto no_display_size;
2539         }
2540
2541         g_mutex_lock (evaspixmapsink->flow_lock);
2542
2543         /* We renew our evaspixmap buffer only if size or format changed;
2544         * the evaspixmap buffer is the same size as the video pixel size */
2545         if ((evaspixmapsink->evas_pixmap_buf) && ((im_format != evaspixmapsink->evas_pixmap_buf->im_format)
2546                 || (video_width != evaspixmapsink->evas_pixmap_buf->width) || (video_height != evaspixmapsink->evas_pixmap_buf->height))) {
2547                 GST_DEBUG_OBJECT (evaspixmapsink,"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
2548                                 GST_FOURCC_ARGS (evaspixmapsink->evas_pixmap_buf->im_format), GST_FOURCC_ARGS (im_format));
2549                 GST_DEBUG_OBJECT (evaspixmapsink,"renewing evaspixmap buffer");
2550                 gst_buffer_unref (GST_BUFFER (evaspixmapsink->evas_pixmap_buf));
2551                 evaspixmapsink->evas_pixmap_buf = NULL;
2552         }
2553
2554         g_mutex_unlock (evaspixmapsink->flow_lock);
2555
2556         if (evaspixmapsink->eo) {
2557                 if (!gst_evaspixmapsink_xpixmap_link (evaspixmapsink)) {
2558                         GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
2559                         return FALSE;
2560                 } else {
2561                         gst_evaspixmapsink_manage_event_thread (evaspixmapsink);
2562                 }
2563         } else {
2564                 GST_ERROR_OBJECT (evaspixmapsink,"setcaps success, but there is no evas image object..");
2565                 return FALSE;
2566         }
2567
2568         return TRUE;
2569
2570         /* ERRORS */
2571         incompatible_caps:
2572         {
2573                 GST_ERROR_OBJECT (evaspixmapsink,"caps incompatible");
2574                 return FALSE;
2575         }
2576         incomplete_caps:
2577         {
2578                 GST_DEBUG_OBJECT (evaspixmapsink,"Failed to retrieve either width, ""height or framerate from intersected caps");
2579                 return FALSE;
2580         }
2581         invalid_format:
2582         {
2583                 GST_DEBUG_OBJECT (evaspixmapsink,"Could not locate image format from caps %" GST_PTR_FORMAT, caps);
2584                 return FALSE;
2585         }
2586         no_disp_ratio:
2587         {
2588                 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2589                 return FALSE;
2590         }
2591         no_display_size:
2592         {
2593                 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2594                 return FALSE;
2595         }
2596 }
2597
2598 static GstStateChangeReturn
2599 gst_evaspixmapsink_change_state (GstElement *element, GstStateChange transition)
2600 {
2601         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2602         GstEvasPixmapSink *evaspixmapsink;
2603
2604         evaspixmapsink = GST_EVASPIXMAPSINK (element);
2605
2606         switch (transition) {
2607         case GST_STATE_CHANGE_NULL_TO_READY:
2608                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_NULL_TO_READY");
2609
2610                 /* open drm to use gem */
2611                 if (drm_init(evaspixmapsink)) {
2612                         GST_ERROR_OBJECT (evaspixmapsink,"drm_init() failure");
2613                         return GST_STATE_CHANGE_FAILURE;
2614                 }
2615
2616                 /* check if there exist evas image object, need to write code related to making internal evas image object */
2617                 if (!is_evas_image_object (evaspixmapsink->eo)) {
2618                         GST_ERROR_OBJECT (evaspixmapsink,"There is no evas image object..");
2619                         return GST_STATE_CHANGE_FAILURE;
2620                 }
2621
2622                 /* Set xcontext and display */
2623                 if (!evaspixmapsink->xcontext) {
2624                         evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
2625                         if (!evaspixmapsink->xcontext) {
2626                                 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
2627                                 return GST_STATE_CHANGE_FAILURE;
2628                         }
2629                 }
2630
2631                 /* update object's par with calculated one if not set yet */
2632                 if (!evaspixmapsink->par) {
2633                         evaspixmapsink->par = g_new0 (GValue, 1);
2634                         gst_value_init_and_copy (evaspixmapsink->par, evaspixmapsink->xcontext->par);
2635                         GST_DEBUG_OBJECT (evaspixmapsink,"set calculated PAR on object's PAR");
2636                 }
2637
2638                 /* call XSynchronize with the current value of synchronous */
2639                 GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
2640                 XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
2641                 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2642                 break;
2643
2644         case GST_STATE_CHANGE_READY_TO_PAUSED:
2645                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_PAUSED");
2646                 break;
2647
2648         case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2649                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_PLAYING");
2650                 break;
2651
2652         default:
2653                 break;
2654         }
2655
2656         ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2657
2658         switch (transition) {
2659         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2660                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PLAYING_TO_PAUSED");
2661                 break;
2662
2663         case GST_STATE_CHANGE_PAUSED_TO_READY:
2664                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_READY");
2665                 evaspixmapsink->fps_n = 0;
2666                 evaspixmapsink->fps_d = 1;
2667                 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = 0;
2668                 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = 0;
2669                 drm_fini_close_gem_handle(evaspixmapsink);
2670                 break;
2671
2672         case GST_STATE_CHANGE_READY_TO_NULL:
2673                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_NULL");
2674                 gst_evaspixmapsink_reset(evaspixmapsink);
2675                 /* close drm */
2676                 drm_fini(evaspixmapsink);
2677                 break;
2678
2679         default:
2680                 break;
2681         }
2682         return ret;
2683 }
2684
2685 static void
2686 gst_evaspixmapsink_get_times (GstBaseSink *bsink, GstBuffer *buf, GstClockTime *start, GstClockTime *end)
2687 {
2688   GstEvasPixmapSink *evaspixmapsink;
2689
2690   evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2691
2692   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2693     *start = GST_BUFFER_TIMESTAMP (buf);
2694     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2695       *end = *start + GST_BUFFER_DURATION (buf);
2696     } else {
2697       if (evaspixmapsink->fps_n > 0) {
2698         *end = *start +
2699             gst_util_uint64_scale_int (GST_SECOND, evaspixmapsink->fps_d,
2700             evaspixmapsink->fps_n);
2701       }
2702     }
2703   }
2704 }
2705
2706 static GstFlowReturn
2707 gst_evaspixmapsink_show_frame (GstVideoSink *vsink, GstBuffer *buf)
2708 {
2709         GstEvasPixmapSink *evaspixmapsink;
2710         XV_PUTIMAGE_DATA_PTR img_data = NULL;
2711         SCMN_IMGB *scmn_imgb = NULL;
2712         gint format = 0;
2713
2714         MMTA_ACUM_ITEM_BEGIN("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2715
2716         evaspixmapsink = GST_EVASPIXMAPSINK (vsink);
2717
2718         if( evaspixmapsink->stop_video ) {
2719                 GST_INFO_OBJECT (evaspixmapsink, "Stop video is TRUE. so skip show frame..." );
2720                 return GST_FLOW_OK;
2721         }
2722
2723         if (!evaspixmapsink->evas_pixmap_buf) {
2724                 GST_DEBUG_OBJECT (evaspixmapsink,"creating our evaspixmap buffer");
2725                 format = gst_evaspixmapsink_get_format_from_caps(evaspixmapsink, GST_BUFFER_CAPS(buf));
2726                 switch (format) {
2727                 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2728                 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2729                 case GST_MAKE_FOURCC('S', '4', '2', '0'):
2730                 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2731                 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2732                 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2733                         scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2734                         if(scmn_imgb == NULL) {
2735                                 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2736                                 return GST_FLOW_OK;
2737                         }
2738                          /* skip buffer if aligned size is smaller than size of caps */
2739                         if (scmn_imgb->s[0] < evaspixmapsink->video_width || scmn_imgb->e[0] < evaspixmapsink->video_height) {
2740                                 GST_WARNING_OBJECT (evaspixmapsink,"invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
2741                                                 evaspixmapsink->video_width, evaspixmapsink->video_height, scmn_imgb->s[0], scmn_imgb->e[0]);
2742                                 return GST_FLOW_OK;
2743                         }
2744                         evaspixmapsink->aligned_width = scmn_imgb->s[0];
2745                         evaspixmapsink->aligned_height = scmn_imgb->e[0];
2746                         GST_DEBUG_OBJECT (evaspixmapsink,"video width,height[%dx%d]",evaspixmapsink->video_width, evaspixmapsink->video_height);
2747                         GST_INFO_OBJECT (evaspixmapsink,"Use aligned width,height[%dx%d]",evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
2748                         break;
2749                 default:
2750                         GST_INFO_OBJECT (evaspixmapsink,"Use original width,height of caps");
2751                         break;
2752                 }
2753                 evaspixmapsink->evas_pixmap_buf = gst_evaspixmap_buffer_new (evaspixmapsink, GST_BUFFER_CAPS (buf));
2754                 if (!evaspixmapsink->evas_pixmap_buf) {
2755                         /* The create method should have posted an informative error */
2756                         goto no_image;
2757                 }
2758                 if (evaspixmapsink->evas_pixmap_buf->size < GST_BUFFER_SIZE (buf)) {
2759                         GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels",    evaspixmapsink->evas_pixmap_buf->width, evaspixmapsink->evas_pixmap_buf->height),("XServer allocated buffer size did not match input buffer"));
2760                         gst_evaspixmap_buffer_destroy (evaspixmapsink->evas_pixmap_buf);
2761                         evaspixmapsink->evas_pixmap_buf = NULL;
2762                         goto no_image;
2763                 }
2764         }
2765
2766         switch (evaspixmapsink->evas_pixmap_buf->im_format) {
2767         /* Cases for specified formats of Samsung extension */
2768         case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2769         case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2770         case GST_MAKE_FOURCC('S', '4', '2', '0'):
2771         case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2772         case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2773         case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2774         case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
2775         {
2776                 GST_DEBUG_OBJECT (evaspixmapsink,"Samsung extension display format activated. fourcc:%d", evaspixmapsink->evas_pixmap_buf->im_format);
2777
2778                 if (evaspixmapsink->evas_pixmap_buf->xvimage->data) {
2779                         img_data = (XV_PUTIMAGE_DATA_PTR) evaspixmapsink->evas_pixmap_buf->xvimage->data;
2780                         XV_PUTIMAGE_INIT_DATA(img_data);
2781                         scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2782                         if (scmn_imgb == NULL) {
2783                                 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2784                                 return GST_FLOW_OK;
2785                         }
2786
2787                         if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
2788                                 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
2789                                 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
2790                                 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
2791                                 img_data->BufType = XV_BUF_TYPE_LEGACY;
2792                                 if (!img_data->YBuf) {
2793                                         GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2794                                         return GST_FLOW_OK;
2795                                 }
2796                         } else { /* BUF_SHARE_METHOD_FD */
2797                                 /* set gem information to gem_info structure of handle and convert dma-buf fd into drm gem name  */
2798                                 img_data->YBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[0]);
2799                                 img_data->CbBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[1]);
2800                                 img_data->CrBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[2]);
2801                                 img_data->BufType = XV_BUF_TYPE_DMABUF;
2802                                 if (!img_data->YBuf) {
2803                                         GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2804                                         return GST_FLOW_OK;
2805                                 }
2806                         }
2807                         GST_LOG_OBJECT(evaspixmapsink, "YBuf[%d], CbBuf[%d], CrBuf[%d]",
2808                                         img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
2809                 } else {
2810                         GST_WARNING_OBJECT (evaspixmapsink, "xvimage->data is NULL. skip buffer put..." );
2811                         return GST_FLOW_OK;
2812                 }
2813                 break;
2814         }
2815         default:
2816         {
2817                 GST_DEBUG_OBJECT (evaspixmapsink,"Normal format activated. fourcc = %d", evaspixmapsink->evas_pixmap_buf->im_format);
2818                 __ta__("evaspixmapsink memcpy in _show_frame", memcpy (evaspixmapsink->evas_pixmap_buf->xvimage->data, GST_BUFFER_DATA (buf),
2819                 MIN (GST_BUFFER_SIZE (buf), evaspixmapsink->evas_pixmap_buf->size)););
2820                 break;
2821         }
2822         }
2823         if (!gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf)) {
2824                 MMTA_ACUM_ITEM_END("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2825                 return GST_FLOW_OK;
2826         }
2827
2828         MMTA_ACUM_ITEM_END("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2829
2830         return GST_FLOW_OK;
2831
2832         /* ERRORS */
2833         no_image:
2834         {
2835                 /* No image available. That's very bad ! */
2836                 GST_WARNING_OBJECT (evaspixmapsink,"could not create image");
2837                 return GST_FLOW_ERROR;
2838         }
2839 }
2840
2841 static gboolean
2842 gst_evaspixmapsink_event (GstBaseSink *sink, GstEvent *event)
2843 {
2844         GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (sink);
2845
2846         switch (GST_EVENT_TYPE (event)) {
2847         case GST_EVENT_FLUSH_START:
2848                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_START");
2849                 break;
2850         case GST_EVENT_FLUSH_STOP:
2851                 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_STOP");
2852                 break;
2853         default:
2854                 break;
2855         }
2856         if (GST_BASE_SINK_CLASS (parent_class)->event) {
2857                 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2858         } else {
2859                 return TRUE;
2860         }
2861 }
2862
2863 /* Interfaces stuff */
2864
2865 static gboolean
2866 gst_evaspixmapsink_interface_supported (GstImplementsInterface *iface, GType type)
2867 {
2868   g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE);
2869   return TRUE;
2870 }
2871
2872 static void
2873 gst_evaspixmapsink_interface_init (GstImplementsInterfaceClass *klass)
2874 {
2875   klass->supported = gst_evaspixmapsink_interface_supported;
2876 }
2877
2878 static void
2879 gst_evaspixmapsink_navigation_send_event (GstNavigation *navigation, GstStructure *structure)
2880 {
2881   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (navigation);
2882   GstPad *peer;
2883   int i = 0;
2884
2885   if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (evaspixmapsink)))) {
2886     GstEvent *event;
2887     GstVideoRectangle result;
2888     gdouble x, y, xscale = 1.0, yscale = 1.0;
2889
2890     event = gst_event_new_navigation (structure);
2891
2892     /* We take the flow_lock while we look at the window */
2893     g_mutex_lock (evaspixmapsink->flow_lock);
2894
2895     for (i = 0; i < evaspixmapsink->num_of_pixmaps; i ++) {
2896       if (!evaspixmapsink->xpixmap[i]) {
2897         g_mutex_unlock (evaspixmapsink->flow_lock);
2898         return;
2899       }
2900     }
2901
2902     memcpy (&result, &evaspixmapsink->render_rect, sizeof (GstVideoRectangle));
2903
2904     g_mutex_unlock (evaspixmapsink->flow_lock);
2905
2906     /* We calculate scaling using the original video frames geometry to include
2907        pixel aspect ratio scaling. */
2908     xscale = (gdouble) evaspixmapsink->video_width / result.w;
2909     yscale = (gdouble) evaspixmapsink->video_height / result.h;
2910
2911     /* Converting pointer coordinates to the non scaled geometry */
2912     if (gst_structure_get_double (structure, "pointer_x", &x)) {
2913       x = MIN (x, result.x + result.w);
2914       x = MAX (x - result.x, 0);
2915       gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2916           (gdouble) x * xscale, NULL);
2917     }
2918     if (gst_structure_get_double (structure, "pointer_y", &y)) {
2919       y = MIN (y, result.y + result.h);
2920       y = MAX (y - result.y, 0);
2921       gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2922           (gdouble) y * yscale, NULL);
2923     }
2924
2925     gst_pad_send_event (peer, event);
2926     gst_object_unref (peer);
2927   }
2928 }
2929
2930 static void
2931 gst_evaspixmapsink_navigation_init (GstNavigationInterface *iface)
2932 {
2933   iface->send_event = gst_evaspixmapsink_navigation_send_event;
2934 }
2935
2936 static const GList*
2937 gst_evaspixmapsink_colorbalance_list_channels (GstColorBalance *balance)
2938 {
2939   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2940
2941   g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
2942
2943   if (evaspixmapsink->xcontext)
2944     return evaspixmapsink->xcontext->channels_list;
2945   else
2946     return NULL;
2947 }
2948
2949 static void
2950 gst_evaspixmapsink_colorbalance_set_value (GstColorBalance *balance, GstColorBalanceChannel *channel, gint value)
2951 {
2952   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2953
2954   g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2955   g_return_if_fail (channel->label != NULL);
2956
2957   evaspixmapsink->cb_changed = TRUE;
2958
2959   /* Normalize val to [-1000, 1000] */
2960   value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
2961       (double) (channel->max_value - channel->min_value));
2962
2963   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2964     evaspixmapsink->hue = value;
2965   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2966     evaspixmapsink->saturation = value;
2967   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2968     evaspixmapsink->contrast = value;
2969   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2970     evaspixmapsink->brightness = value;
2971   } else {
2972     g_warning ("got an unknown channel %s", channel->label);
2973     return;
2974   }
2975
2976   gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2977 }
2978
2979 static gint
2980 gst_evaspixmapsink_colorbalance_get_value (GstColorBalance *balance, GstColorBalanceChannel *channel)
2981 {
2982   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2983   gint value = 0;
2984
2985   g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2986   g_return_val_if_fail (channel->label != NULL, 0);
2987
2988   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2989     value = evaspixmapsink->hue;
2990   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2991     value = evaspixmapsink->saturation;
2992   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2993     value = evaspixmapsink->contrast;
2994   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2995     value = evaspixmapsink->brightness;
2996   } else {
2997     g_warning ("got an unknown channel %s", channel->label);
2998   }
2999
3000   /* Normalize val to [channel->min_value, channel->max_value] */
3001   value = channel->min_value + (channel->max_value - channel->min_value) * (value + 1000) / 2000;
3002
3003   return value;
3004 }
3005
3006 static void
3007 gst_evaspixmapsink_colorbalance_init (GstColorBalanceClass *iface)
3008 {
3009   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
3010   iface->list_channels = gst_evaspixmapsink_colorbalance_list_channels;
3011   iface->set_value = gst_evaspixmapsink_colorbalance_set_value;
3012   iface->get_value = gst_evaspixmapsink_colorbalance_get_value;
3013 }
3014
3015 static const GList *
3016 gst_evaspixmapsink_probe_get_properties (GstPropertyProbe *probe)
3017 {
3018         GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
3019         static GList *list = NULL;
3020
3021         if (!list) {
3022                 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
3023                 list = g_list_append (list, g_object_class_find_property (klass, "autopaint-colorkey"));
3024                 list = g_list_append (list, g_object_class_find_property (klass, "double-buffer"));
3025                 list = g_list_append (list, g_object_class_find_property (klass, "colorkey"));
3026         }
3027
3028         return list;
3029 }
3030
3031 static void
3032 gst_evaspixmapsink_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3033 {
3034   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3035
3036   switch (prop_id) {
3037     case PROP_DEVICE:
3038     case PROP_AUTOPAINT_COLORKEY:
3039     case PROP_DOUBLE_BUFFER:
3040     case PROP_COLORKEY:
3041       GST_DEBUG_OBJECT (evaspixmapsink,"probing device list and get capabilities");
3042       if (!evaspixmapsink->xcontext) {
3043         GST_DEBUG_OBJECT (evaspixmapsink,"generating xcontext");
3044         evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
3045         if (!evaspixmapsink->xcontext) {
3046           GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
3047         }
3048       }
3049       break;
3050     default:
3051       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3052       break;
3053   }
3054 }
3055
3056 static gboolean
3057 gst_evaspixmapsink_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3058 {
3059   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3060   gboolean ret = FALSE;
3061
3062   switch (prop_id) {
3063     case PROP_DEVICE:
3064     case PROP_AUTOPAINT_COLORKEY:
3065     case PROP_DOUBLE_BUFFER:
3066     case PROP_COLORKEY:
3067       if (evaspixmapsink->xcontext != NULL) {
3068         ret = FALSE;
3069       } else {
3070         ret = TRUE;
3071       }
3072       break;
3073     default:
3074       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3075       break;
3076   }
3077
3078   return ret;
3079 }
3080
3081 static GValueArray *
3082 gst_evaspixmapsink_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3083 {
3084   GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3085   GValueArray *array = NULL;
3086
3087   if (G_UNLIKELY (!evaspixmapsink->xcontext)) {
3088     GST_WARNING_OBJECT (evaspixmapsink,"we don't have any xcontext, can't "
3089         "get values");
3090     goto beach;
3091   }
3092
3093   switch (prop_id) {
3094     case PROP_DEVICE:
3095     {
3096       guint i;
3097       GValue value = { 0 };
3098
3099       array = g_value_array_new (evaspixmapsink->xcontext->nb_adaptors);
3100       g_value_init (&value, G_TYPE_STRING);
3101
3102       for (i = 0; i < evaspixmapsink->xcontext->nb_adaptors; i++) {
3103         gchar *adaptor_id_s = g_strdup_printf ("%u", i);
3104
3105         g_value_set_string (&value, adaptor_id_s);
3106         g_value_array_append (array, &value);
3107         g_free (adaptor_id_s);
3108       }
3109       g_value_unset (&value);
3110       break;
3111     }
3112     case PROP_AUTOPAINT_COLORKEY:
3113       if (evaspixmapsink->have_autopaint_colorkey) {
3114         GValue value = { 0 };
3115
3116         array = g_value_array_new (2);
3117         g_value_init (&value, G_TYPE_BOOLEAN);
3118         g_value_set_boolean (&value, FALSE);
3119         g_value_array_append (array, &value);
3120         g_value_set_boolean (&value, TRUE);
3121         g_value_array_append (array, &value);
3122         g_value_unset (&value);
3123       }
3124       break;
3125     case PROP_DOUBLE_BUFFER:
3126       if (evaspixmapsink->have_double_buffer) {
3127         GValue value = { 0 };
3128
3129         array = g_value_array_new (2);
3130         g_value_init (&value, G_TYPE_BOOLEAN);
3131         g_value_set_boolean (&value, FALSE);
3132         g_value_array_append (array, &value);
3133         g_value_set_boolean (&value, TRUE);
3134         g_value_array_append (array, &value);
3135         g_value_unset (&value);
3136       }
3137       break;
3138     case PROP_COLORKEY:
3139       if (evaspixmapsink->have_colorkey) {
3140         GValue value = { 0 };
3141
3142         array = g_value_array_new (1);
3143         g_value_init (&value, GST_TYPE_INT_RANGE);
3144         gst_value_set_int_range (&value, 0, 0xffffff);
3145         g_value_array_append (array, &value);
3146         g_value_unset (&value);
3147       }
3148       break;
3149     default:
3150       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3151       break;
3152   }
3153
3154 beach:
3155   return array;
3156 }
3157
3158 static void
3159 gst_evaspixmapsink_property_probe_interface_init (GstPropertyProbeInterface *iface)
3160 {
3161         iface->get_properties = gst_evaspixmapsink_probe_get_properties;
3162         iface->probe_property = gst_evaspixmapsink_probe_probe_property;
3163         iface->needs_probe = gst_evaspixmapsink_probe_needs_probe;
3164         iface->get_values = gst_evaspixmapsink_probe_get_values;
3165 }
3166
3167 static gboolean
3168 gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink)
3169 {
3170         Display *dpy;
3171         Pixmap *pixmap_id[NUM_OF_PIXMAP];
3172         int evas_object_width = 0;
3173         int evas_object_height = 0;
3174         int pixmap_width = 0;
3175         int pixmap_height = 0;
3176         unsigned int xw = 0;
3177         unsigned int xh = 0;
3178         int i = 0;
3179
3180         GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3181
3182         if (!evaspixmapsink) {
3183                 GST_ERROR_OBJECT (evaspixmapsink,"could not get evaspixmapsink..");
3184                 return FALSE;
3185         }
3186         g_mutex_lock (evaspixmapsink->flow_lock);
3187
3188         /* Set xcontext and display */
3189         if (!evaspixmapsink->xcontext) {
3190                 GST_WARNING_OBJECT (evaspixmapsink,"there's no xcontext, try to get one..");
3191                 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
3192                 if (!evaspixmapsink->xcontext) {
3193                         GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
3194                         return FALSE;
3195                 }
3196         }
3197
3198         dpy = evaspixmapsink->xcontext->disp;
3199
3200         /* Set evas image object size */
3201         evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evas_object_width, &evas_object_height);
3202         if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3203                 pixmap_width = evaspixmapsink->video_width;
3204                 pixmap_height = evaspixmapsink->video_height;
3205                 GST_INFO_OBJECT (evaspixmapsink,"set size to media src size(%dx%d)", pixmap_width, pixmap_height);
3206         }
3207
3208         g_mutex_lock (evaspixmapsink->x_lock);
3209         evaspixmapsink->sizediff_width = 0;
3210         evaspixmapsink->sizediff_height = 0;
3211         if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3212                 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, pixmap_width, pixmap_height, &xw, &xh);
3213                 if (!evas_object_width || !evas_object_height) {
3214                         evaspixmapsink->w = xw;
3215                         evaspixmapsink->h = xh;
3216                 } else {
3217                         evaspixmapsink->w = evas_object_width;
3218                         evaspixmapsink->h = evas_object_height;
3219                 }
3220                 GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, pixmap_width, pixmap_height, xw, xh);
3221         } else {
3222                 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, evas_object_width, evas_object_height, &xw, &xh);
3223                 GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, evas_object_width, evas_object_height, xw, xh);
3224                 evaspixmapsink->w = xw;
3225                 evaspixmapsink->h = xh;
3226                 /* update difference of size information (between evas image object's and pixmap's) */
3227                 evaspixmapsink->sizediff_width = xw - evas_object_width;
3228                 evaspixmapsink->sizediff_height = xh - evas_object_height;
3229         }
3230
3231         /* create xpixmap structure */
3232         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3233                 if (!evaspixmapsink->xpixmap[i]) {
3234                         /* xpixmap can be created in this function only */
3235                         evaspixmapsink->xpixmap[i] = g_new0 (GstXPixmap, 1);
3236                         if(!evaspixmapsink->xpixmap[i]) {
3237                                 GST_ERROR_OBJECT (evaspixmapsink,"xpixmap is not valid..");
3238                                 int j = 0;
3239                                 for (j = 0; j < i; j++) {
3240                                         g_free(evaspixmapsink->xpixmap[j]);
3241                                 }
3242                                 goto GO_OUT_OF_FUNC;
3243                         }
3244                 }
3245         }
3246
3247         /* create pixmap */
3248         if (!xw || !xh) {
3249                 GST_WARNING_OBJECT (evaspixmapsink,"skip creating pixmap..xw(%d),xh(%d)",xw,xh);
3250                 goto GO_OUT_OF_FUNC;
3251         } else {
3252                 /* multiple pixmaps creation */
3253                 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3254                         pixmap_id[i] = XCreatePixmap(dpy, DefaultRootWindow(dpy), xw, xh, DefaultDepth(dpy, DefaultScreen(dpy)));
3255                         if ( (int)pixmap_id[i] == BadAlloc || (int)pixmap_id[i] == BadDrawable || (int)pixmap_id[i] == BadValue ) {
3256                                 GST_ERROR_OBJECT (evaspixmapsink,"pixmap[%d] allocation error..", i);
3257                                 int j = 0;
3258                                 for (j = 0; j < i; j++) {
3259                                         XFreePixmap(dpy, pixmap_id[j]);
3260                                 }
3261                                 goto GO_OUT_OF_FUNC;
3262                         }
3263                         GST_INFO_OBJECT (evaspixmapsink,"creation pixmap_id[%d]:%d success", i, pixmap_id[i]);
3264                         GST_DEBUG_OBJECT (evaspixmapsink,"evas_object_width(%d),evas_object_height(%d),pixmap:%d,depth:%d",
3265                                                                 evas_object_width,evas_object_height,pixmap_id[i],DefaultDepth(dpy, DefaultScreen(dpy)));
3266                 }
3267         }
3268
3269         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3270                 if (evaspixmapsink->xpixmap[i]->pixmap && pixmap_id[i] != evaspixmapsink->xpixmap[i]->pixmap) {
3271                         /* If we reset another pixmap, do below */
3272                         GST_DEBUG_OBJECT (evaspixmapsink,"destroy previous pixmap(%d)",evaspixmapsink->xpixmap[i]->pixmap);
3273                         if (evaspixmapsink->eo) {
3274                                 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3275                         }
3276
3277                         GST_LOG_OBJECT (evaspixmapsink,"Free pixmap(%d)", evaspixmapsink->xpixmap[i]->pixmap);
3278                         XFreePixmap(dpy, evaspixmapsink->xpixmap[i]->pixmap);
3279                         evaspixmapsink->xpixmap[i]->pixmap = 0;
3280                         evaspixmapsink->xpixmap[i]->ref = 0;
3281                         evaspixmapsink->xpixmap[i]->damaged_time = 0;
3282
3283                         XFreeGC (evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap[i]->gc);
3284                         XSync (evaspixmapsink->xcontext->disp, FALSE);
3285                 }
3286         }
3287
3288         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3289                 /* Set pixmap id and create GC */
3290                 evaspixmapsink->xpixmap[i]->pixmap = pixmap_id[i];
3291                 evaspixmapsink->xpixmap[i]->gc = XCreateGC(dpy, evaspixmapsink->xpixmap[i]->pixmap, 0,0);
3292                 XSetForeground(dpy, evaspixmapsink->xpixmap[i]->gc,evaspixmapsink->xcontext->black);
3293                 XFillRectangle(dpy, evaspixmapsink->xpixmap[i]->pixmap, evaspixmapsink->xpixmap[i]->gc, 0, 0, xw, xh);
3294                 XSync(dpy, FALSE);
3295
3296                 /* Create XDamage */
3297                 if (evaspixmapsink->damage[i]) {
3298                         GST_DEBUG_OBJECT (evaspixmapsink,"destroy previous damage(%d)",evaspixmapsink->damage[i]);
3299                         XDamageDestroy(dpy, evaspixmapsink->damage[i]);
3300                         evaspixmapsink->damage[i] = NULL;
3301                 }
3302                 evaspixmapsink->damage[i] = XDamageCreate (dpy, evaspixmapsink->xpixmap[i]->pixmap, XDamageReportRawRectangles);
3303
3304                 GST_WARNING_OBJECT (evaspixmapsink,"xpixmap[%d]->(pixmap:%d,gc:%p), damage[%d]:%d",
3305                                         i, evaspixmapsink->xpixmap[i]->pixmap, evaspixmapsink->xpixmap[i]->gc, i, evaspixmapsink->damage[i]);
3306         }
3307
3308         XSync(dpy, FALSE);
3309
3310         /* Set flag for mapping evas object with xpixmap */
3311         evaspixmapsink->do_link = TRUE;
3312         ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink));
3313
3314         gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3315
3316         g_mutex_unlock (evaspixmapsink->x_lock);
3317         g_mutex_unlock (evaspixmapsink->flow_lock);
3318
3319         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3320
3321         return TRUE;
3322
3323 GO_OUT_OF_FUNC:
3324         g_mutex_unlock (evaspixmapsink->x_lock);
3325         g_mutex_unlock (evaspixmapsink->flow_lock);
3326         return FALSE;
3327 }
3328
3329 static void
3330 gst_evaspixmapsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
3331 {
3332         GstEvasPixmapSink *evaspixmapsink;
3333         g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3334         evaspixmapsink = GST_EVASPIXMAPSINK (object);
3335
3336         switch (prop_id) {
3337         case PROP_HUE:
3338                 evaspixmapsink->hue = g_value_get_int (value);
3339                 evaspixmapsink->cb_changed = TRUE;
3340                 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3341                 break;
3342         case PROP_CONTRAST:
3343                 evaspixmapsink->contrast = g_value_get_int (value);
3344                 evaspixmapsink->cb_changed = TRUE;
3345                 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3346                 break;
3347         case PROP_BRIGHTNESS:
3348                 evaspixmapsink->brightness = g_value_get_int (value);
3349                 evaspixmapsink->cb_changed = TRUE;
3350                 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3351                 break;
3352         case PROP_SATURATION:
3353                 evaspixmapsink->saturation = g_value_get_int (value);
3354                 evaspixmapsink->cb_changed = TRUE;
3355                 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3356                 break;
3357         case PROP_DISPLAY:
3358                 evaspixmapsink->display_name = g_strdup (g_value_get_string (value));
3359                 break;
3360         case PROP_SYNCHRONOUS:
3361                 evaspixmapsink->synchronous = g_value_get_boolean (value);
3362                 if (evaspixmapsink->xcontext) {
3363                         XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
3364                         GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
3365                 }
3366                 break;
3367         case PROP_PIXEL_ASPECT_RATIO:
3368                 g_free (evaspixmapsink->par);
3369                 evaspixmapsink->par = g_new0 (GValue, 1);
3370                 g_value_init (evaspixmapsink->par, GST_TYPE_FRACTION);
3371                 if (!g_value_transform (value, evaspixmapsink->par)) {
3372                         g_warning ("Could not transform string to aspect ratio");
3373                         gst_value_set_fraction (evaspixmapsink->par, 1, 1);
3374                 }
3375                 GST_DEBUG_OBJECT (evaspixmapsink,"set PAR to %d/%d", gst_value_get_fraction_numerator (evaspixmapsink->par), gst_value_get_fraction_denominator (evaspixmapsink->par));
3376                 break;
3377         case PROP_DEVICE:
3378                 evaspixmapsink->adaptor_no = atoi (g_value_get_string (value));
3379                 break;
3380         case PROP_DOUBLE_BUFFER:
3381                 evaspixmapsink->double_buffer = g_value_get_boolean (value);
3382                 break;
3383         case PROP_AUTOPAINT_COLORKEY:
3384                 evaspixmapsink->autopaint_colorkey = g_value_get_boolean (value);
3385                 break;
3386         case PROP_COLORKEY:
3387                 evaspixmapsink->colorkey = g_value_get_int (value);
3388                 break;
3389         case PROP_PIXMAP_WIDTH:
3390         {
3391                 /* To do : code related to pixmap re-link */
3392                 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3393                 break;
3394         }
3395         case PROP_PIXMAP_HEIGHT:
3396         {
3397                 /* To do : code related to pixmap re-link */
3398                 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3399                 break;
3400         }
3401         case PROP_DISPLAY_GEOMETRY_METHOD:
3402         {
3403                 guint new_val = g_value_get_enum (value);
3404                 if (evaspixmapsink->display_geometry_method != new_val) {
3405                         evaspixmapsink->display_geometry_method = new_val;
3406                         GST_INFO_OBJECT (evaspixmapsink,"Overlay geometry method update, display_geometry_method(%d)",evaspixmapsink->display_geometry_method);
3407                         if( evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_FULL_SCREEN &&
3408                                   evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_CROPPED_FULL_SCREEN ) {
3409                                 if( evaspixmapsink->xcontext ) {
3410                                         g_mutex_lock( evaspixmapsink->flow_lock );
3411                                         int i = 0;
3412                                         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3413                                                 if (evaspixmapsink->xpixmap[i]) {
3414                                                         gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3415                                                 }
3416                                         }
3417                                         g_mutex_unlock( evaspixmapsink->flow_lock );
3418                                 }
3419                         }
3420                         if (evaspixmapsink->xcontext) {
3421                                 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
3422                         }
3423                 }
3424                 break;
3425         }
3426         case PROP_DST_ROI_X:
3427                 evaspixmapsink->dst_roi.x = g_value_get_int (value);
3428                 GST_INFO_OBJECT (evaspixmapsink, "ROI_X(%d)",evaspixmapsink->dst_roi.x );
3429                 break;
3430         case PROP_DST_ROI_Y:
3431                 evaspixmapsink->dst_roi.y = g_value_get_int (value);
3432                 GST_INFO_OBJECT (evaspixmapsink, "ROI_Y(%d)",evaspixmapsink->dst_roi.y );
3433                 break;
3434         case PROP_DST_ROI_W:
3435                 evaspixmapsink->dst_roi.w = g_value_get_int (value);
3436                 GST_INFO_OBJECT (evaspixmapsink, "ROI_W(%d)",evaspixmapsink->dst_roi.w );
3437                 break;
3438         case PROP_DST_ROI_H:
3439                 evaspixmapsink->dst_roi.h = g_value_get_int (value);
3440                 GST_INFO_OBJECT (evaspixmapsink, "ROI_H(%d)",evaspixmapsink->dst_roi.h );
3441                 break;
3442         case PROP_STOP_VIDEO:
3443                 evaspixmapsink->stop_video = g_value_get_int (value);
3444                 g_mutex_lock( evaspixmapsink->flow_lock );
3445                 if( evaspixmapsink->stop_video ) {
3446                         GST_INFO_OBJECT (evaspixmapsink, "XPixmap CLEAR when set video-stop property" );
3447                         int i = 0;
3448                         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3449                                 if (evaspixmapsink->xpixmap[i]) {
3450                                         gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3451                                 }
3452                         }
3453                 }
3454                 g_mutex_unlock( evaspixmapsink->flow_lock );
3455                 break;
3456         case PROP_EVAS_OBJECT:
3457         {
3458                 Evas_Object *eo = g_value_get_pointer (value);
3459                 if ( is_evas_image_object (eo)) {
3460                         if (!evaspixmapsink->epipe) {
3461                                 evaspixmapsink->epipe = ecore_pipe_add (ecore_pipe_callback_handler, evaspixmapsink);
3462                                 if (!evaspixmapsink->epipe) {
3463                                         GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: ecore_pipe_add() failed");
3464                                         break;
3465                                 }
3466                         }
3467                         if (eo != evaspixmapsink->eo) {
3468                                 /* delete evas object callbacks registrated on a former evas image object */
3469                                 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3470                                 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3471                                 evaspixmapsink->eo = eo;
3472                                 if (evaspixmapsink->eo) {
3473                                         if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3474                                                 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3475                                                 return;
3476                                         }
3477                                 }
3478                                 /* add evas object callbacks on a new evas image object */
3479                                 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event, evaspixmapsink);
3480                                 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, evaspixmapsink);
3481                                 GST_INFO_OBJECT (evaspixmapsink,"Evas Image Object(%x) is set", evaspixmapsink->eo);
3482                         }
3483                 } else {
3484                         GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: value is not an evas image object");
3485                 }
3486                   break;
3487         }
3488         case PROP_FLIP:
3489                 evaspixmapsink->flip = g_value_get_enum(value);
3490                 break;
3491         case PROP_ROTATE_ANGLE:
3492                 evaspixmapsink->rotate_angle = g_value_get_enum (value);
3493                 break;
3494         case PROP_VISIBLE:
3495         {
3496                 gboolean visible = g_value_get_boolean (value);
3497                 if (evaspixmapsink->visible != visible) {
3498                         evaspixmapsink->visible = visible;
3499                         if (evaspixmapsink->eo) {
3500                                 if (!visible) {
3501                                         int i = 0;
3502                                         g_mutex_lock( evaspixmapsink->flow_lock );
3503                                         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3504                                                 if (evaspixmapsink->xpixmap[i]) {
3505                                                         gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3506                                                 }
3507                                         }
3508                                         g_mutex_unlock( evaspixmapsink->flow_lock );
3509                                         evas_object_hide(evaspixmapsink->eo);
3510                                         GST_INFO_OBJECT (evaspixmapsink,"object hide..");
3511                                 } else {
3512                                         evas_object_show(evaspixmapsink->eo);
3513                                         GST_INFO_OBJECT (evaspixmapsink,"object show..");
3514                                         gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
3515                                 }
3516                         } else {
3517                                 GST_WARNING_OBJECT (evaspixmapsink,"evas image object was not set");
3518                         }
3519                 }
3520                 break;
3521         }
3522         case PROP_ORIGIN_SIZE:
3523                 evaspixmapsink->use_origin_size = g_value_get_boolean (value);
3524                 GST_INFO_OBJECT (evaspixmapsink,"set origin-size (%d)",evaspixmapsink->use_origin_size);
3525                 if (evaspixmapsink->previous_origin_size != evaspixmapsink->use_origin_size) {
3526                         if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3527                                 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3528                         }
3529                         evaspixmapsink->previous_origin_size = evaspixmapsink->use_origin_size;
3530                 }
3531                 break;
3532         default:
3533                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3534                 break;
3535         }
3536 }
3537
3538 static void
3539 gst_evaspixmapsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
3540 {
3541         GstEvasPixmapSink *evaspixmapsink;
3542
3543         g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3544
3545         evaspixmapsink = GST_EVASPIXMAPSINK (object);
3546
3547         switch (prop_id) {
3548         case PROP_HUE:
3549                 g_value_set_int (value, evaspixmapsink->hue);
3550                 break;
3551         case PROP_CONTRAST:
3552                 g_value_set_int (value, evaspixmapsink->contrast);
3553                 break;
3554         case PROP_BRIGHTNESS:
3555                 g_value_set_int (value, evaspixmapsink->brightness);
3556                 break;
3557         case PROP_SATURATION:
3558                 g_value_set_int (value, evaspixmapsink->saturation);
3559                 break;
3560         case PROP_DISPLAY:
3561                 g_value_set_string (value, evaspixmapsink->display_name);
3562                 break;
3563         case PROP_SYNCHRONOUS:
3564                 g_value_set_boolean (value, evaspixmapsink->synchronous);
3565                 break;
3566         case PROP_PIXEL_ASPECT_RATIO:
3567                 if (evaspixmapsink->par) {
3568                         if (!g_value_transform (evaspixmapsink->par, value)) {
3569                                 g_warning ("g_value_transform() failure");
3570                         }
3571                 }
3572                 break;
3573         case PROP_DEVICE:
3574         {
3575                 char *adaptor_no_s = g_strdup_printf ("%u", evaspixmapsink->adaptor_no);
3576                 g_value_set_string (value, adaptor_no_s);
3577                 g_free (adaptor_no_s);
3578                 break;
3579         }
3580         case PROP_DEVICE_NAME:
3581                 if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->adaptors) {
3582                         g_value_set_string (value,
3583                         evaspixmapsink->xcontext->adaptors[evaspixmapsink->adaptor_no]);
3584                 } else {
3585                         g_value_set_string (value, NULL);
3586                 }
3587                 break;
3588         case PROP_DOUBLE_BUFFER:
3589                 g_value_set_boolean (value, evaspixmapsink->double_buffer);
3590                 break;
3591         case PROP_AUTOPAINT_COLORKEY:
3592                 g_value_set_boolean (value, evaspixmapsink->autopaint_colorkey);
3593                 break;
3594         case PROP_COLORKEY:
3595                 g_value_set_int (value, evaspixmapsink->colorkey);
3596                 break;
3597         case PROP_PIXMAP_WIDTH:
3598         {
3599                 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3600                 break;
3601         }
3602         case PROP_PIXMAP_HEIGHT:
3603         {
3604                 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3605                 break;
3606         }
3607         case PROP_DISPLAY_GEOMETRY_METHOD:
3608                 g_value_set_enum (value, evaspixmapsink->display_geometry_method);
3609                 break;
3610         case PROP_DST_ROI_X:
3611                 g_value_set_int (value, evaspixmapsink->dst_roi.x);
3612                 break;
3613         case PROP_DST_ROI_Y:
3614                 g_value_set_int (value, evaspixmapsink->dst_roi.y);
3615                 break;
3616         case PROP_DST_ROI_W:
3617                 g_value_set_int (value, evaspixmapsink->dst_roi.w);
3618                 break;
3619         case PROP_DST_ROI_H:
3620                 g_value_set_int (value, evaspixmapsink->dst_roi.h);
3621                 break;
3622         case PROP_STOP_VIDEO:
3623                 g_value_set_int (value, evaspixmapsink->stop_video);
3624                 break;
3625         case PROP_EVAS_OBJECT:
3626                 g_value_set_pointer (value, evaspixmapsink->eo);
3627                 break;
3628         case PROP_FLIP:
3629                 g_value_set_enum(value, evaspixmapsink->flip);
3630                 break;
3631         case PROP_ROTATE_ANGLE:
3632                 g_value_set_enum (value, evaspixmapsink->rotate_angle);
3633                 break;
3634         case PROP_VISIBLE:
3635                 g_value_set_boolean (value, evaspixmapsink->visible);
3636                 break;
3637         case PROP_ORIGIN_SIZE:
3638                 g_value_set_boolean (value, evaspixmapsink->use_origin_size);
3639                 break;
3640         default:
3641                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3642                 break;
3643   }
3644 }
3645
3646 static void
3647 gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink)
3648 {
3649         GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3650
3651         GThread *thread;
3652         GST_OBJECT_LOCK (evaspixmapsink);
3653         evaspixmapsink->running = FALSE;
3654         int i = 0;
3655
3656         /* grab thread and mark it as NULL */
3657         thread = evaspixmapsink->event_thread;
3658         evaspixmapsink->event_thread = NULL;
3659         GST_OBJECT_UNLOCK (evaspixmapsink);
3660
3661         /* Wait for our event thread to finish before we clean up our stuff. */
3662         if (thread) {
3663                 g_thread_join (thread);
3664         }
3665
3666         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3667                 if(evaspixmapsink->damage[i]) {
3668                         XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage[i]);
3669                         evaspixmapsink->damage[i] = NULL;
3670                 }
3671         }
3672         evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3673         evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3674
3675         if (evaspixmapsink->evas_pixmap_buf) {
3676                 gst_buffer_unref (GST_BUFFER_CAST (evaspixmapsink->evas_pixmap_buf));
3677                 evaspixmapsink->evas_pixmap_buf = NULL;
3678         }
3679
3680         for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3681                 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3682                 gst_evaspixmapsink_xpixmap_destroy (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3683                 evaspixmapsink->xpixmap[i] = NULL;
3684         }
3685         if (evaspixmapsink->eo) {
3686                 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3687                 evaspixmapsink->eo = NULL;
3688         }
3689
3690         evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y =
3691         evaspixmapsink->render_rect.w = evaspixmapsink->render_rect.h = 0;
3692         evaspixmapsink->have_render_rect = FALSE;
3693
3694         gst_evaspixmapsink_xcontext_clear (evaspixmapsink);
3695
3696         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3697 }
3698
3699 /* Finalize is called only once, dispose can be called multiple times.
3700  * We use mutexes and don't reset stuff to NULL here so let's register
3701  * as a finalize. */
3702 static void
3703 gst_evaspixmapsink_finalize (GObject *object)
3704 {
3705         GstEvasPixmapSink *evaspixmapsink;
3706         evaspixmapsink = GST_EVASPIXMAPSINK (object);
3707         GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3708
3709         if (evaspixmapsink->display_name) {
3710                 g_free (evaspixmapsink->display_name);
3711                 evaspixmapsink->display_name = NULL;
3712         }
3713         if (evaspixmapsink->par) {
3714                 g_free (evaspixmapsink->par);
3715                 evaspixmapsink->par = NULL;
3716         }
3717         if (evaspixmapsink->x_lock) {
3718                 g_mutex_free (evaspixmapsink->x_lock);
3719                 evaspixmapsink->x_lock = NULL;
3720         }
3721         if (evaspixmapsink->flow_lock) {
3722                 g_mutex_free (evaspixmapsink->flow_lock);
3723                 evaspixmapsink->flow_lock = NULL;
3724         }
3725         if (evaspixmapsink->pixmap_ref_lock) {
3726                 g_mutex_free (evaspixmapsink->pixmap_ref_lock);
3727                 evaspixmapsink->pixmap_ref_lock = NULL;
3728         }
3729         if (evaspixmapsink->epipe) {
3730                 ecore_pipe_del (evaspixmapsink->epipe);
3731                 evaspixmapsink->epipe = NULL;
3732         }
3733
3734         GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3735
3736         G_OBJECT_CLASS (parent_class)->finalize (object);
3737
3738         MMTA_ACUM_ITEM_SHOW_RESULT_TO(MMTA_SHOW_FILE);
3739         MMTA_RELEASE();
3740 }
3741
3742 static void
3743 gst_evaspixmapsink_init (GstEvasPixmapSink *evaspixmapsink)
3744 {
3745         int i = 0;
3746         evaspixmapsink->display_name = NULL;
3747         evaspixmapsink->adaptor_no = 0;
3748         evaspixmapsink->xcontext = NULL;
3749
3750         for (i = 0; i < NUM_OF_PIXMAP; i++) {
3751                 evaspixmapsink->xpixmap[i] = NULL;
3752                 evaspixmapsink->damage[i] = 0;
3753         }
3754
3755         evaspixmapsink->evas_pixmap_buf = NULL;
3756
3757         evaspixmapsink->hue = evaspixmapsink->saturation = 0;
3758         evaspixmapsink->contrast = evaspixmapsink->brightness = 0;
3759         evaspixmapsink->cb_changed = FALSE;
3760
3761         evaspixmapsink->fps_n = 0;
3762         evaspixmapsink->fps_d = 0;
3763         evaspixmapsink->video_width = 0;
3764         evaspixmapsink->video_height = 0;
3765
3766         evaspixmapsink->x_lock = g_mutex_new ();
3767         evaspixmapsink->flow_lock = g_mutex_new ();
3768         evaspixmapsink->pixmap_ref_lock = g_mutex_new();
3769
3770         evaspixmapsink->synchronous = FALSE;
3771         evaspixmapsink->double_buffer = TRUE;
3772         evaspixmapsink->par = NULL;
3773         evaspixmapsink->autopaint_colorkey = TRUE;
3774         evaspixmapsink->running = FALSE;
3775
3776         /* on 16bit displays this becomes r,g,b = 1,2,3
3777         * on 24bit displays this becomes r,g,b = 8,8,16
3778         * as a port atom value
3779         */
3780         evaspixmapsink->colorkey = (8 << 16) | (8 << 8) | 16;
3781
3782         evaspixmapsink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
3783         evaspixmapsink->dst_roi.x = 0;
3784         evaspixmapsink->dst_roi.y = 0;
3785         evaspixmapsink->dst_roi.w = 0;
3786         evaspixmapsink->dst_roi.h = 0;
3787         evaspixmapsink->scr_w = 0;
3788         evaspixmapsink->scr_h = 0;
3789         evaspixmapsink->aligned_width = 0;
3790         evaspixmapsink->aligned_height = 0;
3791         evaspixmapsink->stop_video = FALSE;
3792         evaspixmapsink->eo = NULL;
3793         evaspixmapsink->epipe = NULL;
3794         evaspixmapsink->do_link = FALSE;
3795         evaspixmapsink->flip = DEF_DISPLAY_FLIP;
3796         evaspixmapsink->rotate_angle = DEGREE_0;
3797         evaspixmapsink->visible = TRUE;
3798         evaspixmapsink->use_origin_size = FALSE;
3799         evaspixmapsink->previous_origin_size = FALSE;
3800
3801         evaspixmapsink->num_of_pixmaps = NUM_OF_PIXMAP;
3802
3803         MMTA_INIT();
3804  }
3805
3806 static void
3807 gst_evaspixmapsink_base_init (gpointer g_class)
3808 {
3809   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3810
3811   gst_element_class_set_details_simple (element_class,
3812       "EvasPixmapSink", "Sink/Video",
3813       "evas image object videosink based on Xv extension", "Sangchul Lee <sc11.lee@samsung.com>");
3814
3815   gst_element_class_add_pad_template (element_class,
3816       gst_static_pad_template_get (&gst_evaspixmapsink_sink_template_factory));
3817 }
3818
3819 static void
3820 gst_evaspixmapsink_class_init (GstEvasPixmapSinkClass *klass)
3821 {
3822   GObjectClass *gobject_class;
3823   GstElementClass *gstelement_class;
3824   GstBaseSinkClass *gstbasesink_class;
3825   GstVideoSinkClass *videosink_class;
3826
3827   gobject_class = (GObjectClass *) klass;
3828   gstelement_class = (GstElementClass *) klass;
3829   gstbasesink_class = (GstBaseSinkClass *) klass;
3830   videosink_class = (GstVideoSinkClass *) klass;
3831
3832   parent_class = g_type_class_peek_parent (klass);
3833
3834   gobject_class->set_property = gst_evaspixmapsink_set_property;
3835   gobject_class->get_property = gst_evaspixmapsink_get_property;
3836
3837   g_object_class_install_property (gobject_class, PROP_CONTRAST,
3838       g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
3839           -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3840   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
3841       g_param_spec_int ("brightness", "Brightness",
3842           "The brightness of the video", -1000, 1000, 0,
3843           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3844   g_object_class_install_property (gobject_class, PROP_HUE,
3845       g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
3846           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3847   g_object_class_install_property (gobject_class, PROP_SATURATION,
3848       g_param_spec_int ("saturation", "Saturation",
3849           "The saturation of the video", -1000, 1000, 0,
3850           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3851   g_object_class_install_property (gobject_class, PROP_DISPLAY,
3852       g_param_spec_string ("display", "Display", "X Display name", NULL,
3853           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3854   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
3855       g_param_spec_boolean ("synchronous", "Synchronous",
3856           "When enabled, runs "
3857           "the X display in synchronous mode. (used only for debugging)", FALSE,
3858           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3859   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
3860       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
3861           "The pixel aspect ratio of the device", "1/1",
3862           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3863   g_object_class_install_property (gobject_class, PROP_DEVICE,
3864       g_param_spec_string ("device", "Adaptor number",
3865           "The number of the video adaptor", "0",
3866           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3867   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
3868       g_param_spec_string ("device-name", "Adaptor name",
3869           "The name of the video adaptor", NULL,
3870           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3871
3872   /**
3873    * GstEvasPixmapSink:double-buffer
3874    *
3875    * Whether to double-buffer the output.
3876    *
3877    * Since: 0.10.14
3878    */
3879   g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
3880       g_param_spec_boolean ("double-buffer", "Double-buffer",
3881           "Whether to double-buffer the output", TRUE,
3882           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3883   /**
3884    * GstEvasPixmapSink:autopaint-colorkey
3885    *
3886    * Whether to autofill overlay with colorkey
3887    *
3888    * Since: 0.10.21
3889    */
3890   g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
3891       g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
3892           "Whether to autofill overlay with colorkey", TRUE,
3893           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3894   /**
3895    * GstEvasPixmapSink:colorkey
3896    *
3897    * Color to use for the overlay mask.
3898    *
3899    * Since: 0.10.21
3900    */
3901   g_object_class_install_property (gobject_class, PROP_COLORKEY,
3902       g_param_spec_int ("colorkey", "Colorkey",
3903           "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
3904           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3905
3906   /**
3907    * GstEvasPixmapSink:pixmap-width
3908    *
3909    * Actual width of the pixmap.
3910    */
3911   g_object_class_install_property (gobject_class, PROP_PIXMAP_WIDTH,
3912       g_param_spec_uint64 ("pixmap-width", "pixmap-width", "Width of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3913
3914   /**
3915    * GstEvasPixmapSink:pixmap-height
3916    *
3917    * Actual height of the pixmap.
3918    */
3919   g_object_class_install_property (gobject_class, PROP_PIXMAP_HEIGHT,
3920       g_param_spec_uint64 ("pixmap-height", "pixmap-height", "Height of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3921
3922   /**
3923    * GstEvasPixmapSink:display-geometry-method
3924    *
3925    * Display geometrical method setting
3926    */
3927   g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
3928     g_param_spec_enum("display-geometry-method", "Display geometry method",
3929       "Geometrical method for display",
3930       GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
3931       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3932
3933   /**
3934    * GstEvasPixmapSink:dst-roi-x
3935    *
3936    * X value of Destination ROI
3937    */
3938   g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
3939       g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
3940           "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3941           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3942
3943   /**
3944    * GstEvasPixmapSink:dst-roi-y
3945    *
3946    * Y value of Destination ROI
3947    */
3948   g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
3949       g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
3950           "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3951           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3952
3953   /**
3954    * GstEvasPixmapSink:dst-roi-w
3955    *
3956    * W value of Destination ROI
3957    */
3958   g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
3959       g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
3960           "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3961           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3962
3963   /**
3964    * GstEvasPixmapSink:dst-roi-h
3965    *
3966    * H value of Destination ROI
3967    */
3968   g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
3969       g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
3970           "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3971           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3972
3973   /**
3974    * GstEvasPixmapSink:stop-video
3975    *
3976    * Stop video for releasing video source buffer
3977    */
3978   g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
3979       g_param_spec_int ("stop-video", "Stop-Video", "Stop video for releasing video source buffer", 0, 1, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3980
3981   /**
3982    * GstEvasPixmapSink:evas-object
3983    *
3984    * Evas image object for rendering
3985    */
3986   g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
3987     g_param_spec_pointer ("evas-object", "Destination Evas Object",     "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3988
3989   /**
3990    * GstEvasPixmapSink:display-flip
3991    *
3992    * Display flip setting
3993    */
3994   g_object_class_install_property(gobject_class, PROP_FLIP,
3995     g_param_spec_enum("flip", "Display flip",
3996       "Flip for display",
3997       GST_TYPE_EVASPIXMAPSINK_FLIP, DEF_DISPLAY_FLIP,
3998       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3999
4000   /**
4001    * GstEvasPixmapSink:rotate
4002    *
4003    * draw rotation angle setting
4004    */
4005   g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
4006     g_param_spec_enum("rotate", "Rotate angle", "Rotate angle of display output",GST_TYPE_EVASPIXMAPSINK_ROTATE_ANGLE, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4007
4008   /**
4009    * GstEvasPixmapSink:visible
4010    *
4011    * visible setting for a evas image object
4012    */
4013   g_object_class_install_property (gobject_class, PROP_VISIBLE,
4014         g_param_spec_boolean ("visible", "Visible", "When setting it false, evas image object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4015
4016    /**
4017    * GstEvasPixmapSink:origin-size
4018    *
4019    * Set pixmap size with media source's width and height
4020    */
4021   g_object_class_install_property (gobject_class, PROP_ORIGIN_SIZE,
4022         g_param_spec_boolean ("origin-size", "Origin-Size", "When setting it true, pixmap will be created with media source's width and height", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4023
4024   gobject_class->finalize = gst_evaspixmapsink_finalize;
4025
4026   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_change_state);
4027   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_getcaps);
4028   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_setcaps);
4029   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_get_times);
4030   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_event);
4031   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_show_frame);
4032 }
4033
4034 /* Object typing & Creation */
4035 GType
4036 gst_evaspixmapsink_get_type (void)
4037 {
4038   static GType evaspixmapsink_type = 0;
4039
4040   if (!evaspixmapsink_type) {
4041     static const GTypeInfo evaspixmapsink_info = {
4042       sizeof (GstEvasPixmapSinkClass),
4043       gst_evaspixmapsink_base_init,
4044       NULL,
4045       (GClassInitFunc) gst_evaspixmapsink_class_init,
4046       NULL,
4047       NULL,
4048       sizeof (GstEvasPixmapSink),
4049       0,
4050       (GInstanceInitFunc) gst_evaspixmapsink_init,
4051     };
4052     static const GInterfaceInfo iface_info = {
4053       (GInterfaceInitFunc) gst_evaspixmapsink_interface_init,
4054       NULL,
4055       NULL,
4056     };
4057     static const GInterfaceInfo navigation_info = {
4058       (GInterfaceInitFunc) gst_evaspixmapsink_navigation_init,
4059       NULL,
4060       NULL,
4061     };
4062     static const GInterfaceInfo colorbalance_info = {
4063       (GInterfaceInitFunc) gst_evaspixmapsink_colorbalance_init,
4064       NULL,
4065       NULL,
4066     };
4067     static const GInterfaceInfo propertyprobe_info = {
4068       (GInterfaceInitFunc) gst_evaspixmapsink_property_probe_interface_init,
4069       NULL,
4070       NULL,
4071     };
4072     evaspixmapsink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, "GstEvasPixmapSink", &evaspixmapsink_info, 0);
4073
4074     g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
4075     g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_NAVIGATION, &navigation_info);
4076     g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_COLOR_BALANCE, &colorbalance_info);
4077     g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
4078
4079     /* register type and create class in a more safe place instead of at
4080      * runtime since the type registration and class creation is not
4081      * threadsafe. */
4082     g_type_class_ref (gst_evaspixmap_buffer_get_type ());
4083   }
4084
4085   return evaspixmapsink_type;
4086 }
4087
4088 static gboolean
4089 plugin_init (GstPlugin *plugin)
4090 {
4091         if (!gst_element_register (plugin, "evaspixmapsink", GST_RANK_NONE, GST_TYPE_EVASPIXMAPSINK)) {
4092                 return FALSE;
4093         }
4094         GST_DEBUG_CATEGORY_INIT (gst_debug_evaspixmapsink, "evaspixmapsink", 0, "evaspixmapsink element");
4095         GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
4096
4097         return TRUE;
4098 }
4099
4100 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
4101         "evaspixmapsink","Evas image object render plugin using Xv extension", plugin_init,
4102         VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)