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