[xvimagesink] Fix seg.fault when user set visible property in case of pixmap usage
[framework/multimedia/gst-plugins-base0.10.git] / sys / xvimage / xvimagesink.c
1 /* GStreamer
2  * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3  *               <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
4  * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * * Modifications by Samsung Electronics Co., Ltd.
22  * 1. Add display related properties
23  * 2. Support samsung extension format to improve performance
24  * 3. Support video texture overlay of OSP layer
25  */
26
27 /**
28  * SECTION:element-xvimagesink
29  *
30  * XvImageSink renders video frames to a drawable (XWindow) on a local display
31  * using the XVideo extension. Rendering to a remote display is theoretically
32  * possible but i doubt that the XVideo extension is actually available when
33  * connecting to a remote display. This element can receive a Window ID from the
34  * application through the XOverlay interface and will then render video frames
35  * in this drawable. If no Window ID was provided by the application, the
36  * element will create its own internal window and render into it.
37  *
38  * <refsect2>
39  * <title>Scaling</title>
40  * <para>
41  * The XVideo extension, when it's available, handles hardware accelerated
42  * scaling of video frames. This means that the element will just accept
43  * incoming video frames no matter their geometry and will then put them to the
44  * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
45  * property it is possible to enforce scaling with a constant aspect ratio,
46  * which means drawing black borders around the video frame.
47  * </para>
48  * </refsect2>
49  * <refsect2>
50  * <title>Events</title>
51  * <para>
52  * XvImageSink creates a thread to handle events coming from the drawable. There
53  * are several kind of events that can be grouped in 2 big categories: input
54  * events and window state related events. Input events will be translated to
55  * navigation events and pushed upstream for other elements to react on them.
56  * This includes events such as pointer moves, key press/release, clicks etc...
57  * Other events are used to handle the drawable appearance even when the data
58  * is not flowing (GST_STATE_PAUSED). That means that even when the element is
59  * paused, it will receive expose events from the drawable and draw the latest
60  * frame with correct borders/aspect-ratio.
61  * </para>
62  * </refsect2>
63  * <refsect2>
64  * <title>Pixel aspect ratio</title>
65  * <para>
66  * When changing state to GST_STATE_READY, XvImageSink will open a connection to
67  * the display specified in the #GstXvImageSink:display property or the
68  * default display if nothing specified. Once this connection is open it will
69  * inspect the display configuration including the physical display geometry and
70  * then calculate the pixel aspect ratio. When receiving video frames with a
71  * different pixel aspect ratio, XvImageSink will use hardware scaling to
72  * display the video frames correctly on display's pixel aspect ratio.
73  * Sometimes the calculated pixel aspect ratio can be wrong, it is
74  * then possible to enforce a specific pixel aspect ratio using the
75  * #GstXvImageSink:pixel-aspect-ratio property.
76  * </para>
77  * </refsect2>
78  * <refsect2>
79  * <title>Examples</title>
80  * |[
81  * gst-launch -v videotestsrc ! xvimagesink
82  * ]| A pipeline to test hardware scaling.
83  * When the test video signal appears you can resize the window and see that
84  * video frames are scaled through hardware (no extra CPU cost).
85  * |[
86  * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
87  * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
88  * You can observe the borders drawn around the scaled image respecting aspect
89  * ratio.
90  * |[
91  * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
92  * ]| A pipeline to test navigation events.
93  * While moving the mouse pointer over the test signal you will see a black box
94  * following the mouse pointer. If you press the mouse button somewhere on the
95  * video and release it somewhere else a green box will appear where you pressed
96  * the button and a red one where you released it. (The navigationtest element
97  * is part of gst-plugins-good.) You can observe here that even if the images
98  * are scaled through hardware the pointer coordinates are converted back to the
99  * original video frame geometry so that the box can be drawn to the correct
100  * position. This also handles borders correctly, limiting coordinates to the
101  * image area
102  * |[
103  * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
104  * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
105  * videotestsrc, in most cases the pixel aspect ratio of the display will be
106  * 1/1. This means that XvImageSink will have to do the scaling to convert
107  * incoming frames to a size that will match the display pixel aspect ratio
108  * (from 320x240 to 320x180 in this case). Note that you might have to escape
109  * some characters for your shell like '\(fraction\)'.
110  * |[
111  * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
112  * ]| Demonstrates how to use the colorbalance interface.
113  * </refsect2>
114  */
115
116 /* for developers: there are two useful tools : xvinfo and xvattr */
117
118 #ifdef HAVE_CONFIG_H
119 #include "config.h"
120 #endif
121
122 /* Our interfaces */
123 #include <gst/interfaces/navigation.h>
124 #include <gst/interfaces/xoverlay.h>
125 #include <gst/interfaces/colorbalance.h>
126 #include <gst/interfaces/propertyprobe.h>
127 /* Helper functions */
128 #include <gst/video/video.h>
129
130 /* Object header */
131 #include "xvimagesink.h"
132
133 #ifdef GST_EXT_XV_ENHANCEMENT
134 /* Samsung extension headers */
135 /* For xv extension header for buffer transfer (output) */
136 #include "xv_types.h"
137
138 /* headers for drm */
139 #include <sys/stat.h>
140 #include <sys/ioctl.h>
141 #include <fcntl.h>
142 #include <unistd.h>
143 #include <xf86drm.h>
144 #include <xf86drmMode.h>
145 #include <X11/Xmd.h>
146 #include <dri2/dri2.h>
147 #include <tbm_bufmgr.h>
148
149 /* for performance checking */
150 #include <mm_ta.h>
151
152 typedef enum {
153         BUF_SHARE_METHOD_PADDR = 0,
154         BUF_SHARE_METHOD_FD,
155         BUF_SHARE_METHOD_TIZEN_BUFFER
156 } buf_share_method_t;
157
158 #define _BUFFER_WAIT_TIMEOUT            2000000
159 #define _CHECK_DISPLAYED_BUFFER_COUNT   30
160 #define _EVENT_THREAD_CHECK_INTERVAL    15000   /* us */
161
162 /* max channel count *********************************************************/
163 #define SCMN_IMGB_MAX_PLANE         (4)
164
165 /* image buffer definition ***************************************************
166
167     +------------------------------------------+ ---
168     |                                          |  ^
169     |     a[], p[]                             |  |
170     |     +---------------------------+ ---    |  |
171     |     |                           |  ^     |  |
172     |     |<---------- w[] ---------->|  |     |  |
173     |     |                           |  |     |  |
174     |     |                           |        |
175     |     |                           |  h[]   |  e[]
176     |     |                           |        |
177     |     |                           |  |     |  |
178     |     |                           |  |     |  |
179     |     |                           |  v     |  |
180     |     +---------------------------+ ---    |  |
181     |                                          |  v
182     +------------------------------------------+ ---
183
184     |<----------------- s[] ------------------>|
185 */
186
187 typedef struct
188 {
189         /* width of each image plane */
190         int w[SCMN_IMGB_MAX_PLANE];
191         /* height of each image plane */
192         int h[SCMN_IMGB_MAX_PLANE];
193         /* stride of each image plane */
194         int s[SCMN_IMGB_MAX_PLANE];
195         /* elevation of each image plane */
196         int e[SCMN_IMGB_MAX_PLANE];
197         /* user space address of each image plane */
198         void *a[SCMN_IMGB_MAX_PLANE];
199         /* physical address of each image plane, if needs */
200         void *p[SCMN_IMGB_MAX_PLANE];
201         /* color space type of image */
202         int cs;
203         /* left postion, if needs */
204         int x;
205         /* top position, if needs */
206         int y;
207         /* to align memory */
208         int __dummy2;
209         /* arbitrary data */
210         int data[16];
211         /* dma buf fd */
212         int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
213         /* buffer share method */
214         int buf_share_method;
215         /* Y plane size in case of ST12 */
216         int y_size;
217         /* UV plane size in case of ST12 */
218         int uv_size;
219         /* Tizen buffer object */
220         void *bo[SCMN_IMGB_MAX_PLANE];
221         /* JPEG data */
222         void *jpeg_data;
223         /* JPEG size */
224         int jpeg_size;
225         /* TZ memory buffer */
226         int tz_enable;
227 } SCMN_IMGB;
228 #endif /* GST_EXT_XV_ENHANCEMENT */
229
230 /* Debugging category */
231 #include <gst/gstinfo.h>
232
233 #include "gst/glib-compat-private.h"
234
235 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
236 #define GST_CAT_DEFAULT gst_debug_xvimagesink
237 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
238
239 #ifdef GST_EXT_XV_ENHANCEMENT
240 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
241 #define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
242
243 static GType
244 gst_xvimagesink_display_mode_get_type(void)
245 {
246         static GType xvimagesink_display_mode_type = 0;
247         static const GEnumValue display_mode_type[] = {
248                 { 0, "Default mode", "DEFAULT"},
249                 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
250                 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
251                 { 3, NULL, NULL},
252         };
253
254         if (!xvimagesink_display_mode_type) {
255                 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
256         }
257
258         return xvimagesink_display_mode_type;
259 }
260
261 static GType
262 gst_xvimagesink_csc_range_get_type(void)
263 {
264         static GType xvimagesink_csc_range_type = 0;
265         static const GEnumValue csc_range_type[] = {
266                 { 0, "Narrow range", "NARROW"},
267                 { 1, "Wide range", "WIDE"},
268                 { 2, NULL, NULL},
269         };
270
271         if (!xvimagesink_csc_range_type) {
272                 xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
273         }
274
275         return xvimagesink_csc_range_type;
276 }
277
278 enum {
279     DEGREE_0,
280     DEGREE_90,
281     DEGREE_180,
282     DEGREE_270,
283     DEGREE_NUM,
284 };
285
286 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
287
288 static GType
289 gst_xvimagesink_rotate_angle_get_type(void)
290 {
291         static GType xvimagesink_rotate_angle_type = 0;
292         static const GEnumValue rotate_angle_type[] = {
293                 { 0, "No rotate", "DEGREE_0"},
294                 { 1, "Rotate 90 degree", "DEGREE_90"},
295                 { 2, "Rotate 180 degree", "DEGREE_180"},
296                 { 3, "Rotate 270 degree", "DEGREE_270"},
297                 { 4, NULL, NULL},
298         };
299
300         if (!xvimagesink_rotate_angle_type) {
301                 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
302         }
303
304         return xvimagesink_rotate_angle_type;
305 }
306
307 enum {
308     DISP_GEO_METHOD_LETTER_BOX = 0,
309     DISP_GEO_METHOD_ORIGIN_SIZE,
310     DISP_GEO_METHOD_FULL_SCREEN,
311     DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
312     DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
313     DISP_GEO_METHOD_CUSTOM_ROI,
314     DISP_GEO_METHOD_NUM,
315 };
316 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
317
318 enum {
319     FLIP_NONE = 0,
320     FLIP_HORIZONTAL,
321     FLIP_VERTICAL,
322     FLIP_BOTH,
323     FLIP_NUM,
324 };
325 #define DEF_DISPLAY_FLIP            FLIP_NONE
326
327 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
328 #define GST_TYPE_XVIMAGESINK_FLIP                    (gst_xvimagesink_flip_get_type())
329
330 static GType
331 gst_xvimagesink_display_geometry_method_get_type(void)
332 {
333         static GType xvimagesink_display_geometry_method_type = 0;
334         static const GEnumValue display_geometry_method_type[] = {
335                 { 0, "Letter box", "LETTER_BOX"},
336                 { 1, "Origin size", "ORIGIN_SIZE"},
337                 { 2, "Full-screen", "FULL_SCREEN"},
338                 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
339                 { 4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"},
340                 { 5, "Explicitly described destination ROI", "CUSTOM_ROI"},
341                 { 6, NULL, NULL},
342         };
343
344         if (!xvimagesink_display_geometry_method_type) {
345                 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
346         }
347
348         return xvimagesink_display_geometry_method_type;
349 }
350
351 static GType
352 gst_xvimagesink_flip_get_type(void)
353 {
354         static GType xvimagesink_flip_type = 0;
355         static const GEnumValue flip_type[] = {
356                 { FLIP_NONE,       "Flip NONE", "FLIP_NONE"},
357                 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
358                 { FLIP_VERTICAL,   "Flip VERTICAL", "FLIP_VERTICAL"},
359                 { FLIP_BOTH,       "Flip BOTH", "FLIP_BOTH"},
360                 { FLIP_NUM, NULL, NULL},
361         };
362
363         if (!xvimagesink_flip_type) {
364                 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
365         }
366
367         return xvimagesink_flip_type;
368 }
369
370 #define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
371 void
372 gst_xvimagesink_BOOLEAN__POINTER (GClosure         *closure,
373                                      GValue         *return_value G_GNUC_UNUSED,
374                                      guint          n_param_values,
375                                      const GValue   *param_values,
376                                      gpointer       invocation_hint G_GNUC_UNUSED,
377                                      gpointer       marshal_data)
378 {
379   typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer     data1,
380                                                      gpointer     arg_1,
381                                                      gpointer     data2);
382   register GMarshalFunc_BOOLEAN__POINTER callback;
383   register GCClosure *cc = (GCClosure*) closure;
384   register gpointer data1, data2;
385
386   gboolean v_return;
387
388   g_return_if_fail (return_value != NULL);
389   g_return_if_fail (n_param_values == 2);
390
391   if (G_CCLOSURE_SWAP_DATA (closure)) {
392     data1 = closure->data;
393     data2 = g_value_peek_pointer (param_values + 0);
394   } else {
395     data1 = g_value_peek_pointer (param_values + 0);
396     data2 = closure->data;
397   }
398   callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
399
400   v_return = callback (data1,
401                       g_marshal_value_peek_pointer (param_values + 1),
402                       data2);
403
404   g_value_set_boolean (return_value, v_return);
405 }
406
407 enum
408 {
409     SIGNAL_FRAME_RENDER_ERROR,
410     LAST_SIGNAL
411 };
412 static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
413
414 #endif /* GST_EXT_XV_ENHANCEMENT */
415
416 typedef struct
417 {
418   unsigned long flags;
419   unsigned long functions;
420   unsigned long decorations;
421   long input_mode;
422   unsigned long status;
423 }
424 MotifWmHints, MwmHints;
425
426 #define MWM_HINTS_DECORATIONS   (1L << 1)
427
428 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
429
430 static GstBufferClass *xvimage_buffer_parent_class = NULL;
431 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
432
433 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
434     xvimagesink);
435 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
436     GstCaps * caps);
437 static void gst_xvimagesink_expose (GstXOverlay * overlay);
438
439 #ifdef GST_EXT_XV_ENHANCEMENT
440 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
441 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
442 static gboolean set_csc_range(GstXContext *xcontext, int set_range);
443 static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
444 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
445 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
446 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
447 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
448 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
449 #endif /* GST_EXT_XV_ENHANCEMENT */
450
451 /* Default template - initiated with class struct to allow gst-register to work
452    without X running */
453 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
454     GST_STATIC_PAD_TEMPLATE ("sink",
455     GST_PAD_SINK,
456     GST_PAD_ALWAYS,
457     GST_STATIC_CAPS ("video/x-raw-rgb, "
458         "framerate = (fraction) [ 0, MAX ], "
459         "width = (int) [ 1, MAX ], "
460         "height = (int) [ 1, MAX ]; "
461         "video/x-raw-yuv, "
462         "framerate = (fraction) [ 0, MAX ], "
463         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
464     );
465
466 enum
467 {
468   PROP_0,
469   PROP_CONTRAST,
470   PROP_BRIGHTNESS,
471   PROP_HUE,
472   PROP_SATURATION,
473   PROP_DISPLAY,
474   PROP_SYNCHRONOUS,
475   PROP_PIXEL_ASPECT_RATIO,
476   PROP_FORCE_ASPECT_RATIO,
477   PROP_HANDLE_EVENTS,
478   PROP_DEVICE,
479   PROP_DEVICE_NAME,
480   PROP_HANDLE_EXPOSE,
481   PROP_DOUBLE_BUFFER,
482   PROP_AUTOPAINT_COLORKEY,
483   PROP_COLORKEY,
484   PROP_DRAW_BORDERS,
485   PROP_WINDOW_WIDTH,
486   PROP_WINDOW_HEIGHT,
487 #ifdef GST_EXT_XV_ENHANCEMENT
488   PROP_DISPLAY_MODE,
489   PROP_CSC_RANGE,
490   PROP_ROTATE_ANGLE,
491   PROP_FLIP,
492   PROP_DISPLAY_GEOMETRY_METHOD,
493   PROP_VISIBLE,
494   PROP_ZOOM,
495   PROP_DST_ROI_X,
496   PROP_DST_ROI_Y,
497   PROP_DST_ROI_W,
498   PROP_DST_ROI_H,
499   PROP_STOP_VIDEO,
500   PROP_PIXMAP_CB,
501   PROP_PIXMAP_CB_USER_DATA,
502 #endif /* GST_EXT_XV_ENHANCEMENT */
503 };
504
505 static void gst_xvimagesink_init_interfaces (GType type);
506
507 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
508     GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
509
510
511 /* ============================================================= */
512 /*                                                               */
513 /*                       Private Methods                         */
514 /*                                                               */
515 /* ============================================================= */
516
517 /* xvimage buffers */
518
519 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
520
521 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
522 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
523 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
524
525 /* This function destroys a GstXvImage handling XShm availability */
526 static void
527 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
528 {
529   GstXvImageSink *xvimagesink;
530
531   GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
532
533   xvimagesink = xvimage->xvimagesink;
534   if (G_UNLIKELY (xvimagesink == NULL))
535     goto no_sink;
536
537   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
538
539   GST_OBJECT_LOCK (xvimagesink);
540
541   /* If the destroyed image is the current one we destroy our reference too */
542   if (xvimagesink->cur_image == xvimage)
543     xvimagesink->cur_image = NULL;
544
545   /* We might have some buffers destroyed after changing state to NULL */
546   if (xvimagesink->xcontext == NULL) {
547     GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
548 #ifdef HAVE_XSHM
549     /* Need to free the shared memory segment even if the x context
550      * was already cleaned up */
551     if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
552       shmdt (xvimage->SHMInfo.shmaddr);
553     }
554 #endif
555     goto beach;
556   }
557
558   g_mutex_lock (xvimagesink->x_lock);
559
560 #ifdef HAVE_XSHM
561   if (xvimagesink->xcontext->use_xshm) {
562     if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
563       GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
564           xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
565       XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
566       XSync (xvimagesink->xcontext->disp, FALSE);
567
568       shmdt (xvimage->SHMInfo.shmaddr);
569     }
570     if (xvimage->xvimage)
571       XFree (xvimage->xvimage);
572   } else
573 #endif /* HAVE_XSHM */
574   {
575     if (xvimage->xvimage) {
576       if (xvimage->xvimage->data) {
577         g_free (xvimage->xvimage->data);
578       }
579       XFree (xvimage->xvimage);
580     }
581   }
582
583   XSync (xvimagesink->xcontext->disp, FALSE);
584
585   g_mutex_unlock (xvimagesink->x_lock);
586
587 beach:
588   GST_OBJECT_UNLOCK (xvimagesink);
589   xvimage->xvimagesink = NULL;
590   gst_object_unref (xvimagesink);
591
592   GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
593       (xvimage));
594
595   return;
596
597 no_sink:
598   {
599     GST_WARNING ("no sink found");
600     return;
601   }
602 }
603
604 static void
605 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
606 {
607   GstXvImageSink *xvimagesink;
608   gboolean running;
609
610   xvimagesink = xvimage->xvimagesink;
611   if (G_UNLIKELY (xvimagesink == NULL))
612     goto no_sink;
613
614   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
615
616   GST_OBJECT_LOCK (xvimagesink);
617   running = xvimagesink->running;
618   GST_OBJECT_UNLOCK (xvimagesink);
619
620   /* If our geometry changed we can't reuse that image. */
621   if (running == FALSE) {
622     GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
623     gst_xvimage_buffer_destroy (xvimage);
624   } else if ((xvimage->width != xvimagesink->video_width) ||
625       (xvimage->height != xvimagesink->video_height)) {
626     GST_LOG_OBJECT (xvimage,
627         "destroy image as its size changed %dx%d vs current %dx%d",
628         xvimage->width, xvimage->height,
629         xvimagesink->video_width, xvimagesink->video_height);
630     gst_xvimage_buffer_destroy (xvimage);
631   } else {
632     /* In that case we can reuse the image and add it to our image pool. */
633     GST_LOG_OBJECT (xvimage, "recycling image in pool");
634     /* need to increment the refcount again to recycle */
635     gst_buffer_ref (GST_BUFFER_CAST (xvimage));
636     g_mutex_lock (xvimagesink->pool_lock);
637     xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
638         xvimage);
639     g_mutex_unlock (xvimagesink->pool_lock);
640   }
641   return;
642
643 no_sink:
644   {
645     GST_WARNING ("no sink found");
646     return;
647   }
648 }
649
650 static void
651 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
652 {
653   /* make sure it is not recycled */
654   xvimage->width = -1;
655   xvimage->height = -1;
656   gst_buffer_unref (GST_BUFFER (xvimage));
657 }
658
659 static void
660 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
661 {
662 #ifdef HAVE_XSHM
663   xvimage->SHMInfo.shmaddr = ((void *) -1);
664   xvimage->SHMInfo.shmid = -1;
665 #endif
666 }
667
668 static void
669 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
670 {
671   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
672
673   xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
674
675   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
676       gst_xvimage_buffer_finalize;
677 }
678
679 static GType
680 gst_xvimage_buffer_get_type (void)
681 {
682   static GType _gst_xvimage_buffer_type;
683
684   if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
685     static const GTypeInfo xvimage_buffer_info = {
686       sizeof (GstBufferClass),
687       NULL,
688       NULL,
689       gst_xvimage_buffer_class_init,
690       NULL,
691       NULL,
692       sizeof (GstXvImageBuffer),
693       0,
694       (GInstanceInitFunc) gst_xvimage_buffer_init,
695       NULL
696     };
697     _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
698         "GstXvImageBuffer", &xvimage_buffer_info, 0);
699   }
700   return _gst_xvimage_buffer_type;
701 }
702
703 /* X11 stuff */
704
705 static gboolean error_caught = FALSE;
706
707 static int
708 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
709 {
710   char error_msg[1024];
711
712 #ifdef GST_EXT_XV_ENHANCEMENT
713   if (xevent) {
714     XGetErrorText (display, xevent->error_code, error_msg, 1024);
715     error_msg[1023] = '\0';
716     GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
717   } else {
718     GST_ERROR("CAUTION:xevent is NULL");
719   }
720 #else /* GST_EXT_XV_ENHANCEMENT */
721   XGetErrorText (display, xevent->error_code, error_msg, 1024);
722   GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
723 #endif /* GST_EXT_XV_ENHANCEMENT */
724   error_caught = TRUE;
725   return 0;
726 }
727
728 #ifdef HAVE_XSHM
729 /* This function checks that it is actually really possible to create an image
730    using XShm */
731 static gboolean
732 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
733 {
734   XvImage *xvimage;
735   XShmSegmentInfo SHMInfo;
736   gint size;
737   int (*handler) (Display *, XErrorEvent *);
738   gboolean result = FALSE;
739   gboolean did_attach = FALSE;
740
741   g_return_val_if_fail (xcontext != NULL, FALSE);
742
743   /* Sync to ensure any older errors are already processed */
744   XSync (xcontext->disp, FALSE);
745
746   /* Set defaults so we don't free these later unnecessarily */
747   SHMInfo.shmaddr = ((void *) -1);
748   SHMInfo.shmid = -1;
749
750   /* Setting an error handler to catch failure */
751   error_caught = FALSE;
752   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
753
754   /* Trying to create a 1x1 picture */
755   GST_DEBUG ("XvShmCreateImage of 1x1");
756   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
757       xcontext->im_format, NULL, 1, 1, &SHMInfo);
758
759   /* Might cause an error, sync to ensure it is noticed */
760   XSync (xcontext->disp, FALSE);
761   if (!xvimage || error_caught) {
762     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
763     goto beach;
764   }
765   size = xvimage->data_size;
766
767   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
768   if (SHMInfo.shmid == -1) {
769     GST_WARNING ("could not get shared memory of %d bytes", size);
770     goto beach;
771   }
772
773   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
774   if (SHMInfo.shmaddr == ((void *) -1)) {
775     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
776     /* Clean up the shared memory segment */
777     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
778     goto beach;
779   }
780
781   xvimage->data = SHMInfo.shmaddr;
782   SHMInfo.readOnly = FALSE;
783
784   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
785     GST_WARNING ("Failed to XShmAttach");
786     /* Clean up the shared memory segment */
787     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
788     goto beach;
789   }
790
791   /* Sync to ensure we see any errors we caused */
792   XSync (xcontext->disp, FALSE);
793
794   /* Delete the shared memory segment as soon as everyone is attached.
795    * This way, it will be deleted as soon as we detach later, and not
796    * leaked if we crash. */
797   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
798
799   if (!error_caught) {
800     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
801         SHMInfo.shmseg);
802
803     did_attach = TRUE;
804     /* store whether we succeeded in result */
805     result = TRUE;
806   } else {
807     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
808         "Not using shared memory.");
809   }
810
811 beach:
812   /* Sync to ensure we swallow any errors we caused and reset error_caught */
813   XSync (xcontext->disp, FALSE);
814
815   error_caught = FALSE;
816   XSetErrorHandler (handler);
817
818   if (did_attach) {
819     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
820         SHMInfo.shmid, SHMInfo.shmseg);
821     XShmDetach (xcontext->disp, &SHMInfo);
822     XSync (xcontext->disp, FALSE);
823   }
824   if (SHMInfo.shmaddr != ((void *) -1))
825     shmdt (SHMInfo.shmaddr);
826   if (xvimage)
827     XFree (xvimage);
828   return result;
829 }
830 #endif /* HAVE_XSHM */
831
832 /* This function handles GstXvImage creation depending on XShm availability */
833 static GstXvImageBuffer *
834 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
835 {
836   GstXvImageBuffer *xvimage = NULL;
837   GstStructure *structure = NULL;
838   gboolean succeeded = FALSE;
839   int (*handler) (Display *, XErrorEvent *);
840
841   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
842
843   if (caps == NULL)
844     return NULL;
845
846   xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
847   GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
848
849   structure = gst_caps_get_structure (caps, 0);
850
851   if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
852       !gst_structure_get_int (structure, "height", &xvimage->height)) {
853     GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
854   }
855
856   GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
857       xvimage->height);
858 #ifdef GST_EXT_XV_ENHANCEMENT
859   GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
860                                xvimagesink->aligned_width, xvimagesink->aligned_height);
861   if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
862     GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
863     xvimagesink->aligned_width = xvimage->width;
864     xvimagesink->aligned_height = xvimage->height;
865   }
866 #endif /* GST_EXT_XV_ENHANCEMENT */
867
868   xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
869   if (xvimage->im_format == -1) {
870     GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
871         GST_PTR_FORMAT, caps);
872     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
873         ("Failed to create output image buffer of %dx%d pixels",
874             xvimage->width, xvimage->height), ("Invalid input caps"));
875     goto beach_unlocked;
876   }
877   xvimage->xvimagesink = gst_object_ref (xvimagesink);
878
879   g_mutex_lock (xvimagesink->x_lock);
880
881 #ifdef GST_EXT_XV_ENHANCEMENT
882   XSync (xvimagesink->xcontext->disp, FALSE);
883 #endif /* GST_EXT_XV_ENHANCEMENT */
884   /* Setting an error handler to catch failure */
885   error_caught = FALSE;
886   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
887
888 #ifdef HAVE_XSHM
889   if (xvimagesink->xcontext->use_xshm) {
890     int expected_size;
891
892     xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
893         xvimagesink->xcontext->xv_port_id,
894         xvimage->im_format, NULL,
895 #ifdef GST_EXT_XV_ENHANCEMENT
896         xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
897 #else /* GST_EXT_XV_ENHANCEMENT */
898         xvimage->width, xvimage->height, &xvimage->SHMInfo);
899 #endif /* GST_EXT_XV_ENHANCEMENT */
900     if (!xvimage->xvimage || error_caught) {
901       g_mutex_unlock (xvimagesink->x_lock);
902
903       /* Reset error flag */
904       error_caught = FALSE;
905
906       /* Push a warning */
907       GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
908           ("Failed to create output image buffer of %dx%d pixels",
909               xvimage->width, xvimage->height),
910           ("could not XvShmCreateImage a %dx%d image",
911               xvimage->width, xvimage->height));
912
913 #ifdef GST_EXT_XV_ENHANCEMENT
914       /* must not change "use_xshm",
915          because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
916       goto beach_unlocked;
917 #else /* GST_EXT_XV_ENHANCEMENT */
918       /* Retry without XShm */
919       xvimagesink->xcontext->use_xshm = FALSE;
920
921       /* Hold X mutex again to try without XShm */
922       g_mutex_lock (xvimagesink->x_lock);
923       goto no_xshm;
924 #endif /* GST_EXT_XV_ENHANCEMENT */
925     }
926
927     /* we have to use the returned data_size for our shm size */
928     xvimage->size = xvimage->xvimage->data_size;
929     GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
930         xvimage->size);
931
932     /* calculate the expected size.  This is only for sanity checking the
933      * number we get from X. */
934     switch (xvimage->im_format) {
935       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
936       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
937       {
938         gint pitches[3];
939         gint offsets[3];
940         guint plane;
941
942         offsets[0] = 0;
943         pitches[0] = GST_ROUND_UP_4 (xvimage->width);
944         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
945         pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
946         offsets[2] =
947             offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
948         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
949
950         expected_size =
951             offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
952
953         for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
954           GST_DEBUG_OBJECT (xvimagesink,
955               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
956               plane, pitches[plane], offsets[plane]);
957         }
958         break;
959       }
960       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
961       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
962         expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
963         break;
964
965 #ifdef GST_EXT_XV_ENHANCEMENT
966       case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
967       case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
968       case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
969       case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
970       case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
971       case GST_MAKE_FOURCC ('S', '4', '2', '0'):
972       case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
973         expected_size = sizeof(SCMN_IMGB);
974         break;
975 #endif /* GST_EXT_XV_ENHANCEMENT */
976       default:
977         expected_size = 0;
978         break;
979     }
980     if (expected_size != 0 && xvimage->size != expected_size) {
981       GST_WARNING_OBJECT (xvimagesink,
982           "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
983           xvimage->size, expected_size);
984     }
985
986     /* Be verbose about our XvImage stride */
987     {
988       guint plane;
989
990       for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
991         GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
992             "offset of %d", plane, xvimage->xvimage->pitches[plane],
993             xvimage->xvimage->offsets[plane]);
994       }
995     }
996
997     xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
998         IPC_CREAT | 0777);
999     if (xvimage->SHMInfo.shmid == -1) {
1000       g_mutex_unlock (xvimagesink->x_lock);
1001       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1002           ("Failed to create output image buffer of %dx%d pixels",
1003               xvimage->width, xvimage->height),
1004           ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1005               xvimage->size));
1006       goto beach_unlocked;
1007     }
1008
1009     xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1010     if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1011       g_mutex_unlock (xvimagesink->x_lock);
1012       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1013           ("Failed to create output image buffer of %dx%d pixels",
1014               xvimage->width, xvimage->height),
1015           ("Failed to shmat: %s", g_strerror (errno)));
1016       /* Clean up the shared memory segment */
1017       shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1018       goto beach_unlocked;
1019     }
1020
1021     xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1022     xvimage->SHMInfo.readOnly = FALSE;
1023
1024     if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1025       /* Clean up the shared memory segment */
1026       shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1027
1028       g_mutex_unlock (xvimagesink->x_lock);
1029       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1030           ("Failed to create output image buffer of %dx%d pixels",
1031               xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1032       goto beach_unlocked;
1033     }
1034
1035     XSync (xvimagesink->xcontext->disp, FALSE);
1036
1037     /* Delete the shared memory segment as soon as we everyone is attached.
1038      * This way, it will be deleted as soon as we detach later, and not
1039      * leaked if we crash. */
1040     shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1041
1042     GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1043         xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1044   } else
1045 #ifndef GST_EXT_XV_ENHANCEMENT
1046   no_xshm:
1047 #endif /* GST_EXT_XV_ENHANCEMENT */
1048 #endif /* HAVE_XSHM */
1049   {
1050     xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1051         xvimagesink->xcontext->xv_port_id,
1052 #ifdef GST_EXT_XV_ENHANCEMENT
1053         xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1054 #else /* GST_EXT_XV_ENHANCEMENT */
1055         xvimage->im_format, NULL, xvimage->width, xvimage->height);
1056 #endif /* GST_EXT_XV_ENHANCEMENT */
1057     if (!xvimage->xvimage || error_caught) {
1058       g_mutex_unlock (xvimagesink->x_lock);
1059       /* Reset error handler */
1060       error_caught = FALSE;
1061       XSetErrorHandler (handler);
1062       /* Push an error */
1063       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1064           ("Failed to create outputimage buffer of %dx%d pixels",
1065               xvimage->width, xvimage->height),
1066           ("could not XvCreateImage a %dx%d image",
1067               xvimage->width, xvimage->height));
1068       goto beach_unlocked;
1069     }
1070
1071     /* we have to use the returned data_size for our image size */
1072     xvimage->size = xvimage->xvimage->data_size;
1073     xvimage->xvimage->data = g_malloc (xvimage->size);
1074
1075     XSync (xvimagesink->xcontext->disp, FALSE);
1076   }
1077
1078   /* Reset error handler */
1079   error_caught = FALSE;
1080   XSetErrorHandler (handler);
1081
1082   succeeded = TRUE;
1083
1084   GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1085   GST_BUFFER_SIZE (xvimage) = xvimage->size;
1086
1087   g_mutex_unlock (xvimagesink->x_lock);
1088
1089 beach_unlocked:
1090   if (!succeeded) {
1091     gst_xvimage_buffer_free (xvimage);
1092     xvimage = NULL;
1093   }
1094
1095   return xvimage;
1096 }
1097
1098 /* We are called with the x_lock taken */
1099 static void
1100 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
1101     GstXWindow * xwindow, GstVideoRectangle rect)
1102 {
1103   gint t1, t2;
1104
1105   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1106   g_return_if_fail (xwindow != NULL);
1107
1108   XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1109       xvimagesink->xcontext->black);
1110
1111   /* Left border */
1112   if (rect.x > xvimagesink->render_rect.x) {
1113     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1114         xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1115         rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
1116   }
1117
1118   /* Right border */
1119   t1 = rect.x + rect.w;
1120   t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
1121   if (t1 < t2) {
1122     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1123         t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
1124   }
1125
1126   /* Top border */
1127   if (rect.y > xvimagesink->render_rect.y) {
1128     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1129         xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1130         xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
1131   }
1132
1133   /* Bottom border */
1134   t1 = rect.y + rect.h;
1135   t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
1136   if (t1 < t2) {
1137     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1138         xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
1139   }
1140 }
1141
1142 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
1143  * if no window was available  */
1144 static gboolean
1145 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
1146     GstXvImageBuffer * xvimage)
1147 {
1148   GstVideoRectangle result;
1149   gboolean draw_border = FALSE;
1150
1151 #ifdef GST_EXT_XV_ENHANCEMENT
1152   static Atom atom_rotation = None;
1153   static Atom atom_hflip = None;
1154   static Atom atom_vflip = None;
1155   gboolean set_hflip = FALSE;
1156   gboolean set_vflip = FALSE;
1157
1158   GstVideoRectangle src_origin = { 0, 0, 0, 0};
1159   GstVideoRectangle src_input  = { 0, 0, 0, 0};
1160   GstVideoRectangle src = { 0, 0, 0, 0};
1161   GstVideoRectangle dst = { 0, 0, 0, 0};
1162
1163   int rotate        = 0;
1164   int ret           = 0;
1165   int idx           = 0;
1166   int (*handler) (Display *, XErrorEvent *) = NULL;
1167   gboolean res = FALSE;
1168   XV_DATA_PTR img_data = NULL;
1169 #endif /* GST_EXT_XV_ENHANCEMENT */
1170
1171   /* We take the flow_lock. If expose is in there we don't want to run
1172      concurrently from the data flow thread */
1173   g_mutex_lock (xvimagesink->flow_lock);
1174
1175 #ifdef GST_EXT_XV_ENHANCEMENT
1176   if (xvimagesink->xid_updated) {
1177     if (xvimage && xvimagesink->xvimage == NULL) {
1178       GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
1179       xvimage = NULL;
1180     }
1181     xvimagesink->xid_updated = FALSE;
1182   }
1183 #endif /* GST_EXT_XV_ENHANCEMENT */
1184
1185   if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1186 #ifdef GST_EXT_XV_ENHANCEMENT
1187     if (xvimagesink->get_pixmap_cb) {
1188       GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
1189     } else {
1190       GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
1191       g_mutex_unlock(xvimagesink->flow_lock);
1192       return FALSE;
1193     }
1194 #else /* GST_EXT_XV_ENHANCEMENT */
1195     g_mutex_unlock (xvimagesink->flow_lock);
1196     return FALSE;
1197 #endif /* GST_EXT_XV_ENHANCEMENT */
1198   }
1199
1200 #ifdef GST_EXT_XV_ENHANCEMENT
1201   if (xvimagesink->visible == FALSE ||
1202       xvimagesink->is_hided) {
1203     GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
1204              xvimagesink->visible, xvimagesink->is_hided);
1205     g_mutex_unlock(xvimagesink->flow_lock);
1206     return TRUE;
1207   }
1208 #endif /* GST_EXT_XV_ENHANCEMENT */
1209
1210   /* Draw borders when displaying the first frame. After this
1211      draw borders only on expose event or after a size change. */
1212   if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1213     draw_border = TRUE;
1214   }
1215
1216   /* Store a reference to the last image we put, lose the previous one */
1217   if (xvimage && xvimagesink->cur_image != xvimage) {
1218     if (xvimagesink->cur_image) {
1219       GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1220       gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1221     }
1222     GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1223     xvimagesink->cur_image =
1224         GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1225   }
1226
1227   /* Expose sends a NULL image, we take the latest frame */
1228   if (!xvimage) {
1229     if (xvimagesink->cur_image) {
1230       draw_border = TRUE;
1231       xvimage = xvimagesink->cur_image;
1232     } else {
1233 #ifdef GST_EXT_XV_ENHANCEMENT
1234       GST_INFO_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1235       /* no need to release gem handle */
1236 #endif /* GST_EXT_XV_ENHANCEMENT */
1237       g_mutex_unlock (xvimagesink->flow_lock);
1238       return TRUE;
1239     }
1240   }
1241
1242 #ifdef GST_EXT_XV_ENHANCEMENT
1243   if (!xvimagesink->get_pixmap_cb) {
1244     gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1245   } else {
1246     /* for multi-pixmap usage for the video texture */
1247     gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
1248     idx = xvimagesink->current_pixmap_idx;
1249     if (idx == -1) {
1250       g_mutex_unlock (xvimagesink->flow_lock);
1251       return FALSE;
1252     } else if (idx == -2) {
1253       GST_WARNING_OBJECT(xvimagesink, "Skip putImage().");
1254       g_mutex_unlock (xvimagesink->flow_lock);
1255       return TRUE;
1256     }
1257   }
1258
1259   src.x = src.y = 0;
1260   src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1261
1262   src_input.w = src_origin.w = xvimagesink->video_width;
1263   src_input.h = src_origin.h = xvimagesink->video_height;
1264
1265   if (xvimagesink->rotate_angle == DEGREE_0 ||
1266       xvimagesink->rotate_angle == DEGREE_180) {
1267     src.w = src_origin.w;
1268     src.h = src_origin.h;
1269   } else {
1270     src.w = src_origin.h;
1271     src.h = src_origin.w;
1272   }
1273
1274   dst.w = xvimagesink->render_rect.w;
1275   dst.h = xvimagesink->render_rect.h;
1276
1277   switch (xvimagesink->display_geometry_method)
1278   {
1279     case DISP_GEO_METHOD_LETTER_BOX:
1280       gst_video_sink_center_rect (src, dst, &result, TRUE);
1281       result.x += xvimagesink->render_rect.x;
1282       result.y += xvimagesink->render_rect.y;
1283       break;
1284
1285     case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
1286       GST_WARNING_OBJECT(xvimagesink, "not supported API, set ORIGIN_SIZE mode");
1287     case DISP_GEO_METHOD_ORIGIN_SIZE:
1288       gst_video_sink_center_rect (src, dst, &result, FALSE);
1289       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1290
1291       if (xvimagesink->rotate_angle == DEGREE_90 ||
1292           xvimagesink->rotate_angle == DEGREE_270) {
1293         src_input.x = src_input.x ^ src_input.y;
1294         src_input.y = src_input.x ^ src_input.y;
1295         src_input.x = src_input.x ^ src_input.y;
1296
1297         src_input.w = src_input.w ^ src_input.h;
1298         src_input.h = src_input.w ^ src_input.h;
1299         src_input.w = src_input.w ^ src_input.h;
1300       }
1301       break;
1302
1303    case DISP_GEO_METHOD_FULL_SCREEN:
1304       result.x = result.y = 0;
1305       if (!xvimagesink->get_pixmap_cb) {
1306         result.w = xvimagesink->xwindow->width;
1307         result.h = xvimagesink->xwindow->height;
1308       } else {
1309         result.w = xvimagesink->xpixmap[idx]->width;
1310         result.h = xvimagesink->xpixmap[idx]->height;
1311       }
1312       break;
1313
1314    case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1315       gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1316
1317       result.x = result.y = 0;
1318       result.w = dst.w;
1319       result.h = dst.h;
1320
1321       if (xvimagesink->rotate_angle == DEGREE_90 ||
1322           xvimagesink->rotate_angle == DEGREE_270) {
1323         src_input.x = src_input.x ^ src_input.y;
1324         src_input.y = src_input.x ^ src_input.y;
1325         src_input.x = src_input.x ^ src_input.y;
1326
1327         src_input.w = src_input.w ^ src_input.h;
1328         src_input.h = src_input.w ^ src_input.h;
1329         src_input.w = src_input.w ^ src_input.h;
1330       }
1331       break;
1332
1333     case DISP_GEO_METHOD_CUSTOM_ROI:
1334 #ifdef GST_EXT_XV_ENHANCEMENT_ROI_MODE
1335       switch (xvimagesink->rotate_angle) {
1336       case DEGREE_90:
1337         result.w = xvimagesink->dst_roi.h;
1338         result.h = xvimagesink->dst_roi.w;
1339
1340         result.x = xvimagesink->dst_roi.y;
1341         if (!xvimagesink->get_pixmap_cb) {
1342           result.y = xvimagesink->xwindow->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
1343         } else {
1344           result.y = xvimagesink->xpixmap[idx]->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
1345         }
1346         break;
1347       case DEGREE_180:
1348         result.w = xvimagesink->dst_roi.w;
1349         result.h = xvimagesink->dst_roi.h;
1350
1351         if (!xvimagesink->get_pixmap_cb) {
1352           result.x = xvimagesink->xwindow->width - result.w - xvimagesink->dst_roi.x;
1353           result.y = xvimagesink->xwindow->height - result.h - xvimagesink->dst_roi.y;
1354         } else {
1355           result.x = xvimagesink->xpixmap[idx]->width - result.w - xvimagesink->dst_roi.x;
1356           result.y = xvimagesink->xpixmap[idx]->height - result.h - xvimagesink->dst_roi.y;
1357         }
1358         break;
1359       case DEGREE_270:
1360         result.w = xvimagesink->dst_roi.h;
1361         result.h = xvimagesink->dst_roi.w;
1362
1363         if (!xvimagesink->get_pixmap_cb) {
1364           result.x = xvimagesink->xwindow->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
1365         } else {
1366           result.x = xvimagesink->xpixmap[idx]->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
1367         }
1368         result.y = xvimagesink->dst_roi.x;
1369         break;
1370       default:
1371         result.x = xvimagesink->dst_roi.x;
1372         result.y = xvimagesink->dst_roi.y;
1373         result.w = xvimagesink->dst_roi.w;
1374         result.h = xvimagesink->dst_roi.h;
1375         break;
1376       }
1377
1378       GST_LOG_OBJECT(xvimagesink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1379                      xvimagesink->rotate_angle,
1380                      xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1381                      result.x, result.y, result.w, result.h);
1382 #else /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1383       result.x = xvimagesink->dst_roi.x;
1384       result.y = xvimagesink->dst_roi.y;
1385       result.w = xvimagesink->dst_roi.w;
1386       result.h = xvimagesink->dst_roi.h;
1387
1388       if (xvimagesink->rotate_angle == DEGREE_90 ||
1389           xvimagesink->rotate_angle == DEGREE_270) {
1390         result.w = xvimagesink->dst_roi.h;
1391         result.h = xvimagesink->dst_roi.w;
1392       }
1393 #endif /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1394       break;
1395
1396     default:
1397       break;
1398   }
1399
1400   if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) {
1401     src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1;
1402     src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1;
1403     src_input.w /= xvimagesink->zoom;
1404     src_input.h /= xvimagesink->zoom;
1405   }
1406
1407 #else /* GST_EXT_XV_ENHANCEMENT */
1408   if (xvimagesink->keep_aspect) {
1409     GstVideoRectangle src, dst;
1410
1411     /* We use the calculated geometry from _setcaps as a source to respect
1412        source and screen pixel aspect ratios. */
1413     src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1414     src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1415     dst.w = xvimagesink->render_rect.w;
1416     dst.h = xvimagesink->render_rect.h;
1417
1418     gst_video_sink_center_rect (src, dst, &result, TRUE);
1419     result.x += xvimagesink->render_rect.x;
1420     result.y += xvimagesink->render_rect.y;
1421   } else {
1422     memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1423   }
1424 #endif /* GST_EXT_XV_ENHANCEMENT */
1425
1426   g_mutex_lock (xvimagesink->x_lock);
1427
1428 #ifdef GST_EXT_XV_ENHANCEMENT
1429   if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
1430 #else
1431   if (draw_border && xvimagesink->draw_borders) {
1432 #endif /* GST_EXT_XV_ENHANCEMENT */
1433     gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1434         result);
1435     xvimagesink->redraw_border = FALSE;
1436   }
1437
1438   /* We scale to the window's geometry */
1439 #ifdef HAVE_XSHM
1440   if (xvimagesink->xcontext->use_xshm) {
1441     GST_LOG_OBJECT (xvimagesink,
1442         "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1443         GST_PTR_FORMAT,
1444         xvimage->width, xvimage->height,
1445         xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1446
1447 #ifdef GST_EXT_XV_ENHANCEMENT
1448     switch( xvimagesink->rotate_angle )
1449     {
1450       /* There's slightly weired code (CCW? CW?) */
1451       case DEGREE_0:
1452         break;
1453       case DEGREE_90:
1454         rotate = 270;
1455         break;
1456       case DEGREE_180:
1457         rotate = 180;
1458         break;
1459       case DEGREE_270:
1460         rotate = 90;
1461         break;
1462       default:
1463         GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1464           xvimagesink->rotate_angle );
1465         break;
1466     }
1467
1468     /* Trim as proper size */
1469     if (src_input.w % 2 == 1) {
1470         src_input.w += 1;
1471     }
1472     if (src_input.h % 2 == 1) {
1473         src_input.h += 1;
1474     }
1475
1476     if (!xvimagesink->get_pixmap_cb) {
1477       GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1478         xvimagesink->scr_w, xvimagesink->scr_h,
1479         xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1480         xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1481         src_origin.w, src_origin.h,
1482         dst.x, dst.y, dst.w, dst.h,
1483         src_input.x, src_input.y, src_input.w, src_input.h,
1484         result.x, result.y, result.w, result.h );
1485     } else {
1486       GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1487       xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
1488       xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1489       src_origin.w, src_origin.h,
1490       dst.x, dst.y, dst.w, dst.h,
1491       src_input.x, src_input.y, src_input.w, src_input.h,
1492       result.x, result.y, result.w, result.h );
1493     }
1494
1495     /* set display rotation */
1496     if (atom_rotation == None) {
1497       atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1498                                   "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1499     }
1500
1501     ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate);
1502     if (ret != Success) {
1503       GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1504         ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1505       return FALSE;
1506     }
1507
1508     /* set display flip */
1509     if (atom_hflip == None) {
1510       atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
1511                                "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1512     }
1513     if (atom_vflip == None) {
1514       atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
1515                                "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1516     }
1517
1518     switch (xvimagesink->flip) {
1519     case FLIP_HORIZONTAL:
1520       set_hflip = TRUE;
1521       set_vflip = FALSE;
1522       break;
1523     case FLIP_VERTICAL:
1524       set_hflip = FALSE;
1525       set_vflip = TRUE;
1526       break;
1527     case FLIP_BOTH:
1528       set_hflip = TRUE;
1529       set_vflip = TRUE;
1530       break;
1531     case FLIP_NONE:
1532     default:
1533       set_hflip = FALSE;
1534       set_vflip = FALSE;
1535       break;
1536     }
1537
1538     GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
1539
1540     ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1541     if (ret != Success) {
1542       GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1543                   ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1544     }
1545     ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1546     if (ret != Success) {
1547       GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1548                   ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1549     }
1550
1551     /* set error handler */
1552     error_caught = FALSE;
1553     handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
1554
1555     /* src input indicates the status when degree is 0 */
1556     /* dst input indicates the area that src will be shown regardless of rotate */
1557     if (xvimagesink->visible && !xvimagesink->is_hided) {
1558       if (xvimagesink->xim_transparenter) {
1559         GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1560         XPutImage(xvimagesink->xcontext->disp,
1561           xvimagesink->xwindow->win,
1562           xvimagesink->xwindow->gc,
1563           xvimagesink->xim_transparenter,
1564           0, 0,
1565           result.x, result.y, result.w, result.h);
1566       }
1567
1568       /* store buffer */
1569       if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) {
1570         img_data = (XV_DATA_PTR)xvimage->xvimage->data;
1571         if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
1572           _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
1573           xvimage->current_buffer = NULL;
1574         }
1575       }
1576
1577       g_mutex_lock(xvimagesink->display_buffer_lock);
1578       if (xvimagesink->displaying_buffer_count > 3) {
1579         g_mutex_unlock(xvimagesink->display_buffer_lock);
1580         GST_WARNING("too many buffers are pushed. skip this... [displaying_buffer_count %d]",
1581                     xvimagesink->displaying_buffer_count);
1582         ret = -1;
1583       } else if (xvimagesink->get_pixmap_cb) {
1584         gint idx = xvimagesink->current_pixmap_idx;
1585
1586         g_mutex_unlock(xvimagesink->display_buffer_lock);
1587
1588         ret = XvShmPutImage (xvimagesink->xcontext->disp,
1589           xvimagesink->xcontext->xv_port_id,
1590           xvimagesink->xpixmap[idx]->pixmap,
1591           xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
1592           src_input.x, src_input.y, src_input.w, src_input.h,
1593           result.x, result.y, result.w, result.h, FALSE);
1594         GST_LOG_OBJECT(xvimagesink, "pixmap[%d]->pixmap = %d", idx, xvimagesink->xpixmap[idx]->pixmap);
1595       } else {
1596         g_mutex_unlock(xvimagesink->display_buffer_lock);
1597
1598         ret = XvShmPutImage (xvimagesink->xcontext->disp,
1599           xvimagesink->xcontext->xv_port_id,
1600           xvimagesink->xwindow->win,
1601           xvimagesink->xwindow->gc, xvimage->xvimage,
1602           src_input.x, src_input.y, src_input.w, src_input.h,
1603           result.x, result.y, result.w, result.h, FALSE);
1604       }
1605       GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret );
1606     } else {
1607       GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1608     }
1609 #else /* GST_EXT_XV_ENHANCEMENT */
1610     XvShmPutImage (xvimagesink->xcontext->disp,
1611         xvimagesink->xcontext->xv_port_id,
1612         xvimagesink->xwindow->win,
1613         xvimagesink->xwindow->gc, xvimage->xvimage,
1614         xvimagesink->disp_x, xvimagesink->disp_y,
1615         xvimagesink->disp_width, xvimagesink->disp_height,
1616         result.x, result.y, result.w, result.h, FALSE);
1617 #endif /* GST_EXT_XV_ENHANCEMENT */
1618   } else
1619 #endif /* HAVE_XSHM */
1620   {
1621     XvPutImage (xvimagesink->xcontext->disp,
1622         xvimagesink->xcontext->xv_port_id,
1623         xvimagesink->xwindow->win,
1624         xvimagesink->xwindow->gc, xvimage->xvimage,
1625         xvimagesink->disp_x, xvimagesink->disp_y,
1626         xvimagesink->disp_width, xvimagesink->disp_height,
1627         result.x, result.y, result.w, result.h);
1628   }
1629
1630   XSync (xvimagesink->xcontext->disp, FALSE);
1631
1632 #ifdef HAVE_XSHM
1633 #ifdef GST_EXT_XV_ENHANCEMENT
1634   if (ret || error_caught || xvimagesink->get_pixmap_cb) {
1635     GST_DEBUG("error or pixmap_cb");
1636
1637     if (ret || error_caught) {
1638       GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
1639                   ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
1640
1641       if (xvimagesink->get_pixmap_cb) {
1642         g_signal_emit (G_OBJECT (xvimagesink),
1643                        gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
1644                        0,
1645                        &xvimagesink->xpixmap[idx]->pixmap,
1646                        &res);
1647       }
1648     }
1649
1650     /* release gem handle */
1651     if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
1652       unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
1653       gem_name[0] = img_data->YBuf;
1654       gem_name[1] = img_data->CbBuf;
1655       gem_name[2] = img_data->CrBuf;
1656       _remove_displaying_buffer(xvimagesink, gem_name);
1657     }
1658   }
1659
1660   /* Reset error handler */
1661   if (handler) {
1662     error_caught = FALSE;
1663     XSetErrorHandler (handler);
1664   }
1665 #endif /* GST_EXT_XV_ENHANCEMENT */
1666 #endif /* HAVE_XSHM */
1667
1668   g_mutex_unlock (xvimagesink->x_lock);
1669
1670   g_mutex_unlock (xvimagesink->flow_lock);
1671
1672   return TRUE;
1673 }
1674
1675 static gboolean
1676 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
1677     GstXWindow * window)
1678 {
1679   Atom hints_atom = None;
1680   MotifWmHints *hints;
1681
1682   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
1683   g_return_val_if_fail (window != NULL, FALSE);
1684
1685   g_mutex_lock (xvimagesink->x_lock);
1686
1687   hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
1688       True);
1689   if (hints_atom == None) {
1690     g_mutex_unlock (xvimagesink->x_lock);
1691     return FALSE;
1692   }
1693
1694   hints = g_malloc0 (sizeof (MotifWmHints));
1695
1696   hints->flags |= MWM_HINTS_DECORATIONS;
1697   hints->decorations = 1 << 0;
1698
1699   XChangeProperty (xvimagesink->xcontext->disp, window->win,
1700       hints_atom, hints_atom, 32, PropModeReplace,
1701       (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
1702
1703   XSync (xvimagesink->xcontext->disp, FALSE);
1704
1705   g_mutex_unlock (xvimagesink->x_lock);
1706
1707   g_free (hints);
1708
1709   return TRUE;
1710 }
1711
1712 static void
1713 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1714     GstXWindow * xwindow, const gchar * media_title)
1715 {
1716   if (media_title) {
1717     g_free (xvimagesink->media_title);
1718     xvimagesink->media_title = g_strdup (media_title);
1719   }
1720   if (xwindow) {
1721     /* we have a window */
1722     if (xwindow->internal) {
1723       XTextProperty xproperty;
1724       const gchar *app_name;
1725       const gchar *title = NULL;
1726       gchar *title_mem = NULL;
1727
1728       /* set application name as a title */
1729       app_name = g_get_application_name ();
1730
1731       if (app_name && xvimagesink->media_title) {
1732         title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1733             app_name, NULL);
1734       } else if (app_name) {
1735         title = app_name;
1736       } else if (xvimagesink->media_title) {
1737         title = xvimagesink->media_title;
1738       }
1739
1740       if (title) {
1741         if ((XStringListToTextProperty (((char **) &title), 1,
1742                     &xproperty)) != 0) {
1743           XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
1744           XFree (xproperty.value);
1745         }
1746
1747         g_free (title_mem);
1748       }
1749     }
1750   }
1751 }
1752
1753 #ifdef GST_EXT_XV_ENHANCEMENT
1754 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
1755 {
1756   XImage *xim;
1757
1758   /* create a normal ximage */
1759   xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)),  24, ZPixmap, 0, NULL, w, h, 32, 0);
1760
1761   GST_INFO("ximage %p", xim);
1762
1763   /* allocate data for it */
1764   if (xim) {
1765     xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
1766     if (xim->data) {
1767       memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
1768       return xim;
1769     } else {
1770       GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
1771     }
1772
1773     XDestroyImage(xim);
1774   }
1775
1776   GST_ERROR("failed to create Ximage");
1777
1778   return NULL;
1779 }
1780
1781
1782 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
1783 {
1784   int ret = 0;
1785   static gboolean is_exist = FALSE;
1786   static XvPortID current_port_id = -1;
1787   Atom atom_output = None;
1788
1789   if (xcontext == NULL) {
1790     GST_WARNING("xcontext is NULL");
1791     return FALSE;
1792   }
1793
1794   /* check once per one xv_port_id */
1795   if (current_port_id != xcontext->xv_port_id) {
1796     /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
1797     int i = 0;
1798     int count = 0;
1799     XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
1800                                                     xcontext->xv_port_id, &count);
1801     if (attr) {
1802       current_port_id = xcontext->xv_port_id;
1803       for (i = 0 ; i < count ; i++) {
1804         if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
1805           is_exist = TRUE;
1806           GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
1807           break;
1808         }
1809       }
1810       XFree(attr);
1811     } else {
1812       GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
1813                   xcontext->disp, xcontext->xv_port_id);
1814     }
1815   }
1816
1817   if (is_exist) {
1818     GST_WARNING("set display mode %d", set_mode);
1819     atom_output = XInternAtom(xcontext->disp,
1820                               "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
1821     ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
1822                              atom_output, set_mode);
1823     if (ret == Success) {
1824       return TRUE;
1825     } else {
1826       GST_WARNING("display mode[%d] set failed.", set_mode);
1827     }
1828   } else {
1829     GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
1830   }
1831
1832   return FALSE;
1833 }
1834
1835
1836 static gboolean set_csc_range(GstXContext *xcontext, int set_range)
1837 {
1838   int ret = 0;
1839   static gboolean is_exist = FALSE;
1840   static XvPortID current_port_id = -1;
1841   Atom atom_csc_range = None;
1842
1843   if (xcontext == NULL) {
1844     GST_WARNING("xcontext is NULL");
1845     return FALSE;
1846   }
1847
1848   /* check once per one xv_port_id */
1849   if (current_port_id != xcontext->xv_port_id) {
1850     /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
1851     int i = 0;
1852     int count = 0;
1853     XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
1854                                                     xcontext->xv_port_id, &count);
1855     if (attr) {
1856       current_port_id = xcontext->xv_port_id;
1857       for (i = 0 ; i < count ; i++) {
1858         if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
1859           is_exist = TRUE;
1860           GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
1861           break;
1862         }
1863       }
1864       XFree(attr);
1865     } else {
1866       GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
1867                   xcontext->disp, xcontext->xv_port_id);
1868     }
1869   }
1870
1871   if (is_exist) {
1872     GST_WARNING("set csc range %d", set_range);
1873     atom_csc_range = XInternAtom(xcontext->disp,
1874                                  "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
1875     ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
1876                              atom_csc_range, set_range);
1877     if (ret == Success) {
1878       return TRUE;
1879     } else {
1880       GST_WARNING("csc range[%d] set failed.", set_range);
1881     }
1882   } else {
1883     GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
1884   }
1885
1886   return FALSE;
1887 }
1888
1889
1890 static void drm_init(GstXvImageSink *xvimagesink)
1891 {
1892         Display *dpy;
1893         int eventBase = 0;
1894         int errorBase = 0;
1895         int dri2Major = 0;
1896         int dri2Minor = 0;
1897         char *driverName = NULL;
1898         char *deviceName = NULL;
1899         struct drm_auth auth_arg = {0};
1900
1901         xvimagesink->drm_fd = -1;
1902
1903         dpy = XOpenDisplay(0);
1904         if (!dpy) {
1905                 GST_ERROR("XOpenDisplay failed errno:%d", errno);
1906                 return;
1907         }
1908
1909         GST_INFO("START");
1910
1911         /* DRI2 */
1912         if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
1913                 GST_ERROR("DRI2QueryExtension !!");
1914                 goto DRM_INIT_ERROR;
1915         }
1916
1917         if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
1918                 GST_ERROR("DRI2QueryVersion !!");
1919                 goto DRM_INIT_ERROR;
1920         }
1921
1922         if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
1923                 GST_ERROR("DRI2Connect !!");
1924                 goto DRM_INIT_ERROR;
1925         }
1926
1927         if (!driverName || !deviceName) {
1928                 GST_ERROR("driverName or deviceName is not valid");
1929                 goto DRM_INIT_ERROR;
1930         }
1931
1932         GST_INFO("Open drm device : %s", deviceName);
1933
1934         /* get the drm_fd though opening the deviceName */
1935         xvimagesink->drm_fd = open(deviceName, O_RDWR);
1936         if (xvimagesink->drm_fd < 0) {
1937                 GST_ERROR("cannot open drm device (%s)", deviceName);
1938                 goto DRM_INIT_ERROR;
1939         }
1940
1941         /* get magic from drm to authentication */
1942         if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
1943                 GST_ERROR("cannot get drm auth magic");
1944                 goto DRM_INIT_ERROR;
1945         }
1946
1947         if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
1948                 GST_ERROR("cannot get drm authentication from X");
1949                 goto DRM_INIT_ERROR;
1950         }
1951
1952         XCloseDisplay(dpy);
1953         free(driverName);
1954         free(deviceName);
1955
1956         GST_INFO("DONE");
1957
1958         return;
1959
1960 DRM_INIT_ERROR:
1961         if (xvimagesink->drm_fd >= 0) {
1962                 close(xvimagesink->drm_fd);
1963                 xvimagesink->drm_fd = -1;
1964         }
1965         if (dpy) {
1966                 XCloseDisplay(dpy);
1967         }
1968         if (driverName) {
1969                 free(driverName);
1970         }
1971         if (deviceName) {
1972                 free(deviceName);
1973         }
1974
1975         return;
1976 }
1977
1978 static void drm_fini(GstXvImageSink *xvimagesink)
1979 {
1980         GST_INFO("START");
1981
1982         if (xvimagesink->drm_fd >= 0) {
1983                 int i;
1984                 int j;
1985                 gboolean is_timeout = FALSE;
1986
1987                 /* close remained gem handle */
1988                 g_mutex_lock(xvimagesink->display_buffer_lock);
1989                 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
1990                         if (xvimagesink->displaying_buffers[i].buffer) {
1991                                 GTimeVal abstimeout;
1992
1993                                 GST_WARNING("remained buffer %p, name %u %u %u, handle %u %u %u",
1994                                             xvimagesink->displaying_buffers[i].buffer,
1995                                             xvimagesink->displaying_buffers[i].gem_name[0],
1996                                             xvimagesink->displaying_buffers[i].gem_name[1],
1997                                             xvimagesink->displaying_buffers[i].gem_name[2],
1998                                             xvimagesink->displaying_buffers[i].gem_handle[0],
1999                                             xvimagesink->displaying_buffers[i].gem_handle[1],
2000                                             xvimagesink->displaying_buffers[i].gem_handle[2]);
2001
2002                                 g_get_current_time(&abstimeout);
2003                                 g_time_val_add(&abstimeout, _BUFFER_WAIT_TIMEOUT);
2004
2005                                 if (is_timeout ||
2006                                     !g_cond_timed_wait(xvimagesink->display_buffer_cond,
2007                                                        xvimagesink->display_buffer_lock,
2008                                                        &abstimeout)) {
2009                                         GST_ERROR("Buffer wait timeout[%d usec] or is_timeout[%d]. Force Unref buffer",
2010                                                   _BUFFER_WAIT_TIMEOUT, is_timeout);
2011
2012                                         /* set flag not to wait next time */
2013                                         is_timeout = TRUE;
2014
2015                                         for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2016                                                 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2017                                                         drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2018                                                 }
2019                                                 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2020                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2021                                                 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2022                                         }
2023
2024                                         gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2025                                         xvimagesink->displaying_buffers[i].buffer = NULL;
2026                                 } else {
2027                                         GST_WARNING("Signal received. check again...");
2028                                 }
2029
2030                                 /* init index and check again from first */
2031                                 i = -1;
2032                         }
2033                 }
2034                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2035
2036                 GST_INFO("close drm_fd %d", xvimagesink->drm_fd);
2037                 close(xvimagesink->drm_fd);
2038                 xvimagesink->drm_fd = -1;
2039         } else {
2040                 GST_INFO("DRM device is NOT opened");
2041         }
2042
2043         GST_INFO("DONE");
2044 }
2045
2046 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
2047 {
2048         int ret = 0;
2049
2050         struct drm_prime_handle prime_arg = {0,};
2051         struct drm_gem_flink flink_arg = {0,};
2052
2053         if (!xvimagesink || !gem_handle) {
2054                 GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
2055                 return 0;
2056         }
2057
2058         if (xvimagesink->drm_fd <= 0) {
2059                 GST_ERROR("DRM is not opened");
2060                 return 0;
2061         }
2062
2063         if (dmabuf_fd <= 0) {
2064                 GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
2065                 return 0;
2066         }
2067
2068         prime_arg.fd = dmabuf_fd;
2069         ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
2070         if (ret) {
2071                 GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u", ret, dmabuf_fd);
2072                 return 0;
2073         }
2074
2075         *gem_handle = prime_arg.handle;
2076         flink_arg.handle = prime_arg.handle;
2077         ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
2078         if (ret) {
2079                 GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u", ret, *gem_handle, flink_arg.name);
2080                 return 0;
2081         }
2082
2083         return flink_arg.name;
2084 }
2085
2086 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
2087 {
2088         struct drm_gem_close close_arg = {0,};
2089
2090         if (xvimagesink->drm_fd < 0 || !gem_handle) {
2091                 GST_ERROR("DRM is not opened");
2092                 return;
2093         }
2094
2095         if (*gem_handle <= 0) {
2096                 GST_DEBUG("invalid gem handle %u", *gem_handle);
2097                 return;
2098         }
2099
2100         GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
2101
2102         close_arg.handle = *gem_handle;
2103         if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
2104                 GST_ERROR("cannot close drm gem handle %u", *gem_handle);
2105                 return;
2106         }
2107
2108         *gem_handle = 0;
2109
2110         return;
2111 }
2112
2113
2114 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
2115 {
2116         int i = 0;
2117         int j = 0;
2118
2119         if (!xvimagesink || !img_data) {
2120                 GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
2121                 return;
2122         }
2123
2124         /* lock display buffer mutex */
2125         g_mutex_lock(xvimagesink->display_buffer_lock);
2126
2127         /* increase displaying buffer count */
2128         xvimagesink->displaying_buffer_count++;
2129
2130         /* check duplicated */
2131         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2132                 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2133                         if ((img_data->dmabuf_fd[0] > 0 &&
2134                              xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
2135                              xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
2136                              xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
2137                             (img_data->bo[0] &&
2138                              xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
2139                              xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
2140                              xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
2141                                 /* increase ref count */
2142                                 xvimagesink->displaying_buffers[i].ref_count++;
2143
2144                                 /* set buffer info */
2145                                 img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
2146                                 img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
2147                                 img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
2148
2149                                 if (img_data->dmabuf_fd[0] > 0) {
2150                                         GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
2151                                                     img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
2152                                                     img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2153                                 } else {
2154                                         GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
2155                                                     img_data->bo[0], img_data->bo[1], img_data->bo[2],
2156                                                     img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2157                                 }
2158
2159                                 /* unlock display buffer mutex */
2160                                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2161                                 return;
2162                         }
2163                 }
2164         }
2165
2166         /* store buffer temporarily */
2167         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2168                 if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
2169                         if (buffer) {
2170                                 /* increase ref count of buffer */
2171                                 gst_buffer_ref(buffer);
2172                                 xvimagesink->displaying_buffers[i].buffer = buffer;
2173                         }
2174
2175                         if (img_data->dmabuf_fd[0] > 0) {
2176                                 /* convert fd to name */
2177                                 img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
2178                                 img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
2179                                 img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
2180                         } else {
2181                                 /* export bo */
2182                                 if (img_data->bo[0]) {
2183                                         img_data->YBuf = tbm_bo_export(img_data->bo[0]);
2184                                 }
2185                                 if (img_data->bo[1]) {
2186                                         img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
2187                                 }
2188                                 if (img_data->bo[2]) {
2189                                         img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
2190                                 }
2191                         }
2192
2193                         for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2194                                 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
2195                                 xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
2196                                 xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
2197                         }
2198
2199                         /* set buffer info */
2200                         xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
2201                         xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
2202                         xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
2203
2204                         /* set ref count */
2205                         xvimagesink->displaying_buffers[i].ref_count = 1;
2206
2207                         if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2208                                 GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2209                                                                 xvimagesink->displayed_buffer_count,
2210                                                                 i, xvimagesink->displaying_buffers[i].buffer,
2211                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2212                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2213                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2214                                                                 xvimagesink->displaying_buffers[i].gem_handle[0],
2215                                                                 xvimagesink->displaying_buffers[i].gem_handle[1],
2216                                                                 xvimagesink->displaying_buffers[i].gem_handle[2],
2217                                                                 xvimagesink->displaying_buffers[i].gem_name[0],
2218                                                                 xvimagesink->displaying_buffers[i].gem_name[1],
2219                                                                 xvimagesink->displaying_buffers[i].gem_name[2]);
2220                         } else {
2221                                 GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2222                                                               i, xvimagesink->displaying_buffers[i].buffer,
2223                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2224                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2225                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2226                                                               xvimagesink->displaying_buffers[i].gem_handle[0],
2227                                                               xvimagesink->displaying_buffers[i].gem_handle[1],
2228                                                               xvimagesink->displaying_buffers[i].gem_handle[2],
2229                                                               xvimagesink->displaying_buffers[i].gem_name[0],
2230                                                               xvimagesink->displaying_buffers[i].gem_name[1],
2231                                                               xvimagesink->displaying_buffers[i].gem_name[2]);
2232                         }
2233
2234                         /* unlock display buffer mutex */
2235                         g_mutex_unlock(xvimagesink->display_buffer_lock);
2236
2237                         /* get current time */
2238                         gettimeofday(&xvimagesink->request_time[i], NULL);
2239                         return;
2240                 }
2241         }
2242
2243         /* decrease displaying buffer count */
2244         xvimagesink->displaying_buffer_count--;
2245
2246         /* unlock display buffer mutex */
2247         g_mutex_unlock(xvimagesink->display_buffer_lock);
2248
2249         GST_ERROR("should not be reached here. buffer slot is FULL...");
2250
2251         return;
2252 }
2253
2254
2255 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
2256 {
2257         int i = 0;
2258         int j = 0;
2259
2260         if (!xvimagesink || !gem_name) {
2261                 GST_ERROR("handle is NULL %p, %p", xvimagesink, gem_name);
2262                 return;
2263         }
2264
2265         /* lock display buffer mutex */
2266         g_mutex_lock(xvimagesink->display_buffer_lock);
2267
2268         if (xvimagesink->displaying_buffer_count == 0) {
2269                 GST_WARNING("there is no displaying buffer");
2270                 /* unlock display buffer mutex */
2271                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2272                 return;
2273         }
2274
2275         GST_DEBUG("gem name [%u %u %u], displaying buffer count %d",
2276                   gem_name[0], gem_name[1], gem_name[2],
2277                   xvimagesink->displaying_buffer_count);
2278
2279         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2280                 if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
2281                     xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
2282                     xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
2283                         struct timeval current_time;
2284
2285                         /* get current time to calculate displaying time */
2286                         gettimeofday(&current_time, NULL);
2287
2288                         GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
2289                                                       (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
2290                                                       (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
2291
2292                         if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2293                                 xvimagesink->displayed_buffer_count++;
2294                                 GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2295                                                                 xvimagesink->displayed_buffer_count,
2296                                                                 i, xvimagesink->displaying_buffers[i].buffer,
2297                                                                 xvimagesink->displaying_buffers[i].gem_handle[0],
2298                                                                 xvimagesink->displaying_buffers[i].gem_handle[1],
2299                                                                 xvimagesink->displaying_buffers[i].gem_handle[2],
2300                                                                 xvimagesink->displaying_buffers[i].gem_name[0],
2301                                                                 xvimagesink->displaying_buffers[i].gem_name[1],
2302                                                                 xvimagesink->displaying_buffers[i].gem_name[2]);
2303                         } else {
2304                                 GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2305                                                               i, xvimagesink->displaying_buffers[i].buffer,
2306                                                               xvimagesink->displaying_buffers[i].gem_handle[0],
2307                                                               xvimagesink->displaying_buffers[i].gem_handle[1],
2308                                                               xvimagesink->displaying_buffers[i].gem_handle[2],
2309                                                               xvimagesink->displaying_buffers[i].gem_name[0],
2310                                                               xvimagesink->displaying_buffers[i].gem_name[1],
2311                                                               xvimagesink->displaying_buffers[i].gem_name[2]);
2312                         }
2313
2314                         /* decrease displaying buffer count */
2315                         xvimagesink->displaying_buffer_count--;
2316
2317                         /* decrease ref count */
2318                         xvimagesink->displaying_buffers[i].ref_count--;
2319
2320                         if (xvimagesink->displaying_buffers[i].ref_count > 0) {
2321                                 GST_WARNING("ref count not zero[%d], skip close gem handle",
2322                                             xvimagesink->displaying_buffers[i].ref_count);
2323                                 break;
2324                         }
2325
2326                         for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2327                                 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2328                                         drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2329                                 }
2330                                 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2331                                 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2332                                 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2333                         }
2334
2335                         if (xvimagesink->displaying_buffers[i].buffer) {
2336                                 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2337                                 xvimagesink->displaying_buffers[i].buffer = NULL;
2338                         } else {
2339                                 GST_WARNING("no buffer to unref");
2340                         }
2341                         break;
2342                 }
2343         }
2344
2345         /* send signal to wait display_buffer_cond */
2346         g_cond_signal(xvimagesink->display_buffer_cond);
2347
2348         /* unlock display buffer mutex */
2349         g_mutex_unlock(xvimagesink->display_buffer_lock);
2350
2351         return;
2352 }
2353
2354
2355 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
2356 {
2357         Atom type_ret = 0;
2358         int i = 0;
2359         int ret = 0;
2360         int size_ret = 0;
2361         unsigned long num_ret = 0;
2362         unsigned long bytes = 0;
2363         unsigned char *prop_ret = NULL;
2364         unsigned int data = 0;
2365         Atom atom_output_external;
2366
2367         atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
2368                                            "XV_OUTPUT_EXTERNAL", False);
2369         if (atom_output_external != None) {
2370                 ret = XGetWindowProperty(xvimagesink->xcontext->disp,
2371                                          xvimagesink->xwindow->win,
2372                                          atom_output_external, 0, 0x7fffffff,
2373                                          False, XA_CARDINAL, &type_ret, &size_ret,
2374                                          &num_ret, &bytes, &prop_ret);
2375                 if (ret != Success) {
2376                         GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
2377                         if (prop_ret) {
2378                                 XFree(prop_ret);
2379                         }
2380                         return False;
2381                 }
2382
2383                 if (!num_ret) {
2384                         GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
2385                         if (prop_ret) {
2386                                 XFree(prop_ret);
2387                         }
2388                         return False;
2389                 }
2390
2391                 if (prop_ret) {
2392                         switch (size_ret) {
2393                         case 8:
2394                                 for (i = 0 ; i < num_ret ; i++) {
2395                                         (&data)[i] = prop_ret[i];
2396                                 }
2397                                 break;
2398                         case 16:
2399                                 for (i = 0 ; i < num_ret ; i++) {
2400                                         ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
2401                                 }
2402                                 break;
2403                         case 32:
2404                                 for (i = 0 ; i < num_ret ; i++) {
2405                                         ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
2406                                 }
2407                                 break;
2408                         }
2409                         XFree(prop_ret);
2410                         prop_ret = NULL;
2411
2412                         GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
2413
2414                         return (int)data;
2415                 } else {
2416                         GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
2417                         return False;
2418                 }
2419         } else {
2420                 GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
2421         }
2422
2423         return False;
2424 }
2425 #endif /* GST_EXT_XV_ENHANCEMENT */
2426
2427 /* This function handles a GstXWindow creation
2428  * The width and height are the actual pixel size on the display */
2429 static GstXWindow *
2430 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
2431     gint width, gint height)
2432 {
2433   GstXWindow *xwindow = NULL;
2434   XGCValues values;
2435 #ifdef GST_EXT_XV_ENHANCEMENT
2436   XSetWindowAttributes win_attr;
2437   XWindowAttributes root_attr;
2438 #endif /* GST_EXT_XV_ENHANCEMENT */
2439
2440   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2441
2442   xwindow = g_new0 (GstXWindow, 1);
2443
2444   xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2445 #ifdef GST_EXT_XV_ENHANCEMENT
2446   /* 0 or 180 */
2447   if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
2448     xvimagesink->render_rect.w = xwindow->width = width;
2449     xvimagesink->render_rect.h = xwindow->height = height;
2450   /* 90 or 270 */
2451   } else {
2452     xvimagesink->render_rect.w = xwindow->width = height;
2453     xvimagesink->render_rect.h = xwindow->height = width;
2454   }
2455
2456   XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
2457
2458   if (xwindow->width > root_attr.width) {
2459     GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
2460                                  xwindow->width, root_attr.width);
2461     xvimagesink->render_rect.w = xwindow->width = root_attr.width;
2462   }
2463   if (xwindow->height > root_attr.height) {
2464     GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
2465                                  xwindow->height, root_attr.height);
2466     xvimagesink->render_rect.h = xwindow->height = root_attr.height;
2467   }
2468   xwindow->internal = TRUE;
2469
2470   g_mutex_lock (xvimagesink->x_lock);
2471
2472   GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
2473
2474   xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
2475                                      xvimagesink->xcontext->root,
2476                                      0, 0, xwindow->width, xwindow->height,
2477                                      0, 0, 0);
2478
2479   xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
2480                                                           xvimagesink->xcontext->root,
2481                                                           xwindow->width, xwindow->height);
2482
2483   /* Make window manager not to change window size as Full screen */
2484   win_attr.override_redirect = True;
2485   XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
2486 #else /* GST_EXT_XV_ENHANCEMENT */
2487   xvimagesink->render_rect.w = width;
2488   xvimagesink->render_rect.h = height;
2489
2490   xwindow->width = width;
2491   xwindow->height = height;
2492   xwindow->internal = TRUE;
2493
2494   g_mutex_lock (xvimagesink->x_lock);
2495
2496   xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
2497       xvimagesink->xcontext->root,
2498       0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
2499 #endif /* GST_EXT_XV_ENHANCEMENT */
2500
2501   /* We have to do that to prevent X from redrawing the background on
2502    * ConfigureNotify. This takes away flickering of video when resizing. */
2503   XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
2504
2505   /* set application name as a title */
2506   gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
2507
2508   if (xvimagesink->handle_events) {
2509     Atom wm_delete;
2510
2511     XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2512         StructureNotifyMask | PointerMotionMask | KeyPressMask |
2513         KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
2514
2515     /* Tell the window manager we'd like delete client messages instead of
2516      * being killed */
2517     wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2518         "WM_DELETE_WINDOW", True);
2519     if (wm_delete != None) {
2520       (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
2521           &wm_delete, 1);
2522     }
2523   }
2524
2525   xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
2526       xwindow->win, 0, &values);
2527
2528   XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
2529
2530   XSync (xvimagesink->xcontext->disp, FALSE);
2531
2532   g_mutex_unlock (xvimagesink->x_lock);
2533
2534   gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
2535
2536   gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
2537
2538   return xwindow;
2539 }
2540
2541 /* This function destroys a GstXWindow */
2542 static void
2543 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
2544     GstXWindow * xwindow)
2545 {
2546   g_return_if_fail (xwindow != NULL);
2547   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2548
2549   g_mutex_lock (xvimagesink->x_lock);
2550
2551   /* If we did not create that window we just free the GC and let it live */
2552   if (xwindow->internal) {
2553     XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
2554     if (xvimagesink->xim_transparenter) {
2555       XDestroyImage(xvimagesink->xim_transparenter);
2556       xvimagesink->xim_transparenter = NULL;
2557     }
2558   } else {
2559     XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
2560   }
2561
2562   XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
2563
2564   XSync (xvimagesink->xcontext->disp, FALSE);
2565
2566   g_mutex_unlock (xvimagesink->x_lock);
2567
2568   g_free (xwindow);
2569 }
2570
2571 #ifdef GST_EXT_XV_ENHANCEMENT
2572 /* This function destroys a GstXWindow */
2573 static void
2574 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
2575     GstXPixmap * xpixmap)
2576 {
2577   g_return_if_fail (xpixmap != NULL);
2578   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2579
2580   g_mutex_lock (xvimagesink->x_lock);
2581
2582   XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
2583
2584   XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
2585
2586   XSync (xvimagesink->xcontext->disp, FALSE);
2587
2588   g_mutex_unlock (xvimagesink->x_lock);
2589
2590   g_free (xpixmap);
2591 }
2592 #endif /* GST_EXT_XV_ENHANCEMENT */
2593
2594 static void
2595 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
2596 {
2597 #ifdef GST_EXT_XV_ENHANCEMENT
2598   Window root_window, child_window;
2599   XWindowAttributes root_attr;
2600
2601   int cur_win_x = 0;
2602   int cur_win_y = 0;
2603   unsigned int cur_win_width = 0;
2604   unsigned int cur_win_height = 0;
2605   unsigned int cur_win_border_width = 0;
2606   unsigned int cur_win_depth = 0;
2607 #else /* GST_EXT_XV_ENHANCEMENT */
2608   XWindowAttributes attr;
2609 #endif /* GST_EXT_XV_ENHANCEMENT */
2610
2611   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2612
2613   /* Update the window geometry */
2614   g_mutex_lock (xvimagesink->x_lock);
2615   if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
2616     g_mutex_unlock (xvimagesink->x_lock);
2617     return;
2618   }
2619
2620 #ifdef GST_EXT_XV_ENHANCEMENT
2621   /* Get root window and size of current window */
2622   XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
2623     &cur_win_x, &cur_win_y, /* relative x, y */
2624     &cur_win_width, &cur_win_height,
2625     &cur_win_border_width, &cur_win_depth );
2626
2627   xvimagesink->xwindow->width = cur_win_width;
2628   xvimagesink->xwindow->height = cur_win_height;
2629
2630   /* Get absolute coordinates of current window */
2631   XTranslateCoordinates( xvimagesink->xcontext->disp,
2632     xvimagesink->xwindow->win,
2633     root_window,
2634     0, 0,
2635     &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
2636     &child_window );
2637
2638   xvimagesink->xwindow->x = cur_win_x;
2639   xvimagesink->xwindow->y = cur_win_y;
2640
2641   /* Get size of root window == size of screen */
2642   XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
2643
2644   xvimagesink->scr_w = root_attr.width;
2645   xvimagesink->scr_h = root_attr.height;
2646
2647   if (!xvimagesink->have_render_rect) {
2648     xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2649     xvimagesink->render_rect.w = cur_win_width;
2650     xvimagesink->render_rect.h = cur_win_height;
2651   }
2652
2653   GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
2654     xvimagesink->scr_w, xvimagesink->scr_h,
2655     xvimagesink->xwindow->x, xvimagesink->xwindow->y,
2656     xvimagesink->xwindow->width, xvimagesink->xwindow->height,
2657     xvimagesink->render_rect.x, xvimagesink->render_rect.y,
2658     xvimagesink->render_rect.w, xvimagesink->render_rect.h);
2659 #else /* GST_EXT_XV_ENHANCEMENT */
2660   XGetWindowAttributes (xvimagesink->xcontext->disp,
2661       xvimagesink->xwindow->win, &attr);
2662
2663   xvimagesink->xwindow->width = attr.width;
2664   xvimagesink->xwindow->height = attr.height;
2665
2666   if (!xvimagesink->have_render_rect) {
2667     xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2668     xvimagesink->render_rect.w = attr.width;
2669     xvimagesink->render_rect.h = attr.height;
2670   }
2671 #endif /* GST_EXT_XV_ENHANCEMENT */
2672
2673   g_mutex_unlock (xvimagesink->x_lock);
2674 }
2675
2676 static void
2677 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
2678     GstXWindow * xwindow)
2679 {
2680   g_return_if_fail (xwindow != NULL);
2681   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2682
2683   g_mutex_lock (xvimagesink->x_lock);
2684 #ifdef GST_EXT_XV_ENHANCEMENT
2685   GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
2686 #endif /* GST_EXT_XV_ENHANCEMENT */
2687
2688   XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
2689       xwindow->win);
2690 #ifdef GST_EXT_XV_ENHANCEMENT
2691 #if 0
2692   /* NOTE : it should be enabled in pixmap buffer case,
2693             if we can check whether if it is a pixmap or a window by X API */
2694   /* Preview area is not updated before other UI is updated in the screen. */
2695   XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
2696       xvimagesink->xcontext->black);
2697
2698   XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
2699       xvimagesink->render_rect.x, xvimagesink->render_rect.y,
2700       xvimagesink->render_rect.w, xvimagesink->render_rect.h);
2701 #endif
2702 #endif /* GST_EXT_XV_ENHANCEMENT */
2703
2704   XSync (xvimagesink->xcontext->disp, FALSE);
2705
2706   g_mutex_unlock (xvimagesink->x_lock);
2707 }
2708
2709 /* This function commits our internal colorbalance settings to our grabbed Xv
2710    port. If the xcontext is not initialized yet it simply returns */
2711 static void
2712 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
2713 {
2714   GList *channels = NULL;
2715
2716   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2717
2718   /* If we haven't initialized the X context we can't update anything */
2719   if (xvimagesink->xcontext == NULL)
2720     return;
2721
2722   /* Don't set the attributes if they haven't been changed, to avoid
2723    * rounding errors changing the values */
2724   if (!xvimagesink->cb_changed)
2725     return;
2726
2727   /* For each channel of the colorbalance we calculate the correct value
2728      doing range conversion and then set the Xv port attribute to match our
2729      values. */
2730   channels = xvimagesink->xcontext->channels_list;
2731
2732   while (channels) {
2733     if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
2734       GstColorBalanceChannel *channel = NULL;
2735       Atom prop_atom;
2736       gint value = 0;
2737       gdouble convert_coef;
2738
2739       channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
2740       g_object_ref (channel);
2741
2742       /* Our range conversion coef */
2743       convert_coef = (channel->max_value - channel->min_value) / 2000.0;
2744
2745       if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2746         value = xvimagesink->hue;
2747       } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2748         value = xvimagesink->saturation;
2749       } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2750         value = xvimagesink->contrast;
2751       } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2752         value = xvimagesink->brightness;
2753       } else {
2754         g_warning ("got an unknown channel %s", channel->label);
2755         g_object_unref (channel);
2756         return;
2757       }
2758
2759       /* Committing to Xv port */
2760       g_mutex_lock (xvimagesink->x_lock);
2761       prop_atom =
2762           XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
2763       if (prop_atom != None) {
2764         int xv_value;
2765         xv_value =
2766             floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
2767         XvSetPortAttribute (xvimagesink->xcontext->disp,
2768             xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
2769       }
2770       g_mutex_unlock (xvimagesink->x_lock);
2771
2772       g_object_unref (channel);
2773     }
2774     channels = g_list_next (channels);
2775   }
2776 }
2777
2778 /* This function handles XEvents that might be in the queue. It generates
2779    GstEvent that will be sent upstream in the pipeline to handle interactivity
2780    and navigation. It will also listen for configure events on the window to
2781    trigger caps renegotiation so on the fly software scaling can work. */
2782 static void
2783 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
2784 {
2785   XEvent e;
2786   guint pointer_x = 0, pointer_y = 0;
2787   gboolean pointer_moved = FALSE;
2788   gboolean exposed = FALSE, configured = FALSE;
2789
2790   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2791
2792 #ifdef GST_EXT_XV_ENHANCEMENT
2793   GST_LOG("check x event");
2794 #endif /* GST_EXT_XV_ENHANCEMENT */
2795
2796   /* Handle Interaction, produces navigation events */
2797
2798   /* We get all pointer motion events, only the last position is
2799      interesting. */
2800   g_mutex_lock (xvimagesink->flow_lock);
2801   g_mutex_lock (xvimagesink->x_lock);
2802   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2803           xvimagesink->xwindow->win, PointerMotionMask, &e)) {
2804     g_mutex_unlock (xvimagesink->x_lock);
2805     g_mutex_unlock (xvimagesink->flow_lock);
2806
2807     switch (e.type) {
2808       case MotionNotify:
2809         pointer_x = e.xmotion.x;
2810         pointer_y = e.xmotion.y;
2811         pointer_moved = TRUE;
2812         break;
2813       default:
2814         break;
2815     }
2816     g_mutex_lock (xvimagesink->flow_lock);
2817     g_mutex_lock (xvimagesink->x_lock);
2818   }
2819   if (pointer_moved) {
2820     g_mutex_unlock (xvimagesink->x_lock);
2821     g_mutex_unlock (xvimagesink->flow_lock);
2822
2823     GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
2824         pointer_x, pointer_y);
2825     gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2826         "mouse-move", 0, e.xbutton.x, e.xbutton.y);
2827
2828     g_mutex_lock (xvimagesink->flow_lock);
2829     g_mutex_lock (xvimagesink->x_lock);
2830   }
2831
2832   /* We get all events on our window to throw them upstream */
2833   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2834           xvimagesink->xwindow->win,
2835           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
2836           &e)) {
2837     KeySym keysym;
2838
2839     /* We lock only for the X function call */
2840     g_mutex_unlock (xvimagesink->x_lock);
2841     g_mutex_unlock (xvimagesink->flow_lock);
2842
2843     switch (e.type) {
2844       case ButtonPress:
2845         /* Mouse button pressed over our window. We send upstream
2846            events for interactivity/navigation */
2847         GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
2848             e.xbutton.button, e.xbutton.x, e.xbutton.y);
2849         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2850             "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
2851         break;
2852       case ButtonRelease:
2853         /* Mouse button released over our window. We send upstream
2854            events for interactivity/navigation */
2855         GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
2856             e.xbutton.button, e.xbutton.x, e.xbutton.y);
2857         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2858             "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
2859         break;
2860       case KeyPress:
2861       case KeyRelease:
2862         /* Key pressed/released over our window. We send upstream
2863            events for interactivity/navigation */
2864         GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
2865             e.xkey.keycode, e.xkey.x, e.xkey.y);
2866         g_mutex_lock (xvimagesink->x_lock);
2867         keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
2868             e.xkey.keycode, 0);
2869         g_mutex_unlock (xvimagesink->x_lock);
2870         if (keysym != NoSymbol) {
2871           char *key_str = NULL;
2872
2873           g_mutex_lock (xvimagesink->x_lock);
2874           key_str = XKeysymToString (keysym);
2875           g_mutex_unlock (xvimagesink->x_lock);
2876           gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
2877               e.type == KeyPress ? "key-press" : "key-release", key_str);
2878         } else {
2879           gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
2880               e.type == KeyPress ? "key-press" : "key-release", "unknown");
2881         }
2882         break;
2883       default:
2884         GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
2885     }
2886     g_mutex_lock (xvimagesink->flow_lock);
2887     g_mutex_lock (xvimagesink->x_lock);
2888   }
2889
2890   /* Handle Expose */
2891   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2892           xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
2893     switch (e.type) {
2894       case Expose:
2895         exposed = TRUE;
2896         break;
2897       case ConfigureNotify:
2898         g_mutex_unlock (xvimagesink->x_lock);
2899 #ifdef GST_EXT_XV_ENHANCEMENT
2900         GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
2901 #endif /* GST_EXT_XV_ENHANCEMENT */
2902         gst_xvimagesink_xwindow_update_geometry (xvimagesink);
2903 #ifdef GST_EXT_XV_ENHANCEMENT
2904         GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
2905 #endif /* GST_EXT_XV_ENHANCEMENT */
2906         g_mutex_lock (xvimagesink->x_lock);
2907         configured = TRUE;
2908         break;
2909       default:
2910         break;
2911     }
2912   }
2913
2914   if (xvimagesink->handle_expose && (exposed || configured)) {
2915     g_mutex_unlock (xvimagesink->x_lock);
2916     g_mutex_unlock (xvimagesink->flow_lock);
2917
2918     gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
2919
2920     g_mutex_lock (xvimagesink->flow_lock);
2921     g_mutex_lock (xvimagesink->x_lock);
2922   }
2923
2924   /* Handle Display events */
2925   while (XPending (xvimagesink->xcontext->disp)) {
2926     XNextEvent (xvimagesink->xcontext->disp, &e);
2927
2928     switch (e.type) {
2929       case ClientMessage:{
2930 #ifdef GST_EXT_XV_ENHANCEMENT
2931         XClientMessageEvent *cme = (XClientMessageEvent *)&e;
2932         Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
2933 #endif /* GST_EXT_XV_ENHANCEMENT */
2934         Atom wm_delete;
2935
2936 #ifdef GST_EXT_XV_ENHANCEMENT
2937         GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
2938         if (cme->message_type == buffer_atom) {
2939           unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
2940
2941           GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
2942                     cme->data.l[0], cme->data.l[1]);
2943
2944           gem_name[0] = cme->data.l[0];
2945           gem_name[1] = cme->data.l[1];
2946
2947           _remove_displaying_buffer(xvimagesink, gem_name);
2948           break;
2949         }
2950 #endif /* GST_EXT_XV_ENHANCEMENT */
2951
2952         wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2953             "WM_DELETE_WINDOW", True);
2954         if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
2955           /* Handle window deletion by posting an error on the bus */
2956           GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
2957               ("Output window was closed"), (NULL));
2958
2959           g_mutex_unlock (xvimagesink->x_lock);
2960           gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
2961           xvimagesink->xwindow = NULL;
2962           g_mutex_lock (xvimagesink->x_lock);
2963         }
2964         break;
2965       }
2966 #ifdef GST_EXT_XV_ENHANCEMENT
2967       case VisibilityNotify:
2968         if (xvimagesink->xwindow &&
2969             (e.xvisibility.window == xvimagesink->xwindow->win)) {
2970           if (e.xvisibility.state == VisibilityFullyObscured) {
2971             Atom atom_stream;
2972
2973             GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
2974
2975             if (!_is_connected_to_external_display(xvimagesink)) {
2976 #if 0
2977               atom_stream = XInternAtom(xvimagesink->xcontext->disp,
2978                                         "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
2979
2980               GST_WARNING_OBJECT(xvimagesink, "call STREAM_OFF");
2981
2982               xvimagesink->is_hided = TRUE;
2983               atom_stream = XInternAtom(xvimagesink->xcontext->disp,
2984                                         "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
2985               if (atom_stream != None) {
2986                 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
2987                                        xvimagesink->xcontext->xv_port_id,
2988                                        atom_stream, 0) != Success) {
2989                   GST_WARNING_OBJECT(xvimagesink, "STREAM OFF failed");
2990                 }
2991
2992               } else {
2993                 GST_WARNING_OBJECT(xvimagesink, "atom_stream is NONE");
2994               }
2995 #endif
2996               xvimagesink->is_hided = TRUE;
2997               XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
2998               XSync(xvimagesink->xcontext->disp, FALSE);
2999             } else {
3000               GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip STREAM_OFF");
3001             }
3002           } else {
3003             GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
3004
3005             if (xvimagesink->is_hided) {
3006               g_mutex_unlock(xvimagesink->x_lock);
3007               g_mutex_unlock(xvimagesink->flow_lock);
3008
3009               xvimagesink->is_hided = FALSE;
3010               gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
3011
3012               g_mutex_lock(xvimagesink->flow_lock);
3013               g_mutex_lock(xvimagesink->x_lock);
3014             } else {
3015               GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
3016             }
3017           }
3018         }
3019         break;
3020 #endif /* GST_EXT_XV_ENHANCEMENT */
3021       default:
3022         break;
3023     }
3024   }
3025
3026   g_mutex_unlock (xvimagesink->x_lock);
3027   g_mutex_unlock (xvimagesink->flow_lock);
3028 }
3029
3030 static void
3031 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3032     XvAdaptorInfo * adaptors, int adaptor_no)
3033 {
3034   gint j;
3035   gint res;
3036
3037   /* Do we support XvImageMask ? */
3038   if (!(adaptors[adaptor_no].type & XvImageMask)) {
3039     GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3040         adaptors[adaptor_no].name);
3041     return;
3042   }
3043
3044   /* We found such an adaptor, looking for an available port */
3045   for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3046     /* We try to grab the port */
3047     res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3048     if (Success == res) {
3049       xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3050       GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3051           adaptors[adaptor_no].num_ports);
3052     } else {
3053       GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3054           adaptors[adaptor_no].name, res);
3055     }
3056   }
3057 }
3058
3059 /* This function generates a caps with all supported format by the first
3060    Xv grabable port we find. We store each one of the supported formats in a
3061    format list and append the format to a newly created caps that we return
3062    If this function does not return NULL because of an error, it also grabs
3063    the port via XvGrabPort */
3064 static GstCaps *
3065 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3066     GstXContext * xcontext)
3067 {
3068   gint i;
3069   XvAdaptorInfo *adaptors;
3070   gint nb_formats;
3071   XvImageFormatValues *formats = NULL;
3072   guint nb_encodings;
3073   XvEncodingInfo *encodings = NULL;
3074   gulong max_w = G_MAXINT, max_h = G_MAXINT;
3075   GstCaps *caps = NULL;
3076   GstCaps *rgb_caps = NULL;
3077
3078   g_return_val_if_fail (xcontext != NULL, NULL);
3079
3080   /* First let's check that XVideo extension is available */
3081   if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3082     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3083         ("Could not initialise Xv output"),
3084         ("XVideo extension is not available"));
3085     return NULL;
3086   }
3087
3088   /* Then we get adaptors list */
3089   if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3090           &xcontext->nb_adaptors, &adaptors)) {
3091     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3092         ("Could not initialise Xv output"),
3093         ("Failed getting XV adaptors list"));
3094     return NULL;
3095   }
3096
3097   xcontext->xv_port_id = 0;
3098
3099   GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors);
3100
3101   xcontext->adaptors =
3102       (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3103
3104   /* Now fill up our adaptor name array */
3105   for (i = 0; i < xcontext->nb_adaptors; i++) {
3106     xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3107   }
3108
3109   if (xvimagesink->adaptor_no >= 0 &&
3110       xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3111     /* Find xv port from user defined adaptor */
3112     gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
3113         xvimagesink->adaptor_no);
3114   }
3115
3116   if (!xcontext->xv_port_id) {
3117     /* Now search for an adaptor that supports XvImageMask */
3118     for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3119       gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3120       xvimagesink->adaptor_no = i;
3121     }
3122   }
3123
3124   XvFreeAdaptorInfo (adaptors);
3125
3126   if (!xcontext->xv_port_id) {
3127     xvimagesink->adaptor_no = -1;
3128     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3129         ("Could not initialise Xv output"), ("No port available"));
3130     return NULL;
3131   }
3132
3133   /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3134   {
3135     int count, todo = 3;
3136     XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3137         xcontext->xv_port_id, &count);
3138     static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3139     static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3140     static const char colorkey[] = "XV_COLORKEY";
3141
3142     GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3143
3144     xvimagesink->have_autopaint_colorkey = FALSE;
3145     xvimagesink->have_double_buffer = FALSE;
3146     xvimagesink->have_colorkey = FALSE;
3147
3148     for (i = 0; ((i < count) && todo); i++)
3149       if (!strcmp (attr[i].name, autopaint)) {
3150         const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3151
3152         /* turn on autopaint colorkey */
3153         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3154             (xvimagesink->autopaint_colorkey ? 1 : 0));
3155         todo--;
3156         xvimagesink->have_autopaint_colorkey = TRUE;
3157       } else if (!strcmp (attr[i].name, dbl_buffer)) {
3158         const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3159
3160         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3161             (xvimagesink->double_buffer ? 1 : 0));
3162         todo--;
3163         xvimagesink->have_double_buffer = TRUE;
3164       } else if (!strcmp (attr[i].name, colorkey)) {
3165         /* Set the colorkey, default is something that is dark but hopefully
3166          * won't randomly appear on the screen elsewhere (ie not black or greys)
3167          * can be overridden by setting "colorkey" property
3168          */
3169         const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3170         guint32 ckey = 0;
3171         gboolean set_attr = TRUE;
3172         guint cr, cg, cb;
3173
3174         /* set a colorkey in the right format RGB565/RGB888
3175          * We only handle these 2 cases, because they're the only types of
3176          * devices we've encountered. If we don't recognise it, leave it alone
3177          */
3178         cr = (xvimagesink->colorkey >> 16);
3179         cg = (xvimagesink->colorkey >> 8) & 0xFF;
3180         cb = (xvimagesink->colorkey) & 0xFF;
3181         switch (xcontext->depth) {
3182           case 16:             /* RGB 565 */
3183             cr >>= 3;
3184             cg >>= 2;
3185             cb >>= 3;
3186             ckey = (cr << 11) | (cg << 5) | cb;
3187             break;
3188           case 24:
3189           case 32:             /* RGB 888 / ARGB 8888 */
3190             ckey = (cr << 16) | (cg << 8) | cb;
3191             break;
3192           default:
3193             GST_DEBUG_OBJECT (xvimagesink,
3194                 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3195                 xcontext->depth);
3196             set_attr = FALSE;
3197             break;
3198         }
3199
3200         if (set_attr) {
3201           ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3202               (guint32) attr[i].max_value);
3203           GST_LOG_OBJECT (xvimagesink,
3204               "Setting color key for display depth %d to 0x%x",
3205               xcontext->depth, ckey);
3206
3207           XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3208               (gint) ckey);
3209         }
3210         todo--;
3211         xvimagesink->have_colorkey = TRUE;
3212       }
3213
3214     XFree (attr);
3215   }
3216
3217   /* Get the list of encodings supported by the adapter and look for the
3218    * XV_IMAGE encoding so we can determine the maximum width and height
3219    * supported */
3220   XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3221       &encodings);
3222
3223   for (i = 0; i < nb_encodings; i++) {
3224     GST_LOG_OBJECT (xvimagesink,
3225         "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3226         i, encodings[i].name, encodings[i].width, encodings[i].height,
3227         encodings[i].rate.numerator, encodings[i].rate.denominator);
3228     if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3229       max_w = encodings[i].width;
3230       max_h = encodings[i].height;
3231 #ifdef GST_EXT_XV_ENHANCEMENT
3232       xvimagesink->scr_w = max_w;
3233       xvimagesink->scr_h = max_h;
3234 #endif /* GST_EXT_XV_ENHANCEMENT */
3235     }
3236   }
3237
3238   XvFreeEncodingInfo (encodings);
3239
3240   /* We get all image formats supported by our port */
3241   formats = XvListImageFormats (xcontext->disp,
3242       xcontext->xv_port_id, &nb_formats);
3243   caps = gst_caps_new_empty ();
3244   for (i = 0; i < nb_formats; i++) {
3245     GstCaps *format_caps = NULL;
3246     gboolean is_rgb_format = FALSE;
3247
3248     /* We set the image format of the xcontext to an existing one. This
3249        is just some valid image format for making our xshm calls check before
3250        caps negotiation really happens. */
3251     xcontext->im_format = formats[i].id;
3252
3253     switch (formats[i].type) {
3254       case XvRGB:
3255       {
3256         XvImageFormatValues *fmt = &(formats[i]);
3257         gint endianness = G_BIG_ENDIAN;
3258
3259         if (fmt->byte_order == LSBFirst) {
3260           /* our caps system handles 24/32bpp RGB as big-endian. */
3261           if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
3262             fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
3263             fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
3264             fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
3265
3266             if (fmt->bits_per_pixel == 24) {
3267               fmt->red_mask >>= 8;
3268               fmt->green_mask >>= 8;
3269               fmt->blue_mask >>= 8;
3270             }
3271           } else
3272             endianness = G_LITTLE_ENDIAN;
3273         }
3274
3275         format_caps = gst_caps_new_simple ("video/x-raw-rgb",
3276 #ifdef GST_EXT_XV_ENHANCEMENT
3277             "format", GST_TYPE_FOURCC, formats[i].id,
3278 #endif /* GST_EXT_XV_ENHANCEMENT */
3279             "endianness", G_TYPE_INT, endianness,
3280             "depth", G_TYPE_INT, fmt->depth,
3281             "bpp", G_TYPE_INT, fmt->bits_per_pixel,
3282             "red_mask", G_TYPE_INT, fmt->red_mask,
3283             "green_mask", G_TYPE_INT, fmt->green_mask,
3284             "blue_mask", G_TYPE_INT, fmt->blue_mask,
3285             "width", GST_TYPE_INT_RANGE, 1, max_w,
3286             "height", GST_TYPE_INT_RANGE, 1, max_h,
3287             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3288
3289         is_rgb_format = TRUE;
3290         break;
3291       }
3292       case XvYUV:
3293         format_caps = gst_caps_new_simple ("video/x-raw-yuv",
3294             "format", GST_TYPE_FOURCC, formats[i].id,
3295             "width", GST_TYPE_INT_RANGE, 1, max_w,
3296             "height", GST_TYPE_INT_RANGE, 1, max_h,
3297             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3298         break;
3299       default:
3300         g_assert_not_reached ();
3301         break;
3302     }
3303
3304     if (format_caps) {
3305       GstXvImageFormat *format = NULL;
3306
3307       format = g_new0 (GstXvImageFormat, 1);
3308       if (format) {
3309         format->format = formats[i].id;
3310         format->caps = gst_caps_copy (format_caps);
3311         xcontext->formats_list = g_list_append (xcontext->formats_list, format);
3312       }
3313
3314       if (is_rgb_format) {
3315         if (rgb_caps == NULL)
3316           rgb_caps = format_caps;
3317         else
3318           gst_caps_append (rgb_caps, format_caps);
3319       } else
3320         gst_caps_append (caps, format_caps);
3321     }
3322   }
3323
3324   /* Collected all caps into either the caps or rgb_caps structures.
3325    * Append rgb_caps on the end of YUV, so that YUV is always preferred */
3326   if (rgb_caps)
3327     gst_caps_append (caps, rgb_caps);
3328
3329   if (formats)
3330     XFree (formats);
3331
3332   GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
3333
3334   if (gst_caps_is_empty (caps)) {
3335     gst_caps_unref (caps);
3336     XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
3337     GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
3338         ("No supported format found"));
3339     return NULL;
3340   }
3341
3342   return caps;
3343 }
3344
3345 static gpointer
3346 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
3347 {
3348   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3349
3350   GST_OBJECT_LOCK (xvimagesink);
3351   while (xvimagesink->running) {
3352     GST_OBJECT_UNLOCK (xvimagesink);
3353
3354     if (xvimagesink->xwindow) {
3355       gst_xvimagesink_handle_xevents (xvimagesink);
3356     }
3357
3358 #ifdef GST_EXT_XV_ENHANCEMENT
3359     g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
3360 #else /* GST_EXT_XV_ENHANCEMENT */
3361     /* FIXME: do we want to align this with the framerate or anything else? */
3362     g_usleep (G_USEC_PER_SEC / 20);
3363 #endif /* GST_EXT_XV_ENHANCEMENT */
3364
3365     GST_OBJECT_LOCK (xvimagesink);
3366   }
3367   GST_OBJECT_UNLOCK (xvimagesink);
3368
3369   return NULL;
3370 }
3371
3372 static void
3373 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
3374 {
3375   GThread *thread = NULL;
3376
3377   /* don't start the thread too early */
3378   if (xvimagesink->xcontext == NULL) {
3379     return;
3380   }
3381
3382   GST_OBJECT_LOCK (xvimagesink);
3383   if (xvimagesink->handle_expose || xvimagesink->handle_events) {
3384     if (!xvimagesink->event_thread) {
3385       /* Setup our event listening thread */
3386       GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
3387           xvimagesink->handle_expose, xvimagesink->handle_events);
3388       xvimagesink->running = TRUE;
3389 #if !GLIB_CHECK_VERSION (2, 31, 0)
3390       xvimagesink->event_thread = g_thread_create (
3391           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
3392 #else
3393       xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
3394           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
3395 #endif
3396     }
3397   } else {
3398     if (xvimagesink->event_thread) {
3399       GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
3400           xvimagesink->handle_expose, xvimagesink->handle_events);
3401       xvimagesink->running = FALSE;
3402       /* grab thread and mark it as NULL */
3403       thread = xvimagesink->event_thread;
3404       xvimagesink->event_thread = NULL;
3405     }
3406   }
3407   GST_OBJECT_UNLOCK (xvimagesink);
3408
3409   /* Wait for our event thread to finish */
3410   if (thread)
3411     g_thread_join (thread);
3412
3413 }
3414
3415
3416 #ifdef GST_EXT_XV_ENHANCEMENT
3417 /**
3418  * gst_xvimagesink_prepare_xid:
3419  * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
3420  *
3421  * This will post a "prepare-xid" element message with video size and display size on the bus
3422  * to give applications an opportunity to call
3423  * gst_x_overlay_set_xwindow_id() before a plugin creates its own
3424  * window or pixmap.
3425  *
3426  * This function should only be used by video overlay plugin developers.
3427  */
3428 static void
3429 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
3430 {
3431   GstStructure *s;
3432   GstMessage *msg;
3433
3434   g_return_if_fail (overlay != NULL);
3435   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
3436
3437   GstXvImageSink *xvimagesink;
3438   xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
3439
3440   GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
3441         GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
3442
3443   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
3444   s = gst_structure_new ("prepare-xid",
3445         "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
3446         "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
3447         "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
3448         "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
3449         NULL);
3450   msg = gst_message_new_element (GST_OBJECT (overlay), s);
3451   gst_element_post_message (GST_ELEMENT (overlay), msg);
3452 }
3453 #endif /* GST_EXT_XV_ENHANCEMENT */
3454
3455
3456 /* This function calculates the pixel aspect ratio based on the properties
3457  * in the xcontext structure and stores it there. */
3458 static void
3459 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
3460 {
3461   static const gint par[][2] = {
3462     {1, 1},                     /* regular screen */
3463     {16, 15},                   /* PAL TV */
3464     {11, 10},                   /* 525 line Rec.601 video */
3465     {54, 59},                   /* 625 line Rec.601 video */
3466     {64, 45},                   /* 1280x1024 on 16:9 display */
3467     {5, 3},                     /* 1280x1024 on 4:3 display */
3468     {4, 3}                      /*  800x600 on 16:9 display */
3469   };
3470   gint i;
3471   gint index;
3472   gdouble ratio;
3473   gdouble delta;
3474
3475 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
3476
3477   /* first calculate the "real" ratio based on the X values;
3478    * which is the "physical" w/h divided by the w/h in pixels of the display */
3479   ratio = (gdouble) (xcontext->widthmm * xcontext->height)
3480       / (xcontext->heightmm * xcontext->width);
3481
3482   /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
3483    * override here */
3484   if (xcontext->width == 720 && xcontext->height == 576) {
3485     ratio = 4.0 * 576 / (3.0 * 720);
3486   }
3487   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
3488   /* now find the one from par[][2] with the lowest delta to the real one */
3489   delta = DELTA (0);
3490   index = 0;
3491
3492   for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
3493     gdouble this_delta = DELTA (i);
3494
3495     if (this_delta < delta) {
3496       index = i;
3497       delta = this_delta;
3498     }
3499   }
3500
3501   GST_DEBUG ("Decided on index %d (%d/%d)", index,
3502       par[index][0], par[index][1]);
3503
3504   g_free (xcontext->par);
3505   xcontext->par = g_new0 (GValue, 1);
3506   g_value_init (xcontext->par, GST_TYPE_FRACTION);
3507   gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
3508   GST_DEBUG ("set xcontext PAR to %d/%d",
3509       gst_value_get_fraction_numerator (xcontext->par),
3510       gst_value_get_fraction_denominator (xcontext->par));
3511 }
3512
3513 /* This function gets the X Display and global info about it. Everything is
3514    stored in our object and will be cleaned when the object is disposed. Note
3515    here that caps for supported format are generated without any window or
3516    image creation */
3517 static GstXContext *
3518 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
3519 {
3520   GstXContext *xcontext = NULL;
3521   XPixmapFormatValues *px_formats = NULL;
3522   gint nb_formats = 0, i, j, N_attr;
3523   XvAttribute *xv_attr;
3524   Atom prop_atom;
3525   const char *channels[4] = { "XV_HUE", "XV_SATURATION",
3526     "XV_BRIGHTNESS", "XV_CONTRAST"
3527   };
3528
3529   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3530
3531   xcontext = g_new0 (GstXContext, 1);
3532   xcontext->im_format = 0;
3533
3534   g_mutex_lock (xvimagesink->x_lock);
3535
3536   xcontext->disp = XOpenDisplay (xvimagesink->display_name);
3537
3538   if (!xcontext->disp) {
3539     g_mutex_unlock (xvimagesink->x_lock);
3540     g_free (xcontext);
3541     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
3542         ("Could not initialise Xv output"), ("Could not open display"));
3543     return NULL;
3544   }
3545
3546   xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
3547   xcontext->screen_num = DefaultScreen (xcontext->disp);
3548   xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
3549   xcontext->root = DefaultRootWindow (xcontext->disp);
3550   xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
3551   xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
3552   xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
3553
3554   xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
3555   xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
3556   xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
3557   xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
3558
3559   GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
3560       xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
3561
3562   gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
3563   /* We get supported pixmap formats at supported depth */
3564   px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
3565
3566   if (!px_formats) {
3567     XCloseDisplay (xcontext->disp);
3568     g_mutex_unlock (xvimagesink->x_lock);
3569     g_free (xcontext->par);
3570     g_free (xcontext);
3571     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3572         ("Could not initialise Xv output"), ("Could not get pixel formats"));
3573     return NULL;
3574   }
3575
3576   /* We get bpp value corresponding to our running depth */
3577   for (i = 0; i < nb_formats; i++) {
3578     if (px_formats[i].depth == xcontext->depth)
3579       xcontext->bpp = px_formats[i].bits_per_pixel;
3580   }
3581
3582   XFree (px_formats);
3583
3584   xcontext->endianness =
3585       (ImageByteOrder (xcontext->disp) ==
3586       LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
3587
3588   /* our caps system handles 24/32bpp RGB as big-endian. */
3589   if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
3590       xcontext->endianness == G_LITTLE_ENDIAN) {
3591     xcontext->endianness = G_BIG_ENDIAN;
3592     xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
3593     xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
3594     xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
3595     if (xcontext->bpp == 24) {
3596       xcontext->visual->red_mask >>= 8;
3597       xcontext->visual->green_mask >>= 8;
3598       xcontext->visual->blue_mask >>= 8;
3599     }
3600   }
3601
3602   xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
3603
3604   if (!xcontext->caps) {
3605     XCloseDisplay (xcontext->disp);
3606     g_mutex_unlock (xvimagesink->x_lock);
3607     g_free (xcontext->par);
3608     g_free (xcontext);
3609     /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
3610     return NULL;
3611   }
3612 #ifdef HAVE_XSHM
3613   /* Search for XShm extension support */
3614   if (XShmQueryExtension (xcontext->disp) &&
3615       gst_xvimagesink_check_xshm_calls (xcontext)) {
3616     xcontext->use_xshm = TRUE;
3617     GST_DEBUG ("xvimagesink is using XShm extension");
3618   } else
3619 #endif /* HAVE_XSHM */
3620   {
3621     xcontext->use_xshm = FALSE;
3622     GST_DEBUG ("xvimagesink is not using XShm extension");
3623   }
3624
3625   xv_attr = XvQueryPortAttributes (xcontext->disp,
3626       xcontext->xv_port_id, &N_attr);
3627
3628
3629   /* Generate the channels list */
3630   for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
3631     XvAttribute *matching_attr = NULL;
3632
3633     /* Retrieve the property atom if it exists. If it doesn't exist,
3634      * the attribute itself must not either, so we can skip */
3635     prop_atom = XInternAtom (xcontext->disp, channels[i], True);
3636     if (prop_atom == None)
3637       continue;
3638
3639     if (xv_attr != NULL) {
3640       for (j = 0; j < N_attr && matching_attr == NULL; ++j)
3641         if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
3642           matching_attr = xv_attr + j;
3643     }
3644
3645     if (matching_attr) {
3646       GstColorBalanceChannel *channel;
3647
3648       channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
3649       channel->label = g_strdup (channels[i]);
3650       channel->min_value = matching_attr->min_value;
3651       channel->max_value = matching_attr->max_value;
3652
3653       xcontext->channels_list = g_list_append (xcontext->channels_list,
3654           channel);
3655
3656       /* If the colorbalance settings have not been touched we get Xv values
3657          as defaults and update our internal variables */
3658       if (!xvimagesink->cb_changed) {
3659         gint val;
3660
3661         XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
3662             prop_atom, &val);
3663         /* Normalize val to [-1000, 1000] */
3664         val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
3665             (double) (channel->max_value - channel->min_value));
3666
3667         if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
3668           xvimagesink->hue = val;
3669         else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
3670           xvimagesink->saturation = val;
3671         else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
3672           xvimagesink->brightness = val;
3673         else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
3674           xvimagesink->contrast = val;
3675       }
3676     }
3677   }
3678
3679   if (xv_attr)
3680     XFree (xv_attr);
3681
3682 #ifdef GST_EXT_XV_ENHANCEMENT
3683   set_display_mode(xcontext, xvimagesink->display_mode);
3684   set_csc_range(xcontext, xvimagesink->csc_range);
3685 #endif /* GST_EXT_XV_ENHANCEMENT */
3686
3687   g_mutex_unlock (xvimagesink->x_lock);
3688
3689   return xcontext;
3690 }
3691
3692 /* This function cleans the X context. Closing the Display, releasing the XV
3693    port and unrefing the caps for supported formats. */
3694 static void
3695 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
3696 {
3697   GList *formats_list, *channels_list;
3698   GstXContext *xcontext;
3699   gint i = 0;
3700
3701   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3702
3703   GST_OBJECT_LOCK (xvimagesink);
3704   if (xvimagesink->xcontext == NULL) {
3705     GST_OBJECT_UNLOCK (xvimagesink);
3706     return;
3707   }
3708
3709   /* Take the XContext from the sink and clean it up */
3710   xcontext = xvimagesink->xcontext;
3711   xvimagesink->xcontext = NULL;
3712
3713   GST_OBJECT_UNLOCK (xvimagesink);
3714
3715
3716   formats_list = xcontext->formats_list;
3717
3718   while (formats_list) {
3719     GstXvImageFormat *format = formats_list->data;
3720
3721     gst_caps_unref (format->caps);
3722     g_free (format);
3723     formats_list = g_list_next (formats_list);
3724   }
3725
3726   if (xcontext->formats_list)
3727     g_list_free (xcontext->formats_list);
3728
3729   channels_list = xcontext->channels_list;
3730
3731   while (channels_list) {
3732     GstColorBalanceChannel *channel = channels_list->data;
3733
3734     g_object_unref (channel);
3735     channels_list = g_list_next (channels_list);
3736   }
3737
3738   if (xcontext->channels_list)
3739     g_list_free (xcontext->channels_list);
3740
3741   gst_caps_unref (xcontext->caps);
3742   if (xcontext->last_caps)
3743     gst_caps_replace (&xcontext->last_caps, NULL);
3744
3745   for (i = 0; i < xcontext->nb_adaptors; i++) {
3746     g_free (xcontext->adaptors[i]);
3747   }
3748
3749   g_free (xcontext->adaptors);
3750
3751   g_free (xcontext->par);
3752
3753   g_mutex_lock (xvimagesink->x_lock);
3754
3755   GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
3756
3757   XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
3758
3759   XCloseDisplay (xcontext->disp);
3760
3761   g_mutex_unlock (xvimagesink->x_lock);
3762
3763   g_free (xcontext);
3764 }
3765
3766 static void
3767 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
3768 {
3769   g_mutex_lock (xvimagesink->pool_lock);
3770
3771   while (xvimagesink->image_pool) {
3772     GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
3773
3774     xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
3775         xvimagesink->image_pool);
3776     gst_xvimage_buffer_free (xvimage);
3777   }
3778
3779   g_mutex_unlock (xvimagesink->pool_lock);
3780 }
3781
3782 /* Element stuff */
3783
3784 /* This function tries to get a format matching with a given caps in the
3785    supported list of formats we generated in gst_xvimagesink_get_xv_support */
3786 static gint
3787 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
3788     GstCaps * caps)
3789 {
3790   GList *list = NULL;
3791
3792   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
3793
3794   list = xvimagesink->xcontext->formats_list;
3795
3796   while (list) {
3797     GstXvImageFormat *format = list->data;
3798
3799     if (format) {
3800       if (gst_caps_can_intersect (caps, format->caps)) {
3801         return format->format;
3802       }
3803     }
3804     list = g_list_next (list);
3805   }
3806
3807   return -1;
3808 }
3809
3810 static GstCaps *
3811 gst_xvimagesink_getcaps (GstBaseSink * bsink)
3812 {
3813   GstXvImageSink *xvimagesink;
3814
3815   xvimagesink = GST_XVIMAGESINK (bsink);
3816
3817   if (xvimagesink->xcontext)
3818     return gst_caps_ref (xvimagesink->xcontext->caps);
3819
3820   return
3821       gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
3822           (xvimagesink)));
3823 }
3824
3825 static gboolean
3826 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
3827 {
3828   GstXvImageSink *xvimagesink;
3829   GstStructure *structure;
3830   guint32 im_format = 0;
3831   gboolean ret;
3832   gint video_width, video_height;
3833   gint disp_x, disp_y;
3834   gint disp_width, disp_height;
3835   gint video_par_n, video_par_d;        /* video's PAR */
3836   gint display_par_n, display_par_d;    /* display's PAR */
3837   const GValue *caps_par;
3838   const GValue *caps_disp_reg;
3839   const GValue *fps;
3840   guint num, den;
3841 #ifdef GST_EXT_XV_ENHANCEMENT
3842   gboolean enable_last_buffer;
3843 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
3844
3845   xvimagesink = GST_XVIMAGESINK (bsink);
3846
3847   GST_DEBUG_OBJECT (xvimagesink,
3848       "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
3849       GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
3850
3851   if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
3852     goto incompatible_caps;
3853
3854   structure = gst_caps_get_structure (caps, 0);
3855   ret = gst_structure_get_int (structure, "width", &video_width);
3856   ret &= gst_structure_get_int (structure, "height", &video_height);
3857   fps = gst_structure_get_value (structure, "framerate");
3858   ret &= (fps != NULL);
3859
3860   if (!ret)
3861     goto incomplete_caps;
3862
3863 #ifdef GST_EXT_XV_ENHANCEMENT
3864   xvimagesink->aligned_width = video_width;
3865   xvimagesink->aligned_height = video_height;
3866
3867   /* get enable-last-buffer */
3868   g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
3869   GST_INFO_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
3870
3871   /* flush if enable-last-buffer is TRUE */
3872   if (enable_last_buffer) {
3873     GST_INFO_OBJECT(xvimagesink, "flush last-buffer");
3874     g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
3875     g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
3876   }
3877 #endif /* GST_EXT_XV_ENHANCEMENT */
3878
3879   xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
3880   xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
3881
3882   xvimagesink->video_width = video_width;
3883   xvimagesink->video_height = video_height;
3884
3885   im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
3886   if (im_format == -1)
3887     goto invalid_format;
3888
3889   /* get aspect ratio from caps if it's present, and
3890    * convert video width and height to a display width and height
3891    * using wd / hd = wv / hv * PARv / PARd */
3892
3893   /* get video's PAR */
3894   caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
3895   if (caps_par) {
3896     video_par_n = gst_value_get_fraction_numerator (caps_par);
3897     video_par_d = gst_value_get_fraction_denominator (caps_par);
3898   } else {
3899     video_par_n = 1;
3900     video_par_d = 1;
3901   }
3902   /* get display's PAR */
3903   if (xvimagesink->par) {
3904     display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
3905     display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
3906   } else {
3907     display_par_n = 1;
3908     display_par_d = 1;
3909   }
3910
3911   /* get the display region */
3912   caps_disp_reg = gst_structure_get_value (structure, "display-region");
3913   if (caps_disp_reg) {
3914     disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
3915     disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
3916     disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
3917     disp_height =
3918         g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
3919   } else {
3920     disp_x = disp_y = 0;
3921     disp_width = video_width;
3922     disp_height = video_height;
3923   }
3924
3925   if (!gst_video_calculate_display_ratio (&num, &den, video_width,
3926           video_height, video_par_n, video_par_d, display_par_n, display_par_d))
3927     goto no_disp_ratio;
3928
3929   xvimagesink->disp_x = disp_x;
3930   xvimagesink->disp_y = disp_y;
3931   xvimagesink->disp_width = disp_width;
3932   xvimagesink->disp_height = disp_height;
3933
3934   GST_DEBUG_OBJECT (xvimagesink,
3935       "video width/height: %dx%d, calculated display ratio: %d/%d",
3936       video_width, video_height, num, den);
3937
3938   /* now find a width x height that respects this display ratio.
3939    * prefer those that have one of w/h the same as the incoming video
3940    * using wd / hd = num / den */
3941
3942   /* start with same height, because of interlaced video */
3943   /* check hd / den is an integer scale factor, and scale wd with the PAR */
3944   if (video_height % den == 0) {
3945     GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
3946     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
3947         gst_util_uint64_scale_int (video_height, num, den);
3948     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
3949   } else if (video_width % num == 0) {
3950     GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
3951     GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
3952     GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
3953         gst_util_uint64_scale_int (video_width, den, num);
3954   } else {
3955     GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
3956     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
3957         gst_util_uint64_scale_int (video_height, num, den);
3958     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
3959   }
3960   GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
3961       GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
3962
3963   /* Notify application to set xwindow id now */
3964   g_mutex_lock (xvimagesink->flow_lock);
3965 #ifdef GST_EXT_XV_ENHANCEMENT
3966   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
3967     g_mutex_unlock (xvimagesink->flow_lock);
3968     gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
3969 #else
3970   if (!xvimagesink->xwindow) {
3971     g_mutex_unlock (xvimagesink->flow_lock);
3972     gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
3973 #endif
3974   } else {
3975     g_mutex_unlock (xvimagesink->flow_lock);
3976   }
3977
3978   /* Creating our window and our image with the display size in pixels */
3979   if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
3980       GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
3981     goto no_display_size;
3982
3983   g_mutex_lock (xvimagesink->flow_lock);
3984 #ifdef GST_EXT_XV_ENHANCEMENT
3985   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
3986     GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
3987 #else
3988   if (!xvimagesink->xwindow) {
3989 #endif
3990     xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
3991         GST_VIDEO_SINK_WIDTH (xvimagesink),
3992         GST_VIDEO_SINK_HEIGHT (xvimagesink));
3993   }
3994
3995   /* After a resize, we want to redraw the borders in case the new frame size
3996    * doesn't cover the same area */
3997   xvimagesink->redraw_border = TRUE;
3998
3999   /* We renew our xvimage only if size or format changed;
4000    * the xvimage is the same size as the video pixel size */
4001   if ((xvimagesink->xvimage) &&
4002       ((im_format != xvimagesink->xvimage->im_format) ||
4003           (video_width != xvimagesink->xvimage->width) ||
4004           (video_height != xvimagesink->xvimage->height))) {
4005     GST_DEBUG_OBJECT (xvimagesink,
4006         "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4007         GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4008         GST_FOURCC_ARGS (im_format));
4009     GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4010     gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4011     xvimagesink->xvimage = NULL;
4012   }
4013
4014   g_mutex_unlock (xvimagesink->flow_lock);
4015
4016   return TRUE;
4017
4018   /* ERRORS */
4019 incompatible_caps:
4020   {
4021     GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4022     return FALSE;
4023   }
4024 incomplete_caps:
4025   {
4026     GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4027         "height or framerate from intersected caps");
4028     return FALSE;
4029   }
4030 invalid_format:
4031   {
4032     GST_DEBUG_OBJECT (xvimagesink,
4033         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4034     return FALSE;
4035   }
4036 no_disp_ratio:
4037   {
4038     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4039         ("Error calculating the output display ratio of the video."));
4040     return FALSE;
4041   }
4042 no_display_size:
4043   {
4044     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4045         ("Error calculating the output display ratio of the video."));
4046     return FALSE;
4047   }
4048 }
4049
4050 static GstStateChangeReturn
4051 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4052 {
4053   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4054   GstXvImageSink *xvimagesink;
4055   GstXContext *xcontext = NULL;
4056 #ifdef GST_EXT_XV_ENHANCEMENT
4057   Atom atom_preemption = None;
4058 #endif /* GST_EXT_XV_ENHANCEMENT */
4059
4060   xvimagesink = GST_XVIMAGESINK (element);
4061
4062   switch (transition) {
4063     case GST_STATE_CHANGE_NULL_TO_READY:
4064 #ifdef GST_EXT_XV_ENHANCEMENT
4065       GST_WARNING("NULL_TO_READY start");
4066 #endif /* GST_EXT_XV_ENHANCEMENT */
4067       /* Initializing the XContext */
4068       if (xvimagesink->xcontext == NULL) {
4069         xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4070         if (xcontext == NULL)
4071           return GST_STATE_CHANGE_FAILURE;
4072         GST_OBJECT_LOCK (xvimagesink);
4073         if (xcontext)
4074           xvimagesink->xcontext = xcontext;
4075         GST_OBJECT_UNLOCK (xvimagesink);
4076       }
4077
4078       /* update object's par with calculated one if not set yet */
4079       if (!xvimagesink->par) {
4080         xvimagesink->par = g_new0 (GValue, 1);
4081         gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4082         GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4083       }
4084       /* call XSynchronize with the current value of synchronous */
4085       GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4086           xvimagesink->synchronous ? "TRUE" : "FALSE");
4087       XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4088       gst_xvimagesink_update_colorbalance (xvimagesink);
4089       gst_xvimagesink_manage_event_thread (xvimagesink);
4090 #ifdef GST_EXT_XV_ENHANCEMENT
4091       GST_WARNING("NULL_TO_READY done");
4092 #endif /* GST_EXT_XV_ENHANCEMENT */
4093       break;
4094     case GST_STATE_CHANGE_READY_TO_PAUSED:
4095 #ifdef GST_EXT_XV_ENHANCEMENT
4096       GST_WARNING("READY_TO_PAUSED start");
4097 #endif /* GST_EXT_XV_ENHANCEMENT */
4098       g_mutex_lock (xvimagesink->pool_lock);
4099       xvimagesink->pool_invalid = FALSE;
4100       g_mutex_unlock (xvimagesink->pool_lock);
4101 #ifdef GST_EXT_XV_ENHANCEMENT
4102       GST_WARNING("READY_TO_PAUSED done");
4103 #endif /* GST_EXT_XV_ENHANCEMENT */
4104       break;
4105     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4106 #ifdef GST_EXT_XV_ENHANCEMENT
4107       GST_WARNING("PAUSED_TO_PLAYING start");
4108 #if 0 /* This is removed in Xorg */
4109       g_mutex_lock (xvimagesink->x_lock);
4110       atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4111                                      "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4112       if (atom_preemption != None) {
4113          if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4114                                 xvimagesink->xcontext->xv_port_id,
4115                                 atom_preemption, 1 ) != Success) {
4116             GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4117          }
4118          XSync (xvimagesink->xcontext->disp, FALSE);
4119       }
4120       g_mutex_unlock (xvimagesink->x_lock);
4121 #endif
4122       GST_WARNING("PAUSED_TO_PLAYING done");
4123 #endif /* GST_EXT_XV_ENHANCEMENT */
4124       break;
4125     case GST_STATE_CHANGE_PAUSED_TO_READY:
4126 #ifdef GST_EXT_XV_ENHANCEMENT
4127       GST_WARNING("PAUSED_TO_READY start");
4128 #endif /* GST_EXT_XV_ENHANCEMENT */
4129       g_mutex_lock (xvimagesink->pool_lock);
4130       xvimagesink->pool_invalid = TRUE;
4131       g_mutex_unlock (xvimagesink->pool_lock);
4132       break;
4133     default:
4134       break;
4135   }
4136
4137   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4138
4139   switch (transition) {
4140     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4141 #ifdef GST_EXT_XV_ENHANCEMENT
4142       GST_WARNING("PLAYING_TO_PAUSED start");
4143       xvimagesink->rotate_changed = TRUE;
4144 #if 0 /* This is removed in Xorg */
4145       g_mutex_lock (xvimagesink->x_lock);
4146       atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4147                                      "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4148       if (atom_preemption != None) {
4149          if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4150                                 xvimagesink->xcontext->xv_port_id,
4151                                 atom_preemption, 0 ) != Success) {
4152             GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4153          }
4154          XSync (xvimagesink->xcontext->disp, FALSE);
4155       }
4156       g_mutex_unlock (xvimagesink->x_lock);
4157 #endif
4158       /* init displayed buffer count */
4159       xvimagesink->displayed_buffer_count = 0;
4160
4161       GST_WARNING("PLAYING_TO_PAUSED done");
4162 #endif /* GST_EXT_XV_ENHANCEMENT */
4163       break;
4164     case GST_STATE_CHANGE_PAUSED_TO_READY:
4165       xvimagesink->fps_n = 0;
4166       xvimagesink->fps_d = 1;
4167       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
4168       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
4169 #ifdef GST_EXT_XV_ENHANCEMENT
4170       /* close drm */
4171       drm_fini(xvimagesink);
4172
4173       /* init displaying_buffer_count */
4174       xvimagesink->displaying_buffer_count = 0;
4175
4176       GST_WARNING("PAUSED_TO_READY done");
4177 #endif /* GST_EXT_XV_ENHANCEMENT */
4178       break;
4179     case GST_STATE_CHANGE_READY_TO_NULL:
4180 #ifdef GST_EXT_XV_ENHANCEMENT
4181       GST_WARNING("READY_TO_NULL start");
4182 #endif /* GST_EXT_XV_ENHANCEMENT */
4183       gst_xvimagesink_reset (xvimagesink);
4184 #ifdef GST_EXT_XV_ENHANCEMENT
4185       GST_WARNING("READY_TO_NULL done");
4186 #endif /* GST_EXT_XV_ENHANCEMENT */
4187       break;
4188     default:
4189       break;
4190   }
4191
4192   return ret;
4193 }
4194
4195 static void
4196 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
4197     GstClockTime * start, GstClockTime * end)
4198 {
4199   GstXvImageSink *xvimagesink;
4200
4201   xvimagesink = GST_XVIMAGESINK (bsink);
4202
4203   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
4204     *start = GST_BUFFER_TIMESTAMP (buf);
4205     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
4206       *end = *start + GST_BUFFER_DURATION (buf);
4207     } else {
4208       if (xvimagesink->fps_n > 0) {
4209         *end = *start +
4210             gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
4211             xvimagesink->fps_n);
4212       }
4213     }
4214   }
4215 }
4216
4217 static GstFlowReturn
4218 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
4219 {
4220   GstXvImageSink *xvimagesink;
4221
4222 #ifdef GST_EXT_XV_ENHANCEMENT
4223   XV_DATA_PTR img_data = NULL;
4224   SCMN_IMGB *scmn_imgb = NULL;
4225   gint format = 0;
4226   gboolean ret = FALSE;
4227 #endif /* GST_EXT_XV_ENHANCEMENT */
4228
4229   xvimagesink = GST_XVIMAGESINK (vsink);
4230
4231 #ifdef GST_EXT_XV_ENHANCEMENT
4232   if (xvimagesink->stop_video) {
4233     GST_INFO( "Stop video is TRUE. so skip show frame..." );
4234     return GST_FLOW_OK;
4235   }
4236 #endif /* GST_EXT_XV_ENHANCEMENT */
4237
4238   /* If this buffer has been allocated using our buffer management we simply
4239      put the ximage which is in the PRIVATE pointer */
4240   if (GST_IS_XVIMAGE_BUFFER (buf)) {
4241     GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
4242 #ifdef GST_EXT_XV_ENHANCEMENT
4243     xvimagesink->xid_updated = FALSE;
4244 #endif /* GST_EXT_XV_ENHANCEMENT */
4245     if (!gst_xvimagesink_xvimage_put (xvimagesink,
4246             GST_XVIMAGE_BUFFER_CAST (buf)))
4247       goto no_window;
4248   } else {
4249     GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
4250         "slow copy into bufferpool buffer %p", buf);
4251     /* Else we have to copy the data into our private image, */
4252     /* if we have one... */
4253 #ifdef GST_EXT_XV_ENHANCEMENT
4254     g_mutex_lock (xvimagesink->flow_lock);
4255 #endif /* GST_EXT_XV_ENHANCEMENT */
4256     if (!xvimagesink->xvimage) {
4257       GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
4258
4259 #ifdef GST_EXT_XV_ENHANCEMENT
4260       format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
4261       switch (format) {
4262         case GST_MAKE_FOURCC('S', 'T', '1', '2'):
4263         case GST_MAKE_FOURCC('S', 'N', '1', '2'):
4264         case GST_MAKE_FOURCC('S', 'N', '2', '1'):
4265         case GST_MAKE_FOURCC('S', '4', '2', '0'):
4266         case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
4267         case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
4268         case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
4269         case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
4270         case GST_MAKE_FOURCC('S', 'R', '3', '2'):
4271         case GST_MAKE_FOURCC('S', 'V', '1', '2'):
4272           xvimagesink->is_zero_copy_format = TRUE;
4273           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
4274           if(scmn_imgb == NULL) {
4275             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
4276             g_mutex_unlock (xvimagesink->flow_lock);
4277             return GST_FLOW_OK;
4278           }
4279
4280           /* skip buffer if aligned size is smaller than size of caps */
4281           if (scmn_imgb->s[0] < xvimagesink->video_width ||
4282               scmn_imgb->e[0] < xvimagesink->video_height) {
4283             GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
4284                                             xvimagesink->video_width, xvimagesink->video_height,
4285                                             scmn_imgb->s[0], scmn_imgb->e[0]);
4286             g_mutex_unlock (xvimagesink->flow_lock);
4287             return GST_FLOW_OK;
4288           }
4289
4290           xvimagesink->aligned_width = scmn_imgb->s[0];
4291           xvimagesink->aligned_height = scmn_imgb->e[0];
4292           GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
4293                                        xvimagesink->aligned_width, xvimagesink->aligned_height);
4294           break;
4295         default:
4296           xvimagesink->is_zero_copy_format = FALSE;
4297           GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
4298           break;
4299       }
4300
4301       GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
4302 #endif /* GST_EXT_XV_ENHANCEMENT */
4303
4304       xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
4305           GST_BUFFER_CAPS (buf));
4306
4307       if (!xvimagesink->xvimage)
4308         /* The create method should have posted an informative error */
4309         goto no_image;
4310
4311       if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
4312         GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4313             ("Failed to create output image buffer of %dx%d pixels",
4314                 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
4315             ("XServer allocated buffer size did not match input buffer"));
4316
4317         gst_xvimage_buffer_destroy (xvimagesink->xvimage);
4318         xvimagesink->xvimage = NULL;
4319         goto no_image;
4320       }
4321     }
4322
4323 #ifdef GST_EXT_XV_ENHANCEMENT
4324     if (xvimagesink->is_zero_copy_format) {
4325       /* Cases for specified formats of Samsung extension */
4326         GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
4327                 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
4328                 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
4329                 xvimagesink->display_mode, xvimagesink->rotate_angle);
4330
4331         if (xvimagesink->xvimage->xvimage->data) {
4332           img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
4333           memset(img_data, 0x0, sizeof(XV_DATA));
4334           XV_INIT_DATA(img_data);
4335
4336           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
4337           if (scmn_imgb == NULL) {
4338             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
4339             g_mutex_unlock (xvimagesink->flow_lock);
4340             return GST_FLOW_OK;
4341           }
4342
4343           if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
4344             img_data->YBuf = (unsigned int)scmn_imgb->p[0];
4345             img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
4346             img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
4347             img_data->BufType = XV_BUF_TYPE_LEGACY;
4348
4349             GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
4350                       img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
4351           } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
4352                      scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
4353             /* open drm to use gem */
4354             if (xvimagesink->drm_fd < 0) {
4355               drm_init(xvimagesink);
4356             }
4357
4358             if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
4359               /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
4360               img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
4361               img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
4362               img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
4363               img_data->BufType = XV_BUF_TYPE_DMABUF;
4364               GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
4365             } else {
4366               /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
4367               img_data->bo[0] = scmn_imgb->bo[0];
4368               img_data->bo[1] = scmn_imgb->bo[1];
4369               img_data->bo[2] = scmn_imgb->bo[2];
4370               GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
4371             }
4372
4373             /* check secure contents path */
4374             /* NOTE : does it need to set 0 during playing(recovery case)? */
4375             if (scmn_imgb->tz_enable) {
4376               if (!xvimagesink->is_secure_path) {
4377                 Atom atom_secure = None;
4378                 g_mutex_lock (xvimagesink->x_lock);
4379                 atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
4380                 if (atom_secure != None) {
4381                   if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, 1) != Success) {
4382                     GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.\n", atom_secure);
4383                   } else {
4384                     GST_WARNING_OBJECT(xvimagesink, "secure contents path is enabled.\n");
4385                   }
4386                     XSync (xvimagesink->xcontext->disp, FALSE);
4387                 }
4388                 g_mutex_unlock (xvimagesink->x_lock);
4389                 xvimagesink->is_secure_path = TRUE;
4390               }
4391             }
4392
4393             /* set current buffer */
4394             xvimagesink->xvimage->current_buffer = buf;
4395           } else {
4396             GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
4397                         scmn_imgb->buf_share_method);
4398             g_mutex_unlock (xvimagesink->flow_lock);
4399             return GST_FLOW_OK;
4400           }
4401         } else {
4402           GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
4403           g_mutex_unlock (xvimagesink->flow_lock);
4404           return GST_FLOW_OK;
4405         }
4406     } else {
4407         GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
4408         memcpy (xvimagesink->xvimage->xvimage->data,
4409         GST_BUFFER_DATA (buf),
4410         MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
4411     }
4412
4413     g_mutex_unlock (xvimagesink->flow_lock);
4414     ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
4415     if (!ret) {
4416       goto no_window;
4417     }
4418 #else /* GST_EXT_XV_ENHANCEMENT */
4419     memcpy (xvimagesink->xvimage->xvimage->data,
4420         GST_BUFFER_DATA (buf),
4421         MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
4422
4423     if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
4424       goto no_window;
4425 #endif /* GST_EXT_XV_ENHANCEMENT */
4426   }
4427
4428   return GST_FLOW_OK;
4429
4430   /* ERRORS */
4431 no_image:
4432   {
4433     /* No image available. That's very bad ! */
4434     GST_WARNING_OBJECT (xvimagesink, "could not create image");
4435 #ifdef GST_EXT_XV_ENHANCEMENT
4436     g_mutex_unlock (xvimagesink->flow_lock);
4437 #endif
4438     return GST_FLOW_ERROR;
4439   }
4440 no_window:
4441   {
4442     /* No Window available to put our image into */
4443     GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
4444     return GST_FLOW_ERROR;
4445   }
4446 }
4447
4448 static gboolean
4449 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
4450 {
4451   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
4452
4453   switch (GST_EVENT_TYPE (event)) {
4454     case GST_EVENT_TAG:{
4455       GstTagList *l;
4456       gchar *title = NULL;
4457
4458       gst_event_parse_tag (event, &l);
4459       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
4460
4461       if (title) {
4462 #ifdef GST_EXT_XV_ENHANCEMENT
4463         if (!xvimagesink->get_pixmap_cb) {
4464 #endif
4465         GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
4466         gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
4467             title);
4468
4469         g_free (title);
4470 #ifdef GST_EXT_XV_ENHANCEMENT
4471         }
4472 #endif
4473       }
4474       break;
4475     }
4476     default:
4477       break;
4478   }
4479   if (GST_BASE_SINK_CLASS (parent_class)->event)
4480     return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
4481   else
4482     return TRUE;
4483 }
4484
4485 /* Buffer management */
4486
4487 static GstCaps *
4488 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
4489     GstCaps * caps)
4490 {
4491   GstCaps *intersection;
4492   GstCaps *new_caps;
4493   GstStructure *s;
4494   gint width, height;
4495   gint par_n = 1, par_d = 1;
4496   gint dar_n, dar_d;
4497   gint w, h;
4498
4499   new_caps = gst_caps_copy (caps);
4500
4501   s = gst_caps_get_structure (new_caps, 0);
4502
4503   gst_structure_get_int (s, "width", &width);
4504   gst_structure_get_int (s, "height", &height);
4505   gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
4506
4507   gst_structure_remove_field (s, "width");
4508   gst_structure_remove_field (s, "height");
4509   gst_structure_remove_field (s, "pixel-aspect-ratio");
4510
4511   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4512   gst_caps_unref (new_caps);
4513
4514   if (gst_caps_is_empty (intersection))
4515     return intersection;
4516
4517   s = gst_caps_get_structure (intersection, 0);
4518
4519   gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
4520
4521   /* xvimagesink supports all PARs */
4522
4523   gst_structure_fixate_field_nearest_int (s, "width", width);
4524   gst_structure_fixate_field_nearest_int (s, "height", height);
4525   gst_structure_get_int (s, "width", &w);
4526   gst_structure_get_int (s, "height", &h);
4527
4528   gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
4529   gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
4530       NULL);
4531
4532   return intersection;
4533 }
4534
4535 static GstFlowReturn
4536 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
4537     GstCaps * caps, GstBuffer ** buf)
4538 {
4539   GstFlowReturn ret = GST_FLOW_OK;
4540   GstXvImageSink *xvimagesink;
4541   GstXvImageBuffer *xvimage = NULL;
4542   GstCaps *intersection = NULL;
4543   GstStructure *structure = NULL;
4544   gint width, height, image_format;
4545
4546   xvimagesink = GST_XVIMAGESINK (bsink);
4547
4548   if (G_UNLIKELY (!caps))
4549     goto no_caps;
4550
4551   g_mutex_lock (xvimagesink->pool_lock);
4552   if (G_UNLIKELY (xvimagesink->pool_invalid))
4553     goto invalid;
4554
4555   if (G_LIKELY (xvimagesink->xcontext->last_caps &&
4556           gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
4557     GST_LOG_OBJECT (xvimagesink,
4558         "buffer alloc for same last_caps, reusing caps");
4559     intersection = gst_caps_ref (caps);
4560     image_format = xvimagesink->xcontext->last_format;
4561     width = xvimagesink->xcontext->last_width;
4562     height = xvimagesink->xcontext->last_height;
4563
4564     goto reuse_last_caps;
4565   }
4566
4567   GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
4568       GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
4569       caps, xvimagesink->xcontext->caps);
4570
4571   /* Check the caps against our xcontext */
4572   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
4573
4574   GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
4575       GST_PTR_FORMAT, intersection);
4576
4577   if (gst_caps_is_empty (intersection)) {
4578     GstCaps *new_caps;
4579
4580     gst_caps_unref (intersection);
4581
4582     /* So we don't support this kind of buffer, let's define one we'd like */
4583     new_caps = gst_caps_copy (caps);
4584
4585     structure = gst_caps_get_structure (new_caps, 0);
4586     if (!gst_structure_has_field (structure, "width") ||
4587         !gst_structure_has_field (structure, "height")) {
4588       gst_caps_unref (new_caps);
4589       goto invalid;
4590     }
4591
4592     /* Try different dimensions */
4593     intersection =
4594         gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4595
4596     if (gst_caps_is_empty (intersection)) {
4597       /* Try with different YUV formats first */
4598       gst_structure_set_name (structure, "video/x-raw-yuv");
4599
4600       /* Remove format specific fields */
4601       gst_structure_remove_field (structure, "format");
4602       gst_structure_remove_field (structure, "endianness");
4603       gst_structure_remove_field (structure, "depth");
4604       gst_structure_remove_field (structure, "bpp");
4605       gst_structure_remove_field (structure, "red_mask");
4606       gst_structure_remove_field (structure, "green_mask");
4607       gst_structure_remove_field (structure, "blue_mask");
4608       gst_structure_remove_field (structure, "alpha_mask");
4609
4610       /* Reuse intersection with Xcontext */
4611       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4612     }
4613
4614     if (gst_caps_is_empty (intersection)) {
4615       /* Try with different dimensions and YUV formats */
4616       intersection =
4617           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4618     }
4619
4620     if (gst_caps_is_empty (intersection)) {
4621       /* Now try with RGB */
4622       gst_structure_set_name (structure, "video/x-raw-rgb");
4623       /* And interset again */
4624       gst_caps_unref (intersection);
4625       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4626     }
4627
4628     if (gst_caps_is_empty (intersection)) {
4629       /* Try with different dimensions and RGB formats */
4630       intersection =
4631           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4632     }
4633
4634     /* Clean this copy */
4635     gst_caps_unref (new_caps);
4636
4637     if (gst_caps_is_empty (intersection))
4638       goto incompatible;
4639   }
4640
4641   /* Ensure the returned caps are fixed */
4642   gst_caps_truncate (intersection);
4643
4644   GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
4645       GST_PTR_FORMAT, intersection);
4646   if (gst_caps_is_equal (intersection, caps)) {
4647     /* Things work better if we return a buffer with the same caps ptr
4648      * as was asked for when we can */
4649     gst_caps_replace (&intersection, caps);
4650   }
4651
4652   /* Get image format from caps */
4653   image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
4654       intersection);
4655
4656   /* Get geometry from caps */
4657   structure = gst_caps_get_structure (intersection, 0);
4658   if (!gst_structure_get_int (structure, "width", &width) ||
4659       !gst_structure_get_int (structure, "height", &height) ||
4660       image_format == -1)
4661     goto invalid_caps;
4662
4663   /* Store our caps and format as the last_caps to avoid expensive
4664    * caps intersection next time */
4665   gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
4666   xvimagesink->xcontext->last_format = image_format;
4667   xvimagesink->xcontext->last_width = width;
4668   xvimagesink->xcontext->last_height = height;
4669
4670 reuse_last_caps:
4671
4672   /* Walking through the pool cleaning unusable images and searching for a
4673      suitable one */
4674   while (xvimagesink->image_pool) {
4675     xvimage = xvimagesink->image_pool->data;
4676
4677     if (xvimage) {
4678       /* Removing from the pool */
4679       xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4680           xvimagesink->image_pool);
4681
4682       /* We check for geometry or image format changes */
4683       if ((xvimage->width != width) ||
4684           (xvimage->height != height) || (xvimage->im_format != image_format)) {
4685         /* This image is unusable. Destroying... */
4686         gst_xvimage_buffer_free (xvimage);
4687         xvimage = NULL;
4688       } else {
4689         /* We found a suitable image */
4690         GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
4691         break;
4692       }
4693     }
4694   }
4695
4696   if (!xvimage) {
4697 #ifdef GST_EXT_XV_ENHANCEMENT
4698     /* init aligned size */
4699     xvimagesink->aligned_width = 0;
4700     xvimagesink->aligned_height = 0;
4701 #endif /* GST_EXT_XV_ENHANCEMENT */
4702
4703     /* We found no suitable image in the pool. Creating... */
4704     GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
4705     xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
4706   }
4707   g_mutex_unlock (xvimagesink->pool_lock);
4708
4709   if (xvimage) {
4710     /* Make sure the buffer is cleared of any previously used flags */
4711     GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
4712     gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
4713   }
4714
4715   *buf = GST_BUFFER_CAST (xvimage);
4716
4717 beach:
4718   if (intersection) {
4719     gst_caps_unref (intersection);
4720   }
4721
4722   return ret;
4723
4724   /* ERRORS */
4725 invalid:
4726   {
4727     GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
4728     ret = GST_FLOW_WRONG_STATE;
4729     g_mutex_unlock (xvimagesink->pool_lock);
4730     goto beach;
4731   }
4732 incompatible:
4733   {
4734     GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
4735         "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
4736         " are completely incompatible with those caps", caps,
4737         xvimagesink->xcontext->caps);
4738     ret = GST_FLOW_NOT_NEGOTIATED;
4739     g_mutex_unlock (xvimagesink->pool_lock);
4740     goto beach;
4741   }
4742 invalid_caps:
4743   {
4744     GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
4745         GST_PTR_FORMAT, intersection);
4746     ret = GST_FLOW_NOT_NEGOTIATED;
4747     g_mutex_unlock (xvimagesink->pool_lock);
4748     goto beach;
4749   }
4750 no_caps:
4751   {
4752     GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
4753     *buf = NULL;
4754     ret = GST_FLOW_OK;
4755     goto beach;
4756   }
4757 }
4758
4759 /* Interfaces stuff */
4760
4761 static gboolean
4762 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
4763 {
4764   if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
4765       type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
4766     return TRUE;
4767   else
4768     return FALSE;
4769 }
4770
4771 static void
4772 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
4773 {
4774   klass->supported = gst_xvimagesink_interface_supported;
4775 }
4776
4777 static void
4778 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
4779     GstStructure * structure)
4780 {
4781   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
4782   GstPad *peer;
4783
4784   if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
4785     GstEvent *event;
4786     GstVideoRectangle src, dst, result;
4787     gdouble x, y, xscale = 1.0, yscale = 1.0;
4788
4789     event = gst_event_new_navigation (structure);
4790
4791     /* We take the flow_lock while we look at the window */
4792     g_mutex_lock (xvimagesink->flow_lock);
4793
4794     if (!xvimagesink->xwindow) {
4795       g_mutex_unlock (xvimagesink->flow_lock);
4796       return;
4797     }
4798
4799     if (xvimagesink->keep_aspect) {
4800       /* We get the frame position using the calculated geometry from _setcaps
4801          that respect pixel aspect ratios */
4802       src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
4803       src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
4804       dst.w = xvimagesink->render_rect.w;
4805       dst.h = xvimagesink->render_rect.h;
4806
4807       gst_video_sink_center_rect (src, dst, &result, TRUE);
4808       result.x += xvimagesink->render_rect.x;
4809       result.y += xvimagesink->render_rect.y;
4810     } else {
4811       memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
4812     }
4813
4814     g_mutex_unlock (xvimagesink->flow_lock);
4815
4816     /* We calculate scaling using the original video frames geometry to include
4817        pixel aspect ratio scaling. */
4818     xscale = (gdouble) xvimagesink->video_width / result.w;
4819     yscale = (gdouble) xvimagesink->video_height / result.h;
4820
4821     /* Converting pointer coordinates to the non scaled geometry */
4822     if (gst_structure_get_double (structure, "pointer_x", &x)) {
4823       x = MIN (x, result.x + result.w);
4824       x = MAX (x - result.x, 0);
4825       gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
4826           (gdouble) x * xscale, NULL);
4827     }
4828     if (gst_structure_get_double (structure, "pointer_y", &y)) {
4829       y = MIN (y, result.y + result.h);
4830       y = MAX (y - result.y, 0);
4831       gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
4832           (gdouble) y * yscale, NULL);
4833     }
4834
4835     gst_pad_send_event (peer, event);
4836     gst_object_unref (peer);
4837   }
4838 }
4839
4840 static void
4841 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
4842 {
4843   iface->send_event = gst_xvimagesink_navigation_send_event;
4844 }
4845
4846 #ifdef GST_EXT_XV_ENHANCEMENT
4847 static void
4848 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
4849 {
4850   XID pixmap_id = id;
4851   int i = 0;
4852   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
4853   GstXPixmap *xpixmap = NULL;
4854
4855   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4856
4857   /* If the element has not initialized the X11 context try to do so */
4858   if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
4859     /* we have thrown a GST_ELEMENT_ERROR now */
4860     return;
4861   }
4862
4863   gst_xvimagesink_update_colorbalance (xvimagesink);
4864
4865   GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
4866
4867   /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
4868   if (pixmap_id == 0) {
4869     xvimagesink->current_pixmap_idx = -2;
4870     return;
4871   }
4872
4873   g_mutex_lock (xvimagesink->x_lock);
4874
4875   for (i = 0; i < MAX_PIXMAP_NUM; i++) {
4876     if (!xvimagesink->xpixmap[i]) {
4877       Window root_window;
4878       int cur_win_x = 0;
4879       int cur_win_y = 0;
4880       unsigned int cur_win_width = 0;
4881       unsigned int cur_win_height = 0;
4882       unsigned int cur_win_border_width = 0;
4883       unsigned int cur_win_depth = 0;
4884
4885       GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
4886
4887       xpixmap = g_new0 (GstXPixmap, 1);
4888       if (xpixmap) {
4889         xpixmap->pixmap = pixmap_id;
4890
4891         /* Get root window and size of current window */
4892         XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
4893                      &cur_win_x, &cur_win_y, /* relative x, y */
4894                      &cur_win_width, &cur_win_height,
4895                      &cur_win_border_width, &cur_win_depth);
4896         if (!cur_win_width || !cur_win_height) {
4897           GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
4898           g_mutex_unlock (xvimagesink->x_lock);
4899           return;
4900         }
4901         xpixmap->width = cur_win_width;
4902         xpixmap->height = cur_win_height;
4903
4904         if (!xvimagesink->render_rect.w)
4905           xvimagesink->render_rect.w = cur_win_width;
4906         if (!xvimagesink->render_rect.h)
4907           xvimagesink->render_rect.h = cur_win_height;
4908
4909         /* Create a GC */
4910         xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
4911
4912         xvimagesink->xpixmap[i] = xpixmap;
4913         xvimagesink->current_pixmap_idx = i;
4914       } else {
4915         GST_ERROR("failed to create xpixmap errno: %d", errno);
4916       }
4917
4918       g_mutex_unlock (xvimagesink->x_lock);
4919       return;
4920
4921     } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
4922       GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
4923       xvimagesink->current_pixmap_idx = i;
4924
4925       g_mutex_unlock (xvimagesink->x_lock);
4926       return;
4927
4928     } else {
4929       continue;
4930     }
4931   }
4932
4933   GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
4934   xvimagesink->current_pixmap_idx = -1;
4935
4936   g_mutex_unlock (xvimagesink->x_lock);
4937   return;
4938 }
4939 #endif /* GST_EXT_XV_ENHANCEMENT */
4940
4941 static void
4942 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
4943 {
4944   XID xwindow_id = id;
4945   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
4946   GstXWindow *xwindow = NULL;
4947 #ifdef GST_EXT_XV_ENHANCEMENT
4948   GstState current_state = GST_STATE_NULL;
4949 #endif /* GST_EXT_XV_ENHANCEMENT */
4950
4951   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4952
4953   g_mutex_lock (xvimagesink->flow_lock);
4954
4955 #ifdef GST_EXT_XV_ENHANCEMENT
4956   gst_element_get_state(GST_ELEMENT(xvimagesink), &current_state, NULL, 0);
4957   GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
4958                                   xwindow_id, current_state);
4959 #endif /* GST_EXT_XV_ENHANCEMENT */
4960
4961   /* If we already use that window return */
4962   if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
4963     g_mutex_unlock (xvimagesink->flow_lock);
4964     return;
4965   }
4966
4967   /* If the element has not initialized the X11 context try to do so */
4968   if (!xvimagesink->xcontext &&
4969       !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
4970     g_mutex_unlock (xvimagesink->flow_lock);
4971     /* we have thrown a GST_ELEMENT_ERROR now */
4972     return;
4973   }
4974
4975   gst_xvimagesink_update_colorbalance (xvimagesink);
4976
4977   /* Clear image pool as the images are unusable anyway */
4978   gst_xvimagesink_imagepool_clear (xvimagesink);
4979
4980   /* Clear the xvimage */
4981   if (xvimagesink->xvimage) {
4982     gst_xvimage_buffer_free (xvimagesink->xvimage);
4983     xvimagesink->xvimage = NULL;
4984   }
4985
4986   /* If a window is there already we destroy it */
4987   if (xvimagesink->xwindow) {
4988     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
4989     xvimagesink->xwindow = NULL;
4990   }
4991
4992   /* If the xid is 0 we go back to an internal window */
4993   if (xwindow_id == 0) {
4994     /* If no width/height caps nego did not happen window will be created
4995        during caps nego then */
4996 #ifdef GST_EXT_XV_ENHANCEMENT
4997   GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
4998     GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
4999 #endif /* GST_EXT_XV_ENHANCEMENT */
5000     if (GST_VIDEO_SINK_WIDTH (xvimagesink)
5001         && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
5002       xwindow =
5003           gst_xvimagesink_xwindow_new (xvimagesink,
5004           GST_VIDEO_SINK_WIDTH (xvimagesink),
5005           GST_VIDEO_SINK_HEIGHT (xvimagesink));
5006     }
5007   } else {
5008     XWindowAttributes attr;
5009
5010     xwindow = g_new0 (GstXWindow, 1);
5011     xwindow->win = xwindow_id;
5012
5013     /* Set the event we want to receive and create a GC */
5014     g_mutex_lock (xvimagesink->x_lock);
5015
5016     XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
5017
5018     xwindow->width = attr.width;
5019     xwindow->height = attr.height;
5020     xwindow->internal = FALSE;
5021     if (!xvimagesink->have_render_rect) {
5022       xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
5023       xvimagesink->render_rect.w = attr.width;
5024       xvimagesink->render_rect.h = attr.height;
5025     }
5026     if (xvimagesink->handle_events) {
5027       XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
5028           StructureNotifyMask | PointerMotionMask | KeyPressMask |
5029           KeyReleaseMask);
5030     }
5031
5032     xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
5033         xwindow->win, 0, NULL);
5034     g_mutex_unlock (xvimagesink->x_lock);
5035   }
5036
5037   if (xwindow)
5038     xvimagesink->xwindow = xwindow;
5039
5040 #ifdef GST_EXT_XV_ENHANCEMENT
5041   xvimagesink->xid_updated = TRUE;
5042 #endif /* GST_EXT_XV_ENHANCEMENT */
5043
5044   g_mutex_unlock (xvimagesink->flow_lock);
5045
5046 #ifdef GST_EXT_XV_ENHANCEMENT
5047   if (current_state == GST_STATE_PAUSED) {
5048     GstBuffer *last_buffer = NULL;
5049     g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
5050     GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
5051     if (last_buffer) {
5052       gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
5053       gst_buffer_unref(last_buffer);
5054       last_buffer = NULL;
5055     }
5056   }
5057 #endif /* GST_EXT_XV_ENHANCEMENT */
5058 }
5059
5060 static void
5061 gst_xvimagesink_expose (GstXOverlay * overlay)
5062 {
5063   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5064
5065   gst_xvimagesink_xwindow_update_geometry (xvimagesink);
5066 #ifdef GST_EXT_XV_ENHANCEMENT
5067   GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it");
5068   gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5069 #else /* GST_EXT_XV_ENHANCEMENT */
5070   gst_xvimagesink_xvimage_put (xvimagesink, NULL);
5071 #endif /* GST_EXT_XV_ENHANCEMENT */
5072 }
5073
5074 static void
5075 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
5076     gboolean handle_events)
5077 {
5078   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5079
5080   xvimagesink->handle_events = handle_events;
5081
5082   g_mutex_lock (xvimagesink->flow_lock);
5083
5084   if (G_UNLIKELY (!xvimagesink->xwindow)) {
5085     g_mutex_unlock (xvimagesink->flow_lock);
5086     return;
5087   }
5088
5089   g_mutex_lock (xvimagesink->x_lock);
5090
5091   if (handle_events) {
5092     if (xvimagesink->xwindow->internal) {
5093       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
5094 #ifdef GST_EXT_XV_ENHANCEMENT
5095           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
5096 #else /* GST_EXT_XV_ENHANCEMENT */
5097           ExposureMask | StructureNotifyMask | PointerMotionMask |
5098 #endif /* GST_EXT_XV_ENHANCEMENT */
5099           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
5100     } else {
5101       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
5102 #ifdef GST_EXT_XV_ENHANCEMENT
5103           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
5104 #else /* GST_EXT_XV_ENHANCEMENT */
5105           ExposureMask | StructureNotifyMask | PointerMotionMask |
5106 #endif /* GST_EXT_XV_ENHANCEMENT */
5107           KeyPressMask | KeyReleaseMask);
5108     }
5109   } else {
5110     XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
5111   }
5112
5113   g_mutex_unlock (xvimagesink->x_lock);
5114
5115   g_mutex_unlock (xvimagesink->flow_lock);
5116 }
5117
5118 static void
5119 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
5120     gint width, gint height)
5121 {
5122   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5123
5124   /* FIXME: how about some locking? */
5125   if (width >= 0 && height >= 0) {
5126     xvimagesink->render_rect.x = x;
5127     xvimagesink->render_rect.y = y;
5128     xvimagesink->render_rect.w = width;
5129     xvimagesink->render_rect.h = height;
5130     xvimagesink->have_render_rect = TRUE;
5131   } else {
5132     xvimagesink->render_rect.x = 0;
5133     xvimagesink->render_rect.y = 0;
5134     xvimagesink->render_rect.w = xvimagesink->xwindow->width;
5135     xvimagesink->render_rect.h = xvimagesink->xwindow->height;
5136     xvimagesink->have_render_rect = FALSE;
5137   }
5138 }
5139
5140 static void
5141 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
5142 {
5143   iface->set_window_handle = gst_xvimagesink_set_window_handle;
5144   iface->expose = gst_xvimagesink_expose;
5145   iface->handle_events = gst_xvimagesink_set_event_handling;
5146   iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
5147 }
5148
5149 static const GList *
5150 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
5151 {
5152   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5153
5154   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
5155
5156   if (xvimagesink->xcontext)
5157     return xvimagesink->xcontext->channels_list;
5158   else
5159     return NULL;
5160 }
5161
5162 static void
5163 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
5164     GstColorBalanceChannel * channel, gint value)
5165 {
5166   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5167
5168   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
5169   g_return_if_fail (channel->label != NULL);
5170
5171   xvimagesink->cb_changed = TRUE;
5172
5173   /* Normalize val to [-1000, 1000] */
5174   value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
5175       (double) (channel->max_value - channel->min_value));
5176
5177   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
5178     xvimagesink->hue = value;
5179   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
5180     xvimagesink->saturation = value;
5181   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
5182     xvimagesink->contrast = value;
5183   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
5184     xvimagesink->brightness = value;
5185   } else {
5186     g_warning ("got an unknown channel %s", channel->label);
5187     return;
5188   }
5189
5190   gst_xvimagesink_update_colorbalance (xvimagesink);
5191 }
5192
5193 static gint
5194 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
5195     GstColorBalanceChannel * channel)
5196 {
5197   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5198   gint value = 0;
5199
5200   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
5201   g_return_val_if_fail (channel->label != NULL, 0);
5202
5203   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
5204     value = xvimagesink->hue;
5205   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
5206     value = xvimagesink->saturation;
5207   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
5208     value = xvimagesink->contrast;
5209   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
5210     value = xvimagesink->brightness;
5211   } else {
5212     g_warning ("got an unknown channel %s", channel->label);
5213   }
5214
5215   /* Normalize val to [channel->min_value, channel->max_value] */
5216   value = channel->min_value + (channel->max_value - channel->min_value) *
5217       (value + 1000) / 2000;
5218
5219   return value;
5220 }
5221
5222 static void
5223 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
5224 {
5225   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
5226   iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
5227   iface->set_value = gst_xvimagesink_colorbalance_set_value;
5228   iface->get_value = gst_xvimagesink_colorbalance_get_value;
5229 }
5230
5231 static const GList *
5232 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
5233 {
5234   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
5235   static GList *list = NULL;
5236
5237   if (!list) {
5238     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
5239     list =
5240         g_list_append (list, g_object_class_find_property (klass,
5241             "autopaint-colorkey"));
5242     list =
5243         g_list_append (list, g_object_class_find_property (klass,
5244             "double-buffer"));
5245     list =
5246         g_list_append (list, g_object_class_find_property (klass, "colorkey"));
5247   }
5248
5249   return list;
5250 }
5251
5252 static void
5253 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
5254     guint prop_id, const GParamSpec * pspec)
5255 {
5256   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5257
5258   switch (prop_id) {
5259     case PROP_DEVICE:
5260     case PROP_AUTOPAINT_COLORKEY:
5261     case PROP_DOUBLE_BUFFER:
5262     case PROP_COLORKEY:
5263       GST_DEBUG_OBJECT (xvimagesink,
5264           "probing device list and get capabilities");
5265       if (!xvimagesink->xcontext) {
5266         GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
5267         xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
5268       }
5269       break;
5270     default:
5271       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5272       break;
5273   }
5274 }
5275
5276 static gboolean
5277 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
5278     guint prop_id, const GParamSpec * pspec)
5279 {
5280   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5281   gboolean ret = FALSE;
5282
5283   switch (prop_id) {
5284     case PROP_DEVICE:
5285     case PROP_AUTOPAINT_COLORKEY:
5286     case PROP_DOUBLE_BUFFER:
5287     case PROP_COLORKEY:
5288       if (xvimagesink->xcontext != NULL) {
5289         ret = FALSE;
5290       } else {
5291         ret = TRUE;
5292       }
5293       break;
5294     default:
5295       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5296       break;
5297   }
5298
5299   return ret;
5300 }
5301
5302 static GValueArray *
5303 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
5304     guint prop_id, const GParamSpec * pspec)
5305 {
5306   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5307   GValueArray *array = NULL;
5308
5309   if (G_UNLIKELY (!xvimagesink->xcontext)) {
5310     GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
5311         "get values");
5312     goto beach;
5313   }
5314
5315   switch (prop_id) {
5316     case PROP_DEVICE:
5317     {
5318       guint i;
5319       GValue value = { 0 };
5320
5321       array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
5322       g_value_init (&value, G_TYPE_STRING);
5323
5324       for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
5325         gchar *adaptor_id_s = g_strdup_printf ("%u", i);
5326
5327         g_value_set_string (&value, adaptor_id_s);
5328         g_value_array_append (array, &value);
5329         g_free (adaptor_id_s);
5330       }
5331       g_value_unset (&value);
5332       break;
5333     }
5334     case PROP_AUTOPAINT_COLORKEY:
5335       if (xvimagesink->have_autopaint_colorkey) {
5336         GValue value = { 0 };
5337
5338         array = g_value_array_new (2);
5339         g_value_init (&value, G_TYPE_BOOLEAN);
5340         g_value_set_boolean (&value, FALSE);
5341         g_value_array_append (array, &value);
5342         g_value_set_boolean (&value, TRUE);
5343         g_value_array_append (array, &value);
5344         g_value_unset (&value);
5345       }
5346       break;
5347     case PROP_DOUBLE_BUFFER:
5348       if (xvimagesink->have_double_buffer) {
5349         GValue value = { 0 };
5350
5351         array = g_value_array_new (2);
5352         g_value_init (&value, G_TYPE_BOOLEAN);
5353         g_value_set_boolean (&value, FALSE);
5354         g_value_array_append (array, &value);
5355         g_value_set_boolean (&value, TRUE);
5356         g_value_array_append (array, &value);
5357         g_value_unset (&value);
5358       }
5359       break;
5360     case PROP_COLORKEY:
5361       if (xvimagesink->have_colorkey) {
5362         GValue value = { 0 };
5363
5364         array = g_value_array_new (1);
5365         g_value_init (&value, GST_TYPE_INT_RANGE);
5366         gst_value_set_int_range (&value, 0, 0xffffff);
5367         g_value_array_append (array, &value);
5368         g_value_unset (&value);
5369       }
5370       break;
5371     default:
5372       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5373       break;
5374   }
5375
5376 beach:
5377   return array;
5378 }
5379
5380 static void
5381 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
5382     iface)
5383 {
5384   iface->get_properties = gst_xvimagesink_probe_get_properties;
5385   iface->probe_property = gst_xvimagesink_probe_probe_property;
5386   iface->needs_probe = gst_xvimagesink_probe_needs_probe;
5387   iface->get_values = gst_xvimagesink_probe_get_values;
5388 }
5389
5390 /* =========================================== */
5391 /*                                             */
5392 /*              Init & Class init              */
5393 /*                                             */
5394 /* =========================================== */
5395
5396 static void
5397 gst_xvimagesink_set_property (GObject * object, guint prop_id,
5398     const GValue * value, GParamSpec * pspec)
5399 {
5400   GstXvImageSink *xvimagesink;
5401
5402   g_return_if_fail (GST_IS_XVIMAGESINK (object));
5403
5404   xvimagesink = GST_XVIMAGESINK (object);
5405
5406   switch (prop_id) {
5407     case PROP_HUE:
5408       xvimagesink->hue = g_value_get_int (value);
5409       xvimagesink->cb_changed = TRUE;
5410       gst_xvimagesink_update_colorbalance (xvimagesink);
5411       break;
5412     case PROP_CONTRAST:
5413       xvimagesink->contrast = g_value_get_int (value);
5414       xvimagesink->cb_changed = TRUE;
5415       gst_xvimagesink_update_colorbalance (xvimagesink);
5416       break;
5417     case PROP_BRIGHTNESS:
5418       xvimagesink->brightness = g_value_get_int (value);
5419       xvimagesink->cb_changed = TRUE;
5420       gst_xvimagesink_update_colorbalance (xvimagesink);
5421       break;
5422     case PROP_SATURATION:
5423       xvimagesink->saturation = g_value_get_int (value);
5424       xvimagesink->cb_changed = TRUE;
5425       gst_xvimagesink_update_colorbalance (xvimagesink);
5426       break;
5427     case PROP_DISPLAY:
5428       xvimagesink->display_name = g_strdup (g_value_get_string (value));
5429       break;
5430     case PROP_SYNCHRONOUS:
5431       xvimagesink->synchronous = g_value_get_boolean (value);
5432       if (xvimagesink->xcontext) {
5433         XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
5434         GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
5435             xvimagesink->synchronous ? "TRUE" : "FALSE");
5436       }
5437       break;
5438     case PROP_PIXEL_ASPECT_RATIO:
5439       g_free (xvimagesink->par);
5440       xvimagesink->par = g_new0 (GValue, 1);
5441       g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
5442       if (!g_value_transform (value, xvimagesink->par)) {
5443         g_warning ("Could not transform string to aspect ratio");
5444         gst_value_set_fraction (xvimagesink->par, 1, 1);
5445       }
5446       GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
5447           gst_value_get_fraction_numerator (xvimagesink->par),
5448           gst_value_get_fraction_denominator (xvimagesink->par));
5449       break;
5450     case PROP_FORCE_ASPECT_RATIO:
5451       xvimagesink->keep_aspect = g_value_get_boolean (value);
5452       break;
5453     case PROP_HANDLE_EVENTS:
5454       gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
5455           g_value_get_boolean (value));
5456       gst_xvimagesink_manage_event_thread (xvimagesink);
5457       break;
5458     case PROP_DEVICE:
5459       xvimagesink->adaptor_no = atoi (g_value_get_string (value));
5460       break;
5461     case PROP_HANDLE_EXPOSE:
5462       xvimagesink->handle_expose = g_value_get_boolean (value);
5463       gst_xvimagesink_manage_event_thread (xvimagesink);
5464       break;
5465     case PROP_DOUBLE_BUFFER:
5466       xvimagesink->double_buffer = g_value_get_boolean (value);
5467       break;
5468     case PROP_AUTOPAINT_COLORKEY:
5469       xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
5470       break;
5471     case PROP_COLORKEY:
5472       xvimagesink->colorkey = g_value_get_int (value);
5473       break;
5474     case PROP_DRAW_BORDERS:
5475       xvimagesink->draw_borders = g_value_get_boolean (value);
5476       break;
5477 #ifdef GST_EXT_XV_ENHANCEMENT
5478     case PROP_DISPLAY_MODE:
5479     {
5480       int set_mode = g_value_get_enum (value);
5481
5482       g_mutex_lock(xvimagesink->flow_lock);
5483       g_mutex_lock(xvimagesink->x_lock);
5484
5485       if (xvimagesink->display_mode != set_mode) {
5486         if (xvimagesink->xcontext) {
5487           /* set display mode */
5488           if (set_display_mode(xvimagesink->xcontext, set_mode)) {
5489             xvimagesink->display_mode = set_mode;
5490           } else {
5491             GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
5492           }
5493         } else {
5494           /* "xcontext" is not created yet. It will be applied when xcontext is created. */
5495           GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
5496           xvimagesink->display_mode = set_mode;
5497         }
5498       } else {
5499         GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
5500       }
5501
5502       g_mutex_unlock(xvimagesink->x_lock);
5503       g_mutex_unlock(xvimagesink->flow_lock);
5504     }
5505       break;
5506     case PROP_CSC_RANGE:
5507     {
5508       int set_range = g_value_get_enum (value);
5509
5510       g_mutex_lock(xvimagesink->flow_lock);
5511       g_mutex_lock(xvimagesink->x_lock);
5512
5513       if (xvimagesink->csc_range != set_range) {
5514         if (xvimagesink->xcontext) {
5515           /* set color space range */
5516           if (set_csc_range(xvimagesink->xcontext, set_range)) {
5517             xvimagesink->csc_range = set_range;
5518           } else {
5519             GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
5520           }
5521         } else {
5522           /* "xcontext" is not created yet. It will be applied when xcontext is created. */
5523           GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
5524           xvimagesink->csc_range = set_range;
5525         }
5526       } else {
5527         GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
5528       }
5529
5530       g_mutex_unlock(xvimagesink->x_lock);
5531       g_mutex_unlock(xvimagesink->flow_lock);
5532     }
5533       break;
5534     case PROP_DISPLAY_GEOMETRY_METHOD:
5535       xvimagesink->display_geometry_method = g_value_get_enum (value);
5536       GST_LOG("Overlay geometry changed. update it");
5537       gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5538       break;
5539     case PROP_FLIP:
5540       xvimagesink->flip = g_value_get_enum(value);
5541       break;
5542     case PROP_ROTATE_ANGLE:
5543       xvimagesink->rotate_angle = g_value_get_enum (value);
5544       xvimagesink->rotate_changed = TRUE;
5545       break;
5546     case PROP_VISIBLE:
5547       g_mutex_lock( xvimagesink->flow_lock );
5548       g_mutex_lock( xvimagesink->x_lock );
5549
5550       GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
5551
5552       if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
5553         if (xvimagesink->xcontext) {
5554 #if 0
5555           Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
5556                                           "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
5557           if (atom_stream != None) {
5558             GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
5559             if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5560                                    xvimagesink->xcontext->xv_port_id,
5561                                    atom_stream, 0 ) != Success) {
5562               GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
5563             }
5564           }
5565 #endif
5566           xvimagesink->visible = g_value_get_boolean (value);
5567           if ( xvimagesink->get_pixmap_cb ) {
5568             if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5569               XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5570               }
5571           } else {
5572             XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
5573           }
5574           XSync( xvimagesink->xcontext->disp, FALSE );
5575         } else {
5576           GST_WARNING_OBJECT( xvimagesink, "xcontext is null, failed to set visible");
5577           g_mutex_unlock( xvimagesink->x_lock );
5578           g_mutex_unlock( xvimagesink->flow_lock );
5579           break;
5580         }
5581       } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
5582         g_mutex_unlock( xvimagesink->x_lock );
5583         g_mutex_unlock( xvimagesink->flow_lock );
5584         GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." );
5585         xvimagesink->visible = g_value_get_boolean (value);
5586         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5587         g_mutex_lock( xvimagesink->flow_lock );
5588         g_mutex_lock( xvimagesink->x_lock );
5589       }
5590
5591       GST_INFO("set visible done");
5592
5593       g_mutex_unlock( xvimagesink->x_lock );
5594       g_mutex_unlock( xvimagesink->flow_lock );
5595       break;
5596     case PROP_ZOOM:
5597       xvimagesink->zoom = g_value_get_int (value);
5598       break;
5599     case PROP_DST_ROI_X:
5600       xvimagesink->dst_roi.x = g_value_get_int (value);
5601       break;
5602     case PROP_DST_ROI_Y:
5603       xvimagesink->dst_roi.y = g_value_get_int (value);
5604       break;
5605     case PROP_DST_ROI_W:
5606       xvimagesink->dst_roi.w = g_value_get_int (value);
5607       break;
5608     case PROP_DST_ROI_H:
5609       xvimagesink->dst_roi.h = g_value_get_int (value);
5610       break;
5611     case PROP_STOP_VIDEO:
5612       xvimagesink->stop_video = g_value_get_int (value);
5613       g_mutex_lock( xvimagesink->flow_lock );
5614
5615       if( xvimagesink->stop_video )
5616       {
5617         if ( xvimagesink->get_pixmap_cb ) {
5618           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5619             g_mutex_lock (xvimagesink->x_lock);
5620             GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
5621             XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5622             g_mutex_unlock (xvimagesink->x_lock);
5623           }
5624         } else {
5625           GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
5626           gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
5627         }
5628       }
5629
5630       g_mutex_unlock( xvimagesink->flow_lock );
5631       break;
5632     case PROP_PIXMAP_CB:
5633     {
5634       void *cb_func;
5635       cb_func = g_value_get_pointer(value);
5636       if (cb_func) {
5637         xvimagesink->get_pixmap_cb = cb_func;
5638         GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
5639       }
5640       break;
5641     }
5642     case PROP_PIXMAP_CB_USER_DATA:
5643     {
5644       void *user_data;
5645       user_data = g_value_get_pointer(value);
5646       if (user_data) {
5647         xvimagesink->get_pixmap_cb_user_data = user_data;
5648         GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
5649       }
5650       break;
5651     }
5652 #endif /* GST_EXT_XV_ENHANCEMENT */
5653     default:
5654       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5655       break;
5656   }
5657 }
5658
5659 static void
5660 gst_xvimagesink_get_property (GObject * object, guint prop_id,
5661     GValue * value, GParamSpec * pspec)
5662 {
5663   GstXvImageSink *xvimagesink;
5664
5665   g_return_if_fail (GST_IS_XVIMAGESINK (object));
5666
5667   xvimagesink = GST_XVIMAGESINK (object);
5668
5669   switch (prop_id) {
5670     case PROP_HUE:
5671       g_value_set_int (value, xvimagesink->hue);
5672       break;
5673     case PROP_CONTRAST:
5674       g_value_set_int (value, xvimagesink->contrast);
5675       break;
5676     case PROP_BRIGHTNESS:
5677       g_value_set_int (value, xvimagesink->brightness);
5678       break;
5679     case PROP_SATURATION:
5680       g_value_set_int (value, xvimagesink->saturation);
5681       break;
5682     case PROP_DISPLAY:
5683       g_value_set_string (value, xvimagesink->display_name);
5684       break;
5685     case PROP_SYNCHRONOUS:
5686       g_value_set_boolean (value, xvimagesink->synchronous);
5687       break;
5688     case PROP_PIXEL_ASPECT_RATIO:
5689       if (xvimagesink->par)
5690         g_value_transform (xvimagesink->par, value);
5691       break;
5692     case PROP_FORCE_ASPECT_RATIO:
5693       g_value_set_boolean (value, xvimagesink->keep_aspect);
5694       break;
5695     case PROP_HANDLE_EVENTS:
5696       g_value_set_boolean (value, xvimagesink->handle_events);
5697       break;
5698     case PROP_DEVICE:
5699     {
5700       char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
5701
5702       g_value_set_string (value, adaptor_no_s);
5703       g_free (adaptor_no_s);
5704       break;
5705     }
5706     case PROP_DEVICE_NAME:
5707       if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
5708         g_value_set_string (value,
5709             xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
5710       } else {
5711         g_value_set_string (value, NULL);
5712       }
5713       break;
5714     case PROP_HANDLE_EXPOSE:
5715       g_value_set_boolean (value, xvimagesink->handle_expose);
5716       break;
5717     case PROP_DOUBLE_BUFFER:
5718       g_value_set_boolean (value, xvimagesink->double_buffer);
5719       break;
5720     case PROP_AUTOPAINT_COLORKEY:
5721       g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
5722       break;
5723     case PROP_COLORKEY:
5724       g_value_set_int (value, xvimagesink->colorkey);
5725       break;
5726     case PROP_DRAW_BORDERS:
5727       g_value_set_boolean (value, xvimagesink->draw_borders);
5728       break;
5729     case PROP_WINDOW_WIDTH:
5730       if (xvimagesink->xwindow)
5731         g_value_set_uint64 (value, xvimagesink->xwindow->width);
5732       else
5733         g_value_set_uint64 (value, 0);
5734       break;
5735     case PROP_WINDOW_HEIGHT:
5736       if (xvimagesink->xwindow)
5737         g_value_set_uint64 (value, xvimagesink->xwindow->height);
5738       else
5739         g_value_set_uint64 (value, 0);
5740       break;
5741 #ifdef GST_EXT_XV_ENHANCEMENT
5742     case PROP_DISPLAY_MODE:
5743       g_value_set_enum (value, xvimagesink->display_mode);
5744       break;
5745     case PROP_CSC_RANGE:
5746       g_value_set_enum (value, xvimagesink->csc_range);
5747       break;
5748     case PROP_DISPLAY_GEOMETRY_METHOD:
5749       g_value_set_enum (value, xvimagesink->display_geometry_method);
5750       break;
5751     case PROP_FLIP:
5752       g_value_set_enum(value, xvimagesink->flip);
5753       break;
5754     case PROP_ROTATE_ANGLE:
5755       g_value_set_enum (value, xvimagesink->rotate_angle);
5756       break;
5757     case PROP_VISIBLE:
5758       g_value_set_boolean (value, xvimagesink->visible);
5759       break;
5760     case PROP_ZOOM:
5761       g_value_set_int (value, xvimagesink->zoom);
5762       break;
5763     case PROP_DST_ROI_X:
5764       g_value_set_int (value, xvimagesink->dst_roi.x);
5765       break;
5766     case PROP_DST_ROI_Y:
5767       g_value_set_int (value, xvimagesink->dst_roi.y);
5768       break;
5769     case PROP_DST_ROI_W:
5770       g_value_set_int (value, xvimagesink->dst_roi.w);
5771       break;
5772     case PROP_DST_ROI_H:
5773       g_value_set_int (value, xvimagesink->dst_roi.h);
5774       break;
5775     case PROP_STOP_VIDEO:
5776       g_value_set_int (value, xvimagesink->stop_video);
5777       break;
5778     case PROP_PIXMAP_CB:
5779       g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
5780       break;
5781     case PROP_PIXMAP_CB_USER_DATA:
5782       g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
5783       break;
5784 #endif /* GST_EXT_XV_ENHANCEMENT */
5785     default:
5786       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5787       break;
5788   }
5789 }
5790
5791 static void
5792 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
5793 {
5794   GThread *thread;
5795
5796   GST_OBJECT_LOCK (xvimagesink);
5797   xvimagesink->running = FALSE;
5798   /* grab thread and mark it as NULL */
5799   thread = xvimagesink->event_thread;
5800   xvimagesink->event_thread = NULL;
5801   GST_OBJECT_UNLOCK (xvimagesink);
5802
5803   /* invalidate the pool, current allocations continue, new buffer_alloc fails
5804    * with wrong_state */
5805   g_mutex_lock (xvimagesink->pool_lock);
5806   xvimagesink->pool_invalid = TRUE;
5807   g_mutex_unlock (xvimagesink->pool_lock);
5808
5809   /* Wait for our event thread to finish before we clean up our stuff. */
5810   if (thread)
5811     g_thread_join (thread);
5812
5813   if (xvimagesink->cur_image) {
5814     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
5815     xvimagesink->cur_image = NULL;
5816   }
5817   if (xvimagesink->xvimage) {
5818     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
5819     xvimagesink->xvimage = NULL;
5820   }
5821
5822   gst_xvimagesink_imagepool_clear (xvimagesink);
5823
5824   if (xvimagesink->xwindow) {
5825     gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
5826     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
5827     xvimagesink->xwindow = NULL;
5828   }
5829 #ifdef GST_EXT_XV_ENHANCEMENT
5830   if (xvimagesink->get_pixmap_cb) {
5831     int i = 0;
5832     if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5833       g_mutex_lock (xvimagesink->x_lock);
5834       GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
5835       XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5836       g_mutex_unlock (xvimagesink->x_lock);
5837     }
5838     for (i = 0; i < MAX_PIXMAP_NUM; i++) {
5839       if (xvimagesink->xpixmap[i]) {
5840         gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
5841         xvimagesink->xpixmap[i] = NULL;
5842       }
5843     }
5844     xvimagesink->get_pixmap_cb = NULL;
5845     xvimagesink->get_pixmap_cb_user_data = NULL;
5846   }
5847 #endif /* GST_EXT_XV_ENHANCEMENT */
5848   xvimagesink->render_rect.x = xvimagesink->render_rect.y =
5849       xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
5850   xvimagesink->have_render_rect = FALSE;
5851
5852   gst_xvimagesink_xcontext_clear (xvimagesink);
5853 }
5854
5855 /* Finalize is called only once, dispose can be called multiple times.
5856  * We use mutexes and don't reset stuff to NULL here so let's register
5857  * as a finalize. */
5858 static void
5859 gst_xvimagesink_finalize (GObject * object)
5860 {
5861   GstXvImageSink *xvimagesink;
5862
5863   xvimagesink = GST_XVIMAGESINK (object);
5864
5865   gst_xvimagesink_reset (xvimagesink);
5866
5867   if (xvimagesink->display_name) {
5868     g_free (xvimagesink->display_name);
5869     xvimagesink->display_name = NULL;
5870   }
5871
5872   if (xvimagesink->par) {
5873     g_free (xvimagesink->par);
5874     xvimagesink->par = NULL;
5875   }
5876   if (xvimagesink->x_lock) {
5877     g_mutex_free (xvimagesink->x_lock);
5878     xvimagesink->x_lock = NULL;
5879   }
5880   if (xvimagesink->flow_lock) {
5881     g_mutex_free (xvimagesink->flow_lock);
5882     xvimagesink->flow_lock = NULL;
5883   }
5884   if (xvimagesink->pool_lock) {
5885     g_mutex_free (xvimagesink->pool_lock);
5886     xvimagesink->pool_lock = NULL;
5887   }
5888 #ifdef GST_EXT_XV_ENHANCEMENT
5889   if (xvimagesink->display_buffer_lock) {
5890     g_mutex_free (xvimagesink->display_buffer_lock);
5891     xvimagesink->display_buffer_lock = NULL;
5892   }
5893   if (xvimagesink->display_buffer_cond) {
5894     g_cond_free (xvimagesink->display_buffer_cond);
5895     xvimagesink->display_buffer_cond = NULL;
5896   }
5897 #endif /* GST_EXT_XV_ENHANCEMENT */
5898
5899   g_free (xvimagesink->media_title);
5900
5901   G_OBJECT_CLASS (parent_class)->finalize (object);
5902 }
5903
5904 static void
5905 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
5906     GstXvImageSinkClass * xvimagesinkclass)
5907 {
5908 #ifdef GST_EXT_XV_ENHANCEMENT
5909   int i;
5910   int j;
5911 #endif /* GST_EXT_XV_ENHANCEMENT */
5912
5913   xvimagesink->display_name = NULL;
5914   xvimagesink->adaptor_no = 0;
5915   xvimagesink->xcontext = NULL;
5916   xvimagesink->xwindow = NULL;
5917   xvimagesink->xvimage = NULL;
5918   xvimagesink->cur_image = NULL;
5919
5920   xvimagesink->hue = xvimagesink->saturation = 0;
5921   xvimagesink->contrast = xvimagesink->brightness = 0;
5922   xvimagesink->cb_changed = FALSE;
5923
5924   xvimagesink->fps_n = 0;
5925   xvimagesink->fps_d = 0;
5926   xvimagesink->video_width = 0;
5927   xvimagesink->video_height = 0;
5928
5929   xvimagesink->x_lock = g_mutex_new ();
5930   xvimagesink->flow_lock = g_mutex_new ();
5931
5932   xvimagesink->image_pool = NULL;
5933   xvimagesink->pool_lock = g_mutex_new ();
5934
5935   xvimagesink->synchronous = FALSE;
5936   xvimagesink->double_buffer = TRUE;
5937   xvimagesink->running = FALSE;
5938   xvimagesink->keep_aspect = FALSE;
5939   xvimagesink->handle_events = TRUE;
5940   xvimagesink->par = NULL;
5941   xvimagesink->handle_expose = TRUE;
5942   xvimagesink->autopaint_colorkey = TRUE;
5943
5944   /* on 16bit displays this becomes r,g,b = 1,2,3
5945    * on 24bit displays this becomes r,g,b = 8,8,16
5946    * as a port atom value
5947    */
5948   xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
5949   xvimagesink->draw_borders = TRUE;
5950
5951 #ifdef GST_EXT_XV_ENHANCEMENT
5952   xvimagesink->xid_updated = FALSE;
5953   xvimagesink->display_mode = DISPLAY_MODE_DEFAULT;
5954   xvimagesink->csc_range = CSC_RANGE_NARROW;
5955   xvimagesink->rotate_changed = TRUE;
5956   xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
5957   xvimagesink->flip = DEF_DISPLAY_FLIP;
5958   xvimagesink->rotate_angle = DEGREE_270;
5959   xvimagesink->visible = TRUE;
5960   xvimagesink->zoom = 1;
5961   xvimagesink->rotation = -1;
5962   xvimagesink->dst_roi.x = 0;
5963   xvimagesink->dst_roi.y = 0;
5964   xvimagesink->dst_roi.w = 0;
5965   xvimagesink->dst_roi.h = 0;
5966   xvimagesink->xim_transparenter = NULL;
5967   xvimagesink->scr_w = 0;
5968   xvimagesink->scr_h = 0;
5969   xvimagesink->aligned_width = 0;
5970   xvimagesink->aligned_height = 0;
5971   xvimagesink->stop_video = FALSE;
5972   xvimagesink->is_hided = FALSE;
5973   xvimagesink->drm_fd = -1;
5974   xvimagesink->current_pixmap_idx = -1;
5975   xvimagesink->get_pixmap_cb = NULL;
5976   xvimagesink->get_pixmap_cb_user_data = NULL;
5977
5978   for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5979     xvimagesink->displaying_buffers[i].buffer = NULL;
5980     for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
5981       xvimagesink->displaying_buffers[i].gem_name[j] = 0;
5982       xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
5983       xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
5984       xvimagesink->displaying_buffers[i].ref_count = 0;
5985     }
5986   }
5987
5988   xvimagesink->display_buffer_lock = g_mutex_new ();
5989   xvimagesink->display_buffer_cond = g_cond_new ();
5990
5991   xvimagesink->displayed_buffer_count = 0;
5992   xvimagesink->displaying_buffer_count = 0;
5993   xvimagesink->is_zero_copy_format = FALSE;
5994   xvimagesink->is_secure_path = FALSE;
5995 #endif /* GST_EXT_XV_ENHANCEMENT */
5996 }
5997
5998 static void
5999 gst_xvimagesink_base_init (gpointer g_class)
6000 {
6001   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
6002
6003   gst_element_class_set_details_simple (element_class,
6004       "Video sink", "Sink/Video",
6005       "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
6006
6007   gst_element_class_add_static_pad_template (element_class,
6008       &gst_xvimagesink_sink_template_factory);
6009 }
6010
6011 static void
6012 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
6013 {
6014   GObjectClass *gobject_class;
6015   GstElementClass *gstelement_class;
6016   GstBaseSinkClass *gstbasesink_class;
6017   GstVideoSinkClass *videosink_class;
6018
6019   gobject_class = (GObjectClass *) klass;
6020   gstelement_class = (GstElementClass *) klass;
6021   gstbasesink_class = (GstBaseSinkClass *) klass;
6022   videosink_class = (GstVideoSinkClass *) klass;
6023
6024   gobject_class->set_property = gst_xvimagesink_set_property;
6025   gobject_class->get_property = gst_xvimagesink_get_property;
6026
6027   g_object_class_install_property (gobject_class, PROP_CONTRAST,
6028       g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
6029           -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6030   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
6031       g_param_spec_int ("brightness", "Brightness",
6032           "The brightness of the video", -1000, 1000, 0,
6033           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6034   g_object_class_install_property (gobject_class, PROP_HUE,
6035       g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
6036           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6037   g_object_class_install_property (gobject_class, PROP_SATURATION,
6038       g_param_spec_int ("saturation", "Saturation",
6039           "The saturation of the video", -1000, 1000, 0,
6040           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6041   g_object_class_install_property (gobject_class, PROP_DISPLAY,
6042       g_param_spec_string ("display", "Display", "X Display name", NULL,
6043           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6044   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
6045       g_param_spec_boolean ("synchronous", "Synchronous",
6046           "When enabled, runs the X display in synchronous mode. "
6047           "(unrelated to A/V sync, used only for debugging)", FALSE,
6048           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6049   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
6050       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
6051           "The pixel aspect ratio of the device", "1/1",
6052           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6053   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
6054       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
6055           "When enabled, scaling will respect original aspect ratio", FALSE,
6056           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6057   g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
6058       g_param_spec_boolean ("handle-events", "Handle XEvents",
6059           "When enabled, XEvents will be selected and handled", TRUE,
6060           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6061   g_object_class_install_property (gobject_class, PROP_DEVICE,
6062       g_param_spec_string ("device", "Adaptor number",
6063           "The number of the video adaptor", "0",
6064           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6065   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
6066       g_param_spec_string ("device-name", "Adaptor name",
6067           "The name of the video adaptor", NULL,
6068           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6069   /**
6070    * GstXvImageSink:handle-expose
6071    *
6072    * When enabled, the current frame will always be drawn in response to X
6073    * Expose.
6074    *
6075    * Since: 0.10.14
6076    */
6077   g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
6078       g_param_spec_boolean ("handle-expose", "Handle expose",
6079           "When enabled, "
6080           "the current frame will always be drawn in response to X Expose "
6081           "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6082
6083   /**
6084    * GstXvImageSink:double-buffer
6085    *
6086    * Whether to double-buffer the output.
6087    *
6088    * Since: 0.10.14
6089    */
6090   g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
6091       g_param_spec_boolean ("double-buffer", "Double-buffer",
6092           "Whether to double-buffer the output", TRUE,
6093           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6094   /**
6095    * GstXvImageSink:autopaint-colorkey
6096    *
6097    * Whether to autofill overlay with colorkey
6098    *
6099    * Since: 0.10.21
6100    */
6101   g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
6102       g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
6103           "Whether to autofill overlay with colorkey", TRUE,
6104           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6105   /**
6106    * GstXvImageSink:colorkey
6107    *
6108    * Color to use for the overlay mask.
6109    *
6110    * Since: 0.10.21
6111    */
6112   g_object_class_install_property (gobject_class, PROP_COLORKEY,
6113       g_param_spec_int ("colorkey", "Colorkey",
6114           "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
6115           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6116
6117   /**
6118    * GstXvImageSink:draw-borders
6119    *
6120    * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
6121    * unused parts of the video area.
6122    *
6123    * Since: 0.10.21
6124    */
6125   g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
6126       g_param_spec_boolean ("draw-borders", "Colorkey",
6127           "Draw black borders to fill unused area in force-aspect-ratio mode",
6128           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6129
6130   /**
6131    * GstXvImageSink:window-width
6132    *
6133    * Actual width of the video window.
6134    *
6135    * Since: 0.10.32
6136    */
6137   g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
6138       g_param_spec_uint64 ("window-width", "window-width",
6139           "Width of the window", 0, G_MAXUINT64, 0,
6140           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6141
6142   /**
6143    * GstXvImageSink:window-height
6144    *
6145    * Actual height of the video window.
6146    *
6147    * Since: 0.10.32
6148    */
6149   g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
6150       g_param_spec_uint64 ("window-height", "window-height",
6151           "Height of the window", 0, G_MAXUINT64, 0,
6152           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6153
6154 #ifdef GST_EXT_XV_ENHANCEMENT
6155   /**
6156    * GstXvImageSink:display-mode
6157    *
6158    * select display mode
6159    */
6160   g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
6161     g_param_spec_enum("display-mode", "Display Mode",
6162       "Display device setting",
6163       GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
6164       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6165
6166   /**
6167    * GstXvImageSink:csc-range
6168    *
6169    * select color space range
6170    */
6171   g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
6172     g_param_spec_enum("csc-range", "Color Space Range",
6173       "Color space range setting",
6174       GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
6175       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6176
6177   /**
6178    * GstXvImageSink:display-geometry-method
6179    *
6180    * Display geometrical method setting
6181    */
6182   g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
6183     g_param_spec_enum("display-geometry-method", "Display geometry method",
6184       "Geometrical method for display",
6185       GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
6186       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6187
6188   /**
6189    * GstXvImageSink:display-flip
6190    *
6191    * Display flip setting
6192    */
6193   g_object_class_install_property(gobject_class, PROP_FLIP,
6194     g_param_spec_enum("flip", "Display flip",
6195       "Flip for display",
6196       GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
6197       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6198
6199   /**
6200    * GstXvImageSink:rotate
6201    *
6202    * Draw rotation angle setting
6203    */
6204   g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
6205     g_param_spec_enum("rotate", "Rotate angle",
6206       "Rotate angle of display output",
6207       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
6208       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6209
6210   /**
6211    * GstXvImageSink:visible
6212    *
6213    * Whether reserve original src size or not
6214    */
6215   g_object_class_install_property (gobject_class, PROP_VISIBLE,
6216       g_param_spec_boolean ("visible", "Visible",
6217           "Draws screen or blacks out, true means visible, false blacks out",
6218           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6219
6220   /**
6221    * GstXvImageSink:zoom
6222    *
6223    * Scale small area of screen to 2X, 3X, ... , 9X
6224    */
6225   g_object_class_install_property (gobject_class, PROP_ZOOM,
6226       g_param_spec_int ("zoom", "Zoom",
6227           "Zooms screen as nX", 1, 9, 1,
6228           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6229
6230   /**
6231    * GstXvImageSink:dst-roi-x
6232    *
6233    * X value of Destination ROI
6234    */
6235   g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
6236       g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
6237           "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
6238           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6239
6240   /**
6241    * GstXvImageSink:dst-roi-y
6242    *
6243    * Y value of Destination ROI
6244    */
6245   g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
6246       g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
6247           "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
6248           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6249
6250   /**
6251    * GstXvImageSink:dst-roi-w
6252    *
6253    * W value of Destination ROI
6254    */
6255   g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
6256       g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
6257           "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
6258           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6259
6260   /**
6261    * GstXvImageSink:dst-roi-h
6262    *
6263    * H value of Destination ROI
6264    */
6265   g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
6266       g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
6267           "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
6268           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6269
6270   /**
6271    * GstXvImageSink:stop-video
6272    *
6273    * Stop video for releasing video source buffer
6274    */
6275   g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
6276       g_param_spec_int ("stop-video", "Stop-Video",
6277           "Stop video for releasing video source buffer", 0, 1, 0,
6278           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6279
6280   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
6281       g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
6282           "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
6283
6284   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
6285       g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
6286           "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
6287
6288   /**
6289    * GstXvImageSink::frame-render-error
6290    */
6291   gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
6292           "frame-render-error",
6293           G_TYPE_FROM_CLASS (klass),
6294           G_SIGNAL_RUN_LAST,
6295           0,
6296           NULL,
6297           NULL,
6298           gst_xvimagesink_BOOLEAN__POINTER,
6299           G_TYPE_BOOLEAN,
6300           1,
6301           G_TYPE_POINTER);
6302
6303 #endif /* GST_EXT_XV_ENHANCEMENT */
6304
6305   gobject_class->finalize = gst_xvimagesink_finalize;
6306
6307   gstelement_class->change_state =
6308       GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
6309
6310   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
6311   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
6312   gstbasesink_class->buffer_alloc =
6313       GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
6314   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
6315   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
6316
6317   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
6318 }
6319
6320 /* ============================================================= */
6321 /*                                                               */
6322 /*                       Public Methods                          */
6323 /*                                                               */
6324 /* ============================================================= */
6325
6326 /* =========================================== */
6327 /*                                             */
6328 /*          Object typing & Creation           */
6329 /*                                             */
6330 /* =========================================== */
6331 static void
6332 gst_xvimagesink_init_interfaces (GType type)
6333 {
6334   static const GInterfaceInfo iface_info = {
6335     (GInterfaceInitFunc) gst_xvimagesink_interface_init,
6336     NULL,
6337     NULL,
6338   };
6339   static const GInterfaceInfo navigation_info = {
6340     (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
6341     NULL,
6342     NULL,
6343   };
6344   static const GInterfaceInfo overlay_info = {
6345     (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
6346     NULL,
6347     NULL,
6348   };
6349   static const GInterfaceInfo colorbalance_info = {
6350     (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
6351     NULL,
6352     NULL,
6353   };
6354   static const GInterfaceInfo propertyprobe_info = {
6355     (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
6356     NULL,
6357     NULL,
6358   };
6359
6360   g_type_add_interface_static (type,
6361       GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
6362   g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
6363   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
6364   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
6365       &colorbalance_info);
6366   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
6367       &propertyprobe_info);
6368
6369   /* register type and create class in a more safe place instead of at
6370    * runtime since the type registration and class creation is not
6371    * threadsafe. */
6372   g_type_class_ref (gst_xvimage_buffer_get_type ());
6373 }
6374
6375 static gboolean
6376 plugin_init (GstPlugin * plugin)
6377 {
6378   if (!gst_element_register (plugin, "xvimagesink",
6379           GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
6380     return FALSE;
6381
6382   GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
6383       "xvimagesink element");
6384   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
6385
6386   return TRUE;
6387 }
6388
6389 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
6390     GST_VERSION_MINOR,
6391     "xvimagesink",
6392     "XFree86 video output plugin using Xv extension",
6393     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)