tizen 2.3.1 release
[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 setting vconf about xv state */
150 #include <vconf.h>
151 #include <vconf-internal-player-keys.h>
152
153
154 enum {
155     SECURE_PATH_INIT = -1,
156     SECURE_PATH_OFF = 0,
157     SECURE_PATH_ON = 1
158 };
159
160 enum {
161     DRM_LEVEL_0 = 0,
162     DRM_LEVEL_1
163  };
164
165 enum
166 {
167   DISPLAY_STATUS_NULL = 0,
168   DISPLAY_STATUS_HDMI_ACTIVE,
169   DISPLAY_STATUS_UNKNOWN_ACTIVE,
170 };
171
172 enum
173 {
174   XV_STATUS_NULL = 0,
175   XV_STATUS_READY,
176   XV_STATUS_PAUSED,
177   XV_STATUS_PLAYING,
178   XV_STATUS_SEEK,
179 };
180
181 typedef enum {
182         BUF_SHARE_METHOD_PADDR = 0,
183         BUF_SHARE_METHOD_FD,
184         BUF_SHARE_METHOD_TIZEN_BUFFER,
185         BUF_SHARE_METHOD_FLUSH_BUFFER
186 } buf_share_method_t;
187
188 #define _CHECK_DISPLAYED_BUFFER_COUNT   15
189 #define _EVENT_THREAD_CHECK_INTERVAL    15000   /* us */
190
191 /* max channel count *********************************************************/
192 #define SCMN_IMGB_MAX_PLANE         (4)
193
194 /* image buffer definition ***************************************************
195
196     +------------------------------------------+ ---
197     |                                          |  ^
198     |     a[], p[]                             |  |
199     |     +---------------------------+ ---    |  |
200     |     |                           |  ^     |  |
201     |     |<---------- w[] ---------->|  |     |  |
202     |     |                           |  |     |  |
203     |     |                           |        |
204     |     |                           |  h[]   |  e[]
205     |     |                           |        |
206     |     |                           |  |     |  |
207     |     |                           |  |     |  |
208     |     |                           |  v     |  |
209     |     +---------------------------+ ---    |  |
210     |                                          |  v
211     +------------------------------------------+ ---
212
213     |<----------------- s[] ------------------>|
214 */
215
216 typedef struct
217 {
218         /* width of each image plane */
219         int w[SCMN_IMGB_MAX_PLANE];
220         /* height of each image plane */
221         int h[SCMN_IMGB_MAX_PLANE];
222         /* stride of each image plane */
223         int s[SCMN_IMGB_MAX_PLANE];
224         /* elevation of each image plane */
225         int e[SCMN_IMGB_MAX_PLANE];
226         /* user space address of each image plane */
227         void *a[SCMN_IMGB_MAX_PLANE];
228         /* physical address of each image plane, if needs */
229         void *p[SCMN_IMGB_MAX_PLANE];
230         /* color space type of image */
231         int cs;
232         /* left postion, if needs */
233         int x;
234         /* top position, if needs */
235         int y;
236         /* to align memory */
237         int __dummy2;
238         /* arbitrary data */
239         int data[16];
240         /* dma buf fd */
241         int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
242         /* buffer share method */
243         int buf_share_method;
244         /* Y plane size in case of ST12 */
245         int y_size;
246         /* UV plane size in case of ST12 */
247         int uv_size;
248         /* Tizen buffer object */
249         void *bo[SCMN_IMGB_MAX_PLANE];
250         /* JPEG data */
251         void *jpeg_data;
252         /* JPEG size */
253         int jpeg_size;
254         /* TZ memory buffer */
255         int tz_enable;
256 } SCMN_IMGB;
257
258 static void _release_flush_buffer(GstXvImageSink *xvimagesink);
259 static void _remove_last_buffer(GstXvImageSink *xvimagesink);
260 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink);
261 #endif /* GST_EXT_XV_ENHANCEMENT */
262
263 /* Debugging category */
264 #include <gst/gstinfo.h>
265
266 #include "gst/glib-compat-private.h"
267
268 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
269 #define GST_CAT_DEFAULT gst_debug_xvimagesink
270 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
271
272 #ifdef GST_EXT_XV_ENHANCEMENT
273 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
274 #define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
275
276 static GType
277 gst_xvimagesink_display_mode_get_type(void)
278 {
279         static GType xvimagesink_display_mode_type = 0;
280         static const GEnumValue display_mode_type[] = {
281                 { 0, "Default mode", "DEFAULT"},
282                 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
283                 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
284                 { 3, NULL, NULL},
285         };
286
287         if (!xvimagesink_display_mode_type) {
288                 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
289         }
290
291         return xvimagesink_display_mode_type;
292 }
293
294 static GType
295 gst_xvimagesink_csc_range_get_type(void)
296 {
297         static GType xvimagesink_csc_range_type = 0;
298         static const GEnumValue csc_range_type[] = {
299                 { 0, "Narrow range", "NARROW"},
300                 { 1, "Wide range", "WIDE"},
301                 { 2, NULL, NULL},
302         };
303
304         if (!xvimagesink_csc_range_type) {
305                 xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
306         }
307
308         return xvimagesink_csc_range_type;
309 }
310
311 enum {
312     DEGREE_0,
313     DEGREE_90,
314     DEGREE_180,
315     DEGREE_270,
316     DEGREE_NUM,
317 };
318
319 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
320
321 static GType
322 gst_xvimagesink_rotate_angle_get_type(void)
323 {
324         static GType xvimagesink_rotate_angle_type = 0;
325         static const GEnumValue rotate_angle_type[] = {
326                 { 0, "No rotate", "DEGREE_0"},
327                 { 1, "Rotate 90 degree", "DEGREE_90"},
328                 { 2, "Rotate 180 degree", "DEGREE_180"},
329                 { 3, "Rotate 270 degree", "DEGREE_270"},
330                 { 4, NULL, NULL},
331         };
332
333         if (!xvimagesink_rotate_angle_type) {
334                 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
335         }
336
337         return xvimagesink_rotate_angle_type;
338 }
339
340 enum {
341     DISP_GEO_METHOD_LETTER_BOX = 0,
342     DISP_GEO_METHOD_ORIGIN_SIZE,
343     DISP_GEO_METHOD_FULL_SCREEN,
344     DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
345     DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
346     DISP_GEO_METHOD_CUSTOM_DST_ROI,
347     DISP_GEO_METHOD_NUM,
348 };
349
350 enum {
351     ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
352     ROI_DISP_GEO_METHOD_LETTER_BOX,
353     ROI_DISP_GEO_METHOD_NUM,
354 };
355
356 #define DEF_DISPLAY_GEOMETRY_METHOD         DISP_GEO_METHOD_LETTER_BOX
357 #define DEF_ROI_DISPLAY_GEOMETRY_METHOD     ROI_DISP_GEO_METHOD_FULL_SCREEN
358
359 enum {
360     FLIP_NONE = 0,
361     FLIP_HORIZONTAL,
362     FLIP_VERTICAL,
363     FLIP_BOTH,
364     FLIP_NUM,
365 };
366 #define DEF_DISPLAY_FLIP            FLIP_NONE
367
368 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
369 #define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
370 #define GST_TYPE_XVIMAGESINK_FLIP                    (gst_xvimagesink_flip_get_type())
371
372 static GType
373 gst_xvimagesink_display_geometry_method_get_type(void)
374 {
375         static GType xvimagesink_display_geometry_method_type = 0;
376         static const GEnumValue display_geometry_method_type[] = {
377                 { 0, "Letter box", "LETTER_BOX"},
378                 { 1, "Origin size", "ORIGIN_SIZE"},
379                 { 2, "Full-screen", "FULL_SCREEN"},
380                 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
381                 { 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"},
382                 { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
383                 { 6, NULL, NULL},
384         };
385
386         if (!xvimagesink_display_geometry_method_type) {
387                 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
388         }
389
390         return xvimagesink_display_geometry_method_type;
391 }
392
393 static GType
394 gst_xvimagesink_roi_display_geometry_method_get_type(void)
395 {
396         static GType xvimagesink_roi_display_geometry_method_type = 0;
397         static const GEnumValue roi_display_geometry_method_type[] = {
398                 { 0, "ROI-Full-screen", "FULL_SCREEN"},
399                 { 1, "ROI-Letter box", "LETTER_BOX"},
400                 { 2, NULL, NULL},
401         };
402
403         if (!xvimagesink_roi_display_geometry_method_type) {
404                 xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
405         }
406
407         return xvimagesink_roi_display_geometry_method_type;
408 }
409
410 static GType
411 gst_xvimagesink_flip_get_type(void)
412 {
413         static GType xvimagesink_flip_type = 0;
414         static const GEnumValue flip_type[] = {
415                 { FLIP_NONE,       "Flip NONE", "FLIP_NONE"},
416                 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
417                 { FLIP_VERTICAL,   "Flip VERTICAL", "FLIP_VERTICAL"},
418                 { FLIP_BOTH,       "Flip BOTH", "FLIP_BOTH"},
419                 { FLIP_NUM, NULL, NULL},
420         };
421
422         if (!xvimagesink_flip_type) {
423                 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
424         }
425
426         return xvimagesink_flip_type;
427 }
428
429 #define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
430 void
431 gst_xvimagesink_BOOLEAN__POINTER (GClosure         *closure,
432                                      GValue         *return_value G_GNUC_UNUSED,
433                                      guint          n_param_values,
434                                      const GValue   *param_values,
435                                      gpointer       invocation_hint G_GNUC_UNUSED,
436                                      gpointer       marshal_data)
437 {
438   typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer     data1,
439                                                      gpointer     arg_1,
440                                                      gpointer     data2);
441   register GMarshalFunc_BOOLEAN__POINTER callback;
442   register GCClosure *cc = (GCClosure*) closure;
443   register gpointer data1, data2;
444
445   gboolean v_return;
446
447   g_return_if_fail (return_value != NULL);
448   g_return_if_fail (n_param_values == 2);
449
450   if (G_CCLOSURE_SWAP_DATA (closure)) {
451     data1 = closure->data;
452     data2 = g_value_peek_pointer (param_values + 0);
453   } else {
454     data1 = g_value_peek_pointer (param_values + 0);
455     data2 = closure->data;
456   }
457   callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
458
459   v_return = callback (data1,
460                       g_marshal_value_peek_pointer (param_values + 1),
461                       data2);
462
463   g_value_set_boolean (return_value, v_return);
464 }
465
466 enum
467 {
468     SIGNAL_FRAME_RENDER_ERROR,
469     SIGNAL_DISPLAY_STATUS,
470     SIGNAL_EXTERNAL_RESOLUTION,
471     SIGNAL_WINDOW_STATUS,
472     SIGNAL_QUICKPANEL_STATUS,
473     SIGNAL_MULTIWINDOW_STATUS,
474     LAST_SIGNAL
475 };
476 static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
477
478 #endif /* GST_EXT_XV_ENHANCEMENT */
479
480 typedef struct
481 {
482   unsigned long flags;
483   unsigned long functions;
484   unsigned long decorations;
485   long input_mode;
486   unsigned long status;
487 }
488 MotifWmHints, MwmHints;
489
490 #define MWM_HINTS_DECORATIONS   (1L << 1)
491
492 #ifdef GST_EXT_XV_ENHANCEMENT
493 #define MAX_DISPLAY_IN_XVIMAGESINK  20
494 static Display *g_display_id[MAX_DISPLAY_IN_XVIMAGESINK] = {0};
495 #endif
496
497 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
498
499 static GstBufferClass *xvimage_buffer_parent_class = NULL;
500 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
501
502 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
503     xvimagesink);
504 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
505     GstCaps * caps);
506 static void gst_xvimagesink_expose (GstXOverlay * overlay);
507
508 #ifdef GST_EXT_XV_ENHANCEMENT
509 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
510 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
511 static gboolean set_csc_range(GstXContext *xcontext, int set_range);
512 static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
513 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
514 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
515 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
516 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
517 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
518 static void check_hdmi_connected(GstXvImageSink *xvimagesink);
519 static int get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type, unsigned int *val, unsigned int len);
520 static gboolean check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name);
521 #endif /* GST_EXT_XV_ENHANCEMENT */
522
523 /* Default template - initiated with class struct to allow gst-register to work
524    without X running */
525 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
526     GST_STATIC_PAD_TEMPLATE ("sink",
527     GST_PAD_SINK,
528     GST_PAD_ALWAYS,
529     GST_STATIC_CAPS ("video/x-raw-rgb, "
530         "framerate = (fraction) [ 0, MAX ], "
531         "width = (int) [ 1, MAX ], "
532         "height = (int) [ 1, MAX ]; "
533         "video/x-raw-yuv, "
534         "framerate = (fraction) [ 0, MAX ], "
535         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
536     );
537
538 enum
539 {
540   PROP_0,
541   PROP_CONTRAST,
542   PROP_BRIGHTNESS,
543   PROP_HUE,
544   PROP_SATURATION,
545   PROP_DISPLAY,
546   PROP_SYNCHRONOUS,
547   PROP_PIXEL_ASPECT_RATIO,
548   PROP_FORCE_ASPECT_RATIO,
549   PROP_HANDLE_EVENTS,
550   PROP_DEVICE,
551   PROP_DEVICE_NAME,
552   PROP_HANDLE_EXPOSE,
553   PROP_DOUBLE_BUFFER,
554   PROP_AUTOPAINT_COLORKEY,
555   PROP_COLORKEY,
556   PROP_DRAW_BORDERS,
557   PROP_WINDOW_WIDTH,
558   PROP_WINDOW_HEIGHT,
559 #ifdef GST_EXT_XV_ENHANCEMENT
560   PROP_DISPLAY_MODE,
561   PROP_CSC_RANGE,
562   PROP_ROTATE_ANGLE,
563   PROP_FLIP,
564   PROP_DISPLAY_GEOMETRY_METHOD,
565   PROP_VISIBLE,
566   PROP_ZOOM,
567   PROP_ZOOM_POS_X,
568   PROP_ZOOM_POS_Y,
569   PROP_ORIENTATION,
570   PROP_DST_ROI_MODE,
571   PROP_DST_ROI_X,
572   PROP_DST_ROI_Y,
573   PROP_DST_ROI_W,
574   PROP_DST_ROI_H,
575   PROP_SRC_CROP_X,
576   PROP_SRC_CROP_Y,
577   PROP_SRC_CROP_W,
578   PROP_SRC_CROP_H,
579   PROP_STOP_VIDEO,
580   PROP_PIXMAP_CB,
581   PROP_PIXMAP_CB_USER_DATA,
582   PROP_SUBPICTURE,
583   PROP_EXTERNAL_WIDTH,
584   PROP_EXTERNAL_HEIGHT,
585   PROP_ENABLE_FLUSH_BUFFER,
586   PROP_PIXMAP,
587   PROP_HIDED_WINDOW,
588   PROP_QUICKPANEL_ON,
589   PROP_MULTIWINDOW_ACTIVE,
590   PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
591   PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
592 #endif /* GST_EXT_XV_ENHANCEMENT */
593 };
594
595 static void gst_xvimagesink_init_interfaces (GType type);
596
597 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
598     GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
599
600
601 /* ============================================================= */
602 /*                                                               */
603 /*                       Private Methods                         */
604 /*                                                               */
605 /* ============================================================= */
606
607 /* xvimage buffers */
608
609 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
610
611 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
612 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
613 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
614
615 /* This function destroys a GstXvImage handling XShm availability */
616 static void
617 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
618 {
619   GstXvImageSink *xvimagesink;
620
621   GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
622
623   xvimagesink = xvimage->xvimagesink;
624   if (G_UNLIKELY (xvimagesink == NULL))
625     goto no_sink;
626
627   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
628
629   GST_OBJECT_LOCK (xvimagesink);
630
631   /* If the destroyed image is the current one we destroy our reference too */
632   if (xvimagesink->cur_image == xvimage)
633     xvimagesink->cur_image = NULL;
634
635   /* We might have some buffers destroyed after changing state to NULL */
636   if (xvimagesink->xcontext == NULL) {
637     GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
638 #ifdef HAVE_XSHM
639     /* Need to free the shared memory segment even if the x context
640      * was already cleaned up */
641     if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
642       shmdt (xvimage->SHMInfo.shmaddr);
643     }
644 #endif
645     goto beach;
646   }
647
648   g_mutex_lock (xvimagesink->x_lock);
649
650 #ifdef HAVE_XSHM
651   if (xvimagesink->xcontext->use_xshm) {
652     if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
653       GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
654           xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
655       XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
656       XSync (xvimagesink->xcontext->disp, FALSE);
657
658       shmdt (xvimage->SHMInfo.shmaddr);
659     }
660     if (xvimage->xvimage)
661       XFree (xvimage->xvimage);
662   } else
663 #endif /* HAVE_XSHM */
664   {
665     if (xvimage->xvimage) {
666       if (xvimage->xvimage->data) {
667         g_free (xvimage->xvimage->data);
668       }
669       XFree (xvimage->xvimage);
670     }
671   }
672
673   XSync (xvimagesink->xcontext->disp, FALSE);
674
675   g_mutex_unlock (xvimagesink->x_lock);
676
677 beach:
678   GST_OBJECT_UNLOCK (xvimagesink);
679   xvimage->xvimagesink = NULL;
680   gst_object_unref (xvimagesink);
681
682   GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
683       (xvimage));
684
685   return;
686
687 no_sink:
688   {
689     GST_WARNING ("no sink found");
690     return;
691   }
692 }
693
694 static void
695 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
696 {
697   GstXvImageSink *xvimagesink;
698   gboolean running;
699
700   xvimagesink = xvimage->xvimagesink;
701   if (G_UNLIKELY (xvimagesink == NULL))
702     goto no_sink;
703
704   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
705
706   GST_OBJECT_LOCK (xvimagesink);
707   running = xvimagesink->running;
708   GST_OBJECT_UNLOCK (xvimagesink);
709
710   /* If our geometry changed we can't reuse that image. */
711   if (running == FALSE) {
712     GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
713     gst_xvimage_buffer_destroy (xvimage);
714   } else if ((xvimage->width != xvimagesink->video_width) ||
715       (xvimage->height != xvimagesink->video_height)) {
716     GST_LOG_OBJECT (xvimage,
717         "destroy image as its size changed %dx%d vs current %dx%d",
718         xvimage->width, xvimage->height,
719         xvimagesink->video_width, xvimagesink->video_height);
720     gst_xvimage_buffer_destroy (xvimage);
721   } else {
722     /* In that case we can reuse the image and add it to our image pool. */
723     GST_LOG_OBJECT (xvimage, "recycling image in pool");
724     /* need to increment the refcount again to recycle */
725     gst_buffer_ref (GST_BUFFER_CAST (xvimage));
726     g_mutex_lock (xvimagesink->pool_lock);
727     xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
728         xvimage);
729     g_mutex_unlock (xvimagesink->pool_lock);
730   }
731   return;
732
733 no_sink:
734   {
735     GST_WARNING ("no sink found");
736     return;
737   }
738 }
739
740 static void
741 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
742 {
743   /* make sure it is not recycled */
744   xvimage->width = -1;
745   xvimage->height = -1;
746   gst_buffer_unref (GST_BUFFER (xvimage));
747 }
748
749 static void
750 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
751 {
752 #ifdef HAVE_XSHM
753   xvimage->SHMInfo.shmaddr = ((void *) -1);
754   xvimage->SHMInfo.shmid = -1;
755 #endif
756 }
757
758 static void
759 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
760 {
761   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
762
763   xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
764
765   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
766       gst_xvimage_buffer_finalize;
767 }
768
769 static GType
770 gst_xvimage_buffer_get_type (void)
771 {
772   static GType _gst_xvimage_buffer_type;
773
774   if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
775     static const GTypeInfo xvimage_buffer_info = {
776       sizeof (GstBufferClass),
777       NULL,
778       NULL,
779       gst_xvimage_buffer_class_init,
780       NULL,
781       NULL,
782       sizeof (GstXvImageBuffer),
783       0,
784       (GInstanceInitFunc) gst_xvimage_buffer_init,
785       NULL
786     };
787     _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
788         "GstXvImageBuffer", &xvimage_buffer_info, 0);
789   }
790   return _gst_xvimage_buffer_type;
791 }
792
793 /* X11 stuff */
794
795 static gboolean error_caught = FALSE;
796
797 static int
798 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
799 {
800   char error_msg[1024];
801
802   XGetErrorText (display, xevent->error_code, error_msg, 1024);
803 #ifndef GST_EXT_XV_ENHANCEMENT
804   GST_DEBUG ("xvimagesink triggered an XError. error: %s, display(%p)", error_msg, display);
805 #else
806   {
807     int i = 0;
808     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
809       if (g_display_id[i] == display) {
810         GST_ERROR ("xvimagesink triggered an XError. error: %s, display(%p), xevent->request_code: %d", error_msg, display, xevent->request_code);
811         error_caught = TRUE;
812         break;
813       }
814     }
815     if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
816       GST_ERROR ("xvimagesink triggered an XError. error: %s, xevent->request_code: %d, but the display(%p) was not created in xvimagesink, skip it...", error_msg, xevent->request_code, display);
817     }
818   }
819 #endif
820   return 0;
821 }
822
823 #ifdef HAVE_XSHM
824 /* This function checks that it is actually really possible to create an image
825    using XShm */
826 static gboolean
827 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
828 {
829   XvImage *xvimage;
830   XShmSegmentInfo SHMInfo;
831   gint size;
832   int (*handler) (Display *, XErrorEvent *);
833   gboolean result = FALSE;
834   gboolean did_attach = FALSE;
835
836   g_return_val_if_fail (xcontext != NULL, FALSE);
837
838   /* Sync to ensure any older errors are already processed */
839   XSync (xcontext->disp, FALSE);
840
841   /* Set defaults so we don't free these later unnecessarily */
842   SHMInfo.shmaddr = ((void *) -1);
843   SHMInfo.shmid = -1;
844
845   /* Setting an error handler to catch failure */
846   error_caught = FALSE;
847   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
848
849   /* Trying to create a 1x1 picture */
850   GST_DEBUG ("XvShmCreateImage of 1x1");
851   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
852       xcontext->im_format, NULL, 1, 1, &SHMInfo);
853
854   /* Might cause an error, sync to ensure it is noticed */
855   XSync (xcontext->disp, FALSE);
856   if (!xvimage || error_caught) {
857     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
858     goto beach;
859   }
860   size = xvimage->data_size;
861
862   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
863   if (SHMInfo.shmid == -1) {
864     GST_WARNING ("could not get shared memory of %d bytes", size);
865     goto beach;
866   }
867
868   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
869   if (SHMInfo.shmaddr == ((void *) -1)) {
870     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
871     /* Clean up the shared memory segment */
872     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
873     goto beach;
874   }
875
876   xvimage->data = SHMInfo.shmaddr;
877   SHMInfo.readOnly = FALSE;
878
879   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
880     GST_WARNING ("Failed to XShmAttach");
881     /* Clean up the shared memory segment */
882     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
883     goto beach;
884   }
885
886   /* Sync to ensure we see any errors we caused */
887   XSync (xcontext->disp, FALSE);
888
889   /* Delete the shared memory segment as soon as everyone is attached.
890    * This way, it will be deleted as soon as we detach later, and not
891    * leaked if we crash. */
892   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
893
894   if (!error_caught) {
895     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
896         SHMInfo.shmseg);
897
898     did_attach = TRUE;
899     /* store whether we succeeded in result */
900     result = TRUE;
901   } else {
902     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
903         "Not using shared memory.");
904   }
905
906 beach:
907   /* Sync to ensure we swallow any errors we caused and reset error_caught */
908   XSync (xcontext->disp, FALSE);
909
910   error_caught = FALSE;
911   XSetErrorHandler (handler);
912
913   if (did_attach) {
914     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
915         SHMInfo.shmid, SHMInfo.shmseg);
916     XShmDetach (xcontext->disp, &SHMInfo);
917     XSync (xcontext->disp, FALSE);
918   }
919   if (SHMInfo.shmaddr != ((void *) -1))
920     shmdt (SHMInfo.shmaddr);
921   if (xvimage)
922     XFree (xvimage);
923   return result;
924 }
925 #endif /* HAVE_XSHM */
926
927 /* This function handles GstXvImage creation depending on XShm availability */
928 static GstXvImageBuffer *
929 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
930 {
931   GstXvImageBuffer *xvimage = NULL;
932   GstStructure *structure = NULL;
933   gboolean succeeded = FALSE;
934   int (*handler) (Display *, XErrorEvent *);
935
936   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
937
938   if (caps == NULL)
939     return NULL;
940
941   xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
942   GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
943
944   structure = gst_caps_get_structure (caps, 0);
945
946   if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
947       !gst_structure_get_int (structure, "height", &xvimage->height)) {
948     GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
949   }
950
951   GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
952       xvimage->height);
953 #ifdef GST_EXT_XV_ENHANCEMENT
954   GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
955                                xvimagesink->aligned_width, xvimagesink->aligned_height);
956   if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
957     GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
958     xvimagesink->aligned_width = xvimage->width;
959     xvimagesink->aligned_height = xvimage->height;
960   }
961   if (xvimagesink->subpicture) {
962     GST_LOG("because of subpicture's format, pass xvimage_new");
963     return xvimage;
964   }
965 #endif /* GST_EXT_XV_ENHANCEMENT */
966
967   xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
968   if (xvimage->im_format == -1) {
969     GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
970         GST_PTR_FORMAT, caps);
971     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
972         ("Failed to create output image buffer of %dx%d pixels",
973             xvimage->width, xvimage->height), ("Invalid input caps"));
974     goto beach_unlocked;
975   }
976   xvimage->xvimagesink = gst_object_ref (xvimagesink);
977
978   g_mutex_lock (xvimagesink->x_lock);
979
980 #ifdef GST_EXT_XV_ENHANCEMENT
981   XSync (xvimagesink->xcontext->disp, FALSE);
982 #endif /* GST_EXT_XV_ENHANCEMENT */
983   /* Setting an error handler to catch failure */
984   error_caught = FALSE;
985   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
986
987 #ifdef HAVE_XSHM
988   if (xvimagesink->xcontext->use_xshm) {
989     int expected_size;
990
991     xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
992         xvimagesink->xcontext->xv_port_id,
993         xvimage->im_format, NULL,
994 #ifdef GST_EXT_XV_ENHANCEMENT
995         xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
996 #else /* GST_EXT_XV_ENHANCEMENT */
997         xvimage->width, xvimage->height, &xvimage->SHMInfo);
998 #endif /* GST_EXT_XV_ENHANCEMENT */
999     if (!xvimage->xvimage || error_caught) {
1000       g_mutex_unlock (xvimagesink->x_lock);
1001
1002       /* Reset error flag */
1003       error_caught = FALSE;
1004
1005       /* Push a warning */
1006       GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
1007           ("Failed to create output image buffer of %dx%d pixels",
1008               xvimage->width, xvimage->height),
1009           ("could not XvShmCreateImage a %dx%d image",
1010               xvimage->width, xvimage->height));
1011
1012 #ifdef GST_EXT_XV_ENHANCEMENT
1013       /* must not change "use_xshm",
1014          because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
1015       goto beach_unlocked;
1016 #else /* GST_EXT_XV_ENHANCEMENT */
1017       /* Retry without XShm */
1018       xvimagesink->xcontext->use_xshm = FALSE;
1019
1020       /* Hold X mutex again to try without XShm */
1021       g_mutex_lock (xvimagesink->x_lock);
1022       goto no_xshm;
1023 #endif /* GST_EXT_XV_ENHANCEMENT */
1024     }
1025
1026     /* we have to use the returned data_size for our shm size */
1027     xvimage->size = xvimage->xvimage->data_size;
1028     GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
1029         xvimage->size);
1030
1031     /* calculate the expected size.  This is only for sanity checking the
1032      * number we get from X. */
1033     switch (xvimage->im_format) {
1034       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
1035       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
1036       {
1037         gint pitches[3];
1038         gint offsets[3];
1039         guint plane;
1040
1041         offsets[0] = 0;
1042         pitches[0] = GST_ROUND_UP_4 (xvimage->width);
1043         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
1044         pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
1045         offsets[2] =
1046             offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
1047         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
1048
1049         expected_size =
1050             offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
1051
1052         for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1053           GST_DEBUG_OBJECT (xvimagesink,
1054               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
1055               plane, pitches[plane], offsets[plane]);
1056         }
1057         break;
1058       }
1059       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
1060       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
1061         expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
1062         break;
1063
1064 #ifdef GST_EXT_XV_ENHANCEMENT
1065       case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
1066       case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
1067       case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
1068       case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
1069       case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
1070       case GST_MAKE_FOURCC ('S', '4', '2', '0'):
1071       case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
1072         expected_size = sizeof(SCMN_IMGB);
1073         break;
1074 #endif /* GST_EXT_XV_ENHANCEMENT */
1075       default:
1076         expected_size = 0;
1077         break;
1078     }
1079     if (expected_size != 0 && xvimage->size != expected_size) {
1080       GST_WARNING_OBJECT (xvimagesink,
1081           "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
1082           xvimage->size, expected_size);
1083     }
1084
1085     /* Be verbose about our XvImage stride */
1086     {
1087       guint plane;
1088
1089       for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1090         GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
1091             "offset of %d", plane, xvimage->xvimage->pitches[plane],
1092             xvimage->xvimage->offsets[plane]);
1093       }
1094     }
1095
1096     xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
1097         IPC_CREAT | 0777);
1098     if (xvimage->SHMInfo.shmid == -1) {
1099       g_mutex_unlock (xvimagesink->x_lock);
1100       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1101           ("Failed to create output image buffer of %dx%d pixels",
1102               xvimage->width, xvimage->height),
1103           ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1104               xvimage->size));
1105       goto beach_unlocked;
1106     }
1107
1108     xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1109     if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1110       g_mutex_unlock (xvimagesink->x_lock);
1111       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1112           ("Failed to create output image buffer of %dx%d pixels",
1113               xvimage->width, xvimage->height),
1114           ("Failed to shmat: %s", g_strerror (errno)));
1115       /* Clean up the shared memory segment */
1116       shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1117       goto beach_unlocked;
1118     }
1119
1120     xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1121     xvimage->SHMInfo.readOnly = FALSE;
1122
1123     if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1124       /* Clean up the shared memory segment */
1125       shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1126
1127       g_mutex_unlock (xvimagesink->x_lock);
1128       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1129           ("Failed to create output image buffer of %dx%d pixels",
1130               xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1131       goto beach_unlocked;
1132     }
1133
1134     XSync (xvimagesink->xcontext->disp, FALSE);
1135
1136     /* Delete the shared memory segment as soon as we everyone is attached.
1137      * This way, it will be deleted as soon as we detach later, and not
1138      * leaked if we crash. */
1139     shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1140
1141     GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1142         xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1143   } else
1144 #ifndef GST_EXT_XV_ENHANCEMENT
1145   no_xshm:
1146 #endif /* GST_EXT_XV_ENHANCEMENT */
1147 #endif /* HAVE_XSHM */
1148   {
1149     xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1150         xvimagesink->xcontext->xv_port_id,
1151 #ifdef GST_EXT_XV_ENHANCEMENT
1152         xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1153 #else /* GST_EXT_XV_ENHANCEMENT */
1154         xvimage->im_format, NULL, xvimage->width, xvimage->height);
1155 #endif /* GST_EXT_XV_ENHANCEMENT */
1156     if (!xvimage->xvimage || error_caught) {
1157       g_mutex_unlock (xvimagesink->x_lock);
1158       /* Reset error handler */
1159       error_caught = FALSE;
1160       XSetErrorHandler (handler);
1161       /* Push an error */
1162       GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1163           ("Failed to create outputimage buffer of %dx%d pixels",
1164               xvimage->width, xvimage->height),
1165           ("could not XvCreateImage a %dx%d image",
1166               xvimage->width, xvimage->height));
1167       goto beach_unlocked;
1168     }
1169
1170     /* we have to use the returned data_size for our image size */
1171     xvimage->size = xvimage->xvimage->data_size;
1172     xvimage->xvimage->data = g_malloc (xvimage->size);
1173
1174     XSync (xvimagesink->xcontext->disp, FALSE);
1175   }
1176
1177   /* Reset error handler */
1178   error_caught = FALSE;
1179   XSetErrorHandler (handler);
1180
1181   succeeded = TRUE;
1182
1183   GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1184   GST_BUFFER_SIZE (xvimage) = xvimage->size;
1185
1186   g_mutex_unlock (xvimagesink->x_lock);
1187
1188 beach_unlocked:
1189   if (!succeeded) {
1190     gst_xvimage_buffer_free (xvimage);
1191     xvimage = NULL;
1192   }
1193
1194   return xvimage;
1195 }
1196
1197 /* We are called with the x_lock taken */
1198 static void
1199 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
1200     GstXWindow * xwindow, GstVideoRectangle rect)
1201 {
1202   gint t1, t2;
1203
1204   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1205   g_return_if_fail (xwindow != NULL);
1206
1207   XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1208       xvimagesink->xcontext->black);
1209
1210   /* Left border */
1211   if (rect.x > xvimagesink->render_rect.x) {
1212     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1213         xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1214         rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
1215   }
1216
1217   /* Right border */
1218   t1 = rect.x + rect.w;
1219   t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
1220   if (t1 < t2) {
1221     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1222         t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
1223   }
1224
1225   /* Top border */
1226   if (rect.y > xvimagesink->render_rect.y) {
1227     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1228         xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1229         xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
1230   }
1231
1232   /* Bottom border */
1233   t1 = rect.y + rect.h;
1234   t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
1235   if (t1 < t2) {
1236     XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1237         xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
1238   }
1239 }
1240
1241 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
1242  * if no window was available  */
1243 static gboolean
1244 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
1245     GstXvImageBuffer * xvimage)
1246 {
1247   GstVideoRectangle result;
1248   gboolean draw_border = FALSE;
1249
1250 #ifdef GST_EXT_XV_ENHANCEMENT
1251   static Atom atom_rotation = None;
1252   static Atom atom_hflip = None;
1253   static Atom atom_vflip = None;
1254   static Atom atom_contents_rotation = None;
1255   gboolean set_hflip = FALSE;
1256   gboolean set_vflip = FALSE;
1257   XWindowAttributes map_attr;
1258
1259   GstVideoRectangle src_origin = { 0, 0, 0, 0};
1260   GstVideoRectangle src_input  = { 0, 0, 0, 0};
1261   GstVideoRectangle src = { 0, 0, 0, 0};
1262   GstVideoRectangle dst = { 0, 0, 0, 0};
1263
1264   gint res_rotate_angle = 0;
1265   int rotate        = 0;
1266   int orientation = 0;
1267   int ret           = 0;
1268   int idx           = 0;
1269   int (*handler) (Display *, XErrorEvent *) = NULL;
1270   gboolean res = FALSE;
1271   XV_DATA_PTR img_data = NULL;
1272
1273   if (xvimagesink->is_subpicture_format)
1274     return TRUE;
1275 #endif /* GST_EXT_XV_ENHANCEMENT */
1276
1277   /* We take the flow_lock. If expose is in there we don't want to run
1278      concurrently from the data flow thread */
1279   g_mutex_lock (xvimagesink->flow_lock);
1280
1281 #ifdef GST_EXT_XV_ENHANCEMENT
1282   if (xvimagesink->xid_updated) {
1283     if (xvimage && xvimagesink->xvimage == NULL) {
1284       GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
1285       xvimage = NULL;
1286     }
1287     xvimagesink->xid_updated = FALSE;
1288   }
1289 #endif /* GST_EXT_XV_ENHANCEMENT */
1290
1291   if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1292 #ifdef GST_EXT_XV_ENHANCEMENT
1293     if (xvimagesink->get_pixmap_cb) {
1294       GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
1295     } else {
1296       GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
1297       g_mutex_unlock(xvimagesink->flow_lock);
1298       return FALSE;
1299     }
1300 #else /* GST_EXT_XV_ENHANCEMENT */
1301     g_mutex_unlock (xvimagesink->flow_lock);
1302     return FALSE;
1303 #endif /* GST_EXT_XV_ENHANCEMENT */
1304   }
1305
1306 #ifdef GST_EXT_XV_ENHANCEMENT
1307   /* check map status of window */
1308   if(!xvimagesink->is_pixmap) {
1309     if (xvimagesink->xcontext && xvimagesink->xwindow) {
1310       if (XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &map_attr)) {
1311         if (map_attr.map_state != IsViewable) {
1312           GST_WARNING_OBJECT(xvimagesink, "window is unmapped, skip putimage");
1313           g_mutex_unlock(xvimagesink->flow_lock);
1314           return TRUE;
1315         }
1316       } else {
1317       GST_WARNING_OBJECT(xvimagesink, "XGetWindowAttributes failed");
1318       }
1319     }
1320   }
1321 #endif /* GST_EXT_XV_ENHANCEMENT */
1322
1323   /* Draw borders when displaying the first frame. After this
1324      draw borders only on expose event or after a size change. */
1325   if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1326     draw_border = TRUE;
1327   }
1328
1329   /* Store a reference to the last image we put, lose the previous one */
1330   if (xvimage && xvimagesink->cur_image != xvimage) {
1331     if (xvimagesink->cur_image) {
1332       GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1333       gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1334     }
1335     GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1336     xvimagesink->cur_image =
1337         GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1338   }
1339
1340   /* Expose sends a NULL image, we take the latest frame */
1341   if (!xvimage) {
1342 #ifdef GST_EXT_XV_ENHANCEMENT
1343     g_mutex_lock(xvimagesink->display_buffer_lock);
1344     if (xvimagesink->is_zero_copy_format  &&
1345         xvimagesink->displaying_buffer_count < 1) {
1346       g_mutex_unlock(xvimagesink->display_buffer_lock);
1347       g_mutex_unlock (xvimagesink->flow_lock);
1348       GST_WARNING_OBJECT(xvimagesink, "no buffer to display. skip putimage");
1349       return TRUE;
1350     }
1351     g_mutex_unlock(xvimagesink->display_buffer_lock);
1352 #endif /* GST_EXT_XV_ENHANCEMENT */
1353     if (xvimagesink->cur_image) {
1354       draw_border = TRUE;
1355       xvimage = xvimagesink->cur_image;
1356     } else {
1357 #ifdef GST_EXT_XV_ENHANCEMENT
1358       GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1359       /* no need to release gem handle */
1360 #endif /* GST_EXT_XV_ENHANCEMENT */
1361       g_mutex_unlock (xvimagesink->flow_lock);
1362       return TRUE;
1363     }
1364   }
1365
1366 #ifdef GST_EXT_XV_ENHANCEMENT
1367   gboolean enable_last_buffer;
1368   g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
1369   if(enable_last_buffer) {
1370     if (xvimagesink->cur_image && xvimagesink->is_zero_copy_format) {
1371       GstBuffer *last_buffer= NULL;
1372       g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
1373       if (last_buffer) {
1374         if(last_buffer != xvimagesink->cur_image)
1375         {
1376           GST_LOG("curimage : %p , last_buffer : %p", xvimagesink->cur_image, last_buffer);
1377         }
1378       } else {
1379         GST_WARNING_OBJECT(xvimagesink, "zero copy format and last buffer is NULL, so skip this putimage");
1380         g_mutex_unlock (xvimagesink->flow_lock);
1381         return TRUE;
1382       }
1383       gst_buffer_unref(last_buffer);
1384       last_buffer = NULL;
1385     }
1386   }
1387
1388   if (xvimagesink->visible == FALSE ||
1389       (xvimagesink->is_hided && GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
1390     GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
1391              xvimagesink->visible, xvimagesink->is_hided);
1392     g_mutex_unlock(xvimagesink->flow_lock);
1393     return TRUE;
1394   }
1395
1396   if (!xvimagesink->get_pixmap_cb) {
1397     gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1398     if (!xvimagesink->subpicture && !xvimagesink->is_during_seek) {
1399       if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
1400         set_display_mode(xvimagesink->xcontext, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE);
1401       } else {
1402         set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
1403       }
1404     }
1405   } else {
1406     /* for multi-pixmap usage for the video texture */
1407     gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
1408     idx = xvimagesink->current_pixmap_idx;
1409     if (idx == -1) {
1410       g_mutex_unlock (xvimagesink->flow_lock);
1411       return FALSE;
1412     } else if (idx == -2) {
1413       GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
1414       g_mutex_unlock (xvimagesink->flow_lock);
1415       return TRUE;
1416     }
1417   }
1418
1419   res_rotate_angle = xvimagesink->rotate_angle;
1420
1421   src.x = src.y = 0;
1422   src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1423
1424   src_input.w = src_origin.w = xvimagesink->video_width;
1425   src_input.h = src_origin.h = xvimagesink->video_height;
1426
1427   if ((xvimagesink->display_geometry_method == DISP_GEO_METHOD_LETTER_BOX ||
1428       xvimagesink->display_geometry_method == DISP_GEO_METHOD_FULL_SCREEN ||
1429       xvimagesink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_DST_ROI) &&
1430       xvimagesink->src_crop.w && xvimagesink->src_crop.h) {
1431       GST_LOG_OBJECT(xvimagesink, "set src crop %d,%d,%dx%d -> %d,%d,%dx%d",
1432                                   src_input.x, src_input.y, src_input.w, src_input.h,
1433                                   xvimagesink->src_crop.x, xvimagesink->src_crop.y, xvimagesink->src_crop.w, xvimagesink->src_crop.h);
1434       src_input.x = src_origin.w = xvimagesink->src_crop.x;
1435       src_input.y = src_origin.y = xvimagesink->src_crop.y;
1436       src_input.w = src_origin.w = xvimagesink->src_crop.w;
1437       src_input.h = src_origin.h = xvimagesink->src_crop.h;
1438   }
1439
1440   if (xvimagesink->rotate_angle == DEGREE_0 ||
1441       xvimagesink->rotate_angle == DEGREE_180) {
1442     src.w = src_origin.w;
1443     src.h = src_origin.h;
1444   } else {
1445     src.w = src_origin.h;
1446     src.h = src_origin.w;
1447   }
1448
1449   dst.w = xvimagesink->render_rect.w;
1450   dst.h = xvimagesink->render_rect.h;
1451
1452   switch (xvimagesink->display_geometry_method)
1453   {
1454     case DISP_GEO_METHOD_LETTER_BOX:
1455       gst_video_sink_center_rect (src, dst, &result, TRUE);
1456       result.x += xvimagesink->render_rect.x;
1457       result.y += xvimagesink->render_rect.y;
1458       break;
1459
1460     case DISP_GEO_METHOD_ORIGIN_SIZE:
1461       gst_video_sink_center_rect (src, dst, &result, FALSE);
1462       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1463
1464       if (xvimagesink->rotate_angle == DEGREE_90 ||
1465           xvimagesink->rotate_angle == DEGREE_270) {
1466         src_input.x = src_input.x ^ src_input.y;
1467         src_input.y = src_input.x ^ src_input.y;
1468         src_input.x = src_input.x ^ src_input.y;
1469
1470         src_input.w = src_input.w ^ src_input.h;
1471         src_input.h = src_input.w ^ src_input.h;
1472         src_input.w = src_input.w ^ src_input.h;
1473       }
1474       break;
1475
1476    case DISP_GEO_METHOD_FULL_SCREEN:
1477       result.x = result.y = 0;
1478       if (!xvimagesink->get_pixmap_cb) {
1479         result.w = xvimagesink->xwindow->width;
1480         result.h = xvimagesink->xwindow->height;
1481       } else {
1482         result.w = xvimagesink->xpixmap[idx]->width;
1483         result.h = xvimagesink->xpixmap[idx]->height;
1484       }
1485       break;
1486
1487    case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1488       gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1489
1490       result.x = result.y = 0;
1491       result.w = dst.w;
1492       result.h = dst.h;
1493
1494       if (xvimagesink->rotate_angle == DEGREE_90 ||
1495           xvimagesink->rotate_angle == DEGREE_270) {
1496         src_input.x = src_input.x ^ src_input.y;
1497         src_input.y = src_input.x ^ src_input.y;
1498         src_input.x = src_input.x ^ src_input.y;
1499
1500         src_input.w = src_input.w ^ src_input.h;
1501         src_input.h = src_input.w ^ src_input.h;
1502         src_input.w = src_input.w ^ src_input.h;
1503       }
1504       break;
1505
1506    case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
1507      if (src.w > dst.w || src.h > dst.h) {
1508        /* LETTER BOX */
1509        gst_video_sink_center_rect (src, dst, &result, TRUE);
1510        result.x += xvimagesink->render_rect.x;
1511        result.y += xvimagesink->render_rect.y;
1512      } else {
1513        /* ORIGIN SIZE */
1514        gst_video_sink_center_rect (src, dst, &result, FALSE);
1515        gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1516
1517        if (xvimagesink->rotate_angle == DEGREE_90 ||
1518            xvimagesink->rotate_angle == DEGREE_270) {
1519          src_input.x = src_input.x ^ src_input.y;
1520          src_input.y = src_input.x ^ src_input.y;
1521          src_input.x = src_input.x ^ src_input.y;
1522
1523          src_input.w = src_input.w ^ src_input.h;
1524          src_input.h = src_input.w ^ src_input.h;
1525          src_input.w = src_input.w ^ src_input.h;
1526        }
1527      }
1528      break;
1529
1530     case DISP_GEO_METHOD_CUSTOM_DST_ROI:
1531     {
1532       GstVideoRectangle dst_roi_cmpns;
1533       dst_roi_cmpns.w = xvimagesink->dst_roi.w;
1534       dst_roi_cmpns.h = xvimagesink->dst_roi.h;
1535       dst_roi_cmpns.x = xvimagesink->dst_roi.x;
1536       dst_roi_cmpns.y = xvimagesink->dst_roi.y;
1537
1538       /* setting for DST ROI mode */
1539       switch (xvimagesink->dst_roi_mode) {
1540       case ROI_DISP_GEO_METHOD_FULL_SCREEN:
1541         break;
1542       case ROI_DISP_GEO_METHOD_LETTER_BOX:
1543        {
1544         GstVideoRectangle roi_result;
1545         if (xvimagesink->orientation == DEGREE_0 ||
1546             xvimagesink->orientation == DEGREE_180) {
1547           src.w = src_origin.w;
1548           src.h = src_origin.h;
1549         } else {
1550           src.w = src_origin.h;
1551           src.h = src_origin.w;
1552         }
1553         dst.w = xvimagesink->dst_roi.w;
1554         dst.h = xvimagesink->dst_roi.h;
1555
1556         gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
1557         dst_roi_cmpns.w = roi_result.w;
1558         dst_roi_cmpns.h = roi_result.h;
1559         dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
1560         dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
1561        }
1562         break;
1563       default:
1564         break;
1565       }
1566
1567       /* calculating coordinates according to rotation angle for DST ROI */
1568       switch (xvimagesink->rotate_angle) {
1569       case DEGREE_90:
1570         result.w = dst_roi_cmpns.h;
1571         result.h = dst_roi_cmpns.w;
1572
1573         result.x = dst_roi_cmpns.y;
1574         if (!xvimagesink->get_pixmap_cb) {
1575           result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1576         } else {
1577           result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1578         }
1579         break;
1580       case DEGREE_180:
1581         result.w = dst_roi_cmpns.w;
1582         result.h = dst_roi_cmpns.h;
1583
1584         if (!xvimagesink->get_pixmap_cb) {
1585           result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
1586           result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
1587         } else {
1588           result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
1589           result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
1590         }
1591         break;
1592       case DEGREE_270:
1593         result.w = dst_roi_cmpns.h;
1594         result.h = dst_roi_cmpns.w;
1595
1596         if (!xvimagesink->get_pixmap_cb) {
1597           result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1598         } else {
1599           result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1600         }
1601         result.y = dst_roi_cmpns.x;
1602         break;
1603       default:
1604         result.x = dst_roi_cmpns.x;
1605         result.y = dst_roi_cmpns.y;
1606         result.w = dst_roi_cmpns.w;
1607         result.h = dst_roi_cmpns.h;
1608         break;
1609       }
1610
1611       /* orientation setting for auto rotation in DST ROI */
1612       if (xvimagesink->orientation) {
1613         res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation);
1614         if (res_rotate_angle < 0) {
1615           res_rotate_angle += DEGREE_NUM;
1616         }
1617         GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
1618                      xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle);
1619       }
1620
1621       GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
1622                      xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode,
1623                      xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1624                      result.x, result.y, result.w, result.h);
1625       break;
1626     }
1627     default:
1628       break;
1629   }
1630
1631   if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
1632     GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]",
1633                    xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
1634     gint default_offset_x = 0;
1635     gint default_offset_y = 0;
1636     gfloat w = (gfloat)src_input.w;
1637     gfloat h = (gfloat)src_input.h;
1638     if (xvimagesink->orientation == DEGREE_0 ||
1639         xvimagesink->orientation == DEGREE_180) {
1640       default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
1641       default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
1642     } else {
1643       default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1;
1644       default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1;
1645     }
1646     GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation);
1647     if (xvimagesink->zoom_pos_x == -1) {
1648       src_input.x += default_offset_x;
1649     } else {
1650       if (xvimagesink->orientation == DEGREE_0 ||
1651           xvimagesink->orientation == DEGREE_180) {
1652         if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) {
1653           xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom);
1654         }
1655         src_input.x += xvimagesink->zoom_pos_x;
1656       } else {
1657         if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) {
1658           xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom);
1659         }
1660         src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x;
1661       }
1662     }
1663     if (xvimagesink->zoom_pos_y == -1) {
1664       src_input.y += default_offset_y;
1665     } else {
1666       if (xvimagesink->orientation == DEGREE_0 ||
1667           xvimagesink->orientation == DEGREE_180) {
1668         if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) {
1669           xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom);
1670         }
1671         src_input.y += xvimagesink->zoom_pos_y;
1672       } else {
1673         if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) {
1674           xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom);
1675         }
1676         src_input.x += (xvimagesink->zoom_pos_y);
1677       }
1678     }
1679     src_input.w = (gint)(w/xvimagesink->zoom);
1680     src_input.h = (gint)(h/xvimagesink->zoom);
1681     GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
1682                    xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
1683   }
1684
1685 #else /* GST_EXT_XV_ENHANCEMENT */
1686   if (xvimagesink->keep_aspect) {
1687     GstVideoRectangle src, dst;
1688
1689     /* We use the calculated geometry from _setcaps as a source to respect
1690        source and screen pixel aspect ratios. */
1691     src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1692     src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1693     dst.w = xvimagesink->render_rect.w;
1694     dst.h = xvimagesink->render_rect.h;
1695
1696     gst_video_sink_center_rect (src, dst, &result, TRUE);
1697     result.x += xvimagesink->render_rect.x;
1698     result.y += xvimagesink->render_rect.y;
1699   } else {
1700     memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1701   }
1702 #endif /* GST_EXT_XV_ENHANCEMENT */
1703
1704   g_mutex_lock (xvimagesink->x_lock);
1705
1706 #ifdef GST_EXT_XV_ENHANCEMENT
1707   if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
1708 #else
1709   if (draw_border && xvimagesink->draw_borders) {
1710 #endif /* GST_EXT_XV_ENHANCEMENT */
1711     gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1712         result);
1713     xvimagesink->redraw_border = FALSE;
1714   }
1715
1716   /* We scale to the window's geometry */
1717 #ifdef HAVE_XSHM
1718   if (xvimagesink->xcontext->use_xshm) {
1719     GST_LOG_OBJECT (xvimagesink,
1720         "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1721         GST_PTR_FORMAT,
1722         xvimage->width, xvimage->height,
1723         xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1724
1725 #ifdef GST_EXT_XV_ENHANCEMENT
1726     switch( res_rotate_angle )
1727     {
1728       /* There's slightly weired code (CCW? CW?) */
1729       case DEGREE_0:
1730         break;
1731       case DEGREE_90:
1732         rotate = 270;
1733         break;
1734       case DEGREE_180:
1735         rotate = 180;
1736         break;
1737       case DEGREE_270:
1738         rotate = 90;
1739         break;
1740       default:
1741         GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1742           res_rotate_angle );
1743         break;
1744     }
1745
1746     /* Trim as proper size */
1747     if (src_input.w % 2 == 1) {
1748         src_input.w += 1;
1749     }
1750     if (src_input.h % 2 == 1) {
1751         src_input.h += 1;
1752     }
1753
1754     if (!xvimagesink->get_pixmap_cb) {
1755       GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1756         xvimagesink->scr_w, xvimagesink->scr_h,
1757         xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1758         xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1759         src_origin.w, src_origin.h,
1760         dst.x, dst.y, dst.w, dst.h,
1761         src_input.x, src_input.y, src_input.w, src_input.h,
1762         result.x, result.y, result.w, result.h );
1763     } else {
1764       GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1765       xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
1766       xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1767       src_origin.w, src_origin.h,
1768       dst.x, dst.y, dst.w, dst.h,
1769       src_input.x, src_input.y, src_input.w, src_input.h,
1770       result.x, result.y, result.w, result.h );
1771     }
1772     /* skip request to render if dst rect is 0 */
1773     if (xvimagesink->is_zero_copy_format && (!result.w || !result.h)) {
1774       GST_WARNING_OBJECT(xvimagesink, "result.w[%d] or result.h[%d] is 0. Skip xvimage_put.", result.w, result.h);
1775       g_mutex_unlock(xvimagesink->x_lock);
1776       g_mutex_unlock(xvimagesink->flow_lock);
1777       return TRUE;
1778     }
1779
1780     static gboolean is_exist = FALSE;
1781     gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_ROTATION");
1782     is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1783     g_free(attr_name);
1784
1785     if (is_exist) {
1786       /* set display rotation */
1787       if (atom_rotation == None) {
1788         atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1789                                   "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1790       }
1791       ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1792                                atom_rotation, rotate);
1793       if (ret != Success) {
1794         GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1795           ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1796
1797         g_mutex_unlock(xvimagesink->x_lock);
1798         g_mutex_unlock(xvimagesink->flow_lock);
1799         return FALSE;
1800       }
1801     } else {
1802       GST_WARNING("_USER_WM_PORT_ATTRIBUTE_ROTATION is not existed");
1803     }
1804
1805     switch( xvimagesink->orientation )
1806     {
1807       case DEGREE_0:
1808         orientation = 0;
1809         break;
1810       case DEGREE_90:
1811         orientation = 90;
1812         break;
1813       case DEGREE_180:
1814         orientation = 180;
1815         break;
1816       case DEGREE_270:
1817         orientation = 270;
1818         break;
1819       default:
1820         GST_WARNING_OBJECT( xvimagesink, "Unsupported orientation [%d]...",
1821           xvimagesink->orientation );
1822         break;
1823     }
1824
1825     is_exist = FALSE;
1826     attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION");
1827     is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1828     g_free(attr_name);
1829
1830     if (is_exist) {
1831       /* set contents rotation for connecting with external display */
1832       if (atom_contents_rotation == None) {
1833         atom_contents_rotation = XInternAtom(xvimagesink->xcontext->disp,
1834                                  "_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION", False);
1835       }
1836       ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1837                                atom_contents_rotation, orientation);
1838       if (ret != Success) {
1839         GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],orientation[%d]",
1840           ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_contents_rotation, orientation );
1841
1842         g_mutex_unlock(xvimagesink->x_lock);
1843         g_mutex_unlock(xvimagesink->flow_lock);
1844         return FALSE;
1845       }
1846     }else {
1847       GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION is not existed");
1848     }
1849
1850     switch (xvimagesink->flip) {
1851     case FLIP_HORIZONTAL:
1852       set_hflip = TRUE;
1853       set_vflip = FALSE;
1854       break;
1855     case FLIP_VERTICAL:
1856       set_hflip = FALSE;
1857       set_vflip = TRUE;
1858       break;
1859     case FLIP_BOTH:
1860       set_hflip = TRUE;
1861       set_vflip = TRUE;
1862       break;
1863     case FLIP_NONE:
1864     default:
1865       set_hflip = FALSE;
1866       set_vflip = FALSE;
1867       break;
1868     }
1869
1870     GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
1871
1872     is_exist = FALSE;
1873     attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_HFLIP");
1874     is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1875     g_free(attr_name);
1876
1877     if (is_exist) {
1878       if (atom_hflip == None) {
1879         /* set display flip */
1880         atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
1881                                  "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1882     }
1883       ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1884       if (ret != Success) {
1885         GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1886                     ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1887       }
1888     }
1889
1890     is_exist = FALSE;
1891     attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_VFLIP");
1892     is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1893     g_free(attr_name);
1894
1895     if (is_exist) {
1896       if (atom_vflip == None) {
1897         /* set display flip */
1898         atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
1899                                  "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1900        }
1901       ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1902       if (ret != Success) {
1903         GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1904                     ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1905       }
1906     }
1907
1908     /* set error handler */
1909     error_caught = FALSE;
1910     handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
1911
1912     /* src input indicates the status when degree is 0 */
1913     /* dst input indicates the area that src will be shown regardless of rotate */
1914     if (xvimagesink->visible &&
1915       ((!xvimagesink->is_hided) || (xvimagesink->is_hided && (GST_STATE(xvimagesink) == GST_STATE_PLAYING)))) {
1916       if (xvimagesink->xim_transparenter) {
1917         GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1918         XPutImage(xvimagesink->xcontext->disp,
1919           xvimagesink->xwindow->win,
1920           xvimagesink->xwindow->gc,
1921           xvimagesink->xim_transparenter,
1922           0, 0,
1923           result.x, result.y, result.w, result.h);
1924       }
1925
1926       /* store buffer */
1927       if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) {
1928         img_data = (XV_DATA_PTR)xvimage->xvimage->data;
1929         if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
1930           _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
1931           xvimage->current_buffer = NULL;
1932         }
1933       }
1934
1935       g_mutex_lock(xvimagesink->display_buffer_lock);
1936       if (xvimagesink->displaying_buffer_count > 3) {
1937         GST_WARNING("too many buffers are not released. [displaying_buffer_count %d]", xvimagesink->displaying_buffer_count);
1938       }
1939       g_mutex_unlock(xvimagesink->display_buffer_lock);
1940
1941       if (xvimagesink->get_pixmap_cb) {
1942         gint idx = xvimagesink->current_pixmap_idx;
1943         ret = XvShmPutImage (xvimagesink->xcontext->disp,
1944           xvimagesink->xcontext->xv_port_id,
1945           xvimagesink->xpixmap[idx]->pixmap,
1946           xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
1947           src_input.x, src_input.y, src_input.w, src_input.h,
1948           result.x, result.y, result.w, result.h, FALSE);
1949         GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], pixmap id[%d], idx[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xpixmap[idx]->gc, xvimagesink->xpixmap[idx]->pixmap, idx);
1950       } else {
1951         ret = XvShmPutImage (xvimagesink->xcontext->disp,
1952           xvimagesink->xcontext->xv_port_id,
1953           xvimagesink->xwindow->win,
1954           xvimagesink->xwindow->gc, xvimage->xvimage,
1955           src_input.x, src_input.y, src_input.w, src_input.h,
1956           result.x, result.y, result.w, result.h, FALSE);
1957         GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], xid[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xwindow->gc, xvimagesink->xwindow->win);
1958       }
1959     } else {
1960       GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1961     }
1962 #else /* GST_EXT_XV_ENHANCEMENT */
1963     XvShmPutImage (xvimagesink->xcontext->disp,
1964         xvimagesink->xcontext->xv_port_id,
1965         xvimagesink->xwindow->win,
1966         xvimagesink->xwindow->gc, xvimage->xvimage,
1967         xvimagesink->disp_x, xvimagesink->disp_y,
1968         xvimagesink->disp_width, xvimagesink->disp_height,
1969         result.x, result.y, result.w, result.h, FALSE);
1970 #endif /* GST_EXT_XV_ENHANCEMENT */
1971   } else
1972 #endif /* HAVE_XSHM */
1973   {
1974     XvPutImage (xvimagesink->xcontext->disp,
1975         xvimagesink->xcontext->xv_port_id,
1976         xvimagesink->xwindow->win,
1977         xvimagesink->xwindow->gc, xvimage->xvimage,
1978         xvimagesink->disp_x, xvimagesink->disp_y,
1979         xvimagesink->disp_width, xvimagesink->disp_height,
1980         result.x, result.y, result.w, result.h);
1981   }
1982
1983   XSync (xvimagesink->xcontext->disp, FALSE);
1984
1985 #ifdef HAVE_XSHM
1986 #ifdef GST_EXT_XV_ENHANCEMENT
1987   if (ret || error_caught || xvimagesink->get_pixmap_cb) {
1988     GST_DEBUG("error or pixmap_cb");
1989
1990     if (ret || error_caught) {
1991       GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
1992                   ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
1993
1994       if (xvimagesink->get_pixmap_cb) {
1995         g_signal_emit (G_OBJECT (xvimagesink),
1996                        gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
1997                        0,
1998                        &xvimagesink->xpixmap[idx]->pixmap,
1999                        &res);
2000       }
2001     }
2002
2003     /* release gem handle */
2004     if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
2005       unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
2006       gem_name[0] = img_data->YBuf;
2007       gem_name[1] = img_data->CbBuf;
2008       gem_name[2] = img_data->CrBuf;
2009       _remove_displaying_buffer(xvimagesink, gem_name);
2010     }
2011   }
2012
2013   /* Reset error handler */
2014   if (handler) {
2015     error_caught = FALSE;
2016     XSetErrorHandler (handler);
2017   }
2018 #endif /* GST_EXT_XV_ENHANCEMENT */
2019 #endif /* HAVE_XSHM */
2020
2021   g_mutex_unlock (xvimagesink->x_lock);
2022
2023   g_mutex_unlock (xvimagesink->flow_lock);
2024
2025   return TRUE;
2026 }
2027
2028 static gboolean
2029 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
2030     GstXWindow * window)
2031 {
2032   Atom hints_atom = None;
2033   MotifWmHints *hints;
2034
2035   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
2036   g_return_val_if_fail (window != NULL, FALSE);
2037
2038   g_mutex_lock (xvimagesink->x_lock);
2039
2040   hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
2041       True);
2042   if (hints_atom == None) {
2043     g_mutex_unlock (xvimagesink->x_lock);
2044     return FALSE;
2045   }
2046
2047   hints = g_malloc0 (sizeof (MotifWmHints));
2048
2049   hints->flags |= MWM_HINTS_DECORATIONS;
2050   hints->decorations = 1 << 0;
2051
2052   XChangeProperty (xvimagesink->xcontext->disp, window->win,
2053       hints_atom, hints_atom, 32, PropModeReplace,
2054       (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
2055
2056   XSync (xvimagesink->xcontext->disp, FALSE);
2057
2058   g_mutex_unlock (xvimagesink->x_lock);
2059
2060   g_free (hints);
2061
2062   return TRUE;
2063 }
2064
2065 static void
2066 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
2067     GstXWindow * xwindow, const gchar * media_title)
2068 {
2069   if (media_title) {
2070     g_free (xvimagesink->media_title);
2071     xvimagesink->media_title = g_strdup (media_title);
2072   }
2073   if (xwindow) {
2074     /* we have a window */
2075     if (xwindow->internal) {
2076       XTextProperty xproperty;
2077       const gchar *app_name;
2078       const gchar *title = NULL;
2079       gchar *title_mem = NULL;
2080
2081       /* set application name as a title */
2082       app_name = g_get_application_name ();
2083
2084       if (app_name && xvimagesink->media_title) {
2085         title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
2086             app_name, NULL);
2087       } else if (app_name) {
2088         title = app_name;
2089       } else if (xvimagesink->media_title) {
2090         title = xvimagesink->media_title;
2091       }
2092
2093       if (title) {
2094         if ((XStringListToTextProperty (((char **) &title), 1,
2095                     &xproperty)) != 0) {
2096           XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
2097           XFree (xproperty.value);
2098         }
2099
2100         g_free (title_mem);
2101       }
2102     }
2103   }
2104 }
2105
2106 #ifdef GST_EXT_XV_ENHANCEMENT
2107 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
2108 {
2109   XImage *xim;
2110
2111   /* create a normal ximage */
2112   xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)),  24, ZPixmap, 0, NULL, w, h, 32, 0);
2113
2114   GST_INFO("ximage %p", xim);
2115
2116   /* allocate data for it */
2117   if (xim) {
2118     xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
2119     if (xim->data) {
2120       memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
2121       return xim;
2122     } else {
2123       GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
2124     }
2125
2126     XDestroyImage(xim);
2127   }
2128
2129   GST_ERROR("failed to create Ximage");
2130
2131   return NULL;
2132 }
2133
2134
2135 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
2136 {
2137   int ret = 0;
2138   static gboolean is_exist = FALSE;
2139   static XvPortID current_port_id = -1;
2140   Atom atom_output = None;
2141
2142   if (xcontext == NULL) {
2143     GST_WARNING("xcontext is NULL");
2144     return FALSE;
2145   }
2146
2147   /* check once per one xv_port_id */
2148   if (current_port_id != xcontext->xv_port_id) {
2149     /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2150     int i = 0;
2151     int count = 0;
2152     XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2153                                                     xcontext->xv_port_id, &count);
2154     if (attr) {
2155       current_port_id = xcontext->xv_port_id;
2156       for (i = 0 ; i < count ; i++) {
2157         if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
2158           is_exist = TRUE;
2159           GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2160           break;
2161         }
2162       }
2163       XFree(attr);
2164     } else {
2165       GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2166                   xcontext->disp, xcontext->xv_port_id);
2167     }
2168   }
2169
2170   if (is_exist) {
2171     GST_DEBUG("set display mode %d", set_mode);
2172     atom_output = XInternAtom(xcontext->disp,
2173                               "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
2174     ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2175                              atom_output, set_mode);
2176     if (ret == Success) {
2177       return TRUE;
2178     } else {
2179       GST_WARNING("display mode[%d] set failed.", set_mode);
2180     }
2181   } else {
2182     GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
2183   }
2184
2185   return FALSE;
2186 }
2187
2188
2189 static gboolean set_csc_range(GstXContext *xcontext, int set_range)
2190 {
2191   int ret = 0;
2192   static gboolean is_exist = FALSE;
2193   static XvPortID current_port_id = -1;
2194   Atom atom_csc_range = None;
2195
2196   if (xcontext == NULL) {
2197     GST_WARNING("xcontext is NULL");
2198     return FALSE;
2199   }
2200
2201   /* check once per one xv_port_id */
2202   if (current_port_id != xcontext->xv_port_id) {
2203     /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2204     int i = 0;
2205     int count = 0;
2206     XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2207                                                     xcontext->xv_port_id, &count);
2208     if (attr) {
2209       current_port_id = xcontext->xv_port_id;
2210       for (i = 0 ; i < count ; i++) {
2211         if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
2212           is_exist = TRUE;
2213           GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2214           break;
2215         }
2216       }
2217       XFree(attr);
2218     } else {
2219       GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2220                   xcontext->disp, xcontext->xv_port_id);
2221     }
2222   }
2223
2224   if (is_exist) {
2225     GST_WARNING("set csc range %d", set_range);
2226     atom_csc_range = XInternAtom(xcontext->disp,
2227                                  "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
2228     ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2229                              atom_csc_range, set_range);
2230     if (ret == Success) {
2231       return TRUE;
2232     } else {
2233       GST_WARNING("csc range[%d] set failed.", set_range);
2234     }
2235   } else {
2236     GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
2237   }
2238
2239   return FALSE;
2240 }
2241
2242
2243 static void drm_init(GstXvImageSink *xvimagesink)
2244 {
2245         Display *dpy;
2246         int eventBase = 0;
2247         int errorBase = 0;
2248         int dri2Major = 0;
2249         int dri2Minor = 0;
2250         char *driverName = NULL;
2251         char *deviceName = NULL;
2252         struct drm_auth auth_arg = {0};
2253
2254         xvimagesink->drm_fd = -1;
2255
2256         dpy = XOpenDisplay(0);
2257         if (!dpy) {
2258                 GST_ERROR("XOpenDisplay failed errno:%d", errno);
2259                 return;
2260         }
2261
2262         GST_INFO("START");
2263
2264         /* DRI2 */
2265         if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
2266                 GST_ERROR("DRI2QueryExtension !!");
2267                 goto DRM_INIT_ERROR;
2268         }
2269
2270         if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
2271                 GST_ERROR("DRI2QueryVersion !!");
2272                 goto DRM_INIT_ERROR;
2273         }
2274
2275         if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
2276                 GST_ERROR("DRI2Connect !!");
2277                 goto DRM_INIT_ERROR;
2278         }
2279
2280         if (!driverName || !deviceName) {
2281                 GST_ERROR("driverName or deviceName is not valid");
2282                 goto DRM_INIT_ERROR;
2283         }
2284
2285         GST_INFO("Open drm device : %s", deviceName);
2286
2287         /* get the drm_fd though opening the deviceName */
2288         xvimagesink->drm_fd = open(deviceName, O_RDWR);
2289         if (xvimagesink->drm_fd < 0) {
2290                 GST_ERROR("cannot open drm device (%s)", deviceName);
2291                 goto DRM_INIT_ERROR;
2292         }
2293
2294         /* get magic from drm to authentication */
2295         if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
2296                 GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd);
2297                 goto DRM_INIT_ERROR;
2298         }
2299
2300         if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
2301                 GST_ERROR("cannot get drm authentication from X");
2302                 goto DRM_INIT_ERROR;
2303         }
2304
2305         XCloseDisplay(dpy);
2306         free(driverName);
2307         free(deviceName);
2308
2309         xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd);
2310         if (xvimagesink->bufmgr == NULL) {
2311                 GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed");
2312                 goto DRM_INIT_ERROR;
2313         }
2314
2315         GST_INFO("DONE");
2316
2317         return;
2318
2319 DRM_INIT_ERROR:
2320         if (xvimagesink->drm_fd >= 0) {
2321                 close(xvimagesink->drm_fd);
2322                 xvimagesink->drm_fd = -1;
2323         }
2324         if (dpy) {
2325                 XCloseDisplay(dpy);
2326         }
2327         if (driverName) {
2328                 free(driverName);
2329         }
2330         if (deviceName) {
2331                 free(deviceName);
2332         }
2333
2334         return;
2335 }
2336
2337 static void drm_fini(GstXvImageSink *xvimagesink)
2338 {
2339         GST_WARNING_OBJECT(xvimagesink, "START");
2340
2341         if (xvimagesink->drm_fd >= 0) {
2342                 int i = 0;
2343                 int j = 0;
2344
2345                 /* close remained gem handle */
2346                 g_mutex_lock(xvimagesink->display_buffer_lock);
2347                 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2348                         if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2349                                 GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u",
2350                                             xvimagesink->displaying_buffers[i].buffer,
2351                                             xvimagesink->displaying_buffers[i].gem_name[0],
2352                                             xvimagesink->displaying_buffers[i].gem_name[1],
2353                                             xvimagesink->displaying_buffers[i].gem_name[2],
2354                                             xvimagesink->displaying_buffers[i].gem_handle[0],
2355                                             xvimagesink->displaying_buffers[i].gem_handle[1],
2356                                             xvimagesink->displaying_buffers[i].gem_handle[2]);
2357
2358                                 /* release flush buffer */
2359                                 if (xvimagesink->flush_buffer) {
2360                                         if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] &&
2361                                             xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] &&
2362                                             xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) {
2363                                                 _release_flush_buffer(xvimagesink);
2364                                         }
2365                                 } else {
2366                                         GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer");
2367                                 }
2368
2369                                 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2370                                         if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2371                                                 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2372                                         }
2373                                         xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2374                                         xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2375                                         xvimagesink->displaying_buffers[i].bo[j] = NULL;
2376                                 }
2377
2378                                 if (xvimagesink->displaying_buffers[i].buffer) {
2379                                         gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2380                                         xvimagesink->displaying_buffers[i].buffer = NULL;
2381                                 }
2382                         }
2383                 }
2384                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2385
2386                 GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager");
2387                 tbm_bufmgr_deinit(xvimagesink->bufmgr);
2388                 xvimagesink->bufmgr = NULL;
2389
2390                 GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd);
2391                 close(xvimagesink->drm_fd);
2392                 xvimagesink->drm_fd = -1;
2393         } else {
2394                 GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened");
2395         }
2396
2397         GST_WARNING_OBJECT(xvimagesink, "DONE");
2398 }
2399
2400 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
2401 {
2402         int ret = 0;
2403
2404         struct drm_prime_handle prime_arg = {0,};
2405         struct drm_gem_flink flink_arg = {0,};
2406
2407         if (!xvimagesink || !gem_handle) {
2408                 GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
2409                 return 0;
2410         }
2411
2412         if (xvimagesink->drm_fd < 0) {
2413                 GST_ERROR("DRM is not opened");
2414                 return 0;
2415         }
2416
2417         if (dmabuf_fd <= 0) {
2418                 GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
2419                 return 0;
2420         }
2421
2422         prime_arg.fd = dmabuf_fd;
2423         ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
2424         if (ret) {
2425                 GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]",
2426                           ret, dmabuf_fd, xvimagesink->drm_fd);
2427                 return 0;
2428         }
2429
2430         *gem_handle = prime_arg.handle;
2431         flink_arg.handle = prime_arg.handle;
2432         ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
2433         if (ret) {
2434                 GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]",
2435                           ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd);
2436                 return 0;
2437         }
2438
2439         return flink_arg.name;
2440 }
2441
2442 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
2443 {
2444         struct drm_gem_close close_arg = {0,};
2445
2446         if (xvimagesink->drm_fd < 0 || !gem_handle) {
2447                 GST_ERROR("DRM is not opened");
2448                 return;
2449         }
2450
2451         if (*gem_handle <= 0) {
2452                 GST_DEBUG("invalid gem handle %u", *gem_handle);
2453                 return;
2454         }
2455
2456         GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
2457
2458         close_arg.handle = *gem_handle;
2459         if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
2460                 GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd);
2461                 return;
2462         }
2463
2464         *gem_handle = 0;
2465
2466         return;
2467 }
2468
2469
2470 static void _remove_last_buffer(GstXvImageSink *xvimagesink)
2471 {
2472   gboolean enable_last_buffer = FALSE;
2473
2474   if (xvimagesink == NULL) {
2475     GST_ERROR("handle is NULL");
2476     return;
2477   }
2478
2479   /* get enable-last-buffer */
2480   g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
2481
2482   GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
2483
2484   /* flush if enable-last-buffer is TRUE */
2485   if (enable_last_buffer) {
2486     g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
2487     g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
2488   }
2489
2490   return;
2491 }
2492
2493
2494 static void _release_flush_buffer(GstXvImageSink *xvimagesink)
2495 {
2496         int i = 0;
2497
2498         if (xvimagesink == NULL ||
2499             xvimagesink->flush_buffer == NULL) {
2500                 GST_WARNING("handle is NULL");
2501                 return;
2502         }
2503
2504         GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER");
2505
2506         for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
2507                 if (xvimagesink->flush_buffer->bo[i]) {
2508                         tbm_bo_unref(xvimagesink->flush_buffer->bo[i]);
2509                         xvimagesink->flush_buffer->bo[i] = NULL;
2510                 }
2511         }
2512
2513         GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done");
2514
2515         free(xvimagesink->flush_buffer);
2516         xvimagesink->flush_buffer = NULL;
2517
2518         return;
2519 }
2520
2521
2522 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
2523 {
2524         int i = 0;
2525         int j = 0;
2526
2527         if (!xvimagesink || !img_data) {
2528                 GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
2529                 return;
2530         }
2531
2532         /* lock display buffer mutex */
2533         g_mutex_lock(xvimagesink->display_buffer_lock);
2534
2535         /* increase displaying buffer count */
2536         xvimagesink->displaying_buffer_count++;
2537
2538         /* check duplicated */
2539         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2540                 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2541                         if ((img_data->dmabuf_fd[0] > 0 &&
2542                              xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
2543                              xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
2544                              xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
2545                             (img_data->bo[0] &&
2546                              xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
2547                              xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
2548                              xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
2549                                 /* increase ref count */
2550                                 xvimagesink->displaying_buffers[i].ref_count++;
2551
2552                                 /* set buffer info */
2553                                 img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
2554                                 img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
2555                                 img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
2556
2557                                 if (img_data->dmabuf_fd[0] > 0) {
2558                                         GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
2559                                                     img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
2560                                                     img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2561                                 } else {
2562                                         GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
2563                                                     img_data->bo[0], img_data->bo[1], img_data->bo[2],
2564                                                     img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2565                                 }
2566
2567                                 /* unlock display buffer mutex */
2568                                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2569                                 return;
2570                         }
2571                 }
2572         }
2573
2574         /* store buffer temporarily */
2575         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2576                 if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
2577                         if (buffer) {
2578                                 /* increase ref count of buffer */
2579                                 gst_buffer_ref(buffer);
2580                                 xvimagesink->displaying_buffers[i].buffer = buffer;
2581                         }
2582
2583                         if (img_data->dmabuf_fd[0] > 0) {
2584                                 /* convert fd to name */
2585                                 img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
2586                                 img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
2587                                 img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
2588                         } else {
2589                                 /* export bo */
2590                                 if (img_data->bo[0]) {
2591                                         img_data->YBuf = tbm_bo_export(img_data->bo[0]);
2592                                 }
2593                                 if (img_data->bo[1]) {
2594                                         img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
2595                                 }
2596                                 if (img_data->bo[2]) {
2597                                         img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
2598                                 }
2599                         }
2600
2601                         for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2602                                 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
2603                                 xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
2604                                 xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
2605                         }
2606
2607                         /* set buffer info */
2608                         xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
2609                         xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
2610                         xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
2611
2612                         /* set ref count */
2613                         xvimagesink->displaying_buffers[i].ref_count = 1;
2614
2615                         if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2616                                 GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2617                                                                 xvimagesink->displayed_buffer_count,
2618                                                                 i, xvimagesink->displaying_buffers[i].buffer,
2619                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2620                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2621                                                                 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2622                                                                 xvimagesink->displaying_buffers[i].gem_handle[0],
2623                                                                 xvimagesink->displaying_buffers[i].gem_handle[1],
2624                                                                 xvimagesink->displaying_buffers[i].gem_handle[2],
2625                                                                 xvimagesink->displaying_buffers[i].gem_name[0],
2626                                                                 xvimagesink->displaying_buffers[i].gem_name[1],
2627                                                                 xvimagesink->displaying_buffers[i].gem_name[2]);
2628                         } else {
2629                                 GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2630                                                               i, xvimagesink->displaying_buffers[i].buffer,
2631                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2632                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2633                                                               xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2634                                                               xvimagesink->displaying_buffers[i].gem_handle[0],
2635                                                               xvimagesink->displaying_buffers[i].gem_handle[1],
2636                                                               xvimagesink->displaying_buffers[i].gem_handle[2],
2637                                                               xvimagesink->displaying_buffers[i].gem_name[0],
2638                                                               xvimagesink->displaying_buffers[i].gem_name[1],
2639                                                               xvimagesink->displaying_buffers[i].gem_name[2]);
2640                         }
2641
2642                         /* set last added buffer index */
2643                         xvimagesink->last_added_buffer_index = i;
2644                         GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i);
2645
2646                         /* unlock display buffer mutex */
2647                         g_mutex_unlock(xvimagesink->display_buffer_lock);
2648
2649                         /* get current time */
2650                         gettimeofday(&xvimagesink->request_time[i], NULL);
2651                         return;
2652                 }
2653         }
2654
2655         /* decrease displaying buffer count */
2656         xvimagesink->displaying_buffer_count--;
2657
2658         /* unlock display buffer mutex */
2659         g_mutex_unlock(xvimagesink->display_buffer_lock);
2660
2661         GST_ERROR("should not be reached here. buffer slot is FULL...");
2662
2663         return;
2664 }
2665
2666
2667 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
2668 {
2669         int i = 0;
2670         int j = 0;
2671
2672         if (!xvimagesink || !gem_name) {
2673                 GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name);
2674                 return;
2675         }
2676
2677         /* lock display buffer mutex */
2678         g_mutex_lock(xvimagesink->display_buffer_lock);
2679
2680         if (xvimagesink->displaying_buffer_count == 0) {
2681                 GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer");
2682                 /* unlock display buffer mutex */
2683                 g_mutex_unlock(xvimagesink->display_buffer_lock);
2684                 return;
2685         }
2686
2687         GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d",
2688                   gem_name[0], gem_name[1], gem_name[2],
2689                   xvimagesink->displaying_buffer_count);
2690
2691         for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2692                 if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
2693                     xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
2694                     xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
2695                         struct timeval current_time;
2696
2697                         /* get current time to calculate displaying time */
2698                         gettimeofday(&current_time, NULL);
2699
2700                         GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
2701                                                       (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
2702                                                       (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
2703
2704                         if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2705                                 xvimagesink->displayed_buffer_count++;
2706                                 GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2707                                                                 xvimagesink->displayed_buffer_count,
2708                                                                 i, xvimagesink->displaying_buffers[i].buffer,
2709                                                                 xvimagesink->displaying_buffers[i].gem_handle[0],
2710                                                                 xvimagesink->displaying_buffers[i].gem_handle[1],
2711                                                                 xvimagesink->displaying_buffers[i].gem_handle[2],
2712                                                                 xvimagesink->displaying_buffers[i].gem_name[0],
2713                                                                 xvimagesink->displaying_buffers[i].gem_name[1],
2714                                                                 xvimagesink->displaying_buffers[i].gem_name[2]);
2715                         } else {
2716                                 GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2717                                                               i, xvimagesink->displaying_buffers[i].buffer,
2718                                                               xvimagesink->displaying_buffers[i].gem_handle[0],
2719                                                               xvimagesink->displaying_buffers[i].gem_handle[1],
2720                                                               xvimagesink->displaying_buffers[i].gem_handle[2],
2721                                                               xvimagesink->displaying_buffers[i].gem_name[0],
2722                                                               xvimagesink->displaying_buffers[i].gem_name[1],
2723                                                               xvimagesink->displaying_buffers[i].gem_name[2]);
2724                         }
2725
2726                         /* decrease displaying buffer count */
2727                         xvimagesink->displaying_buffer_count--;
2728
2729                         /* decrease ref count */
2730                         xvimagesink->displaying_buffers[i].ref_count--;
2731
2732                         if (xvimagesink->displaying_buffers[i].ref_count > 0) {
2733                                 GST_WARNING("ref count not zero[%d], skip close gem handle",
2734                                             xvimagesink->displaying_buffers[i].ref_count);
2735                                 break;
2736                         }
2737
2738                         /* release flush buffer */
2739                         if (xvimagesink->flush_buffer) {
2740                                 if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] &&
2741                                     xvimagesink->flush_buffer->gem_name[1] == gem_name[1] &&
2742                                     xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) {
2743                                         _release_flush_buffer(xvimagesink);
2744                                 }
2745                         }
2746
2747                         for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2748                                 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2749                                         drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2750                                 }
2751                                 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2752                                 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2753                                 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2754                         }
2755
2756                         /* reset last_added_buffer_index */
2757                         if (xvimagesink->displaying_buffer_count < 1) {
2758                                 xvimagesink->last_added_buffer_index = -1;
2759                                 GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d",
2760                                                                 xvimagesink->displaying_buffer_count);
2761                         }
2762
2763                         if (xvimagesink->displaying_buffers[i].buffer) {
2764                                 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2765                                 xvimagesink->displaying_buffers[i].buffer = NULL;
2766                         } else {
2767                                 GST_WARNING("no buffer to unref");
2768                         }
2769                         break;
2770                 }
2771         }
2772
2773         /* unlock display buffer mutex */
2774         g_mutex_unlock(xvimagesink->display_buffer_lock);
2775
2776         return;
2777 }
2778
2779
2780 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
2781 {
2782   Atom type_ret = 0;
2783   int i = 0;
2784   int ret = 0;
2785   int size_ret = 0;
2786   unsigned long num_ret = 0;
2787   unsigned long bytes = 0;
2788   unsigned char *prop_ret = NULL;
2789   unsigned int data = 0;
2790   int (*handler) (Display *, XErrorEvent *) = NULL;
2791   Atom atom_output_external;
2792
2793   atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
2794                                        "XV_OUTPUT_EXTERNAL", False);
2795   if (atom_output_external != None) {
2796     /* set error handler */
2797     error_caught = FALSE;
2798     handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
2799
2800     ret = XGetWindowProperty(xvimagesink->xcontext->disp,
2801                              xvimagesink->xwindow->win,
2802                              atom_output_external, 0, 0x7fffffff,
2803                              False, XA_CARDINAL, &type_ret, &size_ret,
2804                              &num_ret, &bytes, &prop_ret);
2805     XSync(xvimagesink->xcontext->disp, FALSE);
2806     if (ret != Success || error_caught) {
2807       GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
2808       if (prop_ret) {
2809         XFree(prop_ret);
2810       }
2811       if (error_caught) {
2812         GST_WARNING_OBJECT(xvimagesink, "error caught in XGetWindowProperty()");
2813       }
2814       if (handler) {
2815         error_caught = FALSE;
2816         XSetErrorHandler (handler);
2817       }
2818       return False;
2819     }
2820
2821     if (handler) {
2822       error_caught = FALSE;
2823       XSetErrorHandler (handler);
2824     }
2825
2826     if (!num_ret) {
2827       GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
2828       if (prop_ret) {
2829         XFree(prop_ret);
2830       }
2831       return False;
2832     }
2833
2834     if (prop_ret) {
2835       switch (size_ret) {
2836       case 8:
2837         for (i = 0 ; i < num_ret ; i++) {
2838           (&data)[i] = prop_ret[i];
2839         }
2840         break;
2841       case 16:
2842         for (i = 0 ; i < num_ret ; i++) {
2843           ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
2844         }
2845         break;
2846       case 32:
2847         for (i = 0 ; i < num_ret ; i++) {
2848           ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
2849         }
2850         break;
2851       }
2852       XFree(prop_ret);
2853       prop_ret = NULL;
2854
2855       GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
2856
2857       return (int)data;
2858     } else {
2859       GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
2860       return False;
2861     }
2862   } else {
2863     GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
2864   }
2865
2866   return False;
2867 }
2868 #endif /* GST_EXT_XV_ENHANCEMENT */
2869
2870 /* This function handles a GstXWindow creation
2871  * The width and height are the actual pixel size on the display */
2872 static GstXWindow *
2873 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
2874     gint width, gint height)
2875 {
2876   GstXWindow *xwindow = NULL;
2877   XGCValues values;
2878 #ifdef GST_EXT_XV_ENHANCEMENT
2879   XSetWindowAttributes win_attr;
2880   XWindowAttributes root_attr = {0 , };
2881 #endif /* GST_EXT_XV_ENHANCEMENT */
2882
2883   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2884
2885   xwindow = g_new0 (GstXWindow, 1);
2886
2887   xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2888 #ifdef GST_EXT_XV_ENHANCEMENT
2889   /* 0 or 180 */
2890   if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
2891     xvimagesink->render_rect.w = xwindow->width = width;
2892     xvimagesink->render_rect.h = xwindow->height = height;
2893   /* 90 or 270 */
2894   } else {
2895     xvimagesink->render_rect.w = xwindow->width = height;
2896     xvimagesink->render_rect.h = xwindow->height = width;
2897   }
2898
2899   if(!xvimagesink->is_pixmap)
2900     XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
2901
2902   if (xwindow->width > root_attr.width) {
2903     GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
2904                                  xwindow->width, root_attr.width);
2905     xvimagesink->render_rect.w = xwindow->width = root_attr.width;
2906   }
2907   if (xwindow->height > root_attr.height) {
2908     GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
2909                                  xwindow->height, root_attr.height);
2910     xvimagesink->render_rect.h = xwindow->height = root_attr.height;
2911   }
2912   xwindow->internal = TRUE;
2913
2914   g_mutex_lock (xvimagesink->x_lock);
2915
2916   GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
2917
2918   xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
2919                                      xvimagesink->xcontext->root,
2920                                      0, 0, xwindow->width, xwindow->height,
2921                                      0, 0, 0);
2922
2923   xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
2924                                                           xvimagesink->xcontext->root,
2925                                                           xwindow->width, xwindow->height);
2926
2927   /* Make window manager not to change window size as Full screen */
2928   win_attr.override_redirect = True;
2929   if(!xvimagesink->is_pixmap)
2930     XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
2931 #else /* GST_EXT_XV_ENHANCEMENT */
2932   xvimagesink->render_rect.w = width;
2933   xvimagesink->render_rect.h = height;
2934
2935   xwindow->width = width;
2936   xwindow->height = height;
2937   xwindow->internal = TRUE;
2938
2939   g_mutex_lock (xvimagesink->x_lock);
2940
2941   xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
2942       xvimagesink->xcontext->root,
2943       0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
2944 #endif /* GST_EXT_XV_ENHANCEMENT */
2945
2946   /* We have to do that to prevent X from redrawing the background on
2947    * ConfigureNotify. This takes away flickering of video when resizing. */
2948   XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
2949
2950   /* set application name as a title */
2951   gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
2952
2953   if (xvimagesink->handle_events) {
2954     Atom wm_delete;
2955 #ifdef GST_EXT_XV_ENHANCEMENT
2956     XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
2957     XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2958          StructureNotifyMask | PointerMotionMask | KeyPressMask |
2959          KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask);
2960 #else
2961     XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2962         StructureNotifyMask | PointerMotionMask | KeyPressMask |
2963         KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
2964 #endif
2965
2966
2967     /* Tell the window manager we'd like delete client messages instead of
2968      * being killed */
2969     wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2970         "WM_DELETE_WINDOW", True);
2971     if (wm_delete != None) {
2972       (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
2973           &wm_delete, 1);
2974     }
2975   }
2976
2977   xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
2978       xwindow->win, 0, &values);
2979
2980   XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
2981
2982   XSync (xvimagesink->xcontext->disp, FALSE);
2983
2984   g_mutex_unlock (xvimagesink->x_lock);
2985
2986   gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
2987
2988   gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
2989
2990   return xwindow;
2991 }
2992
2993 /* This function destroys a GstXWindow */
2994 static void
2995 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
2996     GstXWindow * xwindow)
2997 {
2998   g_return_if_fail (xwindow != NULL);
2999   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3000
3001   g_mutex_lock (xvimagesink->x_lock);
3002
3003   /* If we did not create that window we just free the GC and let it live */
3004   if (xwindow->internal) {
3005     XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
3006     if (xvimagesink->xim_transparenter) {
3007       XDestroyImage(xvimagesink->xim_transparenter);
3008       xvimagesink->xim_transparenter = NULL;
3009     }
3010   } else {
3011     XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
3012   }
3013
3014   XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
3015
3016   XSync (xvimagesink->xcontext->disp, FALSE);
3017
3018   g_mutex_unlock (xvimagesink->x_lock);
3019
3020   g_free (xwindow);
3021 }
3022
3023 #ifdef GST_EXT_XV_ENHANCEMENT
3024 /* This function destroys a GstXWindow */
3025 static void
3026 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
3027     GstXPixmap * xpixmap)
3028 {
3029   g_return_if_fail (xpixmap != NULL);
3030   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3031
3032   g_mutex_lock (xvimagesink->x_lock);
3033
3034   XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
3035
3036   XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
3037
3038   XSync (xvimagesink->xcontext->disp, FALSE);
3039
3040   g_mutex_unlock (xvimagesink->x_lock);
3041
3042   g_free (xpixmap);
3043 }
3044 #endif /* GST_EXT_XV_ENHANCEMENT */
3045
3046 static void
3047 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
3048 {
3049 #ifdef GST_EXT_XV_ENHANCEMENT
3050   Window root_window, child_window;
3051   XWindowAttributes root_attr = {0 , };
3052
3053   int cur_win_x = 0;
3054   int cur_win_y = 0;
3055   unsigned int cur_win_width = 0;
3056   unsigned int cur_win_height = 0;
3057   unsigned int cur_win_border_width = 0;
3058   unsigned int cur_win_depth = 0;
3059 #else /* GST_EXT_XV_ENHANCEMENT */
3060   XWindowAttributes attr;
3061 #endif /* GST_EXT_XV_ENHANCEMENT */
3062
3063   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3064
3065   /* Update the window geometry */
3066   g_mutex_lock (xvimagesink->x_lock);
3067   if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
3068     g_mutex_unlock (xvimagesink->x_lock);
3069     return;
3070   }
3071
3072 #ifdef GST_EXT_XV_ENHANCEMENT
3073   /* Get root window and size of current window */
3074   XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
3075     &cur_win_x, &cur_win_y, /* relative x, y */
3076     &cur_win_width, &cur_win_height,
3077     &cur_win_border_width, &cur_win_depth );
3078
3079   xvimagesink->xwindow->width = cur_win_width;
3080   xvimagesink->xwindow->height = cur_win_height;
3081
3082   /* Get absolute coordinates of current window */
3083   if(!xvimagesink->is_pixmap) {
3084     XTranslateCoordinates( xvimagesink->xcontext->disp,
3085       xvimagesink->xwindow->win,
3086       root_window,
3087       0, 0,
3088       &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
3089       &child_window );
3090   }
3091
3092   xvimagesink->xwindow->x = cur_win_x;
3093   xvimagesink->xwindow->y = cur_win_y;
3094
3095   /* Get size of root window == size of screen */
3096   if(!xvimagesink->is_pixmap)
3097     XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
3098
3099   xvimagesink->scr_w = root_attr.width;
3100   xvimagesink->scr_h = root_attr.height;
3101
3102   if (!xvimagesink->have_render_rect) {
3103     xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3104     xvimagesink->render_rect.w = cur_win_width;
3105     xvimagesink->render_rect.h = cur_win_height;
3106   }
3107   if (xvimagesink->scr_w != xvimagesink->xwindow->width ||
3108     xvimagesink->scr_h != xvimagesink->xwindow->height) {
3109     xvimagesink->is_multi_window = TRUE;
3110     g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
3111     GST_INFO_OBJECT(xvimagesink, "It may be multi-window scenario");
3112   } else {
3113     xvimagesink->is_multi_window = FALSE;
3114     g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
3115     GST_INFO_OBJECT(xvimagesink, "It may be full-window scenario");
3116   }
3117
3118   GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
3119     xvimagesink->scr_w, xvimagesink->scr_h,
3120     xvimagesink->xwindow->x, xvimagesink->xwindow->y,
3121     xvimagesink->xwindow->width, xvimagesink->xwindow->height,
3122     xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3123     xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3124 #else /* GST_EXT_XV_ENHANCEMENT */
3125   XGetWindowAttributes (xvimagesink->xcontext->disp,
3126       xvimagesink->xwindow->win, &attr);
3127
3128   xvimagesink->xwindow->width = attr.width;
3129   xvimagesink->xwindow->height = attr.height;
3130
3131   if (!xvimagesink->have_render_rect) {
3132     xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3133     xvimagesink->render_rect.w = attr.width;
3134     xvimagesink->render_rect.h = attr.height;
3135   }
3136 #endif /* GST_EXT_XV_ENHANCEMENT */
3137
3138   g_mutex_unlock (xvimagesink->x_lock);
3139 }
3140
3141 static void
3142 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
3143     GstXWindow * xwindow)
3144 {
3145 #ifdef GST_EXT_XV_ENHANCEMENT
3146   if (xvimagesink->is_subpicture_format)
3147     return;
3148 #endif
3149   g_return_if_fail (xwindow != NULL);
3150   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3151
3152   g_mutex_lock (xvimagesink->x_lock);
3153 #ifdef GST_EXT_XV_ENHANCEMENT
3154   GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
3155 #endif /* GST_EXT_XV_ENHANCEMENT */
3156
3157   XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
3158       xwindow->win);
3159 #ifdef GST_EXT_XV_ENHANCEMENT
3160 #if 0
3161   /* NOTE : it should be enabled in pixmap buffer case,
3162             if we can check whether if it is a pixmap or a window by X API */
3163   /* Preview area is not updated before other UI is updated in the screen. */
3164   XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
3165       xvimagesink->xcontext->black);
3166
3167   XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
3168       xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3169       xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3170 #endif
3171 #endif /* GST_EXT_XV_ENHANCEMENT */
3172
3173   XSync (xvimagesink->xcontext->disp, FALSE);
3174
3175   g_mutex_unlock (xvimagesink->x_lock);
3176 }
3177
3178 /* This function commits our internal colorbalance settings to our grabbed Xv
3179    port. If the xcontext is not initialized yet it simply returns */
3180 static void
3181 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
3182 {
3183   GList *channels = NULL;
3184
3185   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3186
3187   /* If we haven't initialized the X context we can't update anything */
3188   if (xvimagesink->xcontext == NULL)
3189     return;
3190
3191   /* Don't set the attributes if they haven't been changed, to avoid
3192    * rounding errors changing the values */
3193   if (!xvimagesink->cb_changed)
3194     return;
3195
3196   /* For each channel of the colorbalance we calculate the correct value
3197      doing range conversion and then set the Xv port attribute to match our
3198      values. */
3199   channels = xvimagesink->xcontext->channels_list;
3200
3201   while (channels) {
3202     if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
3203       GstColorBalanceChannel *channel = NULL;
3204       Atom prop_atom;
3205       gint value = 0;
3206       gdouble convert_coef;
3207
3208       channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
3209       g_object_ref (channel);
3210
3211       /* Our range conversion coef */
3212       convert_coef = (channel->max_value - channel->min_value) / 2000.0;
3213
3214       if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3215         value = xvimagesink->hue;
3216       } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3217         value = xvimagesink->saturation;
3218       } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3219         value = xvimagesink->contrast;
3220       } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3221         value = xvimagesink->brightness;
3222       } else {
3223         g_warning ("got an unknown channel %s", channel->label);
3224         g_object_unref (channel);
3225         return;
3226       }
3227
3228       /* Committing to Xv port */
3229       g_mutex_lock (xvimagesink->x_lock);
3230       prop_atom =
3231           XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
3232       if (prop_atom != None) {
3233         int xv_value;
3234         xv_value =
3235             floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
3236         XvSetPortAttribute (xvimagesink->xcontext->disp,
3237             xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
3238       }
3239       g_mutex_unlock (xvimagesink->x_lock);
3240
3241       g_object_unref (channel);
3242     }
3243     channels = g_list_next (channels);
3244   }
3245 }
3246
3247 /* This function handles XEvents that might be in the queue. It generates
3248    GstEvent that will be sent upstream in the pipeline to handle interactivity
3249    and navigation. It will also listen for configure events on the window to
3250    trigger caps renegotiation so on the fly software scaling can work. */
3251 static void
3252 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
3253 {
3254   XEvent e;
3255   guint pointer_x = 0, pointer_y = 0;
3256   gboolean pointer_moved = FALSE;
3257   gboolean exposed = FALSE, configured = FALSE;
3258
3259   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3260
3261 #ifdef GST_EXT_XV_ENHANCEMENT
3262   GST_LOG("check x event");
3263   Atom sc_status_atom = XInternAtom (xvimagesink->xcontext->disp, STR_ATOM_SCRNCONF_STATUS, FALSE);
3264   Atom external_atom = XInternAtom (xvimagesink->xcontext->disp, "XV_OUTPUT_EXTERNAL", FALSE);
3265 #endif /* GST_EXT_XV_ENHANCEMENT */
3266
3267   /* Handle Interaction, produces navigation events */
3268
3269   /* We get all pointer motion events, only the last position is
3270      interesting. */
3271   g_mutex_lock (xvimagesink->flow_lock);
3272   g_mutex_lock (xvimagesink->x_lock);
3273 #ifdef GST_EXT_XV_ENHANCEMENT
3274   if (xvimagesink->xcontext->disp) {
3275 #endif //GST_EXT_XV_ENHANCEMENT
3276   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3277           xvimagesink->xwindow->win, PointerMotionMask, &e)) {
3278     g_mutex_unlock (xvimagesink->x_lock);
3279     g_mutex_unlock (xvimagesink->flow_lock);
3280
3281     switch (e.type) {
3282       case MotionNotify:
3283         pointer_x = e.xmotion.x;
3284         pointer_y = e.xmotion.y;
3285         pointer_moved = TRUE;
3286         break;
3287       default:
3288         break;
3289     }
3290     g_mutex_lock (xvimagesink->flow_lock);
3291     g_mutex_lock (xvimagesink->x_lock);
3292   }
3293 #ifdef GST_EXT_XV_ENHANCEMENT
3294   }
3295 #endif //GST_EXT_XV_ENHANCEMENT
3296   if (pointer_moved) {
3297     g_mutex_unlock (xvimagesink->x_lock);
3298     g_mutex_unlock (xvimagesink->flow_lock);
3299
3300     GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
3301         pointer_x, pointer_y);
3302     gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3303         "mouse-move", 0, e.xbutton.x, e.xbutton.y);
3304
3305     g_mutex_lock (xvimagesink->flow_lock);
3306     g_mutex_lock (xvimagesink->x_lock);
3307   }
3308
3309   /* We get all events on our window to throw them upstream */
3310   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3311           xvimagesink->xwindow->win,
3312           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
3313           &e)) {
3314     KeySym keysym;
3315
3316     /* We lock only for the X function call */
3317     g_mutex_unlock (xvimagesink->x_lock);
3318     g_mutex_unlock (xvimagesink->flow_lock);
3319
3320     switch (e.type) {
3321       case ButtonPress:
3322         /* Mouse button pressed over our window. We send upstream
3323            events for interactivity/navigation */
3324         GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
3325             e.xbutton.button, e.xbutton.x, e.xbutton.y);
3326         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3327             "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3328         break;
3329       case ButtonRelease:
3330         /* Mouse button released over our window. We send upstream
3331            events for interactivity/navigation */
3332         GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
3333             e.xbutton.button, e.xbutton.x, e.xbutton.y);
3334         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3335             "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3336         break;
3337       case KeyPress:
3338       case KeyRelease:
3339         /* Key pressed/released over our window. We send upstream
3340            events for interactivity/navigation */
3341         GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
3342             e.xkey.keycode, e.xkey.x, e.xkey.y);
3343         g_mutex_lock (xvimagesink->x_lock);
3344         keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
3345             e.xkey.keycode, 0);
3346         g_mutex_unlock (xvimagesink->x_lock);
3347         if (keysym != NoSymbol) {
3348           char *key_str = NULL;
3349
3350           g_mutex_lock (xvimagesink->x_lock);
3351           key_str = XKeysymToString (keysym);
3352           g_mutex_unlock (xvimagesink->x_lock);
3353           gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3354               e.type == KeyPress ? "key-press" : "key-release", key_str);
3355         } else {
3356           gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3357               e.type == KeyPress ? "key-press" : "key-release", "unknown");
3358         }
3359         break;
3360       default:
3361         GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
3362     }
3363     g_mutex_lock (xvimagesink->flow_lock);
3364     g_mutex_lock (xvimagesink->x_lock);
3365   }
3366   /* Handle Expose */
3367   while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3368           xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
3369     switch (e.type) {
3370       case Expose:
3371         exposed = TRUE;
3372         break;
3373       case ConfigureNotify:
3374         g_mutex_unlock (xvimagesink->x_lock);
3375 #ifdef GST_EXT_XV_ENHANCEMENT
3376         GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
3377 #endif /* GST_EXT_XV_ENHANCEMENT */
3378         gst_xvimagesink_xwindow_update_geometry (xvimagesink);
3379 #ifdef GST_EXT_XV_ENHANCEMENT
3380         GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
3381 #endif /* GST_EXT_XV_ENHANCEMENT */
3382         g_mutex_lock (xvimagesink->x_lock);
3383         configured = TRUE;
3384         break;
3385       default:
3386         break;
3387     }
3388   }
3389
3390   if (xvimagesink->handle_expose && (exposed || configured)) {
3391     g_mutex_unlock (xvimagesink->x_lock);
3392     g_mutex_unlock (xvimagesink->flow_lock);
3393
3394     gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
3395
3396     g_mutex_lock (xvimagesink->flow_lock);
3397     g_mutex_lock (xvimagesink->x_lock);
3398   }
3399
3400   /* Handle Display events */
3401   while (XPending (xvimagesink->xcontext->disp)) {
3402     XNextEvent (xvimagesink->xcontext->disp, &e);
3403     switch (e.type) {
3404       case ClientMessage:{
3405 #ifdef GST_EXT_XV_ENHANCEMENT
3406         XClientMessageEvent *cme = (XClientMessageEvent *)&e;
3407         Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
3408         Atom qp_state_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_STATE", False);
3409         Atom qp_on_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_ON", False);
3410         Atom qp_off_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_OFF", False);
3411 #endif /* GST_EXT_XV_ENHANCEMENT */
3412         Atom wm_delete;
3413
3414 #ifdef GST_EXT_XV_ENHANCEMENT
3415         GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
3416         if (cme->message_type == buffer_atom) {
3417           unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
3418
3419           GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
3420                     cme->data.l[0], cme->data.l[1]);
3421
3422           gem_name[0] = cme->data.l[0];
3423           gem_name[1] = cme->data.l[1];
3424
3425           _remove_displaying_buffer(xvimagesink, gem_name);
3426           break;
3427         } else if (cme->message_type == sc_status_atom) {
3428           int stat = cme->data.s[0];
3429           if (stat == UTILX_SCRNCONF_STATUS_NULL) {
3430             GST_WARNING ("get UTILX_SCRNCONF_STATUS_NULL event\n");
3431             check_hdmi_connected(xvimagesink);
3432           } else if (stat == UTILX_SCRNCONF_STATUS_CONNECT) {
3433             GST_WARNING ("get UTILX_SCRNCONF_STATUS_CONNECT event\n");
3434             check_hdmi_connected(xvimagesink);
3435           } else if (stat == UTILX_SCRNCONF_STATUS_ACTIVE) {
3436             GST_WARNING ("get UTILX_SCRNCONF_STATUS_ACTIVE event\n");
3437             g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_HDMI_ACTIVE);
3438             check_hdmi_connected(xvimagesink);
3439           } else {
3440             GST_INFO ("Wrong status\n");
3441           }
3442           break;
3443         } else if (cme->message_type == qp_state_atom) {
3444           if ((Atom) cme->data.l[0] == qp_on_atom) {
3445             /* quick panel on */
3446             GST_WARNING_OBJECT(xvimagesink, "quick panel is ON");
3447             xvimagesink->is_quick_panel_on = TRUE;
3448             g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", TRUE);
3449           } else if ((Atom) cme->data.l[0] == qp_off_atom) {
3450             /* quick panel off */
3451             GST_WARNING_OBJECT(xvimagesink, "quick panel is OFF");
3452             xvimagesink->is_quick_panel_on = FALSE;
3453             g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", FALSE);
3454           }
3455           break;
3456         }
3457 #endif /* GST_EXT_XV_ENHANCEMENT */
3458
3459         wm_delete = XInternAtom (xvimagesink->xcontext->disp,
3460             "WM_DELETE_WINDOW", True);
3461         if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
3462           /* Handle window deletion by posting an error on the bus */
3463           GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
3464               ("Output window was closed"), (NULL));
3465
3466           g_mutex_unlock (xvimagesink->x_lock);
3467           gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
3468           xvimagesink->xwindow = NULL;
3469           g_mutex_lock (xvimagesink->x_lock);
3470         }
3471         break;
3472       }
3473 #ifdef GST_EXT_XV_ENHANCEMENT
3474       case VisibilityNotify:
3475         if (xvimagesink->xwindow &&
3476             (e.xvisibility.window == xvimagesink->xwindow->win)) {
3477           if (e.xvisibility.state == VisibilityFullyObscured) {
3478             Atom atom_stream;
3479
3480             GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
3481
3482             xvimagesink->is_hided = TRUE;
3483             g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", TRUE);
3484             if (!_is_connected_to_external_display(xvimagesink)) {
3485               GST_WARNING_OBJECT(xvimagesink, "no external display, calling XvStopVideo()");
3486               XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
3487               XSync(xvimagesink->xcontext->disp, FALSE);
3488             } else {
3489               if (GST_STATE(xvimagesink) == GST_STATE_PLAYING || xvimagesink->keep_external_fullscreen_prev) {
3490                 GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip XvStopVideo()");
3491               } else {
3492                 GST_WARNING_OBJECT(xvimagesink, "external display is enabled, but not in the middle of playing, calling XvStopVideo()");
3493                 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
3494                 XSync(xvimagesink->xcontext->disp, FALSE);
3495               }
3496             }
3497           } else {
3498             GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
3499
3500             if (xvimagesink->is_hided) {
3501               g_mutex_unlock(xvimagesink->x_lock);
3502               g_mutex_unlock(xvimagesink->flow_lock);
3503
3504               xvimagesink->is_hided = FALSE;
3505               g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", FALSE);
3506               gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
3507
3508               g_mutex_lock(xvimagesink->flow_lock);
3509               g_mutex_lock(xvimagesink->x_lock);
3510             } else {
3511               GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
3512             }
3513           }
3514         }
3515         break;
3516
3517       case PropertyNotify:
3518         {
3519           XPropertyEvent *noti = (XPropertyEvent *)&e;
3520           if(xvimagesink->xwindow) {
3521             if (noti->window == xvimagesink->xwindow->win && noti->atom == external_atom) {
3522               int value = 0;
3523               get_window_prop_card32_property (xvimagesink->xcontext->disp,
3524                                                xvimagesink->xwindow->win,
3525                                                external_atom, XA_CARDINAL,
3526                                                (unsigned int*)&value, 1);
3527               if (value) {
3528                 // If value is 1, video will be displayed only on external display.
3529                 // video won't be displayed on LCD.
3530                 g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_UNKNOWN_ACTIVE);
3531                 if(xvimagesink->external_width==0 && xvimagesink->external_height==0) {
3532                   xvimagesink->external_width = 1920;
3533                   xvimagesink->external_height = 1080;
3534                   GST_WARNING("connected unknown external display");
3535                 }
3536               } else {
3537                 g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_NULL); //NULL
3538                 if(xvimagesink->external_width!=0 || xvimagesink->external_height!=0) {
3539                   xvimagesink->external_width = 0;
3540                   xvimagesink->external_height = 0;
3541                   GST_WARNING("disconnected external display");
3542                 }
3543               }
3544
3545               g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3546               GST_INFO ("external device : %s\n", (value)?"on":"off");
3547             }
3548           }
3549           break;
3550        }
3551
3552 #endif /* GST_EXT_XV_ENHANCEMENT */
3553       default:
3554         break;
3555     }
3556   }
3557   g_mutex_unlock (xvimagesink->x_lock);
3558   g_mutex_unlock (xvimagesink->flow_lock);
3559 }
3560 #ifdef GST_EXT_XV_ENHANCEMENT
3561 static int
3562 get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type,
3563                                  unsigned int *val, unsigned int len)
3564 {
3565   unsigned char* prop_ret;
3566   Atom type_ret;
3567   unsigned long bytes_after, num_ret;
3568   int format_ret;
3569   unsigned int i;
3570   int num;
3571   int ret;
3572   int (*handler) (Display *, XErrorEvent *) = NULL;
3573
3574   prop_ret = NULL;
3575
3576   /* set error handler */
3577   error_caught = FALSE;
3578   handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
3579
3580   ret = XGetWindowProperty(dpy, win, atom, 0, 0x7fffffff, False,
3581                            type, &type_ret, &format_ret, &num_ret,
3582                            &bytes_after, &prop_ret);
3583   XSync(dpy, FALSE);
3584   if (ret != Success || error_caught) {
3585     GST_WARNING("XGetWindowProperty failed [%d, %d]", ret, error_caught);
3586     if (handler) {
3587       error_caught = FALSE;
3588       XSetErrorHandler (handler);
3589     }
3590     return -1;
3591   }
3592
3593   if (handler) {
3594     error_caught = FALSE;
3595     XSetErrorHandler(handler);
3596   }
3597
3598   if (type_ret != type || format_ret != 32)
3599     num = -1;
3600   else if (num_ret == 0 || !prop_ret)
3601     num = 0;
3602   else
3603   {
3604     if (num_ret < len)
3605       len = num_ret;
3606     for (i = 0; i < len; i++)
3607       val[i] = ((unsigned long *)prop_ret)[i];
3608     num = len;
3609   }
3610
3611   if (prop_ret)
3612     XFree(prop_ret);
3613
3614   return num;
3615 }
3616
3617 static void check_hdmi_connected(GstXvImageSink *xvimagesink)
3618 {
3619   char *str_output = NULL;
3620   char *str_resolution = NULL;
3621   int external[2];
3622   int cnt = 0;
3623   char** list = NULL;
3624   char** walk = NULL;
3625
3626   UtilxScrnConf *scrnconf = utilx_scrnconf_allocate();
3627   if (!scrnconf)
3628   {
3629     GST_WARNING ("fail to allocate scrnconf");
3630     return;
3631   }
3632   utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf);
3633
3634   str_output = scrnconf->str_output;
3635
3636   if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT)
3637   {
3638     GST_INFO("CONNECT");
3639   }
3640   else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE)
3641   {
3642      GST_INFO("ACTIVE");
3643
3644     list = g_strsplit(scrnconf->str_resolution, "x", 2);
3645
3646     if (!list)
3647     {
3648         if (scrnconf)
3649         utilx_scrnconf_free (scrnconf);
3650         return;
3651     }
3652     for(walk = list; *walk; walk++)
3653     {
3654       external[cnt++] = atoi(*walk);
3655     }
3656     if (cnt!=2) {
3657       GST_WARNING("data error");
3658       if(scrnconf)
3659         utilx_scrnconf_free (scrnconf);
3660       g_strfreev(list);
3661       return;
3662     } else {
3663       xvimagesink->external_width = external[0];
3664       xvimagesink->external_height = external[1];
3665       g_strfreev(list);
3666     }
3667     GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height);
3668     g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3669   }
3670   else
3671   {
3672      GST_INFO("NULL");
3673   }
3674
3675   str_resolution = scrnconf->str_resolution;
3676
3677   if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE)
3678   {
3679      GST_INFO("CLONE mode");
3680   }
3681   else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED)
3682   {
3683     GST_INFO("EXTENDED mode");
3684   }
3685   else
3686   {
3687     GST_INFO("NULL mode");
3688   }
3689
3690   GST_INFO ("[Display status] : %s, %s\n", str_output, str_resolution);
3691
3692   if(scrnconf)
3693     utilx_scrnconf_free (scrnconf);
3694
3695 }
3696
3697 static gboolean
3698 check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name)
3699 {
3700   int i = 0;
3701   int count = 0;
3702
3703   XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp,
3704                                             xvimagesink->xcontext->xv_port_id, &count);
3705   if (attr) {
3706     for (i = 0 ; i < count ; i++) {
3707       if (!strcmp(attr[i].name, attr_name)) {
3708         GST_INFO("%s[index %d] found", attr_name, i);
3709         XFree(attr);
3710         return TRUE;
3711       }
3712     }
3713     XFree(attr);
3714   } else {
3715     GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
3716                 xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id);
3717   }
3718   return FALSE;
3719 }
3720 #endif //GST_EXT_XV_ENHANCEMENT
3721
3722 static void
3723 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3724     XvAdaptorInfo * adaptors, int adaptor_no)
3725 {
3726   gint j;
3727   gint res;
3728
3729   /* Do we support XvImageMask ? */
3730   if (!(adaptors[adaptor_no].type & XvImageMask)) {
3731     GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3732         adaptors[adaptor_no].name);
3733     return;
3734   }
3735
3736   /* We found such an adaptor, looking for an available port */
3737   for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3738     /* We try to grab the port */
3739     res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3740     if (Success == res) {
3741       xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3742       GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3743           adaptors[adaptor_no].num_ports);
3744     } else {
3745       GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3746           adaptors[adaptor_no].name, res);
3747     }
3748   }
3749 }
3750
3751 #ifdef GST_EXT_XV_ENHANCEMENT
3752 static void
3753 gst_lookup_xv_port_for_subtitle (GstXContext * xcontext,
3754     XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors)
3755 {
3756   int i;
3757   if (!adaptors)
3758     return;
3759   for (i = 0; i < nb_adaptors; i++)
3760   {
3761     int min, max;
3762     if (!(adaptors[i].type & XvOutputMask) ||
3763         !(adaptors[i].type & XvStillMask))
3764         continue;
3765     min = adaptors[i].base_id;
3766     max = adaptors[i].base_id + adaptors[i].num_ports;
3767     for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++)
3768     {
3769       if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success)
3770       {
3771         GST_INFO ("========================================");
3772         GST_INFO ("XvGrabPort  success : %ld", adaptors[adaptor_no].num_ports);
3773         GST_INFO ("========================================");
3774         xcontext->xv_port_id = adaptors[adaptor_no].num_ports;
3775         return;
3776       }
3777       GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports);
3778       usleep(10000);
3779     }
3780   }
3781 }
3782 #endif
3783
3784
3785 /* This function generates a caps with all supported format by the first
3786    Xv grabable port we find. We store each one of the supported formats in a
3787    format list and append the format to a newly created caps that we return
3788    If this function does not return NULL because of an error, it also grabs
3789    the port via XvGrabPort */
3790 static GstCaps *
3791 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3792     GstXContext * xcontext)
3793 {
3794   gint i;
3795   XvAdaptorInfo *adaptors;
3796   gint nb_formats;
3797   XvImageFormatValues *formats = NULL;
3798   guint nb_encodings;
3799   XvEncodingInfo *encodings = NULL;
3800   gulong max_w = G_MAXINT, max_h = G_MAXINT;
3801   GstCaps *caps = NULL;
3802   GstCaps *rgb_caps = NULL;
3803
3804   g_return_val_if_fail (xcontext != NULL, NULL);
3805
3806   /* First let's check that XVideo extension is available */
3807   if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3808     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3809         ("Could not initialise Xv output"),
3810         ("XVideo extension is not available"));
3811     return NULL;
3812   }
3813
3814   /* Then we get adaptors list */
3815   if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3816           &xcontext->nb_adaptors, &adaptors)) {
3817     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3818         ("Could not initialise Xv output"),
3819         ("Failed getting XV adaptors list"));
3820     return NULL;
3821   }
3822
3823   xcontext->xv_port_id = 0;
3824
3825   GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
3826
3827   xcontext->adaptors =
3828       (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3829
3830   /* Now fill up our adaptor name array */
3831   for (i = 0; i < xcontext->nb_adaptors; i++) {
3832     xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3833   }
3834
3835   if (xvimagesink->adaptor_no >= 0 &&
3836       xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3837     /* Find xv port from user defined adaptor */
3838 #ifdef GST_EXT_XV_ENHANCEMENT
3839     if(!xvimagesink->subpicture)
3840 #endif
3841       gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no);
3842 #ifdef GST_EXT_XV_ENHANCEMENT
3843     else
3844       gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors);
3845 #endif
3846   }
3847
3848   if (!xcontext->xv_port_id) {
3849     /* Now search for an adaptor that supports XvImageMask */
3850     for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3851 #ifdef GST_EXT_XV_ENHANCEMENT
3852       if(!xvimagesink->subpicture)
3853 #endif
3854         gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3855 #ifdef GST_EXT_XV_ENHANCEMENT
3856       else
3857         gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors);
3858 #endif
3859       xvimagesink->adaptor_no = i;
3860     }
3861   }
3862
3863   XvFreeAdaptorInfo (adaptors);
3864
3865   if (!xcontext->xv_port_id) {
3866     xvimagesink->adaptor_no = -1;
3867     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3868         ("Could not initialise Xv output"), ("No port available"));
3869     return NULL;
3870   }
3871
3872   /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3873   {
3874     int count, todo = 3;
3875     XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3876         xcontext->xv_port_id, &count);
3877     static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3878     static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3879     static const char colorkey[] = "XV_COLORKEY";
3880
3881     GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3882
3883     xvimagesink->have_autopaint_colorkey = FALSE;
3884     xvimagesink->have_double_buffer = FALSE;
3885     xvimagesink->have_colorkey = FALSE;
3886
3887     for (i = 0; ((i < count) && todo); i++)
3888       if (!strcmp (attr[i].name, autopaint)) {
3889         const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3890
3891         /* turn on autopaint colorkey */
3892         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3893             (xvimagesink->autopaint_colorkey ? 1 : 0));
3894         todo--;
3895         xvimagesink->have_autopaint_colorkey = TRUE;
3896       } else if (!strcmp (attr[i].name, dbl_buffer)) {
3897         const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3898
3899         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3900             (xvimagesink->double_buffer ? 1 : 0));
3901         todo--;
3902         xvimagesink->have_double_buffer = TRUE;
3903       } else if (!strcmp (attr[i].name, colorkey)) {
3904         /* Set the colorkey, default is something that is dark but hopefully
3905          * won't randomly appear on the screen elsewhere (ie not black or greys)
3906          * can be overridden by setting "colorkey" property
3907          */
3908         const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3909         guint32 ckey = 0;
3910         gboolean set_attr = TRUE;
3911         guint cr, cg, cb;
3912
3913         /* set a colorkey in the right format RGB565/RGB888
3914          * We only handle these 2 cases, because they're the only types of
3915          * devices we've encountered. If we don't recognise it, leave it alone
3916          */
3917         cr = (xvimagesink->colorkey >> 16);
3918         cg = (xvimagesink->colorkey >> 8) & 0xFF;
3919         cb = (xvimagesink->colorkey) & 0xFF;
3920         switch (xcontext->depth) {
3921           case 16:             /* RGB 565 */
3922             cr >>= 3;
3923             cg >>= 2;
3924             cb >>= 3;
3925             ckey = (cr << 11) | (cg << 5) | cb;
3926             break;
3927           case 24:
3928           case 32:             /* RGB 888 / ARGB 8888 */
3929             ckey = (cr << 16) | (cg << 8) | cb;
3930             break;
3931           default:
3932             GST_DEBUG_OBJECT (xvimagesink,
3933                 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3934                 xcontext->depth);
3935             set_attr = FALSE;
3936             break;
3937         }
3938
3939         if (set_attr) {
3940           ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3941               (guint32) attr[i].max_value);
3942           GST_LOG_OBJECT (xvimagesink,
3943               "Setting color key for display depth %d to 0x%x",
3944               xcontext->depth, ckey);
3945
3946           XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3947               (gint) ckey);
3948         }
3949         todo--;
3950         xvimagesink->have_colorkey = TRUE;
3951       }
3952
3953     XFree (attr);
3954   }
3955
3956   /* Get the list of encodings supported by the adapter and look for the
3957    * XV_IMAGE encoding so we can determine the maximum width and height
3958    * supported */
3959   XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3960       &encodings);
3961
3962   for (i = 0; i < nb_encodings; i++) {
3963     GST_LOG_OBJECT (xvimagesink,
3964         "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3965         i, encodings[i].name, encodings[i].width, encodings[i].height,
3966         encodings[i].rate.numerator, encodings[i].rate.denominator);
3967     if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3968       max_w = encodings[i].width;
3969       max_h = encodings[i].height;
3970 #ifdef GST_EXT_XV_ENHANCEMENT
3971       xvimagesink->scr_w = max_w;
3972       xvimagesink->scr_h = max_h;
3973 #endif /* GST_EXT_XV_ENHANCEMENT */
3974     }
3975   }
3976
3977   XvFreeEncodingInfo (encodings);
3978 #ifdef GST_EXT_XV_ENHANCEMENT
3979 if (!xvimagesink->subpicture) {
3980 #endif
3981   /* We get all image formats supported by our port */
3982   formats = XvListImageFormats (xcontext->disp,
3983       xcontext->xv_port_id, &nb_formats);
3984   caps = gst_caps_new_empty ();
3985   for (i = 0; i < nb_formats; i++) {
3986     GstCaps *format_caps = NULL;
3987     gboolean is_rgb_format = FALSE;
3988
3989     /* We set the image format of the xcontext to an existing one. This
3990        is just some valid image format for making our xshm calls check before
3991        caps negotiation really happens. */
3992     xcontext->im_format = formats[i].id;
3993
3994     switch (formats[i].type) {
3995       case XvRGB:
3996       {
3997         XvImageFormatValues *fmt = &(formats[i]);
3998         gint endianness = G_BIG_ENDIAN;
3999
4000         if (fmt->byte_order == LSBFirst) {
4001           /* our caps system handles 24/32bpp RGB as big-endian. */
4002           if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
4003             fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
4004             fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
4005             fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
4006
4007             if (fmt->bits_per_pixel == 24) {
4008               fmt->red_mask >>= 8;
4009               fmt->green_mask >>= 8;
4010               fmt->blue_mask >>= 8;
4011             }
4012           } else
4013             endianness = G_LITTLE_ENDIAN;
4014         }
4015
4016         format_caps = gst_caps_new_simple ("video/x-raw-rgb",
4017 #ifdef GST_EXT_XV_ENHANCEMENT
4018             "format", GST_TYPE_FOURCC, formats[i].id,
4019 #endif /* GST_EXT_XV_ENHANCEMENT */
4020             "endianness", G_TYPE_INT, endianness,
4021             "depth", G_TYPE_INT, fmt->depth,
4022             "bpp", G_TYPE_INT, fmt->bits_per_pixel,
4023             "red_mask", G_TYPE_INT, fmt->red_mask,
4024             "green_mask", G_TYPE_INT, fmt->green_mask,
4025             "blue_mask", G_TYPE_INT, fmt->blue_mask,
4026             "width", GST_TYPE_INT_RANGE, 1, max_w,
4027             "height", GST_TYPE_INT_RANGE, 1, max_h,
4028             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4029
4030         is_rgb_format = TRUE;
4031         break;
4032       }
4033       case XvYUV:
4034         format_caps = gst_caps_new_simple ("video/x-raw-yuv",
4035             "format", GST_TYPE_FOURCC, formats[i].id,
4036             "width", GST_TYPE_INT_RANGE, 1, max_w,
4037             "height", GST_TYPE_INT_RANGE, 1, max_h,
4038             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4039         break;
4040       default:
4041         g_assert_not_reached ();
4042         break;
4043     }
4044
4045     if (format_caps) {
4046       GstXvImageFormat *format = NULL;
4047
4048       format = g_new0 (GstXvImageFormat, 1);
4049       if (format) {
4050         format->format = formats[i].id;
4051         format->caps = gst_caps_copy (format_caps);
4052         xcontext->formats_list = g_list_append (xcontext->formats_list, format);
4053       }
4054
4055       if (is_rgb_format) {
4056         if (rgb_caps == NULL)
4057           rgb_caps = format_caps;
4058         else
4059           gst_caps_append (rgb_caps, format_caps);
4060       } else
4061         gst_caps_append (caps, format_caps);
4062     }
4063   }
4064
4065   /* Collected all caps into either the caps or rgb_caps structures.
4066    * Append rgb_caps on the end of YUV, so that YUV is always preferred */
4067   if (rgb_caps)
4068     gst_caps_append (caps, rgb_caps);
4069
4070   if (formats)
4071     XFree (formats);
4072
4073   GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
4074
4075   if (gst_caps_is_empty (caps)) {
4076     gst_caps_unref (caps);
4077     XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4078     GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
4079         ("No supported format found"));
4080     return NULL;
4081   }
4082 #ifdef GST_EXT_XV_ENHANCEMENT
4083 } //subpicture
4084 #endif
4085
4086   return caps;
4087 }
4088
4089 static gpointer
4090 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
4091 {
4092   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4093
4094   GST_OBJECT_LOCK (xvimagesink);
4095   while (xvimagesink->running) {
4096     GST_OBJECT_UNLOCK (xvimagesink);
4097
4098     if (xvimagesink->xwindow) {
4099       gst_xvimagesink_handle_xevents (xvimagesink);
4100     }
4101
4102 #ifdef GST_EXT_XV_ENHANCEMENT
4103     g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
4104 #else /* GST_EXT_XV_ENHANCEMENT */
4105     /* FIXME: do we want to align this with the framerate or anything else? */
4106     g_usleep (G_USEC_PER_SEC / 20);
4107 #endif /* GST_EXT_XV_ENHANCEMENT */
4108
4109     GST_OBJECT_LOCK (xvimagesink);
4110   }
4111   GST_OBJECT_UNLOCK (xvimagesink);
4112
4113   return NULL;
4114 }
4115
4116 static void
4117 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
4118 {
4119   GThread *thread = NULL;
4120
4121   /* don't start the thread too early */
4122   if (xvimagesink->xcontext == NULL) {
4123     return;
4124   }
4125
4126   GST_OBJECT_LOCK (xvimagesink);
4127   if (xvimagesink->handle_expose || xvimagesink->handle_events) {
4128     if (!xvimagesink->event_thread) {
4129       /* Setup our event listening thread */
4130       GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
4131           xvimagesink->handle_expose, xvimagesink->handle_events);
4132       xvimagesink->running = TRUE;
4133 #if !GLIB_CHECK_VERSION (2, 31, 0)
4134       xvimagesink->event_thread = g_thread_create (
4135           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
4136 #else
4137       xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
4138           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
4139 #endif
4140     }
4141   } else {
4142     if (xvimagesink->event_thread) {
4143       GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
4144           xvimagesink->handle_expose, xvimagesink->handle_events);
4145       xvimagesink->running = FALSE;
4146       /* grab thread and mark it as NULL */
4147       thread = xvimagesink->event_thread;
4148       xvimagesink->event_thread = NULL;
4149     }
4150   }
4151   GST_OBJECT_UNLOCK (xvimagesink);
4152
4153   /* Wait for our event thread to finish */
4154   if (thread)
4155     g_thread_join (thread);
4156
4157 }
4158
4159
4160 #ifdef GST_EXT_XV_ENHANCEMENT
4161 /**
4162  * gst_xvimagesink_prepare_xid:
4163  * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
4164  *
4165  * This will post a "prepare-xid" element message with video size and display size on the bus
4166  * to give applications an opportunity to call
4167  * gst_x_overlay_set_xwindow_id() before a plugin creates its own
4168  * window or pixmap.
4169  *
4170  * This function should only be used by video overlay plugin developers.
4171  */
4172 static void
4173 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
4174 {
4175   GstStructure *s;
4176   GstMessage *msg;
4177
4178   g_return_if_fail (overlay != NULL);
4179   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
4180
4181   GstXvImageSink *xvimagesink;
4182   xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
4183
4184   GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
4185         GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
4186
4187   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
4188   s = gst_structure_new ("prepare-xid",
4189         "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
4190         "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
4191         "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
4192         "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
4193         NULL);
4194   msg = gst_message_new_element (GST_OBJECT (overlay), s);
4195   gst_element_post_message (GST_ELEMENT (overlay), msg);
4196 }
4197 #endif /* GST_EXT_XV_ENHANCEMENT */
4198
4199
4200 /* This function calculates the pixel aspect ratio based on the properties
4201  * in the xcontext structure and stores it there. */
4202 static void
4203 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
4204 {
4205   static const gint par[][2] = {
4206     {1, 1},                     /* regular screen */
4207     {16, 15},                   /* PAL TV */
4208     {11, 10},                   /* 525 line Rec.601 video */
4209 #ifdef GST_EXT_XV_ENHANCEMENT
4210     {44, 46},                   /* Gear S Curved Display */
4211 #endif
4212     {54, 59},                   /* 625 line Rec.601 video */
4213     {64, 45},                   /* 1280x1024 on 16:9 display */
4214     {5, 3},                     /* 1280x1024 on 4:3 display */
4215     {4, 3}                      /*  800x600 on 16:9 display */
4216   };
4217   gint i;
4218   gint index;
4219   gdouble ratio;
4220   gdouble delta;
4221
4222 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
4223
4224   /* first calculate the "real" ratio based on the X values;
4225    * which is the "physical" w/h divided by the w/h in pixels of the display */
4226   ratio = (gdouble) (xcontext->widthmm * xcontext->height)
4227       / (xcontext->heightmm * xcontext->width);
4228
4229   /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
4230    * override here */
4231   if (xcontext->width == 720 && xcontext->height == 576) {
4232     ratio = 4.0 * 576 / (3.0 * 720);
4233   }
4234   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
4235   /* now find the one from par[][2] with the lowest delta to the real one */
4236   delta = DELTA (0);
4237   index = 0;
4238
4239   for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
4240     gdouble this_delta = DELTA (i);
4241
4242     if (this_delta < delta) {
4243       index = i;
4244       delta = this_delta;
4245     }
4246   }
4247
4248   GST_DEBUG ("Decided on index %d (%d/%d)", index,
4249       par[index][0], par[index][1]);
4250
4251   g_free (xcontext->par);
4252   xcontext->par = g_new0 (GValue, 1);
4253   g_value_init (xcontext->par, GST_TYPE_FRACTION);
4254   gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
4255   GST_DEBUG ("set xcontext PAR to %d/%d",
4256       gst_value_get_fraction_numerator (xcontext->par),
4257       gst_value_get_fraction_denominator (xcontext->par));
4258 }
4259
4260 /* This function gets the X Display and global info about it. Everything is
4261    stored in our object and will be cleaned when the object is disposed. Note
4262    here that caps for supported format are generated without any window or
4263    image creation */
4264 static GstXContext *
4265 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
4266 {
4267   GstXContext *xcontext = NULL;
4268   XPixmapFormatValues *px_formats = NULL;
4269   gint nb_formats = 0, i, j, N_attr;
4270   XvAttribute *xv_attr = NULL;
4271   Atom prop_atom;
4272   const char *channels[4] = { "XV_HUE", "XV_SATURATION",
4273     "XV_BRIGHTNESS", "XV_CONTRAST"
4274   };
4275
4276   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4277
4278   xcontext = g_new0 (GstXContext, 1);
4279   xcontext->im_format = 0;
4280
4281   g_mutex_lock (xvimagesink->x_lock);
4282
4283   xcontext->disp = XOpenDisplay (xvimagesink->display_name);
4284   if (!xcontext->disp) {
4285     g_mutex_unlock (xvimagesink->x_lock);
4286     g_free (xcontext);
4287     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4288         ("Could not initialise Xv output"), ("Could not open display"));
4289     return NULL;
4290   }
4291
4292 #ifdef GST_EXT_XV_ENHANCEMENT
4293   {
4294     int i = 0;
4295     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4296       if (g_display_id[i] == NULL) {
4297         g_display_id[i] = xcontext->disp;
4298         GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
4299         break;
4300       }
4301     }
4302     if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
4303       GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
4304     }
4305   }
4306 #endif
4307
4308   xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
4309   xcontext->screen_num = DefaultScreen (xcontext->disp);
4310   xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
4311   xcontext->root = DefaultRootWindow (xcontext->disp);
4312   xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
4313   xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
4314   xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
4315
4316   xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
4317   xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
4318   xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
4319   xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
4320
4321   GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
4322       xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
4323
4324   gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
4325   /* We get supported pixmap formats at supported depth */
4326   px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
4327
4328   if (!px_formats) {
4329 #ifdef GST_EXT_XV_ENHANCEMENT
4330   {
4331     int i = 0;
4332     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4333       if (g_display_id[i] == xcontext->disp) {
4334         g_display_id[i] = NULL;
4335       }
4336     }
4337   }
4338 #endif
4339     XCloseDisplay (xcontext->disp);
4340     g_mutex_unlock (xvimagesink->x_lock);
4341     g_free (xcontext->par);
4342     g_free (xcontext);
4343     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
4344         ("Could not initialise Xv output"), ("Could not get pixel formats"));
4345     return NULL;
4346   }
4347
4348   /* We get bpp value corresponding to our running depth */
4349   for (i = 0; i < nb_formats; i++) {
4350     if (px_formats[i].depth == xcontext->depth)
4351       xcontext->bpp = px_formats[i].bits_per_pixel;
4352   }
4353
4354   XFree (px_formats);
4355
4356   xcontext->endianness =
4357       (ImageByteOrder (xcontext->disp) ==
4358       LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
4359
4360   /* our caps system handles 24/32bpp RGB as big-endian. */
4361   if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
4362       xcontext->endianness == G_LITTLE_ENDIAN) {
4363     xcontext->endianness = G_BIG_ENDIAN;
4364     xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
4365     xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
4366     xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
4367     if (xcontext->bpp == 24) {
4368       xcontext->visual->red_mask >>= 8;
4369       xcontext->visual->green_mask >>= 8;
4370       xcontext->visual->blue_mask >>= 8;
4371     }
4372   }
4373
4374   xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
4375
4376   if (!xcontext->caps
4377 #ifdef GST_EXT_XV_ENHANCEMENT
4378     && !xvimagesink->subpicture
4379 #endif
4380     ) {
4381 #ifdef GST_EXT_XV_ENHANCEMENT
4382   {
4383     int i = 0;
4384     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4385       if (g_display_id[i] == xcontext->disp) {
4386         g_display_id[i] = NULL;
4387       }
4388     }
4389   }
4390 #endif
4391     XCloseDisplay (xcontext->disp);
4392     g_mutex_unlock (xvimagesink->x_lock);
4393     g_free (xcontext->par);
4394     g_free (xcontext);
4395     /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
4396     return NULL;
4397   }
4398 #ifdef HAVE_XSHM
4399 #ifdef GST_EXT_XV_ENHANCEMENT
4400   if (!xvimagesink->subpicture) {
4401 #endif //GST_EXT_XV_ENHANCEMENT
4402     /* Search for XShm extension support */
4403     if (XShmQueryExtension (xcontext->disp) &&
4404         gst_xvimagesink_check_xshm_calls (xcontext)) {
4405       xcontext->use_xshm = TRUE;
4406       GST_DEBUG ("xvimagesink is using XShm extension");
4407     } else
4408 #endif /* HAVE_XSHM */
4409     {
4410       xcontext->use_xshm = FALSE;
4411       GST_DEBUG ("xvimagesink is not using XShm extension");
4412     }
4413
4414     xv_attr = XvQueryPortAttributes (xcontext->disp,
4415         xcontext->xv_port_id, &N_attr);
4416 #ifdef GST_EXT_XV_ENHANCEMENT
4417   }
4418 #endif //GST_EXT_XV_ENHANCEMENT
4419
4420   /* Generate the channels list */
4421   for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
4422     XvAttribute *matching_attr = NULL;
4423
4424     /* Retrieve the property atom if it exists. If it doesn't exist,
4425      * the attribute itself must not either, so we can skip */
4426     prop_atom = XInternAtom (xcontext->disp, channels[i], True);
4427     if (prop_atom == None)
4428       continue;
4429
4430     if (xv_attr != NULL) {
4431       for (j = 0; j < N_attr && matching_attr == NULL; ++j)
4432         if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
4433           matching_attr = xv_attr + j;
4434     }
4435
4436     if (matching_attr) {
4437       GstColorBalanceChannel *channel;
4438
4439       channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
4440       channel->label = g_strdup (channels[i]);
4441       channel->min_value = matching_attr->min_value;
4442       channel->max_value = matching_attr->max_value;
4443
4444       xcontext->channels_list = g_list_append (xcontext->channels_list,
4445           channel);
4446
4447       /* If the colorbalance settings have not been touched we get Xv values
4448          as defaults and update our internal variables */
4449       if (!xvimagesink->cb_changed) {
4450         gint val;
4451
4452         XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
4453             prop_atom, &val);
4454         /* Normalize val to [-1000, 1000] */
4455         val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
4456             (double) (channel->max_value - channel->min_value));
4457
4458         if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
4459           xvimagesink->hue = val;
4460         else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
4461           xvimagesink->saturation = val;
4462         else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
4463           xvimagesink->brightness = val;
4464         else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
4465           xvimagesink->contrast = val;
4466       }
4467     }
4468   }
4469 #ifdef GST_EXT_XV_ENHANCEMENT
4470   if (!xvimagesink->subpicture) {
4471 #endif
4472   if (xv_attr)
4473     XFree (xv_attr);
4474 #ifdef GST_EXT_XV_ENHANCEMENT
4475   }
4476   if(!xvimagesink->subpicture) {
4477     set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
4478     set_csc_range(xcontext, xvimagesink->csc_range);
4479   }
4480 #endif /* GST_EXT_XV_ENHANCEMENT */
4481
4482   g_mutex_unlock (xvimagesink->x_lock);
4483
4484   return xcontext;
4485 }
4486
4487 /* This function cleans the X context. Closing the Display, releasing the XV
4488    port and unrefing the caps for supported formats. */
4489 static void
4490 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
4491 {
4492   GList *formats_list, *channels_list = NULL;
4493   GstXContext *xcontext;
4494   gint i = 0;
4495
4496   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4497
4498   GST_OBJECT_LOCK (xvimagesink);
4499   if (xvimagesink->xcontext == NULL) {
4500     GST_OBJECT_UNLOCK (xvimagesink);
4501     return;
4502   }
4503
4504   /* Take the XContext from the sink and clean it up */
4505   xcontext = xvimagesink->xcontext;
4506   xvimagesink->xcontext = NULL;
4507
4508   GST_OBJECT_UNLOCK (xvimagesink);
4509
4510 #ifdef GST_EXT_XV_ENHANCEMENT
4511   if (!xvimagesink->subpicture)  {
4512 #endif
4513   formats_list = xcontext->formats_list;
4514
4515   while (formats_list) {
4516     GstXvImageFormat *format = formats_list->data;
4517
4518     gst_caps_unref (format->caps);
4519     g_free (format);
4520     formats_list = g_list_next (formats_list);
4521   }
4522
4523   if (xcontext->formats_list)
4524     g_list_free (xcontext->formats_list);
4525
4526   channels_list = xcontext->channels_list;
4527 #ifdef GST_EXT_XV_ENHANCEMENT
4528   }
4529 #endif
4530   while (channels_list) {
4531     GstColorBalanceChannel *channel = channels_list->data;
4532
4533     g_object_unref (channel);
4534     channels_list = g_list_next (channels_list);
4535   }
4536
4537   if (xcontext->channels_list)
4538     g_list_free (xcontext->channels_list);
4539
4540   gst_caps_unref (xcontext->caps);
4541   if (xcontext->last_caps)
4542     gst_caps_replace (&xcontext->last_caps, NULL);
4543
4544   for (i = 0; i < xcontext->nb_adaptors; i++) {
4545     g_free (xcontext->adaptors[i]);
4546   }
4547
4548   g_free (xcontext->adaptors);
4549
4550   g_free (xcontext->par);
4551
4552   g_mutex_lock (xvimagesink->x_lock);
4553
4554   GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
4555
4556   XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4557
4558 #ifdef GST_EXT_XV_ENHANCEMENT
4559   {
4560     int i = 0;
4561     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4562       if (g_display_id[i] == xcontext->disp) {
4563         g_display_id[i] = NULL;
4564       }
4565     }
4566   }
4567 #endif
4568   XCloseDisplay (xcontext->disp);
4569   g_mutex_unlock (xvimagesink->x_lock);
4570
4571   g_free (xcontext);
4572 }
4573
4574 static void
4575 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
4576 {
4577   g_mutex_lock (xvimagesink->pool_lock);
4578
4579   while (xvimagesink->image_pool) {
4580     GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
4581
4582     xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4583         xvimagesink->image_pool);
4584     gst_xvimage_buffer_free (xvimage);
4585   }
4586
4587   g_mutex_unlock (xvimagesink->pool_lock);
4588 }
4589
4590 /* Element stuff */
4591
4592 /* This function tries to get a format matching with a given caps in the
4593    supported list of formats we generated in gst_xvimagesink_get_xv_support */
4594 static gint
4595 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
4596     GstCaps * caps)
4597 {
4598   GList *list = NULL;
4599
4600   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
4601
4602   list = xvimagesink->xcontext->formats_list;
4603
4604   while (list) {
4605     GstXvImageFormat *format = list->data;
4606
4607     if (format) {
4608       if (gst_caps_can_intersect (caps, format->caps)) {
4609         return format->format;
4610       }
4611     }
4612     list = g_list_next (list);
4613   }
4614
4615   return -1;
4616 }
4617
4618 static GstCaps *
4619 gst_xvimagesink_getcaps (GstBaseSink * bsink)
4620 {
4621   GstXvImageSink *xvimagesink;
4622
4623   xvimagesink = GST_XVIMAGESINK (bsink);
4624   if (xvimagesink->xcontext
4625 #ifdef GST_EXT_XV_ENHANCEMENT
4626     && !xvimagesink->subpicture
4627 #endif
4628 ) {
4629     return gst_caps_ref (xvimagesink->xcontext->caps);
4630   }
4631   return
4632       gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
4633           (xvimagesink)));
4634 }
4635
4636 static gboolean
4637 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
4638 {
4639   GstXvImageSink *xvimagesink;
4640   GstStructure *structure;
4641   guint32 im_format = 0;
4642   gboolean ret;
4643   gint video_width, video_height;
4644   gint disp_x, disp_y;
4645   gint disp_width, disp_height;
4646   gint video_par_n, video_par_d;        /* video's PAR */
4647   gint display_par_n, display_par_d;    /* display's PAR */
4648   const GValue *caps_par;
4649   const GValue *caps_disp_reg;
4650   const GValue *fps;
4651   guint num, den;
4652 #ifdef GST_EXT_XV_ENHANCEMENT
4653   gboolean subtitle;
4654   gchar *str_in = gst_caps_to_string(caps);
4655   if(str_in == NULL) {
4656     GST_ERROR("gst_caps_to_string() returns NULL...");
4657   }else{
4658     GST_INFO("In setcaps. incaps:%s", str_in);
4659     g_free (str_in);
4660     str_in = NULL;
4661   }
4662 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
4663
4664   xvimagesink = GST_XVIMAGESINK (bsink);
4665
4666   GST_DEBUG_OBJECT (xvimagesink,
4667       "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
4668       GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
4669
4670   if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)
4671 #ifdef GST_EXT_XV_ENHANCEMENT
4672     && !xvimagesink->subpicture
4673 #endif
4674     )
4675     goto incompatible_caps;
4676
4677   structure = gst_caps_get_structure (caps, 0);
4678   ret = gst_structure_get_int (structure, "width", &video_width);
4679   ret &= gst_structure_get_int (structure, "height", &video_height);
4680   fps = gst_structure_get_value (structure, "framerate");
4681   ret &= (fps != NULL);
4682 #ifdef GST_EXT_XV_ENHANCEMENT
4683   if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture)
4684   {
4685     xvimagesink->is_subpicture_format = TRUE;
4686     GST_LOG("It is type of subpicture and subtitle.");
4687   }
4688 #endif
4689   if (!ret)
4690     goto incomplete_caps;
4691
4692 #ifdef GST_EXT_XV_ENHANCEMENT
4693   xvimagesink->aligned_width = video_width;
4694   xvimagesink->aligned_height = video_height;
4695
4696 #ifdef GST_EXT_ENABLE_HEVC
4697   /*get combine prop of hevc*/
4698   if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
4699   {
4700     GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
4701   }
4702   else
4703   {
4704     /*Not need to combine data, just directly copy*/
4705     xvimagesink->need_combine_data = 0;
4706   }
4707 #endif
4708   _remove_last_buffer(xvimagesink);
4709 #endif /* GST_EXT_XV_ENHANCEMENT */
4710
4711   xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
4712   xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
4713
4714   xvimagesink->video_width = video_width;
4715   xvimagesink->video_height = video_height;
4716 #ifdef GST_EXT_XV_ENHANCEMENT
4717   if (!xvimagesink->subpicture) {
4718 #endif
4719   im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
4720   if (im_format == -1)
4721     goto invalid_format;
4722 #ifdef GST_EXT_XV_ENHANCEMENT
4723   }
4724 #endif
4725   /* get aspect ratio from caps if it's present, and
4726    * convert video width and height to a display width and height
4727    * using wd / hd = wv / hv * PARv / PARd */
4728
4729   /* get video's PAR */
4730   caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
4731   if (caps_par) {
4732     video_par_n = gst_value_get_fraction_numerator (caps_par);
4733     video_par_d = gst_value_get_fraction_denominator (caps_par);
4734   } else {
4735     video_par_n = 1;
4736     video_par_d = 1;
4737   }
4738   /* get display's PAR */
4739   if (xvimagesink->par) {
4740     display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
4741     display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
4742   } else {
4743     display_par_n = 1;
4744     display_par_d = 1;
4745   }
4746
4747   /* get the display region */
4748   caps_disp_reg = gst_structure_get_value (structure, "display-region");
4749   if (caps_disp_reg) {
4750     disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
4751     disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
4752     disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
4753     disp_height =
4754         g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
4755   } else {
4756     disp_x = disp_y = 0;
4757     disp_width = video_width;
4758     disp_height = video_height;
4759   }
4760
4761   if (!gst_video_calculate_display_ratio (&num, &den, video_width,
4762           video_height, video_par_n, video_par_d, display_par_n, display_par_d))
4763     goto no_disp_ratio;
4764
4765   xvimagesink->disp_x = disp_x;
4766   xvimagesink->disp_y = disp_y;
4767   xvimagesink->disp_width = disp_width;
4768   xvimagesink->disp_height = disp_height;
4769
4770   GST_DEBUG_OBJECT (xvimagesink,
4771       "video width/height: %dx%d, calculated display ratio: %d/%d",
4772       video_width, video_height, num, den);
4773
4774   /* now find a width x height that respects this display ratio.
4775    * prefer those that have one of w/h the same as the incoming video
4776    * using wd / hd = num / den */
4777
4778   /* start with same height, because of interlaced video */
4779   /* check hd / den is an integer scale factor, and scale wd with the PAR */
4780   if (video_height % den == 0) {
4781     GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
4782     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4783         gst_util_uint64_scale_int (video_height, num, den);
4784     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4785   } else if (video_width % num == 0) {
4786     GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
4787     GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
4788     GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
4789         gst_util_uint64_scale_int (video_width, den, num);
4790   } else {
4791     GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
4792     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4793         gst_util_uint64_scale_int (video_height, num, den);
4794     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4795   }
4796   GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
4797       GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
4798
4799   /* Notify application to set xwindow id now */
4800   g_mutex_lock (xvimagesink->flow_lock);
4801 #ifdef GST_EXT_XV_ENHANCEMENT
4802   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4803     g_mutex_unlock (xvimagesink->flow_lock);
4804     gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
4805 #else
4806   if (!xvimagesink->xwindow) {
4807     g_mutex_unlock (xvimagesink->flow_lock);
4808     gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
4809 #endif
4810   } else {
4811     g_mutex_unlock (xvimagesink->flow_lock);
4812   }
4813 #ifdef GST_EXT_XV_ENHANCEMENT
4814 if (!xvimagesink->is_subpicture_format) {
4815 #endif
4816     /* Creating our window and our image with the display size in pixels */
4817     if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
4818         GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
4819       goto no_display_size;
4820
4821     g_mutex_lock (xvimagesink->flow_lock);
4822 #ifdef GST_EXT_XV_ENHANCEMENT
4823     if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4824       GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
4825 #else
4826     if (!xvimagesink->xwindow) {
4827 #endif
4828       xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
4829           GST_VIDEO_SINK_WIDTH (xvimagesink),
4830           GST_VIDEO_SINK_HEIGHT (xvimagesink));
4831     }
4832   }
4833
4834   /* After a resize, we want to redraw the borders in case the new frame size
4835    * doesn't cover the same area */
4836   xvimagesink->redraw_border = TRUE;
4837
4838   /* We renew our xvimage only if size or format changed;
4839    * the xvimage is the same size as the video pixel size */
4840   if ((xvimagesink->xvimage) &&
4841       ((im_format != xvimagesink->xvimage->im_format) ||
4842           (video_width != xvimagesink->xvimage->width) ||
4843           (video_height != xvimagesink->xvimage->height)) &&
4844           (!xvimagesink->subpicture)) {
4845     GST_DEBUG_OBJECT (xvimagesink,
4846         "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4847         GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4848         GST_FOURCC_ARGS (im_format));
4849     GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4850     gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4851     xvimagesink->xvimage = NULL;
4852   }
4853
4854 #ifdef GST_EXT_XV_ENHANCEMENT
4855   /* In case of starting player with connecting external display, we have to check status.
4856    * It will be unconditionally executed. */
4857   if(!xvimagesink->is_subpicture_format)
4858     check_hdmi_connected(xvimagesink);
4859 #endif
4860   g_mutex_unlock (xvimagesink->flow_lock);
4861
4862   return TRUE;
4863
4864   /* ERRORS */
4865 incompatible_caps:
4866   {
4867     GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4868     return FALSE;
4869   }
4870 incomplete_caps:
4871   {
4872     GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4873         "height or framerate from intersected caps");
4874     return FALSE;
4875   }
4876 invalid_format:
4877   {
4878     GST_DEBUG_OBJECT (xvimagesink,
4879         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4880     return FALSE;
4881   }
4882 no_disp_ratio:
4883   {
4884     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4885         ("Error calculating the output display ratio of the video."));
4886     return FALSE;
4887   }
4888 no_display_size:
4889   {
4890     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4891         ("Error calculating the output display ratio of the video."));
4892     return FALSE;
4893   }
4894 #ifdef GST_EXT_XV_ENHANCEMENT
4895 }
4896 #endif
4897
4898 static GstStateChangeReturn
4899 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4900 {
4901   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4902   GstXvImageSink *xvimagesink;
4903   GstXContext *xcontext = NULL;
4904 #ifdef GST_EXT_XV_ENHANCEMENT
4905   Atom atom_preemption = None;
4906 #endif /* GST_EXT_XV_ENHANCEMENT */
4907
4908   xvimagesink = GST_XVIMAGESINK (element);
4909
4910   switch (transition) {
4911     case GST_STATE_CHANGE_NULL_TO_READY:
4912 #ifdef GST_EXT_XV_ENHANCEMENT
4913       GST_WARNING("NULL_TO_READY start");
4914 #endif /* GST_EXT_XV_ENHANCEMENT */
4915       /* Initializing the XContext */
4916       if (xvimagesink->xcontext == NULL) {
4917         xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4918         if (xcontext == NULL)
4919           return GST_STATE_CHANGE_FAILURE;
4920         GST_OBJECT_LOCK (xvimagesink);
4921         if (xcontext)
4922           xvimagesink->xcontext = xcontext;
4923         GST_OBJECT_UNLOCK (xvimagesink);
4924       }
4925
4926       /* update object's par with calculated one if not set yet */
4927       if (!xvimagesink->par) {
4928         xvimagesink->par = g_new0 (GValue, 1);
4929         gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4930         GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4931       }
4932       /* call XSynchronize with the current value of synchronous */
4933       GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4934           xvimagesink->synchronous ? "TRUE" : "FALSE");
4935       XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4936       gst_xvimagesink_update_colorbalance (xvimagesink);
4937       gst_xvimagesink_manage_event_thread (xvimagesink);
4938 #ifdef GST_EXT_XV_ENHANCEMENT
4939       GST_WARNING("NULL_TO_READY done");
4940 #endif /* GST_EXT_XV_ENHANCEMENT */
4941       break;
4942     case GST_STATE_CHANGE_READY_TO_PAUSED:
4943 #ifdef GST_EXT_XV_ENHANCEMENT
4944       GST_WARNING("READY_TO_PAUSED start");
4945 #endif /* GST_EXT_XV_ENHANCEMENT */
4946       g_mutex_lock (xvimagesink->pool_lock);
4947       xvimagesink->pool_invalid = FALSE;
4948       g_mutex_unlock (xvimagesink->pool_lock);
4949 #ifdef GST_EXT_XV_ENHANCEMENT
4950       GST_WARNING("READY_TO_PAUSED done");
4951 #endif /* GST_EXT_XV_ENHANCEMENT */
4952       break;
4953     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4954 #ifdef GST_EXT_XV_ENHANCEMENT
4955       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING))
4956         GST_WARNING("vconf set fail");
4957       GST_WARNING("PAUSED_TO_PLAYING done");
4958       xvimagesink->is_during_seek = FALSE;
4959       xvimagesink->keep_external_fullscreen_prev = FALSE;
4960 #endif /* GST_EXT_XV_ENHANCEMENT */
4961       break;
4962     case GST_STATE_CHANGE_PAUSED_TO_READY:
4963 #ifdef GST_EXT_XV_ENHANCEMENT
4964       GST_WARNING("PAUSED_TO_READY start");
4965 #endif /* GST_EXT_XV_ENHANCEMENT */
4966       g_mutex_lock (xvimagesink->pool_lock);
4967       xvimagesink->pool_invalid = TRUE;
4968       g_mutex_unlock (xvimagesink->pool_lock);
4969 #ifdef GST_EXT_XV_ENHANCEMENT
4970 #endif /* GST_EXT_XV_ENHANCEMENT */
4971       break;
4972     default:
4973       break;
4974   }
4975
4976   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4977
4978   switch (transition) {
4979     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4980 #ifdef GST_EXT_XV_ENHANCEMENT
4981       GST_WARNING("PLAYING_TO_PAUSED start");
4982       g_mutex_lock (xvimagesink->flow_lock);
4983       /* init displayed buffer count */
4984       xvimagesink->displayed_buffer_count = 0;
4985
4986       g_mutex_lock (xvimagesink->x_lock);
4987       if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) {
4988         GST_WARNING_OBJECT(xvimagesink, "release external display mode");
4989         XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
4990                      xvimagesink->xwindow->win);
4991         XSync(xvimagesink->xcontext->disp, FALSE);
4992         xvimagesink->skip_frame_due_to_external_dev = TRUE;
4993       }
4994       if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture)
4995         && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
4996         GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4997         XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4998         XSync(xvimagesink->xcontext->disp, FALSE);
4999       }
5000       g_mutex_unlock (xvimagesink->x_lock);
5001       g_mutex_unlock (xvimagesink->flow_lock);
5002       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED))
5003         GST_WARNING("vconf set fail");
5004       GST_WARNING("PLAYING_TO_PAUSED done");
5005 #endif /* GST_EXT_XV_ENHANCEMENT */
5006       break;
5007     case GST_STATE_CHANGE_PAUSED_TO_READY:
5008 #ifdef GST_EXT_XV_ENHANCEMENT
5009       GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
5010                                       xvimagesink->is_zero_copy_format,
5011                                       xvimagesink->enable_flush_buffer,
5012                                       xvimagesink->secure_path,
5013                                       xvimagesink->get_pixmap_cb);
5014
5015       if ((xvimagesink->enable_flush_buffer == FALSE ||
5016            xvimagesink->secure_path == SECURE_PATH_ON) &&
5017           xvimagesink->xcontext && xvimagesink->xwindow) {
5018         GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
5019         g_mutex_lock(xvimagesink->x_lock);
5020         XvStopVideo(xvimagesink->xcontext->disp,
5021                     xvimagesink->xcontext->xv_port_id,
5022                     xvimagesink->xwindow->win);
5023         XSync(xvimagesink->xcontext->disp, FALSE);
5024         g_mutex_unlock(xvimagesink->x_lock);
5025         _remove_last_buffer(xvimagesink);
5026       } else if (xvimagesink->is_zero_copy_format &&
5027                  xvimagesink->xvimage &&
5028                  xvimagesink->xvimage->xvimage &&
5029                  !xvimagesink->get_pixmap_cb) {
5030         if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5031           int i = 0;
5032           XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5033           memset(img_data, 0x0, sizeof(XV_DATA));
5034           XV_INIT_DATA(img_data);
5035
5036           img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5037           img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5038           img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5039
5040           gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5041
5042           GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
5043
5044           /* check whether putimage is succeeded or not */
5045           g_mutex_lock(xvimagesink->display_buffer_lock);
5046
5047           for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5048             if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
5049               if ((img_data->dmabuf_fd[0] > 0 &&
5050                    xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
5051                    xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
5052                    xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
5053                   (img_data->bo[0] &&
5054                    xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
5055                    xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
5056                    xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
5057                 GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
5058                 break;
5059               }
5060             }
5061           }
5062
5063           if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
5064             GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
5065             _release_flush_buffer(xvimagesink);
5066           } else {
5067             _remove_last_buffer(xvimagesink);
5068           }
5069
5070           g_mutex_unlock(xvimagesink->display_buffer_lock);
5071         }
5072       }
5073 #endif /* GST_EXT_XV_ENHANCEMENT */
5074       xvimagesink->fps_n = 0;
5075       xvimagesink->fps_d = 1;
5076       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
5077       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
5078 #ifdef GST_EXT_XV_ENHANCEMENT
5079       GST_WARNING("PAUSED_TO_READY done");
5080 #endif /* GST_EXT_XV_ENHANCEMENT */
5081       break;
5082     case GST_STATE_CHANGE_READY_TO_NULL:
5083 #ifdef GST_EXT_XV_ENHANCEMENT
5084       GST_WARNING("READY_TO_NULL start");
5085 #endif /* GST_EXT_XV_ENHANCEMENT */
5086       gst_xvimagesink_reset (xvimagesink);
5087 #ifdef GST_EXT_XV_ENHANCEMENT
5088       /* close drm */
5089       drm_fini(xvimagesink);
5090       /* init displaying_buffer_count */
5091       xvimagesink->displaying_buffer_count = 0;
5092       GST_WARNING("READY_TO_NULL done");
5093 #endif /* GST_EXT_XV_ENHANCEMENT */
5094       break;
5095     default:
5096       break;
5097   }
5098
5099   return ret;
5100 }
5101
5102 static void
5103 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
5104     GstClockTime * start, GstClockTime * end)
5105 {
5106   GstXvImageSink *xvimagesink;
5107
5108   xvimagesink = GST_XVIMAGESINK (bsink);
5109
5110   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
5111     *start = GST_BUFFER_TIMESTAMP (buf);
5112     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
5113       *end = *start + GST_BUFFER_DURATION (buf);
5114     } else {
5115       if (xvimagesink->fps_n > 0) {
5116         *end = *start +
5117             gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
5118             xvimagesink->fps_n);
5119       }
5120     }
5121   }
5122 }
5123
5124 #ifdef GST_EXT_ENABLE_HEVC
5125 static void
5126 gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
5127 {
5128     unsigned int outsize = 0;
5129     unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
5130     int cnt = 0, j = 0;
5131     unsigned char *temp_imgb;
5132     SCMN_IMGB *imgb = NULL;
5133     int stride, w, h, i;
5134
5135     GST_DEBUG("Begin");
5136     imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
5137     if(imgb == NULL || imgb->a[0] == NULL)
5138     {
5139         return;
5140     }
5141
5142     stride = GST_ROUND_UP_4 (imgb->w[0]);
5143     h = imgb->h[0];
5144     w = imgb->w[0];
5145     /*Y plane copy */
5146     for (i = 0; i < h; i++)
5147     {
5148         memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
5149     }
5150
5151     temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
5152
5153     stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
5154     h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
5155     w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
5156     /* Cb plane copy */
5157     for (i = 0; i < h; i++)
5158     {
5159         memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
5160     }
5161
5162     temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
5163     /* Same stride, height, width as above */
5164     /* Cr plane copy */
5165     for (i = 0; i < h; i++)
5166     {
5167         memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
5168     }
5169
5170     outsize  = imgb->w[0] * imgb->h[0]* 3 >> 1;
5171     xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
5172
5173     GST_DEBUG("End");
5174 }
5175 #endif
5176
5177 #ifdef GST_EXT_XV_ENHANCEMENT
5178 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
5179 {
5180   GstXvImageFlushBuffer *flush_buffer = NULL;
5181   GstXvImageDisplayingBuffer *display_buffer = NULL;
5182   tbm_bo bo = NULL;
5183   int size = 0;
5184   int i = 0;
5185   int ret = 0;
5186
5187   if (xvimagesink == NULL) {
5188     GST_ERROR("handle is NULL");
5189     return FALSE;
5190   }
5191
5192   if (xvimagesink->last_added_buffer_index == -1) {
5193     GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
5194     return FALSE;
5195   }
5196
5197   if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
5198     GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
5199                                   xvimagesink->drm_fd, xvimagesink->bufmgr);
5200     return FALSE;
5201   }
5202
5203   flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
5204   if (flush_buffer == NULL) {
5205     GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
5206     return FALSE;
5207   }
5208
5209   memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
5210
5211   display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
5212   GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
5213                                   xvimagesink->last_added_buffer_index);
5214
5215   for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5216     if (display_buffer->bo[i]) {
5217       tbm_bo_handle vaddr_src;
5218       tbm_bo_handle vaddr_dst;
5219
5220       /* get bo size */
5221       size = tbm_bo_size(display_buffer->bo[i]);
5222
5223       /* alloc bo */
5224       bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT);
5225       if (bo == NULL) {
5226         GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
5227         goto FLUSH_BUFFER_FAILED;
5228       }
5229
5230       GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
5231
5232       flush_buffer->gem_name[i] = tbm_bo_export(bo);
5233       flush_buffer->bo[i] = bo;
5234
5235       /* get virtual address */
5236       vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5237       vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5238       if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
5239         GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
5240                                         vaddr_src.ptr, vaddr_dst.ptr);
5241         if (vaddr_src.ptr) {
5242           tbm_bo_unmap(display_buffer->bo[i]);
5243         }
5244         if (vaddr_dst.ptr) {
5245           tbm_bo_unmap(bo);
5246         }
5247         goto FLUSH_BUFFER_FAILED;
5248       }
5249
5250       /* copy buffer */
5251       memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
5252
5253       tbm_bo_unmap(display_buffer->bo[i]);
5254       tbm_bo_unmap(bo);
5255
5256       GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
5257
5258       xvimagesink->flush_buffer = flush_buffer;
5259
5260       ret = TRUE;
5261     }
5262   }
5263
5264   return ret;
5265
5266 FLUSH_BUFFER_FAILED:
5267   if (flush_buffer) {
5268     for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5269       if (flush_buffer->bo[i]) {
5270         tbm_bo_unref(flush_buffer->bo[i]);
5271         flush_buffer->bo[i] = NULL;
5272       }
5273     }
5274     free(flush_buffer);
5275     flush_buffer = NULL;
5276   }
5277
5278   return FALSE;
5279 }
5280 #endif /* GST_EXT_XV_ENHANCEMENT */
5281
5282
5283 static GstFlowReturn
5284 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
5285 {
5286   GstXvImageSink *xvimagesink;
5287
5288 #ifdef GST_EXT_XV_ENHANCEMENT
5289   XV_DATA_PTR img_data = NULL;
5290   SCMN_IMGB *scmn_imgb = NULL;
5291   gint format = 0;
5292   gboolean ret = FALSE;
5293   int res = -1;
5294   int (*handler) (Display *, XErrorEvent *) = NULL;
5295   Atom atom_overlay;
5296 #endif /* GST_EXT_XV_ENHANCEMENT */
5297
5298   xvimagesink = GST_XVIMAGESINK (vsink);
5299
5300 #ifdef GST_EXT_XV_ENHANCEMENT
5301   if (xvimagesink->stop_video) {
5302     GST_INFO( "Stop video is TRUE. so skip show frame..." );
5303     return GST_FLOW_OK;
5304   }
5305 #endif /* GST_EXT_XV_ENHANCEMENT */
5306
5307   /* If this buffer has been allocated using our buffer management we simply
5308      put the ximage which is in the PRIVATE pointer */
5309   if (GST_IS_XVIMAGE_BUFFER (buf)) {
5310     GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
5311 #ifdef GST_EXT_XV_ENHANCEMENT
5312     xvimagesink->xid_updated = FALSE;
5313 #endif /* GST_EXT_XV_ENHANCEMENT */
5314     if (!gst_xvimagesink_xvimage_put (xvimagesink,
5315             GST_XVIMAGE_BUFFER_CAST (buf)))
5316       goto no_window;
5317   } else {
5318     GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
5319         "slow copy into bufferpool buffer %p", buf);
5320     /* Else we have to copy the data into our private image, */
5321     /* if we have one... */
5322 #ifdef GST_EXT_XV_ENHANCEMENT
5323     g_mutex_lock (xvimagesink->flow_lock);
5324     if (xvimagesink->skip_frame_due_to_external_dev) {
5325       GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." );
5326       xvimagesink->skip_frame_due_to_external_dev = FALSE;
5327       g_mutex_unlock (xvimagesink->flow_lock);
5328       return GST_FLOW_OK;
5329     }
5330
5331 #endif /* GST_EXT_XV_ENHANCEMENT */
5332       if (!xvimagesink->xvimage
5333 #ifdef GST_EXT_XV_ENHANCEMENT
5334       && !xvimagesink->is_subpicture_format
5335 #endif
5336         ) {
5337         GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
5338
5339 #ifdef GST_EXT_XV_ENHANCEMENT
5340       format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
5341       switch (format) {
5342         case GST_MAKE_FOURCC('S', 'T', '1', '2'):
5343         case GST_MAKE_FOURCC('S', 'N', '1', '2'):
5344         case GST_MAKE_FOURCC('S', 'N', '2', '1'):
5345         case GST_MAKE_FOURCC('S', '4', '2', '0'):
5346         case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
5347         case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
5348         case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
5349         case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
5350         case GST_MAKE_FOURCC('S', 'R', '3', '2'):
5351         case GST_MAKE_FOURCC('S', 'V', '1', '2'):
5352           xvimagesink->is_zero_copy_format = TRUE;
5353           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5354           if(scmn_imgb == NULL) {
5355             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5356             g_mutex_unlock (xvimagesink->flow_lock);
5357             return GST_FLOW_OK;
5358           }
5359
5360           /* skip buffer if aligned size is smaller than size of caps */
5361           if (scmn_imgb->s[0] < xvimagesink->video_width ||
5362               scmn_imgb->e[0] < xvimagesink->video_height) {
5363             GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
5364                                             xvimagesink->video_width, xvimagesink->video_height,
5365                                             scmn_imgb->s[0], scmn_imgb->e[0]);
5366             g_mutex_unlock (xvimagesink->flow_lock);
5367             return GST_FLOW_OK;
5368           }
5369
5370           xvimagesink->aligned_width = scmn_imgb->s[0];
5371           xvimagesink->aligned_height = scmn_imgb->e[0];
5372           GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
5373                                        xvimagesink->aligned_width, xvimagesink->aligned_height);
5374           break;
5375         default:
5376           xvimagesink->is_zero_copy_format = FALSE;
5377           GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
5378           break;
5379       }
5380
5381       GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
5382 #endif /* GST_EXT_XV_ENHANCEMENT */
5383
5384       xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
5385           GST_BUFFER_CAPS (buf));
5386
5387       if (!xvimagesink->xvimage)
5388         /* The create method should have posted an informative error */
5389         goto no_image;
5390
5391 #ifdef GST_EXT_XV_ENHANCEMENT
5392       if ((xvimagesink->is_zero_copy_format == FALSE &&
5393            xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
5394           (xvimagesink->is_zero_copy_format &&
5395            xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
5396 #else /* GST_EXT_XV_ENHANCEMENT */
5397       if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
5398 #endif /* GST_EXT_XV_ENHANCEMENT */
5399         GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
5400             ("Failed to create output image buffer of %dx%d pixels",
5401                 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
5402             ("XServer allocated buffer size did not match input buffer"));
5403
5404         gst_xvimage_buffer_destroy (xvimagesink->xvimage);
5405         xvimagesink->xvimage = NULL;
5406         goto no_image;
5407       }
5408     }
5409
5410 #ifdef GST_EXT_XV_ENHANCEMENT
5411     if (xvimagesink->is_zero_copy_format) {
5412       /* Cases for specified formats of Samsung extension */
5413         GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
5414                 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
5415                 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
5416                 xvimagesink->display_mode, xvimagesink->rotate_angle);
5417
5418         if (xvimagesink->xvimage->xvimage->data) {
5419           int i = 0;
5420           img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5421           memset(img_data, 0x0, sizeof(XV_DATA));
5422           XV_INIT_DATA(img_data);
5423
5424           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5425           if (scmn_imgb == NULL) {
5426             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5427             g_mutex_unlock (xvimagesink->flow_lock);
5428             return GST_FLOW_OK;
5429           }
5430
5431           /* Keep the vaddr of current image for copying last image */
5432           if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
5433             for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
5434               xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
5435             }
5436             GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5437               xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
5438           }
5439
5440           if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
5441             img_data->YBuf = (unsigned int)scmn_imgb->p[0];
5442             img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
5443             img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
5444             img_data->BufType = XV_BUF_TYPE_LEGACY;
5445
5446             GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5447                       img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
5448           } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
5449                      scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
5450             gboolean do_set_secure = FALSE;
5451
5452             /* open drm to use gem */
5453             if (xvimagesink->drm_fd < 0) {
5454               drm_init(xvimagesink);
5455             }
5456
5457             if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
5458               /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
5459               img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
5460               img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
5461               img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
5462               img_data->BufType = XV_BUF_TYPE_DMABUF;
5463               GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
5464             } else {
5465               /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
5466               img_data->bo[0] = scmn_imgb->bo[0];
5467               img_data->bo[1] = scmn_imgb->bo[1];
5468               img_data->bo[2] = scmn_imgb->bo[2];
5469               GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
5470             }
5471
5472             /* check secure contents path */
5473             if (scmn_imgb->tz_enable) {
5474               if (xvimagesink->secure_path != SECURE_PATH_ON) {
5475                 xvimagesink->secure_path = SECURE_PATH_ON;
5476                 do_set_secure = TRUE;
5477               }
5478             } else {
5479               if (xvimagesink->secure_path != SECURE_PATH_OFF) {
5480                 xvimagesink->secure_path = SECURE_PATH_OFF;
5481                 do_set_secure = TRUE;
5482               }
5483             }
5484             static gboolean is_exist = FALSE;
5485             gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE");
5486             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5487             g_free(attr_name);
5488
5489             if (do_set_secure && is_exist) {
5490               Atom atom_secure = None;
5491               g_mutex_lock (xvimagesink->x_lock);
5492               atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
5493               if (atom_secure != None) {
5494                 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
5495                   GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
5496                 } else {
5497                   GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
5498                 }
5499                 XSync (xvimagesink->xcontext->disp, FALSE);
5500               } else {
5501                 GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
5502               }
5503               g_mutex_unlock (xvimagesink->x_lock);
5504             }
5505
5506             is_exist = FALSE;
5507             attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5508             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5509             g_free(attr_name);
5510
5511
5512             if (xvimagesink->drm_level && is_exist) {
5513               Atom atom_drm = None;
5514               g_mutex_lock (xvimagesink->x_lock);
5515               atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5516                                           "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5517               if (atom_drm != None) {
5518                 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5519                 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5520                                      xvimagesink->xcontext->xv_port_id,
5521                                      atom_drm, xvimagesink->drm_level ) != Success) {
5522                   GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5523                 }
5524                 XSync (xvimagesink->xcontext->disp, FALSE);
5525                 g_mutex_unlock (xvimagesink->x_lock);
5526                 xvimagesink->drm_level = DRM_LEVEL_0;
5527               }
5528             }
5529
5530             /* set current buffer */
5531             xvimagesink->xvimage->current_buffer = buf;
5532           } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) {
5533             /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
5534             GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
5535             if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5536               img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5537               img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5538               img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5539             } else {
5540               g_mutex_unlock(xvimagesink->flow_lock);
5541               return GST_FLOW_OK;
5542             }
5543           } else {
5544             GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
5545                         scmn_imgb->buf_share_method);
5546             g_mutex_unlock (xvimagesink->flow_lock);
5547             return GST_FLOW_OK;
5548           }
5549         } else {
5550           GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
5551           g_mutex_unlock (xvimagesink->flow_lock);
5552           return GST_FLOW_OK;
5553         }
5554     } else if (xvimagesink->is_subpicture_format) {
5555       GC gc;
5556       xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf);
5557       if(!xvimagesink->pixmap_for_subpicture) {
5558         GST_ERROR("no pixmap");
5559         g_mutex_unlock (xvimagesink->flow_lock);
5560         return GST_FLOW_OK;
5561       }
5562       if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) {
5563         GST_ERROR("pixmap's size and current resolution are different");
5564         g_mutex_unlock (xvimagesink->flow_lock);
5565         return GST_FLOW_OK;
5566       }
5567       gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0);
5568
5569       GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture,
5570         xvimagesink->xcontext->xv_port_id, gc);
5571
5572       /* set error handler */
5573       error_caught = FALSE;
5574       handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
5575
5576       if(!xvimagesink->set_overlay_for_subpicture_just_once)
5577       {
5578         GST_LOG("setting attribute overlay");
5579         atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE);
5580         XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1);
5581         XSync (xvimagesink->xcontext->disp, FALSE);
5582         xvimagesink->set_overlay_for_subpicture_just_once = TRUE;
5583       }
5584       res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
5585         xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height,
5586         0, 0, xvimagesink->external_width, xvimagesink->external_height);
5587       XSync (xvimagesink->xcontext->disp, FALSE);
5588
5589       GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n",
5590                           GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
5591                           GST_TIME_ARGS(GST_BUFFER_DURATION(buf)),
5592                           GST_BUFFER_SIZE(buf));
5593       if(gc) {
5594         GST_DEBUG("FreeGC");
5595         XFreeGC (xvimagesink->xcontext->disp, gc);
5596       }
5597       if (error_caught)
5598         GST_WARNING_OBJECT(xvimagesink, "XvGetStill error");
5599       else
5600         GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s  ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height);
5601
5602       /* Reset error handler */
5603       if (handler) {
5604         error_caught = FALSE;
5605         XSetErrorHandler (handler);
5606       }
5607     } else {
5608         GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
5609
5610 #ifdef GST_EXT_ENABLE_HEVC
5611         if(xvimagesink->need_combine_data == 1)
5612         {
5613             gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
5614         }
5615         else
5616 #endif
5617         {
5618             memcpy (xvimagesink->xvimage->xvimage->data,
5619             GST_BUFFER_DATA (buf),
5620             MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5621         }
5622     }
5623
5624     g_mutex_unlock (xvimagesink->flow_lock);
5625     ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5626     if (!ret && !xvimagesink->is_subpicture_format) {
5627       goto no_window;
5628     }
5629 #else /* GST_EXT_XV_ENHANCEMENT */
5630     memcpy (xvimagesink->xvimage->xvimage->data,
5631         GST_BUFFER_DATA (buf),
5632         MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5633
5634     if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
5635       goto no_window;
5636 #endif /* GST_EXT_XV_ENHANCEMENT */
5637   }
5638
5639   return GST_FLOW_OK;
5640
5641   /* ERRORS */
5642 no_image:
5643   {
5644     /* No image available. That's very bad ! */
5645     GST_WARNING_OBJECT (xvimagesink, "could not create image");
5646 #ifdef GST_EXT_XV_ENHANCEMENT
5647     g_mutex_unlock (xvimagesink->flow_lock);
5648 #endif
5649     return GST_FLOW_ERROR;
5650   }
5651 no_window:
5652   {
5653     /* No Window available to put our image into */
5654     GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
5655     return GST_FLOW_ERROR;
5656   }
5657 }
5658
5659 static gboolean
5660 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
5661 {
5662   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
5663   if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)
5664   {
5665       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK))
5666         GST_WARNING("vconf set fail");
5667   }
5668
5669   switch (GST_EVENT_TYPE (event)) {
5670     case GST_EVENT_TAG:{
5671       GstTagList *l;
5672       gchar *title = NULL;
5673
5674       gst_event_parse_tag (event, &l);
5675       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
5676
5677       if (title) {
5678 #ifdef GST_EXT_XV_ENHANCEMENT
5679         if (!xvimagesink->get_pixmap_cb) {
5680 #endif
5681         GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
5682         gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
5683             title);
5684
5685         g_free (title);
5686 #ifdef GST_EXT_XV_ENHANCEMENT
5687         }
5688 #endif
5689       }
5690       break;
5691     }
5692 #ifdef GST_EXT_XV_ENHANCEMENT
5693     case GST_EVENT_FLUSH_START:
5694       GST_DEBUG_OBJECT (xvimagesink, "flush start");
5695       break;
5696     case GST_EVENT_FLUSH_STOP:
5697       GST_DEBUG_OBJECT (xvimagesink, "flush stop");
5698       xvimagesink->is_during_seek = TRUE;
5699       break;
5700     case GST_EVENT_CUSTOM_DOWNSTREAM:
5701     {
5702       const GstStructure *st = NULL;
5703       st = gst_event_get_structure (event);
5704       if(!st) {
5705         GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
5706       } else {
5707         if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
5708           GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
5709           xvimagesink->drm_level = DRM_LEVEL_1;
5710           if (xvimagesink->drm_level && xvimagesink->xcontext) {
5711             static gboolean is_exist = FALSE;
5712             gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5713             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5714             g_free(attr_name);
5715
5716             if(is_exist)
5717             {
5718               Atom atom_drm = None;
5719               g_mutex_lock (xvimagesink->x_lock);
5720               atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5721                                           "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5722               if (atom_drm != None) {
5723                 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5724                 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5725                                      xvimagesink->xcontext->xv_port_id,
5726                                      atom_drm, xvimagesink->drm_level ) != Success) {
5727                   GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5728                 }
5729                 XSync (xvimagesink->xcontext->disp, FALSE);
5730                 xvimagesink->drm_level = DRM_LEVEL_0;
5731               }
5732               g_mutex_unlock (xvimagesink->x_lock);
5733             }
5734           }
5735         }
5736       }
5737       break;
5738     }
5739     case GST_EVENT_EOS:
5740       xvimagesink->eos_received = TRUE;
5741       GST_DEBUG_OBJECT(xvimagesink, "got eos");
5742       break;
5743     case GST_EVENT_NEWSEGMENT:
5744       xvimagesink->eos_received = FALSE;
5745       GST_DEBUG_OBJECT(xvimagesink, "got newsegment event");
5746       break;
5747 #endif
5748     default:
5749       break;
5750   }
5751   if (GST_BASE_SINK_CLASS (parent_class)->event)
5752     return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
5753   else
5754     return TRUE;
5755 }
5756
5757 /* Buffer management */
5758
5759 static GstCaps *
5760 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
5761     GstCaps * caps)
5762 {
5763   GstCaps *intersection;
5764   GstCaps *new_caps;
5765   GstStructure *s;
5766   gint width, height;
5767   gint par_n = 1, par_d = 1;
5768   gint dar_n, dar_d;
5769   gint w, h;
5770
5771   new_caps = gst_caps_copy (caps);
5772
5773   s = gst_caps_get_structure (new_caps, 0);
5774
5775   gst_structure_get_int (s, "width", &width);
5776   gst_structure_get_int (s, "height", &height);
5777   gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
5778
5779   gst_structure_remove_field (s, "width");
5780   gst_structure_remove_field (s, "height");
5781   gst_structure_remove_field (s, "pixel-aspect-ratio");
5782
5783   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5784   gst_caps_unref (new_caps);
5785
5786   if (gst_caps_is_empty (intersection))
5787     return intersection;
5788
5789   s = gst_caps_get_structure (intersection, 0);
5790
5791   gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
5792
5793   /* xvimagesink supports all PARs */
5794
5795   gst_structure_fixate_field_nearest_int (s, "width", width);
5796   gst_structure_fixate_field_nearest_int (s, "height", height);
5797   gst_structure_get_int (s, "width", &w);
5798   gst_structure_get_int (s, "height", &h);
5799
5800   gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
5801   gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
5802       NULL);
5803
5804   return intersection;
5805 }
5806
5807 static GstFlowReturn
5808 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
5809     GstCaps * caps, GstBuffer ** buf)
5810 {
5811   GstFlowReturn ret = GST_FLOW_OK;
5812   GstXvImageSink *xvimagesink;
5813   GstXvImageBuffer *xvimage = NULL;
5814   GstCaps *intersection = NULL;
5815   GstStructure *structure = NULL;
5816   gint width, height, image_format;
5817
5818   xvimagesink = GST_XVIMAGESINK (bsink);
5819
5820   if (G_UNLIKELY (!caps))
5821     goto no_caps;
5822
5823   g_mutex_lock (xvimagesink->pool_lock);
5824   if (G_UNLIKELY (xvimagesink->pool_invalid))
5825     goto invalid;
5826
5827   if (G_LIKELY (xvimagesink->xcontext->last_caps &&
5828           gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
5829     GST_LOG_OBJECT (xvimagesink,
5830         "buffer alloc for same last_caps, reusing caps");
5831     intersection = gst_caps_ref (caps);
5832     image_format = xvimagesink->xcontext->last_format;
5833     width = xvimagesink->xcontext->last_width;
5834     height = xvimagesink->xcontext->last_height;
5835
5836     goto reuse_last_caps;
5837   }
5838
5839   GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
5840       GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
5841       caps, xvimagesink->xcontext->caps);
5842
5843   /* Check the caps against our xcontext */
5844   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
5845
5846   GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
5847       GST_PTR_FORMAT, intersection);
5848
5849   if (gst_caps_is_empty (intersection)) {
5850     GstCaps *new_caps;
5851
5852     gst_caps_unref (intersection);
5853
5854     /* So we don't support this kind of buffer, let's define one we'd like */
5855     new_caps = gst_caps_copy (caps);
5856
5857     structure = gst_caps_get_structure (new_caps, 0);
5858     if (!gst_structure_has_field (structure, "width") ||
5859         !gst_structure_has_field (structure, "height")) {
5860       gst_caps_unref (new_caps);
5861       goto invalid;
5862     }
5863
5864     /* Try different dimensions */
5865     intersection =
5866         gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5867
5868     if (gst_caps_is_empty (intersection)) {
5869       /* Try with different YUV formats first */
5870       gst_structure_set_name (structure, "video/x-raw-yuv");
5871
5872       /* Remove format specific fields */
5873       gst_structure_remove_field (structure, "format");
5874       gst_structure_remove_field (structure, "endianness");
5875       gst_structure_remove_field (structure, "depth");
5876       gst_structure_remove_field (structure, "bpp");
5877       gst_structure_remove_field (structure, "red_mask");
5878       gst_structure_remove_field (structure, "green_mask");
5879       gst_structure_remove_field (structure, "blue_mask");
5880       gst_structure_remove_field (structure, "alpha_mask");
5881
5882       /* Reuse intersection with Xcontext */
5883       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5884     }
5885
5886     if (gst_caps_is_empty (intersection)) {
5887       /* Try with different dimensions and YUV formats */
5888       intersection =
5889           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5890     }
5891
5892     if (gst_caps_is_empty (intersection)) {
5893       /* Now try with RGB */
5894       gst_structure_set_name (structure, "video/x-raw-rgb");
5895       /* And interset again */
5896       gst_caps_unref (intersection);
5897       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5898     }
5899
5900     if (gst_caps_is_empty (intersection)) {
5901       /* Try with different dimensions and RGB formats */
5902       intersection =
5903           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5904     }
5905
5906     /* Clean this copy */
5907     gst_caps_unref (new_caps);
5908
5909     if (gst_caps_is_empty (intersection))
5910       goto incompatible;
5911   }
5912
5913   /* Ensure the returned caps are fixed */
5914   gst_caps_truncate (intersection);
5915
5916   GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
5917       GST_PTR_FORMAT, intersection);
5918   if (gst_caps_is_equal (intersection, caps)) {
5919     /* Things work better if we return a buffer with the same caps ptr
5920      * as was asked for when we can */
5921     gst_caps_replace (&intersection, caps);
5922   }
5923
5924   /* Get image format from caps */
5925   image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
5926       intersection);
5927
5928   /* Get geometry from caps */
5929   structure = gst_caps_get_structure (intersection, 0);
5930   if (!gst_structure_get_int (structure, "width", &width) ||
5931       !gst_structure_get_int (structure, "height", &height) ||
5932       image_format == -1)
5933     goto invalid_caps;
5934
5935   /* Store our caps and format as the last_caps to avoid expensive
5936    * caps intersection next time */
5937   gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
5938   xvimagesink->xcontext->last_format = image_format;
5939   xvimagesink->xcontext->last_width = width;
5940   xvimagesink->xcontext->last_height = height;
5941
5942 reuse_last_caps:
5943
5944   /* Walking through the pool cleaning unusable images and searching for a
5945      suitable one */
5946   while (xvimagesink->image_pool) {
5947     xvimage = xvimagesink->image_pool->data;
5948
5949     if (xvimage) {
5950       /* Removing from the pool */
5951       xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
5952           xvimagesink->image_pool);
5953
5954       /* We check for geometry or image format changes */
5955       if ((xvimage->width != width) ||
5956           (xvimage->height != height) || (xvimage->im_format != image_format)) {
5957         /* This image is unusable. Destroying... */
5958         gst_xvimage_buffer_free (xvimage);
5959         xvimage = NULL;
5960       } else {
5961         /* We found a suitable image */
5962         GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
5963         break;
5964       }
5965     }
5966   }
5967
5968   if (!xvimage) {
5969 #ifdef GST_EXT_XV_ENHANCEMENT
5970     /* init aligned size */
5971     xvimagesink->aligned_width = 0;
5972     xvimagesink->aligned_height = 0;
5973 #endif /* GST_EXT_XV_ENHANCEMENT */
5974
5975     /* We found no suitable image in the pool. Creating... */
5976     GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
5977     xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
5978   }
5979   g_mutex_unlock (xvimagesink->pool_lock);
5980
5981   if (xvimage) {
5982     /* Make sure the buffer is cleared of any previously used flags */
5983     GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
5984     gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
5985   }
5986
5987   *buf = GST_BUFFER_CAST (xvimage);
5988
5989 beach:
5990   if (intersection) {
5991     gst_caps_unref (intersection);
5992   }
5993
5994   return ret;
5995
5996   /* ERRORS */
5997 invalid:
5998   {
5999     GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
6000     ret = GST_FLOW_WRONG_STATE;
6001     g_mutex_unlock (xvimagesink->pool_lock);
6002     goto beach;
6003   }
6004 incompatible:
6005   {
6006     GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
6007         "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
6008         " are completely incompatible with those caps", caps,
6009         xvimagesink->xcontext->caps);
6010     ret = GST_FLOW_NOT_NEGOTIATED;
6011     g_mutex_unlock (xvimagesink->pool_lock);
6012     goto beach;
6013   }
6014 invalid_caps:
6015   {
6016     GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
6017         GST_PTR_FORMAT, intersection);
6018     ret = GST_FLOW_NOT_NEGOTIATED;
6019     g_mutex_unlock (xvimagesink->pool_lock);
6020     goto beach;
6021   }
6022 no_caps:
6023   {
6024     GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
6025     *buf = NULL;
6026     ret = GST_FLOW_OK;
6027     goto beach;
6028   }
6029 }
6030
6031 /* Interfaces stuff */
6032
6033 static gboolean
6034 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
6035 {
6036   if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
6037       type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
6038     return TRUE;
6039   else
6040     return FALSE;
6041 }
6042
6043 static void
6044 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
6045 {
6046   klass->supported = gst_xvimagesink_interface_supported;
6047 }
6048
6049 static void
6050 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
6051     GstStructure * structure)
6052 {
6053   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
6054   GstPad *peer;
6055
6056   if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
6057     GstEvent *event;
6058     GstVideoRectangle src, dst, result;
6059     gdouble x, y, xscale = 1.0, yscale = 1.0;
6060
6061     event = gst_event_new_navigation (structure);
6062
6063     /* We take the flow_lock while we look at the window */
6064     g_mutex_lock (xvimagesink->flow_lock);
6065
6066     if (!xvimagesink->xwindow) {
6067       g_mutex_unlock (xvimagesink->flow_lock);
6068       return;
6069     }
6070
6071     if (xvimagesink->keep_aspect) {
6072       /* We get the frame position using the calculated geometry from _setcaps
6073          that respect pixel aspect ratios */
6074       src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
6075       src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
6076       dst.w = xvimagesink->render_rect.w;
6077       dst.h = xvimagesink->render_rect.h;
6078
6079       gst_video_sink_center_rect (src, dst, &result, TRUE);
6080       result.x += xvimagesink->render_rect.x;
6081       result.y += xvimagesink->render_rect.y;
6082     } else {
6083       memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
6084     }
6085
6086     g_mutex_unlock (xvimagesink->flow_lock);
6087
6088     /* We calculate scaling using the original video frames geometry to include
6089        pixel aspect ratio scaling. */
6090     xscale = (gdouble) xvimagesink->video_width / result.w;
6091     yscale = (gdouble) xvimagesink->video_height / result.h;
6092
6093     /* Converting pointer coordinates to the non scaled geometry */
6094     if (gst_structure_get_double (structure, "pointer_x", &x)) {
6095       x = MIN (x, result.x + result.w);
6096       x = MAX (x - result.x, 0);
6097       gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
6098           (gdouble) x * xscale, NULL);
6099     }
6100     if (gst_structure_get_double (structure, "pointer_y", &y)) {
6101       y = MIN (y, result.y + result.h);
6102       y = MAX (y - result.y, 0);
6103       gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
6104           (gdouble) y * yscale, NULL);
6105     }
6106
6107     gst_pad_send_event (peer, event);
6108     gst_object_unref (peer);
6109   }
6110 }
6111
6112 static void
6113 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
6114 {
6115   iface->send_event = gst_xvimagesink_navigation_send_event;
6116 }
6117
6118 #ifdef GST_EXT_XV_ENHANCEMENT
6119 static void
6120 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
6121 {
6122   XID pixmap_id = id;
6123   int i = 0;
6124   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6125   GstXPixmap *xpixmap = NULL;
6126   int (*handler) (Display *, XErrorEvent *);
6127
6128   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6129
6130   if (xvimagesink->subpicture)
6131    return;
6132
6133   /* If the element has not initialized the X11 context try to do so */
6134   if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6135     /* we have thrown a GST_ELEMENT_ERROR now */
6136     return;
6137   }
6138
6139   gst_xvimagesink_update_colorbalance (xvimagesink);
6140
6141   GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
6142
6143   /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
6144   if (pixmap_id == 0) {
6145     xvimagesink->current_pixmap_idx = -2;
6146     return;
6147   }
6148
6149   g_mutex_lock (xvimagesink->x_lock);
6150
6151   for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6152     if (!xvimagesink->xpixmap[i]) {
6153       Window root_window;
6154       int cur_win_x = 0;
6155       int cur_win_y = 0;
6156       unsigned int cur_win_width = 0;
6157       unsigned int cur_win_height = 0;
6158       unsigned int cur_win_border_width = 0;
6159       unsigned int cur_win_depth = 0;
6160
6161       GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
6162
6163       xpixmap = g_new0 (GstXPixmap, 1);
6164       if (xpixmap) {
6165         xpixmap->pixmap = pixmap_id;
6166
6167         /* Get root window and size of current window */
6168         XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
6169                      &cur_win_x, &cur_win_y, /* relative x, y */
6170                      &cur_win_width, &cur_win_height,
6171                      &cur_win_border_width, &cur_win_depth);
6172         if (!cur_win_width || !cur_win_height) {
6173           GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
6174           g_mutex_unlock (xvimagesink->x_lock);
6175           return;
6176         }
6177         xpixmap->width = cur_win_width;
6178         xpixmap->height = cur_win_height;
6179
6180         if (!xvimagesink->render_rect.w)
6181           xvimagesink->render_rect.w = cur_win_width;
6182         if (!xvimagesink->render_rect.h)
6183           xvimagesink->render_rect.h = cur_win_height;
6184
6185         /* Setting an error handler to catch failure */
6186         error_caught = FALSE;
6187         handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6188
6189         /* Create a GC */
6190         xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
6191
6192         XSync(xvimagesink->xcontext->disp, FALSE);
6193         if (error_caught) {
6194           GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
6195         }
6196         if (handler) {
6197           error_caught = FALSE;
6198           XSetErrorHandler (handler);
6199         }
6200
6201         xvimagesink->xpixmap[i] = xpixmap;
6202         xvimagesink->current_pixmap_idx = i;
6203       } else {
6204         GST_ERROR("failed to create xpixmap errno: %d", errno);
6205       }
6206
6207       g_mutex_unlock (xvimagesink->x_lock);
6208       return;
6209
6210     } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
6211       GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
6212       xvimagesink->current_pixmap_idx = i;
6213
6214       g_mutex_unlock (xvimagesink->x_lock);
6215       return;
6216
6217     } else {
6218       continue;
6219     }
6220   }
6221
6222   GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
6223   xvimagesink->current_pixmap_idx = -1;
6224
6225   g_mutex_unlock (xvimagesink->x_lock);
6226   return;
6227 }
6228 #endif /* GST_EXT_XV_ENHANCEMENT */
6229
6230 static void
6231 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
6232 {
6233   XID xwindow_id = id;
6234   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6235   GstXWindow *xwindow = NULL;
6236 #ifdef GST_EXT_XV_ENHANCEMENT
6237   GstState current_state = GST_STATE_NULL;
6238   int (*handler) (Display *, XErrorEvent *);
6239 #endif /* GST_EXT_XV_ENHANCEMENT */
6240
6241   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6242
6243   g_mutex_lock (xvimagesink->flow_lock);
6244
6245 #ifdef GST_EXT_XV_ENHANCEMENT
6246   gst_element_get_state(GST_ELEMENT(xvimagesink), &current_state, NULL, 0);
6247   GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
6248                                   xwindow_id, current_state);
6249 #endif /* GST_EXT_XV_ENHANCEMENT */
6250
6251   /* If we already use that window return */
6252   if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
6253     g_mutex_unlock (xvimagesink->flow_lock);
6254     return;
6255   }
6256
6257   /* If the element has not initialized the X11 context try to do so */
6258   if (!xvimagesink->xcontext &&
6259       !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6260     g_mutex_unlock (xvimagesink->flow_lock);
6261     /* we have thrown a GST_ELEMENT_ERROR now */
6262     return;
6263   }
6264
6265   gst_xvimagesink_update_colorbalance (xvimagesink);
6266
6267   /* Clear image pool as the images are unusable anyway */
6268   gst_xvimagesink_imagepool_clear (xvimagesink);
6269
6270   /* Clear the xvimage */
6271   if (xvimagesink->xvimage) {
6272     gst_xvimage_buffer_free (xvimagesink->xvimage);
6273     xvimagesink->xvimage = NULL;
6274   }
6275
6276   /* If a window is there already we destroy it */
6277   if (xvimagesink->xwindow) {
6278     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
6279     xvimagesink->xwindow = NULL;
6280   }
6281
6282   /* If the xid is 0 we go back to an internal window */
6283   if (xwindow_id == 0) {
6284     /* If no width/height caps nego did not happen window will be created
6285        during caps nego then */
6286 #ifdef GST_EXT_XV_ENHANCEMENT
6287   GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
6288     GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
6289 #endif /* GST_EXT_XV_ENHANCEMENT */
6290     if (GST_VIDEO_SINK_WIDTH (xvimagesink)
6291         && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
6292       xwindow =
6293           gst_xvimagesink_xwindow_new (xvimagesink,
6294           GST_VIDEO_SINK_WIDTH (xvimagesink),
6295           GST_VIDEO_SINK_HEIGHT (xvimagesink));
6296     }
6297   } else {
6298     XWindowAttributes attr;
6299
6300     xwindow = g_new0 (GstXWindow, 1);
6301     xwindow->win = xwindow_id;
6302
6303     /* Set the event we want to receive and create a GC */
6304     g_mutex_lock (xvimagesink->x_lock);
6305
6306     if(!xvimagesink->is_pixmap)
6307       XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
6308
6309     xwindow->width = attr.width;
6310     xwindow->height = attr.height;
6311     xwindow->internal = FALSE;
6312     if (!xvimagesink->have_render_rect) {
6313       xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
6314       xvimagesink->render_rect.w = attr.width;
6315       xvimagesink->render_rect.h = attr.height;
6316     }
6317     if (xvimagesink->handle_events) {
6318 #ifdef GST_EXT_XV_ENHANCEMENT
6319       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6320       XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6321           StructureNotifyMask | PointerMotionMask | KeyPressMask |
6322           KeyReleaseMask | PropertyChangeMask);
6323 #else
6324       XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6325           StructureNotifyMask | PointerMotionMask | KeyPressMask |
6326           KeyReleaseMask);
6327 #endif
6328
6329     }
6330 #ifdef GST_EXT_XV_ENHANCEMENT
6331     /* Setting an error handler to catch failure */
6332     error_caught = FALSE;
6333     handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6334 #endif
6335     xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
6336         xwindow->win, 0, NULL);
6337 #ifdef GST_EXT_XV_ENHANCEMENT
6338     XSync(xvimagesink->xcontext->disp, FALSE);
6339     if (error_caught) {
6340       GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
6341     }
6342     if (handler) {
6343       error_caught = FALSE;
6344       XSetErrorHandler (handler);
6345     }
6346 #endif
6347     g_mutex_unlock (xvimagesink->x_lock);
6348   }
6349
6350   if (xwindow)
6351     xvimagesink->xwindow = xwindow;
6352
6353 #ifdef GST_EXT_XV_ENHANCEMENT
6354   xvimagesink->xid_updated = TRUE;
6355 #endif /* GST_EXT_XV_ENHANCEMENT */
6356
6357   g_mutex_unlock (xvimagesink->flow_lock);
6358
6359 #ifdef GST_EXT_XV_ENHANCEMENT
6360   if (current_state == GST_STATE_PAUSED) {
6361     GstBuffer *last_buffer = NULL;
6362     g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
6363     GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
6364     if (last_buffer) {
6365       gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
6366       gst_buffer_unref(last_buffer);
6367       last_buffer = NULL;
6368     }
6369   }
6370 #endif /* GST_EXT_XV_ENHANCEMENT */
6371 }
6372
6373 static void
6374 gst_xvimagesink_expose (GstXOverlay * overlay)
6375 {
6376   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6377
6378   gst_xvimagesink_xwindow_update_geometry (xvimagesink);
6379 #ifdef GST_EXT_XV_ENHANCEMENT
6380   GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
6381 #endif /* GST_EXT_XV_ENHANCEMENT */
6382   gst_xvimagesink_xvimage_put (xvimagesink, NULL);
6383 }
6384
6385 static void
6386 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
6387     gboolean handle_events)
6388 {
6389   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6390
6391   xvimagesink->handle_events = handle_events;
6392
6393   g_mutex_lock (xvimagesink->flow_lock);
6394
6395   if (G_UNLIKELY (!xvimagesink->xwindow)) {
6396     g_mutex_unlock (xvimagesink->flow_lock);
6397     return;
6398   }
6399
6400   g_mutex_lock (xvimagesink->x_lock);
6401
6402   if (handle_events) {
6403     if (xvimagesink->xwindow->internal) {
6404 #ifdef GST_EXT_XV_ENHANCEMENT
6405       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6406 #endif
6407       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6408 #ifdef GST_EXT_XV_ENHANCEMENT
6409           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6410 #else /* GST_EXT_XV_ENHANCEMENT */
6411           ExposureMask | StructureNotifyMask | PointerMotionMask |
6412 #endif /* GST_EXT_XV_ENHANCEMENT */
6413           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
6414     } else {
6415 #ifdef GST_EXT_XV_ENHANCEMENT
6416       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6417 #endif
6418       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6419 #ifdef GST_EXT_XV_ENHANCEMENT
6420           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6421 #else /* GST_EXT_XV_ENHANCEMENT */
6422           ExposureMask | StructureNotifyMask | PointerMotionMask |
6423 #endif /* GST_EXT_XV_ENHANCEMENT */
6424           KeyPressMask | KeyReleaseMask);
6425     }
6426   } else {
6427     XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
6428   }
6429
6430   g_mutex_unlock (xvimagesink->x_lock);
6431
6432   g_mutex_unlock (xvimagesink->flow_lock);
6433 }
6434
6435 static void
6436 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
6437     gint width, gint height)
6438 {
6439   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6440
6441   /* FIXME: how about some locking? */
6442   if (width >= 0 && height >= 0) {
6443     xvimagesink->render_rect.x = x;
6444     xvimagesink->render_rect.y = y;
6445     xvimagesink->render_rect.w = width;
6446     xvimagesink->render_rect.h = height;
6447     xvimagesink->have_render_rect = TRUE;
6448   } else {
6449     xvimagesink->render_rect.x = 0;
6450     xvimagesink->render_rect.y = 0;
6451     xvimagesink->render_rect.w = xvimagesink->xwindow->width;
6452     xvimagesink->render_rect.h = xvimagesink->xwindow->height;
6453     xvimagesink->have_render_rect = FALSE;
6454   }
6455 }
6456
6457 static void
6458 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
6459 {
6460   iface->set_window_handle = gst_xvimagesink_set_window_handle;
6461   iface->expose = gst_xvimagesink_expose;
6462   iface->handle_events = gst_xvimagesink_set_event_handling;
6463   iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
6464 }
6465
6466 static const GList *
6467 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
6468 {
6469   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6470
6471   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
6472
6473   if (xvimagesink->xcontext)
6474     return xvimagesink->xcontext->channels_list;
6475   else
6476     return NULL;
6477 }
6478
6479 static void
6480 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
6481     GstColorBalanceChannel * channel, gint value)
6482 {
6483   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6484
6485   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6486   g_return_if_fail (channel->label != NULL);
6487
6488   xvimagesink->cb_changed = TRUE;
6489
6490   /* Normalize val to [-1000, 1000] */
6491   value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
6492       (double) (channel->max_value - channel->min_value));
6493
6494   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6495     xvimagesink->hue = value;
6496   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6497     xvimagesink->saturation = value;
6498   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6499     xvimagesink->contrast = value;
6500   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6501     xvimagesink->brightness = value;
6502   } else {
6503     g_warning ("got an unknown channel %s", channel->label);
6504     return;
6505   }
6506
6507   gst_xvimagesink_update_colorbalance (xvimagesink);
6508 }
6509
6510 static gint
6511 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
6512     GstColorBalanceChannel * channel)
6513 {
6514   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6515   gint value = 0;
6516
6517   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
6518   g_return_val_if_fail (channel->label != NULL, 0);
6519
6520   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6521     value = xvimagesink->hue;
6522   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6523     value = xvimagesink->saturation;
6524   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6525     value = xvimagesink->contrast;
6526   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6527     value = xvimagesink->brightness;
6528   } else {
6529     g_warning ("got an unknown channel %s", channel->label);
6530   }
6531
6532   /* Normalize val to [channel->min_value, channel->max_value] */
6533   value = channel->min_value + (channel->max_value - channel->min_value) *
6534       (value + 1000) / 2000;
6535
6536   return value;
6537 }
6538
6539 static void
6540 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
6541 {
6542   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
6543   iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
6544   iface->set_value = gst_xvimagesink_colorbalance_set_value;
6545   iface->get_value = gst_xvimagesink_colorbalance_get_value;
6546 }
6547
6548 static const GList *
6549 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
6550 {
6551   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
6552   static GList *list = NULL;
6553
6554   if (!list) {
6555     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
6556     list =
6557         g_list_append (list, g_object_class_find_property (klass,
6558             "autopaint-colorkey"));
6559     list =
6560         g_list_append (list, g_object_class_find_property (klass,
6561             "double-buffer"));
6562     list =
6563         g_list_append (list, g_object_class_find_property (klass, "colorkey"));
6564   }
6565
6566   return list;
6567 }
6568
6569 static void
6570 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
6571     guint prop_id, const GParamSpec * pspec)
6572 {
6573   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6574
6575   switch (prop_id) {
6576     case PROP_DEVICE:
6577     case PROP_AUTOPAINT_COLORKEY:
6578     case PROP_DOUBLE_BUFFER:
6579     case PROP_COLORKEY:
6580       GST_DEBUG_OBJECT (xvimagesink,
6581           "probing device list and get capabilities");
6582       if (!xvimagesink->xcontext) {
6583         GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
6584         xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
6585       }
6586       break;
6587     default:
6588       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6589       break;
6590   }
6591 }
6592
6593 static gboolean
6594 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
6595     guint prop_id, const GParamSpec * pspec)
6596 {
6597   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6598   gboolean ret = FALSE;
6599
6600   switch (prop_id) {
6601     case PROP_DEVICE:
6602     case PROP_AUTOPAINT_COLORKEY:
6603     case PROP_DOUBLE_BUFFER:
6604     case PROP_COLORKEY:
6605       if (xvimagesink->xcontext != NULL) {
6606         ret = FALSE;
6607       } else {
6608         ret = TRUE;
6609       }
6610       break;
6611     default:
6612       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6613       break;
6614   }
6615
6616   return ret;
6617 }
6618
6619 static GValueArray *
6620 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
6621     guint prop_id, const GParamSpec * pspec)
6622 {
6623   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6624   GValueArray *array = NULL;
6625
6626   if (G_UNLIKELY (!xvimagesink->xcontext)) {
6627     GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
6628         "get values");
6629     goto beach;
6630   }
6631
6632   switch (prop_id) {
6633     case PROP_DEVICE:
6634     {
6635       guint i;
6636       GValue value = { 0 };
6637
6638       array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
6639       g_value_init (&value, G_TYPE_STRING);
6640
6641       for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
6642         gchar *adaptor_id_s = g_strdup_printf ("%u", i);
6643
6644         g_value_set_string (&value, adaptor_id_s);
6645         g_value_array_append (array, &value);
6646         g_free (adaptor_id_s);
6647       }
6648       g_value_unset (&value);
6649       break;
6650     }
6651     case PROP_AUTOPAINT_COLORKEY:
6652       if (xvimagesink->have_autopaint_colorkey) {
6653         GValue value = { 0 };
6654
6655         array = g_value_array_new (2);
6656         g_value_init (&value, G_TYPE_BOOLEAN);
6657         g_value_set_boolean (&value, FALSE);
6658         g_value_array_append (array, &value);
6659         g_value_set_boolean (&value, TRUE);
6660         g_value_array_append (array, &value);
6661         g_value_unset (&value);
6662       }
6663       break;
6664     case PROP_DOUBLE_BUFFER:
6665       if (xvimagesink->have_double_buffer) {
6666         GValue value = { 0 };
6667
6668         array = g_value_array_new (2);
6669         g_value_init (&value, G_TYPE_BOOLEAN);
6670         g_value_set_boolean (&value, FALSE);
6671         g_value_array_append (array, &value);
6672         g_value_set_boolean (&value, TRUE);
6673         g_value_array_append (array, &value);
6674         g_value_unset (&value);
6675       }
6676       break;
6677     case PROP_COLORKEY:
6678       if (xvimagesink->have_colorkey) {
6679         GValue value = { 0 };
6680
6681         array = g_value_array_new (1);
6682         g_value_init (&value, GST_TYPE_INT_RANGE);
6683         gst_value_set_int_range (&value, 0, 0xffffff);
6684         g_value_array_append (array, &value);
6685         g_value_unset (&value);
6686       }
6687       break;
6688     default:
6689       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6690       break;
6691   }
6692
6693 beach:
6694   return array;
6695 }
6696
6697 static void
6698 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
6699     iface)
6700 {
6701   iface->get_properties = gst_xvimagesink_probe_get_properties;
6702   iface->probe_property = gst_xvimagesink_probe_probe_property;
6703   iface->needs_probe = gst_xvimagesink_probe_needs_probe;
6704   iface->get_values = gst_xvimagesink_probe_get_values;
6705 }
6706
6707 /* =========================================== */
6708 /*                                             */
6709 /*              Init & Class init              */
6710 /*                                             */
6711 /* =========================================== */
6712
6713 static void
6714 gst_xvimagesink_set_property (GObject * object, guint prop_id,
6715     const GValue * value, GParamSpec * pspec)
6716 {
6717   GstXvImageSink *xvimagesink;
6718
6719   g_return_if_fail (GST_IS_XVIMAGESINK (object));
6720
6721   xvimagesink = GST_XVIMAGESINK (object);
6722
6723   switch (prop_id) {
6724     case PROP_HUE:
6725       xvimagesink->hue = g_value_get_int (value);
6726       xvimagesink->cb_changed = TRUE;
6727       gst_xvimagesink_update_colorbalance (xvimagesink);
6728       break;
6729     case PROP_CONTRAST:
6730       xvimagesink->contrast = g_value_get_int (value);
6731       xvimagesink->cb_changed = TRUE;
6732       gst_xvimagesink_update_colorbalance (xvimagesink);
6733       break;
6734     case PROP_BRIGHTNESS:
6735       xvimagesink->brightness = g_value_get_int (value);
6736       xvimagesink->cb_changed = TRUE;
6737       gst_xvimagesink_update_colorbalance (xvimagesink);
6738       break;
6739     case PROP_SATURATION:
6740       xvimagesink->saturation = g_value_get_int (value);
6741       xvimagesink->cb_changed = TRUE;
6742       gst_xvimagesink_update_colorbalance (xvimagesink);
6743       break;
6744     case PROP_DISPLAY:
6745       xvimagesink->display_name = g_strdup (g_value_get_string (value));
6746       break;
6747     case PROP_SYNCHRONOUS:
6748       xvimagesink->synchronous = g_value_get_boolean (value);
6749       if (xvimagesink->xcontext) {
6750         XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
6751         GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
6752             xvimagesink->synchronous ? "TRUE" : "FALSE");
6753       }
6754       break;
6755     case PROP_PIXEL_ASPECT_RATIO:
6756       g_free (xvimagesink->par);
6757       xvimagesink->par = g_new0 (GValue, 1);
6758       g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
6759       if (!g_value_transform (value, xvimagesink->par)) {
6760         g_warning ("Could not transform string to aspect ratio");
6761         gst_value_set_fraction (xvimagesink->par, 1, 1);
6762       }
6763       GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
6764           gst_value_get_fraction_numerator (xvimagesink->par),
6765           gst_value_get_fraction_denominator (xvimagesink->par));
6766       break;
6767     case PROP_FORCE_ASPECT_RATIO:
6768       xvimagesink->keep_aspect = g_value_get_boolean (value);
6769       break;
6770     case PROP_HANDLE_EVENTS:
6771       gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
6772           g_value_get_boolean (value));
6773       gst_xvimagesink_manage_event_thread (xvimagesink);
6774       break;
6775     case PROP_DEVICE:
6776       xvimagesink->adaptor_no = atoi (g_value_get_string (value));
6777       break;
6778     case PROP_HANDLE_EXPOSE:
6779       xvimagesink->handle_expose = g_value_get_boolean (value);
6780       gst_xvimagesink_manage_event_thread (xvimagesink);
6781       break;
6782     case PROP_DOUBLE_BUFFER:
6783       xvimagesink->double_buffer = g_value_get_boolean (value);
6784       break;
6785     case PROP_AUTOPAINT_COLORKEY:
6786       xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
6787       break;
6788     case PROP_COLORKEY:
6789       xvimagesink->colorkey = g_value_get_int (value);
6790       break;
6791     case PROP_DRAW_BORDERS:
6792       xvimagesink->draw_borders = g_value_get_boolean (value);
6793       break;
6794 #ifdef GST_EXT_XV_ENHANCEMENT
6795     case PROP_DISPLAY_MODE:
6796     {
6797       int set_mode = g_value_get_enum (value);
6798       g_mutex_lock(xvimagesink->flow_lock);
6799       xvimagesink->display_mode = set_mode;
6800       if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) {
6801         if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) {
6802           if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) {
6803             set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6804           } else {
6805             GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6806           }
6807         } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){
6808           if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
6809             set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6810           } else {
6811             GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6812           }
6813         } else {
6814           GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode);
6815         }
6816       }
6817       g_mutex_unlock(xvimagesink->flow_lock);
6818     }
6819       break;
6820     case PROP_CSC_RANGE:
6821     {
6822       int set_range = g_value_get_enum (value);
6823
6824       g_mutex_lock(xvimagesink->flow_lock);
6825       g_mutex_lock(xvimagesink->x_lock);
6826
6827       if (xvimagesink->csc_range != set_range) {
6828         if (xvimagesink->xcontext && !xvimagesink->subpicture) {
6829           /* set color space range */
6830           if (set_csc_range(xvimagesink->xcontext, set_range)) {
6831             xvimagesink->csc_range = set_range;
6832           } else {
6833             GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
6834           }
6835         } else {
6836           /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6837           GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
6838           xvimagesink->csc_range = set_range;
6839         }
6840       } else if (xvimagesink->subpicture) {
6841         GST_WARNING("skip to set csc range, because it is subpicture format.");
6842       } else {
6843         GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
6844       }
6845
6846       g_mutex_unlock(xvimagesink->x_lock);
6847       g_mutex_unlock(xvimagesink->flow_lock);
6848     }
6849       break;
6850     case PROP_DISPLAY_GEOMETRY_METHOD:
6851       xvimagesink->display_geometry_method = g_value_get_enum (value);
6852       GST_LOG("Overlay geometry changed. update it");
6853       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6854         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6855       }
6856       break;
6857     case PROP_FLIP:
6858       xvimagesink->flip = g_value_get_enum(value);
6859       break;
6860     case PROP_ROTATE_ANGLE:
6861       xvimagesink->rotate_angle = g_value_get_enum (value);
6862       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6863         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6864       }
6865       break;
6866     case PROP_VISIBLE:
6867       g_mutex_lock( xvimagesink->flow_lock );
6868       g_mutex_lock( xvimagesink->x_lock );
6869
6870       GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
6871
6872       if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
6873         if (xvimagesink->xcontext) {
6874 #if 0
6875           Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
6876                                           "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
6877           if (atom_stream != None) {
6878             GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
6879             if (XvSetPortAttribute(xvimagesink->xcontext->disp,
6880                                    xvimagesink->xcontext->xv_port_id,
6881                                    atom_stream, 0 ) != Success) {
6882               GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
6883             }
6884           }
6885 #endif
6886           xvimagesink->visible = g_value_get_boolean (value);
6887           if ( xvimagesink->get_pixmap_cb ) {
6888             if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6889               XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6890               }
6891           } else {
6892             if(xvimagesink->xwindow->win)
6893               XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
6894           }
6895           XSync( xvimagesink->xcontext->disp, FALSE );
6896         } else {
6897           GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
6898           xvimagesink->visible = g_value_get_boolean (value);
6899         }
6900       } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
6901         xvimagesink->visible = g_value_get_boolean (value);
6902         g_mutex_unlock( xvimagesink->x_lock );
6903         g_mutex_unlock( xvimagesink->flow_lock );
6904         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6905         g_mutex_lock( xvimagesink->flow_lock );
6906         g_mutex_lock( xvimagesink->x_lock );
6907       }
6908
6909       GST_INFO("set visible(%d) done", xvimagesink->visible);
6910
6911       g_mutex_unlock( xvimagesink->x_lock );
6912       g_mutex_unlock( xvimagesink->flow_lock );
6913       break;
6914     case PROP_ZOOM:
6915       xvimagesink->zoom = g_value_get_float (value);
6916       break;
6917     case PROP_ZOOM_POS_X:
6918       xvimagesink->zoom_pos_x = g_value_get_int (value);
6919       break;
6920     case PROP_ZOOM_POS_Y:
6921       xvimagesink->zoom_pos_y = g_value_get_int (value);
6922       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6923         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6924       }
6925       break;
6926     case PROP_ORIENTATION:
6927       xvimagesink->orientation = g_value_get_enum (value);
6928       GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
6929       break;
6930     case PROP_DST_ROI_MODE:
6931       xvimagesink->dst_roi_mode = g_value_get_enum (value);
6932       GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
6933       break;
6934     case PROP_DST_ROI_X:
6935       xvimagesink->dst_roi.x = g_value_get_int (value);
6936       break;
6937     case PROP_DST_ROI_Y:
6938       xvimagesink->dst_roi.y = g_value_get_int (value);
6939       break;
6940     case PROP_DST_ROI_W:
6941       xvimagesink->dst_roi.w = g_value_get_int (value);
6942       break;
6943     case PROP_DST_ROI_H:
6944       xvimagesink->dst_roi.h = g_value_get_int (value);
6945       break;
6946     case PROP_SRC_CROP_X:
6947       xvimagesink->src_crop.x = g_value_get_int (value);
6948       break;
6949     case PROP_SRC_CROP_Y:
6950       xvimagesink->src_crop.y = g_value_get_int (value);
6951       break;
6952     case PROP_SRC_CROP_W:
6953       xvimagesink->src_crop.w = g_value_get_int (value);
6954       break;
6955     case PROP_SRC_CROP_H:
6956       xvimagesink->src_crop.h = g_value_get_int (value);
6957       break;
6958     case PROP_STOP_VIDEO:
6959       xvimagesink->stop_video = g_value_get_int (value);
6960       g_mutex_lock( xvimagesink->flow_lock );
6961
6962       if( xvimagesink->stop_video )
6963       {
6964         if ( xvimagesink->get_pixmap_cb ) {
6965           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6966             g_mutex_lock (xvimagesink->x_lock);
6967             GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6968             XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6969             g_mutex_unlock (xvimagesink->x_lock);
6970           }
6971         } else {
6972           GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
6973           gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6974         }
6975       }
6976
6977       g_mutex_unlock( xvimagesink->flow_lock );
6978       break;
6979     case PROP_PIXMAP_CB:
6980     {
6981       void *cb_func;
6982       cb_func = g_value_get_pointer(value);
6983       if (cb_func) {
6984         if (xvimagesink->get_pixmap_cb) {
6985           int i = 0;
6986           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6987             g_mutex_lock (xvimagesink->x_lock);
6988             GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6989             XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6990             g_mutex_unlock (xvimagesink->x_lock);
6991           }
6992           for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6993             if (xvimagesink->xpixmap[i]) {
6994               gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6995               xvimagesink->xpixmap[i] = NULL;
6996             }
6997           }
6998         }
6999         xvimagesink->get_pixmap_cb = cb_func;
7000         GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
7001       }
7002       break;
7003     }
7004     case PROP_PIXMAP_CB_USER_DATA:
7005     {
7006       void *user_data;
7007       user_data = g_value_get_pointer(value);
7008       if (user_data) {
7009         xvimagesink->get_pixmap_cb_user_data = user_data;
7010         GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
7011       }
7012       break;
7013     }
7014     case PROP_SUBPICTURE:
7015       xvimagesink->subpicture = g_value_get_boolean (value);
7016     break;
7017     case PROP_EXTERNAL_WIDTH:
7018     {
7019       xvimagesink->external_width = g_value_get_int (value);
7020       GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width);
7021       break;
7022     }
7023     case PROP_EXTERNAL_HEIGHT:
7024     {
7025       xvimagesink->external_height = g_value_get_int (value);
7026       GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height);
7027       break;
7028     }
7029     case PROP_ENABLE_FLUSH_BUFFER:
7030       xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
7031       break;
7032     case PROP_PIXMAP:
7033       xvimagesink->is_pixmap = g_value_get_boolean(value);
7034       break;
7035     case PROP_HIDED_WINDOW:
7036     {
7037       xvimagesink->is_hided_subpicture = g_value_get_boolean(value);
7038       GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture);
7039       break;
7040     }
7041     case PROP_QUICKPANEL_ON:
7042     {
7043       xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value);
7044       GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture);
7045       break;
7046     }
7047     case PROP_MULTIWINDOW_ACTIVE:
7048     {
7049       xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value);
7050       GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture);
7051       break;
7052     }
7053     case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7054     {
7055       xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value);
7056       GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post);
7057       if(xvimagesink->keep_external_fullscreen_post) {
7058         Atom atom_keep_ext;
7059         atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False);
7060         if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success)
7061         {
7062           GST_WARNING("set atom_keep_ext fail");
7063         }
7064       }
7065       break;
7066     }
7067     case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7068     {
7069       xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value);
7070       GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev);
7071       break;
7072     }
7073
7074 #endif /* GST_EXT_XV_ENHANCEMENT */
7075     default:
7076       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7077       break;
7078   }
7079 }
7080
7081 static void
7082 gst_xvimagesink_get_property (GObject * object, guint prop_id,
7083     GValue * value, GParamSpec * pspec)
7084 {
7085   GstXvImageSink *xvimagesink;
7086
7087   g_return_if_fail (GST_IS_XVIMAGESINK (object));
7088
7089   xvimagesink = GST_XVIMAGESINK (object);
7090
7091   switch (prop_id) {
7092     case PROP_HUE:
7093       g_value_set_int (value, xvimagesink->hue);
7094       break;
7095     case PROP_CONTRAST:
7096       g_value_set_int (value, xvimagesink->contrast);
7097       break;
7098     case PROP_BRIGHTNESS:
7099       g_value_set_int (value, xvimagesink->brightness);
7100       break;
7101     case PROP_SATURATION:
7102       g_value_set_int (value, xvimagesink->saturation);
7103       break;
7104     case PROP_DISPLAY:
7105       g_value_set_string (value, xvimagesink->display_name);
7106       break;
7107     case PROP_SYNCHRONOUS:
7108       g_value_set_boolean (value, xvimagesink->synchronous);
7109       break;
7110     case PROP_PIXEL_ASPECT_RATIO:
7111       if (xvimagesink->par)
7112         g_value_transform (xvimagesink->par, value);
7113       break;
7114     case PROP_FORCE_ASPECT_RATIO:
7115       g_value_set_boolean (value, xvimagesink->keep_aspect);
7116       break;
7117     case PROP_HANDLE_EVENTS:
7118       g_value_set_boolean (value, xvimagesink->handle_events);
7119       break;
7120     case PROP_DEVICE:
7121     {
7122       char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
7123
7124       g_value_set_string (value, adaptor_no_s);
7125       g_free (adaptor_no_s);
7126       break;
7127     }
7128     case PROP_DEVICE_NAME:
7129       if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
7130         g_value_set_string (value,
7131             xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
7132       } else {
7133         g_value_set_string (value, NULL);
7134       }
7135       break;
7136     case PROP_HANDLE_EXPOSE:
7137       g_value_set_boolean (value, xvimagesink->handle_expose);
7138       break;
7139     case PROP_DOUBLE_BUFFER:
7140       g_value_set_boolean (value, xvimagesink->double_buffer);
7141       break;
7142     case PROP_AUTOPAINT_COLORKEY:
7143       g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
7144       break;
7145     case PROP_COLORKEY:
7146       g_value_set_int (value, xvimagesink->colorkey);
7147       break;
7148     case PROP_DRAW_BORDERS:
7149       g_value_set_boolean (value, xvimagesink->draw_borders);
7150       break;
7151     case PROP_WINDOW_WIDTH:
7152       if (xvimagesink->xwindow)
7153         g_value_set_uint64 (value, xvimagesink->xwindow->width);
7154       else
7155         g_value_set_uint64 (value, 0);
7156       break;
7157     case PROP_WINDOW_HEIGHT:
7158       if (xvimagesink->xwindow)
7159         g_value_set_uint64 (value, xvimagesink->xwindow->height);
7160       else
7161         g_value_set_uint64 (value, 0);
7162       break;
7163 #ifdef GST_EXT_XV_ENHANCEMENT
7164     case PROP_DISPLAY_MODE:
7165       g_value_set_enum (value, xvimagesink->display_mode);
7166       break;
7167     case PROP_CSC_RANGE:
7168       g_value_set_enum (value, xvimagesink->csc_range);
7169       break;
7170     case PROP_DISPLAY_GEOMETRY_METHOD:
7171       g_value_set_enum (value, xvimagesink->display_geometry_method);
7172       break;
7173     case PROP_FLIP:
7174       g_value_set_enum(value, xvimagesink->flip);
7175       break;
7176     case PROP_ROTATE_ANGLE:
7177       g_value_set_enum (value, xvimagesink->rotate_angle);
7178       break;
7179     case PROP_VISIBLE:
7180       g_value_set_boolean (value, xvimagesink->visible);
7181       break;
7182     case PROP_ZOOM:
7183       g_value_set_float (value, xvimagesink->zoom);
7184       break;
7185     case PROP_ZOOM_POS_X:
7186       g_value_set_int (value, xvimagesink->zoom_pos_x);
7187       break;
7188     case PROP_ZOOM_POS_Y:
7189       g_value_set_int (value, xvimagesink->zoom_pos_y);
7190       break;
7191     case PROP_ORIENTATION:
7192       g_value_set_enum (value, xvimagesink->orientation);
7193       break;
7194     case PROP_DST_ROI_MODE:
7195       g_value_set_enum (value, xvimagesink->dst_roi_mode);
7196       break;
7197     case PROP_DST_ROI_X:
7198       g_value_set_int (value, xvimagesink->dst_roi.x);
7199       break;
7200     case PROP_DST_ROI_Y:
7201       g_value_set_int (value, xvimagesink->dst_roi.y);
7202       break;
7203     case PROP_DST_ROI_W:
7204       g_value_set_int (value, xvimagesink->dst_roi.w);
7205       break;
7206     case PROP_DST_ROI_H:
7207       g_value_set_int (value, xvimagesink->dst_roi.h);
7208       break;
7209     case PROP_SRC_CROP_X:
7210       g_value_set_int (value, xvimagesink->src_crop.x);
7211       break;
7212     case PROP_SRC_CROP_Y:
7213       g_value_set_int (value, xvimagesink->src_crop.y);
7214       break;
7215     case PROP_SRC_CROP_W:
7216       g_value_set_int (value, xvimagesink->src_crop.w);
7217       break;
7218     case PROP_SRC_CROP_H:
7219       g_value_set_int (value, xvimagesink->src_crop.h);
7220       break;
7221     case PROP_STOP_VIDEO:
7222       g_value_set_int (value, xvimagesink->stop_video);
7223       break;
7224     case PROP_PIXMAP_CB:
7225       g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
7226       break;
7227     case PROP_PIXMAP_CB_USER_DATA:
7228       g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
7229       break;
7230     case PROP_SUBPICTURE:
7231       g_value_set_boolean (value, xvimagesink->subpicture);
7232       break;
7233     case PROP_EXTERNAL_WIDTH:
7234       g_value_set_int (value, xvimagesink->external_width);
7235       break;
7236     case PROP_EXTERNAL_HEIGHT:
7237       g_value_set_int (value, xvimagesink->external_height);
7238       break;
7239     case PROP_ENABLE_FLUSH_BUFFER:
7240       g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
7241       break;
7242     case PROP_PIXMAP:
7243       g_value_set_boolean(value, xvimagesink->is_pixmap);
7244       break;
7245     case PROP_HIDED_WINDOW:
7246       g_value_set_boolean(value, xvimagesink->is_hided_subpicture);
7247       break;
7248     case PROP_QUICKPANEL_ON:
7249       g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture);
7250       break;
7251     case PROP_MULTIWINDOW_ACTIVE:
7252       g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture);
7253       break;
7254     case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7255       g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post);
7256      break;
7257     case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7258       g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev);
7259      break;
7260 #endif /* GST_EXT_XV_ENHANCEMENT */
7261     default:
7262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7263       break;
7264   }
7265 }
7266
7267 static void
7268 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
7269 {
7270   GThread *thread;
7271
7272   GST_OBJECT_LOCK (xvimagesink);
7273   xvimagesink->running = FALSE;
7274   /* grab thread and mark it as NULL */
7275   thread = xvimagesink->event_thread;
7276   xvimagesink->event_thread = NULL;
7277   GST_OBJECT_UNLOCK (xvimagesink);
7278
7279   /* invalidate the pool, current allocations continue, new buffer_alloc fails
7280    * with wrong_state */
7281   g_mutex_lock (xvimagesink->pool_lock);
7282   xvimagesink->pool_invalid = TRUE;
7283   g_mutex_unlock (xvimagesink->pool_lock);
7284
7285   /* Wait for our event thread to finish before we clean up our stuff. */
7286   if (thread)
7287     g_thread_join (thread);
7288
7289   if (xvimagesink->cur_image) {
7290     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
7291     xvimagesink->cur_image = NULL;
7292   }
7293   if (xvimagesink->xvimage) {
7294     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
7295     xvimagesink->xvimage = NULL;
7296   }
7297
7298   gst_xvimagesink_imagepool_clear (xvimagesink);
7299
7300   if (xvimagesink->xwindow) {
7301     gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
7302     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
7303     xvimagesink->xwindow = NULL;
7304   }
7305 #ifdef GST_EXT_XV_ENHANCEMENT
7306   if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
7307       GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7308       XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7309       xvimagesink->pixmap_for_subpicture = 0;
7310   }
7311
7312   if (xvimagesink->get_pixmap_cb) {
7313     int i = 0;
7314     if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
7315       g_mutex_lock (xvimagesink->x_lock);
7316       GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
7317       XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
7318       g_mutex_unlock (xvimagesink->x_lock);
7319     }
7320     for (i = 0; i < MAX_PIXMAP_NUM; i++) {
7321       if (xvimagesink->xpixmap[i]) {
7322         gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
7323         xvimagesink->xpixmap[i] = NULL;
7324       }
7325     }
7326     xvimagesink->get_pixmap_cb = NULL;
7327     xvimagesink->get_pixmap_cb_user_data = NULL;
7328   }
7329 #endif /* GST_EXT_XV_ENHANCEMENT */
7330   xvimagesink->render_rect.x = xvimagesink->render_rect.y =
7331       xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
7332   xvimagesink->have_render_rect = FALSE;
7333
7334   gst_xvimagesink_xcontext_clear (xvimagesink);
7335 }
7336
7337 /* Finalize is called only once, dispose can be called multiple times.
7338  * We use mutexes and don't reset stuff to NULL here so let's register
7339  * as a finalize. */
7340 static void
7341 gst_xvimagesink_finalize (GObject * object)
7342 {
7343   GstXvImageSink *xvimagesink;
7344
7345   xvimagesink = GST_XVIMAGESINK (object);
7346
7347   gst_xvimagesink_reset (xvimagesink);
7348
7349   if (xvimagesink->display_name) {
7350     g_free (xvimagesink->display_name);
7351     xvimagesink->display_name = NULL;
7352   }
7353
7354   if (xvimagesink->par) {
7355     g_free (xvimagesink->par);
7356     xvimagesink->par = NULL;
7357   }
7358   if (xvimagesink->x_lock) {
7359     g_mutex_free (xvimagesink->x_lock);
7360     xvimagesink->x_lock = NULL;
7361   }
7362   if (xvimagesink->flow_lock) {
7363     g_mutex_free (xvimagesink->flow_lock);
7364     xvimagesink->flow_lock = NULL;
7365   }
7366   if (xvimagesink->pool_lock) {
7367     g_mutex_free (xvimagesink->pool_lock);
7368     xvimagesink->pool_lock = NULL;
7369   }
7370 #ifdef GST_EXT_XV_ENHANCEMENT
7371   if (xvimagesink->display_buffer_lock) {
7372     g_mutex_free (xvimagesink->display_buffer_lock);
7373     xvimagesink->display_buffer_lock = NULL;
7374   }
7375 #endif /* GST_EXT_XV_ENHANCEMENT */
7376
7377   g_free (xvimagesink->media_title);
7378
7379   G_OBJECT_CLASS (parent_class)->finalize (object);
7380 }
7381
7382 static void
7383 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
7384     GstXvImageSinkClass * xvimagesinkclass)
7385 {
7386 #ifdef GST_EXT_XV_ENHANCEMENT
7387   int i;
7388   int j;
7389 #endif /* GST_EXT_XV_ENHANCEMENT */
7390
7391   xvimagesink->display_name = NULL;
7392   xvimagesink->adaptor_no = 0;
7393   xvimagesink->xcontext = NULL;
7394   xvimagesink->xwindow = NULL;
7395   xvimagesink->xvimage = NULL;
7396   xvimagesink->cur_image = NULL;
7397
7398   xvimagesink->hue = xvimagesink->saturation = 0;
7399   xvimagesink->contrast = xvimagesink->brightness = 0;
7400   xvimagesink->cb_changed = FALSE;
7401
7402   xvimagesink->fps_n = 0;
7403   xvimagesink->fps_d = 0;
7404   xvimagesink->video_width = 0;
7405   xvimagesink->video_height = 0;
7406
7407   xvimagesink->x_lock = g_mutex_new ();
7408   xvimagesink->flow_lock = g_mutex_new ();
7409
7410   xvimagesink->image_pool = NULL;
7411   xvimagesink->pool_lock = g_mutex_new ();
7412
7413   xvimagesink->synchronous = FALSE;
7414   xvimagesink->double_buffer = TRUE;
7415   xvimagesink->running = FALSE;
7416   xvimagesink->keep_aspect = FALSE;
7417   xvimagesink->handle_events = TRUE;
7418   xvimagesink->par = NULL;
7419   xvimagesink->handle_expose = TRUE;
7420   xvimagesink->autopaint_colorkey = TRUE;
7421
7422   /* on 16bit displays this becomes r,g,b = 1,2,3
7423    * on 24bit displays this becomes r,g,b = 8,8,16
7424    * as a port atom value
7425    */
7426   xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
7427   xvimagesink->draw_borders = TRUE;
7428
7429 #ifdef GST_EXT_XV_ENHANCEMENT
7430   xvimagesink->xid_updated = FALSE;
7431   xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE;
7432   xvimagesink->csc_range = CSC_RANGE_NARROW;
7433   xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
7434   xvimagesink->flip = DEF_DISPLAY_FLIP;
7435   xvimagesink->rotate_angle = DEGREE_270;
7436   xvimagesink->visible = TRUE;
7437   xvimagesink->zoom = 1.0;
7438   xvimagesink->zoom_pos_x = -1;
7439   xvimagesink->zoom_pos_y = -1;
7440   xvimagesink->rotation = -1;
7441   xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
7442   xvimagesink->orientation = DEGREE_0;
7443   xvimagesink->dst_roi.x = 0;
7444   xvimagesink->dst_roi.y = 0;
7445   xvimagesink->dst_roi.w = 0;
7446   xvimagesink->dst_roi.h = 0;
7447   xvimagesink->src_crop.x = 0;
7448   xvimagesink->src_crop.y = 0;
7449   xvimagesink->src_crop.w = 0;
7450   xvimagesink->src_crop.h = 0;
7451   xvimagesink->xim_transparenter = NULL;
7452   xvimagesink->scr_w = 0;
7453   xvimagesink->scr_h = 0;
7454   xvimagesink->aligned_width = 0;
7455   xvimagesink->aligned_height = 0;
7456   xvimagesink->stop_video = FALSE;
7457   xvimagesink->is_hided = FALSE;
7458   xvimagesink->is_quick_panel_on = FALSE;
7459   xvimagesink->is_multi_window = FALSE;
7460   xvimagesink->drm_fd = -1;
7461   xvimagesink->current_pixmap_idx = -1;
7462   xvimagesink->get_pixmap_cb = NULL;
7463   xvimagesink->get_pixmap_cb_user_data = NULL;
7464
7465   for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
7466     xvimagesink->displaying_buffers[i].buffer = NULL;
7467     for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
7468       xvimagesink->displaying_buffers[i].gem_name[j] = 0;
7469       xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
7470       xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
7471       xvimagesink->displaying_buffers[i].ref_count = 0;
7472     }
7473   }
7474
7475   xvimagesink->display_buffer_lock = g_mutex_new ();
7476
7477   xvimagesink->displayed_buffer_count = 0;
7478   xvimagesink->displaying_buffer_count = 0;
7479   xvimagesink->is_zero_copy_format = FALSE;
7480   xvimagesink->secure_path = SECURE_PATH_INIT;
7481   xvimagesink->drm_level = DRM_LEVEL_0;
7482   xvimagesink->last_added_buffer_index = -1;
7483   xvimagesink->bufmgr = NULL;
7484   xvimagesink->flush_buffer = NULL;
7485   xvimagesink->enable_flush_buffer = TRUE;
7486   xvimagesink->pixmap_for_subpicture = 0;
7487   xvimagesink->is_subpicture_format = FALSE;
7488   xvimagesink->set_overlay_for_subpicture_just_once = FALSE;
7489   xvimagesink->subpicture = FALSE;
7490   xvimagesink->external_width = 0;
7491   xvimagesink->external_height = 0;
7492   xvimagesink->skip_frame_due_to_external_dev = FALSE;
7493   xvimagesink->is_hided_subpicture = FALSE;
7494   xvimagesink->is_quick_panel_on_subpicture = FALSE;
7495   xvimagesink->is_multi_window_subpicture = FALSE;
7496   xvimagesink->keep_external_fullscreen_post = FALSE;
7497   xvimagesink->keep_external_fullscreen_prev = FALSE;
7498   if(!XInitThreads())
7499     GST_WARNING("FAIL to call XInitThreads()");
7500   if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL))
7501     GST_WARNING("vconf set fail");
7502 #endif /* GST_EXT_XV_ENHANCEMENT */
7503 }
7504
7505 static void
7506 gst_xvimagesink_base_init (gpointer g_class)
7507 {
7508   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
7509
7510   gst_element_class_set_details_simple (element_class,
7511       "Video sink", "Sink/Video",
7512       "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
7513
7514   gst_element_class_add_static_pad_template (element_class,
7515       &gst_xvimagesink_sink_template_factory);
7516 }
7517
7518 static void
7519 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
7520 {
7521   GObjectClass *gobject_class;
7522   GstElementClass *gstelement_class;
7523   GstBaseSinkClass *gstbasesink_class;
7524   GstVideoSinkClass *videosink_class;
7525
7526   gobject_class = (GObjectClass *) klass;
7527   gstelement_class = (GstElementClass *) klass;
7528   gstbasesink_class = (GstBaseSinkClass *) klass;
7529   videosink_class = (GstVideoSinkClass *) klass;
7530
7531   gobject_class->set_property = gst_xvimagesink_set_property;
7532   gobject_class->get_property = gst_xvimagesink_get_property;
7533
7534   g_object_class_install_property (gobject_class, PROP_CONTRAST,
7535       g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
7536           -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7537   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
7538       g_param_spec_int ("brightness", "Brightness",
7539           "The brightness of the video", -1000, 1000, 0,
7540           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7541   g_object_class_install_property (gobject_class, PROP_HUE,
7542       g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
7543           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7544   g_object_class_install_property (gobject_class, PROP_SATURATION,
7545       g_param_spec_int ("saturation", "Saturation",
7546           "The saturation of the video", -1000, 1000, 0,
7547           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7548   g_object_class_install_property (gobject_class, PROP_DISPLAY,
7549       g_param_spec_string ("display", "Display", "X Display name", NULL,
7550           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7551   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
7552       g_param_spec_boolean ("synchronous", "Synchronous",
7553           "When enabled, runs the X display in synchronous mode. "
7554           "(unrelated to A/V sync, used only for debugging)", FALSE,
7555           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7556   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
7557       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
7558           "The pixel aspect ratio of the device", "1/1",
7559           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7560   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
7561       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
7562           "When enabled, scaling will respect original aspect ratio", FALSE,
7563           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7564   g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
7565       g_param_spec_boolean ("handle-events", "Handle XEvents",
7566           "When enabled, XEvents will be selected and handled", TRUE,
7567           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7568   g_object_class_install_property (gobject_class, PROP_DEVICE,
7569       g_param_spec_string ("device", "Adaptor number",
7570           "The number of the video adaptor", "0",
7571           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7572   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
7573       g_param_spec_string ("device-name", "Adaptor name",
7574           "The name of the video adaptor", NULL,
7575           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7576   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH,
7577       g_param_spec_int ("external-width", "external width",
7578           "width of external display", 0, G_MAXINT,
7579           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7580   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT,
7581       g_param_spec_int ("external-height", "external height",
7582           "height of external display", 0, G_MAXINT,
7583           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7584   /**
7585    * GstXvImageSink:handle-expose
7586    *
7587    * When enabled, the current frame will always be drawn in response to X
7588    * Expose.
7589    *
7590    * Since: 0.10.14
7591    */
7592   g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
7593       g_param_spec_boolean ("handle-expose", "Handle expose",
7594           "When enabled, "
7595           "the current frame will always be drawn in response to X Expose "
7596           "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7597
7598   /**
7599    * GstXvImageSink:double-buffer
7600    *
7601    * Whether to double-buffer the output.
7602    *
7603    * Since: 0.10.14
7604    */
7605   g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
7606       g_param_spec_boolean ("double-buffer", "Double-buffer",
7607           "Whether to double-buffer the output", TRUE,
7608           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7609   /**
7610    * GstXvImageSink:autopaint-colorkey
7611    *
7612    * Whether to autofill overlay with colorkey
7613    *
7614    * Since: 0.10.21
7615    */
7616   g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
7617       g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
7618           "Whether to autofill overlay with colorkey", TRUE,
7619           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7620   /**
7621    * GstXvImageSink:colorkey
7622    *
7623    * Color to use for the overlay mask.
7624    *
7625    * Since: 0.10.21
7626    */
7627   g_object_class_install_property (gobject_class, PROP_COLORKEY,
7628       g_param_spec_int ("colorkey", "Colorkey",
7629           "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
7630           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7631
7632   /**
7633    * GstXvImageSink:draw-borders
7634    *
7635    * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
7636    * unused parts of the video area.
7637    *
7638    * Since: 0.10.21
7639    */
7640   g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
7641       g_param_spec_boolean ("draw-borders", "Colorkey",
7642           "Draw black borders to fill unused area in force-aspect-ratio mode",
7643           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7644
7645   /**
7646    * GstXvImageSink:window-width
7647    *
7648    * Actual width of the video window.
7649    *
7650    * Since: 0.10.32
7651    */
7652   g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
7653       g_param_spec_uint64 ("window-width", "window-width",
7654           "Width of the window", 0, G_MAXUINT64, 0,
7655           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7656
7657   /**
7658    * GstXvImageSink:window-height
7659    *
7660    * Actual height of the video window.
7661    *
7662    * Since: 0.10.32
7663    */
7664   g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
7665       g_param_spec_uint64 ("window-height", "window-height",
7666           "Height of the window", 0, G_MAXUINT64, 0,
7667           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7668
7669 #ifdef GST_EXT_XV_ENHANCEMENT
7670   /**
7671    * GstXvImageSink:display-mode
7672    *
7673    * select display mode
7674    */
7675   g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
7676     g_param_spec_enum("display-mode", "Display Mode",
7677       "Display device setting",
7678       GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE,
7679       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7680
7681   /**
7682    * GstXvImageSink:csc-range
7683    *
7684    * select color space range
7685    */
7686   g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
7687     g_param_spec_enum("csc-range", "Color Space Range",
7688       "Color space range setting",
7689       GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
7690       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7691
7692   /**
7693    * GstXvImageSink:display-geometry-method
7694    *
7695    * Display geometrical method setting
7696    */
7697   g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
7698     g_param_spec_enum("display-geometry-method", "Display geometry method",
7699       "Geometrical method for display",
7700       GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
7701       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7702
7703   /**
7704    * GstXvImageSink:display-flip
7705    *
7706    * Display flip setting
7707    */
7708   g_object_class_install_property(gobject_class, PROP_FLIP,
7709     g_param_spec_enum("flip", "Display flip",
7710       "Flip for display",
7711       GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
7712       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7713
7714   /**
7715    * GstXvImageSink:rotate
7716    *
7717    * Draw rotation angle setting
7718    */
7719   g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
7720     g_param_spec_enum("rotate", "Rotate angle",
7721       "Rotate angle of display output",
7722       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
7723       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7724
7725   /**
7726    * GstXvImageSink:visible
7727    *
7728    * Whether reserve original src size or not
7729    */
7730   g_object_class_install_property (gobject_class, PROP_VISIBLE,
7731       g_param_spec_boolean ("visible", "Visible",
7732           "Draws screen or blacks out, true means visible, false blacks out",
7733           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7734
7735   /**
7736    * GstXvImageSink:zoom
7737    *
7738    * Scale small area of screen to 1X~ 9X
7739    */
7740   g_object_class_install_property (gobject_class, PROP_ZOOM,
7741       g_param_spec_float ("zoom", "Zoom",
7742           "Zooms screen as nX", 1.0, 9.0, 1.0,
7743           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7744
7745   /**
7746    * GstXvImageSink:zoom-pos-x
7747    *
7748    * Standard x-position of zoom
7749    */
7750   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
7751       g_param_spec_int ("zoom-pos-x", "Zoom Position X",
7752           "Standard x-position of zoom", -1, 3840, -1,
7753           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7754
7755   /**
7756    * GstXvImageSink:zoom-pos-y
7757    *
7758    * Standard y-position of zoom
7759    */
7760   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
7761       g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
7762           "Standard y-position of zoom", -1, 3840, -1,
7763           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7764
7765   /**
7766    * GstXvImageSink:dst-roi-mode
7767    *
7768    * Display geometrical method of ROI setting
7769    */
7770   g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
7771     g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
7772       "Geometrical method of ROI for display",
7773       GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
7774       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7775
7776   /**
7777    * GstXvImageSink:orientation
7778    *
7779    * Orientation information which will be used for ROI/ZOOM
7780    */
7781   g_object_class_install_property(gobject_class, PROP_ORIENTATION,
7782     g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
7783       "Orientation information for display",
7784       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
7785       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7786
7787   /**
7788    * GstXvImageSink:dst-roi-x
7789    *
7790    * X value of Destination ROI
7791    */
7792   g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
7793       g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
7794           "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7795           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7796
7797   /**
7798    * GstXvImageSink:dst-roi-y
7799    *
7800    * Y value of Destination ROI
7801    */
7802   g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
7803       g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
7804           "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7805           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7806
7807   /**
7808    * GstXvImageSink:dst-roi-w
7809    *
7810    * W value of Destination ROI
7811    */
7812   g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
7813       g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
7814           "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7815           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7816
7817   /**
7818    * GstXvImageSink:dst-roi-h
7819    *
7820    * H value of Destination ROI
7821    */
7822   g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
7823       g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
7824           "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7825           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7826
7827   /**
7828    * GstXvImageSink:stop-video
7829    *
7830    * Stop video for releasing video source buffer
7831    */
7832   g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
7833       g_param_spec_int ("stop-video", "Stop-Video",
7834           "Stop video for releasing video source buffer", 0, 1, 0,
7835           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7836
7837   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
7838       g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
7839           "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
7840
7841   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
7842       g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
7843           "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
7844
7845   g_object_class_install_property (gobject_class, PROP_SUBPICTURE,
7846       g_param_spec_boolean ("subpicture", "Subpicture",
7847           "identifier of player for supporting subpicture", FALSE,
7848           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7849
7850   /**
7851    * GstXvImageSink:src-crop-x
7852    *
7853    * X value of video source crop
7854    */
7855   g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
7856       g_param_spec_int ("src-crop-x", "Source Crop X",
7857           "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7858           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7859
7860   /**
7861    * GstXvImageSink:src-crop-y
7862    *
7863    * Y value of video source crop
7864    */
7865   g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
7866       g_param_spec_int ("src-crop-y", "Source Crop X",
7867           "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7868           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7869
7870   /**
7871    * GstXvImageSink:src-crop-w
7872    *
7873    * Width value of video source crop
7874    */
7875   g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
7876       g_param_spec_int ("src-crop-w", "Source Crop Width",
7877           "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7878           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7879
7880   /**
7881    * GstXvImageSink:src-crop-h
7882    *
7883    * Height value of video source crop
7884    */
7885   g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
7886       g_param_spec_int ("src-crop-h", "Source Crop Height",
7887           "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7888           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7889
7890   /**
7891    * GstXvImageSink:enable-flush-buffer
7892    *
7893    * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
7894    */
7895   g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
7896       g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
7897           "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
7898           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7899
7900   /**
7901    * GstXvImageSink:is-pixmap
7902    *
7903    * Check using pixmap id for blocking X api
7904    */
7905   g_object_class_install_property (gobject_class, PROP_PIXMAP,
7906       g_param_spec_boolean("is-pixmap", "Check if use pixmap",
7907           "Check using pixmap id for blocking X api",
7908           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7909
7910   /**
7911    * GstXvImageSink:hided-window
7912    *
7913    * check window status for hiding subtitle
7914    */
7915   g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW,
7916       g_param_spec_boolean("hided-window", "Hided window",
7917           "check window status for hiding subtitle",
7918           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7919
7920   /**
7921    * GstXvImageSink:quick-panel-on
7922    *
7923    * check quick-panel status for hiding subtitle
7924    */
7925   g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON,
7926       g_param_spec_boolean("quick-panel-on", "Quick panel On",
7927           "check quick-panel status for hiding subtitle",
7928           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7929
7930   /**
7931    * GstXvImageSink:multiwindow-activated
7932    *
7933    * check multiwindow-activated status for hiding subtitle
7934    */
7935   g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE,
7936       g_param_spec_boolean("multiwindow-active", "Multiwindow Activate",
7937           "check multiwindow status for hiding subtitle",
7938           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7939
7940   /**
7941    * GstXvImageSink:keep-external-fullscreen-post
7942    *
7943    * keep video-only mode for special case, it is set immediately.
7944    */
7945   g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
7946       g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen",
7947           "set video-only mode forcedly for special case",
7948           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7949
7950   /**
7951    * GstXvImageSink:keep-external-fullscreen-prev
7952    *
7953    * keep video-only mode for special case, it is set in advance.
7954    */
7955   g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
7956       g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen",
7957           "set video-only mode forcedly for special case",
7958           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7959
7960   /**
7961    * GstXvImageSink::frame-render-error
7962    */
7963   gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
7964           "frame-render-error",
7965           G_TYPE_FROM_CLASS (klass),
7966           G_SIGNAL_RUN_LAST,
7967           0,
7968           NULL,
7969           NULL,
7970           gst_xvimagesink_BOOLEAN__POINTER,
7971           G_TYPE_BOOLEAN,
7972           1,
7973           G_TYPE_POINTER);
7974   /**
7975    * GstXvImageSink::display-status
7976    */
7977     gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new (
7978           "display-status",
7979           G_TYPE_FROM_CLASS (klass),
7980           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7981           0,
7982           NULL,
7983           NULL,
7984           g_cclosure_marshal_VOID__INT,
7985           G_TYPE_NONE,
7986           1,
7987           G_TYPE_INT);
7988
7989   /**
7990    * GstXvImageSink::external-resolution
7991    */
7992   gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new (
7993           "external-resolution",
7994          G_TYPE_FROM_CLASS (klass),
7995          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7996          0,
7997          NULL,
7998          NULL,
7999          gst_marshal_VOID__INT_INT,
8000          G_TYPE_NONE,
8001          2,
8002          G_TYPE_INT,
8003          G_TYPE_INT);
8004
8005   /**
8006    * GstXvImageSink::hided-window
8007    */
8008     gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new (
8009           "hided-window",
8010           G_TYPE_FROM_CLASS (klass),
8011           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8012           0,
8013           NULL,
8014           NULL,
8015           g_cclosure_marshal_VOID__BOOLEAN,
8016           G_TYPE_NONE,
8017           1,
8018           G_TYPE_BOOLEAN);
8019
8020   /**
8021    * GstXvImageSink::quick-panel-on
8022    */
8023     gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new (
8024           "quick-panel-on",
8025           G_TYPE_FROM_CLASS (klass),
8026           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8027           0,
8028           NULL,
8029           NULL,
8030           g_cclosure_marshal_VOID__BOOLEAN,
8031           G_TYPE_NONE,
8032           1,
8033           G_TYPE_BOOLEAN);
8034
8035   /**
8036    * GstXvImageSink::multiwindow-active
8037    */
8038     gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new (
8039           "multiwindow-active",
8040           G_TYPE_FROM_CLASS (klass),
8041           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8042           0,
8043           NULL,
8044           NULL,
8045           g_cclosure_marshal_VOID__BOOLEAN,
8046           G_TYPE_NONE,
8047           1,
8048           G_TYPE_BOOLEAN);
8049
8050 #endif /* GST_EXT_XV_ENHANCEMENT */
8051
8052   gobject_class->finalize = gst_xvimagesink_finalize;
8053
8054   gstelement_class->change_state =
8055       GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
8056
8057   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
8058   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
8059   gstbasesink_class->buffer_alloc =
8060       GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
8061   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
8062   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
8063
8064   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
8065 }
8066
8067 /* ============================================================= */
8068 /*                                                               */
8069 /*                       Public Methods                          */
8070 /*                                                               */
8071 /* ============================================================= */
8072
8073 /* =========================================== */
8074 /*                                             */
8075 /*          Object typing & Creation           */
8076 /*                                             */
8077 /* =========================================== */
8078 static void
8079 gst_xvimagesink_init_interfaces (GType type)
8080 {
8081   static const GInterfaceInfo iface_info = {
8082     (GInterfaceInitFunc) gst_xvimagesink_interface_init,
8083     NULL,
8084     NULL,
8085   };
8086   static const GInterfaceInfo navigation_info = {
8087     (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
8088     NULL,
8089     NULL,
8090   };
8091   static const GInterfaceInfo overlay_info = {
8092     (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
8093     NULL,
8094     NULL,
8095   };
8096   static const GInterfaceInfo colorbalance_info = {
8097     (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
8098     NULL,
8099     NULL,
8100   };
8101   static const GInterfaceInfo propertyprobe_info = {
8102     (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
8103     NULL,
8104     NULL,
8105   };
8106
8107   g_type_add_interface_static (type,
8108       GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
8109   g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
8110   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
8111   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
8112       &colorbalance_info);
8113   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
8114       &propertyprobe_info);
8115
8116   /* register type and create class in a more safe place instead of at
8117    * runtime since the type registration and class creation is not
8118    * threadsafe. */
8119   g_type_class_ref (gst_xvimage_buffer_get_type ());
8120 }
8121
8122 static gboolean
8123 plugin_init (GstPlugin * plugin)
8124 {
8125   if (!gst_element_register (plugin, "xvimagesink",
8126           GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
8127     return FALSE;
8128
8129   GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
8130       "xvimagesink element");
8131   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
8132
8133   return TRUE;
8134 }
8135
8136 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
8137     GST_VERSION_MINOR,
8138     "xvimagesink",
8139     "XFree86 video output plugin using Xv extension",
8140     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
8141
8142