72d83100c8997cee09fb163b79f75126879063a9
[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_status[10] = {0, };
3621   char *str_resolution = NULL;
3622   char str_dispmode[10] = {0, };
3623   int external[2];
3624   int cnt = 0;
3625   char** list = NULL;
3626   char** walk = NULL;
3627
3628   UtilxScrnConf *scrnconf = utilx_scrnconf_allocate();
3629   if (!scrnconf)
3630   {
3631     GST_WARNING ("fail to allocate scrnconf");
3632     return;
3633   }
3634   utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf);
3635
3636   str_output = scrnconf->str_output;
3637
3638   if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT)
3639   {
3640     strcpy (str_status, "CONNECT");
3641   }
3642   else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE)
3643   {
3644     strcpy (str_status, "ACTIVE");
3645
3646     list = g_strsplit(scrnconf->str_resolution, "x", 2);
3647
3648     if (!list)
3649     {
3650         if (scrnconf)
3651         utilx_scrnconf_free (scrnconf);
3652         return;
3653     }
3654     for(walk = list; *walk; walk++)
3655     {
3656       external[cnt++] = atoi(*walk);
3657     }
3658     if (cnt!=2) {
3659       GST_WARNING("data error");
3660       if(scrnconf)
3661         utilx_scrnconf_free (scrnconf);
3662       g_strfreev(list);
3663       return;
3664     } else {
3665       xvimagesink->external_width = external[0];
3666       xvimagesink->external_height = external[1];
3667       g_strfreev(list);
3668     }
3669     GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height);
3670     g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3671   }
3672   else
3673   {
3674     strcpy (str_status, "null");
3675   }
3676
3677   str_resolution = scrnconf->str_resolution;
3678
3679   if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE)
3680   {
3681     strcpy (str_dispmode, "CLONE");
3682   }
3683   else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED)
3684   {
3685     strcpy (str_dispmode, "EXTENDED");
3686   }
3687   else
3688   {
3689     strcpy (str_dispmode, "null");
3690   }
3691
3692   GST_INFO ("[Display status] : %s, %s, %s, %s\n", str_output, str_status, str_resolution, str_dispmode);
3693
3694   if(scrnconf)
3695     utilx_scrnconf_free (scrnconf);
3696
3697 }
3698
3699 static gboolean
3700 check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name)
3701 {
3702   int i = 0;
3703   int count = 0;
3704
3705   XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp,
3706                                             xvimagesink->xcontext->xv_port_id, &count);
3707   if (attr) {
3708     for (i = 0 ; i < count ; i++) {
3709       if (!strcmp(attr[i].name, attr_name)) {
3710         GST_INFO("%s[index %d] found", attr_name, i);
3711         XFree(attr);
3712         return TRUE;
3713       }
3714     }
3715     XFree(attr);
3716   } else {
3717     GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
3718                 xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id);
3719   }
3720   return FALSE;
3721 }
3722 #endif //GST_EXT_XV_ENHANCEMENT
3723
3724 static void
3725 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3726     XvAdaptorInfo * adaptors, int adaptor_no)
3727 {
3728   gint j;
3729   gint res;
3730
3731   /* Do we support XvImageMask ? */
3732   if (!(adaptors[adaptor_no].type & XvImageMask)) {
3733     GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3734         adaptors[adaptor_no].name);
3735     return;
3736   }
3737
3738   /* We found such an adaptor, looking for an available port */
3739   for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3740     /* We try to grab the port */
3741     res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3742     if (Success == res) {
3743       xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3744       GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3745           adaptors[adaptor_no].num_ports);
3746     } else {
3747       GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3748           adaptors[adaptor_no].name, res);
3749     }
3750   }
3751 }
3752
3753 #ifdef GST_EXT_XV_ENHANCEMENT
3754 static void
3755 gst_lookup_xv_port_for_subtitle (GstXContext * xcontext,
3756     XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors)
3757 {
3758   int i;
3759   if (!adaptors)
3760     return;
3761   for (i = 0; i < nb_adaptors; i++)
3762   {
3763     int min, max;
3764     if (!(adaptors[i].type & XvOutputMask) ||
3765         !(adaptors[i].type & XvStillMask))
3766         continue;
3767     min = adaptors[i].base_id;
3768     max = adaptors[i].base_id + adaptors[i].num_ports;
3769     for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++)
3770     {
3771       if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success)
3772       {
3773         GST_INFO ("========================================");
3774         GST_INFO ("XvGrabPort  success : %ld", adaptors[adaptor_no].num_ports);
3775         GST_INFO ("========================================");
3776         xcontext->xv_port_id = adaptors[adaptor_no].num_ports;
3777         return;
3778       }
3779       GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports);
3780       usleep(10000);
3781     }
3782   }
3783 }
3784 #endif
3785
3786
3787 /* This function generates a caps with all supported format by the first
3788    Xv grabable port we find. We store each one of the supported formats in a
3789    format list and append the format to a newly created caps that we return
3790    If this function does not return NULL because of an error, it also grabs
3791    the port via XvGrabPort */
3792 static GstCaps *
3793 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3794     GstXContext * xcontext)
3795 {
3796   gint i;
3797   XvAdaptorInfo *adaptors;
3798   gint nb_formats;
3799   XvImageFormatValues *formats = NULL;
3800   guint nb_encodings;
3801   XvEncodingInfo *encodings = NULL;
3802   gulong max_w = G_MAXINT, max_h = G_MAXINT;
3803   GstCaps *caps = NULL;
3804   GstCaps *rgb_caps = NULL;
3805
3806   g_return_val_if_fail (xcontext != NULL, NULL);
3807
3808   /* First let's check that XVideo extension is available */
3809   if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3810     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3811         ("Could not initialise Xv output"),
3812         ("XVideo extension is not available"));
3813     return NULL;
3814   }
3815
3816   /* Then we get adaptors list */
3817   if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3818           &xcontext->nb_adaptors, &adaptors)) {
3819     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3820         ("Could not initialise Xv output"),
3821         ("Failed getting XV adaptors list"));
3822     return NULL;
3823   }
3824
3825   xcontext->xv_port_id = 0;
3826
3827   GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
3828
3829   xcontext->adaptors =
3830       (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3831
3832   /* Now fill up our adaptor name array */
3833   for (i = 0; i < xcontext->nb_adaptors; i++) {
3834     xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3835   }
3836
3837   if (xvimagesink->adaptor_no >= 0 &&
3838       xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3839     /* Find xv port from user defined adaptor */
3840 #ifdef GST_EXT_XV_ENHANCEMENT
3841     if(!xvimagesink->subpicture)
3842 #endif
3843       gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no);
3844 #ifdef GST_EXT_XV_ENHANCEMENT
3845     else
3846       gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors);
3847 #endif
3848   }
3849
3850   if (!xcontext->xv_port_id) {
3851     /* Now search for an adaptor that supports XvImageMask */
3852     for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3853 #ifdef GST_EXT_XV_ENHANCEMENT
3854       if(!xvimagesink->subpicture)
3855 #endif
3856         gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3857 #ifdef GST_EXT_XV_ENHANCEMENT
3858       else
3859         gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors);
3860 #endif
3861       xvimagesink->adaptor_no = i;
3862     }
3863   }
3864
3865   XvFreeAdaptorInfo (adaptors);
3866
3867   if (!xcontext->xv_port_id) {
3868     xvimagesink->adaptor_no = -1;
3869     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3870         ("Could not initialise Xv output"), ("No port available"));
3871     return NULL;
3872   }
3873
3874   /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3875   {
3876     int count, todo = 3;
3877     XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3878         xcontext->xv_port_id, &count);
3879     static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3880     static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3881     static const char colorkey[] = "XV_COLORKEY";
3882
3883     GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3884
3885     xvimagesink->have_autopaint_colorkey = FALSE;
3886     xvimagesink->have_double_buffer = FALSE;
3887     xvimagesink->have_colorkey = FALSE;
3888
3889     for (i = 0; ((i < count) && todo); i++)
3890       if (!strcmp (attr[i].name, autopaint)) {
3891         const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3892
3893         /* turn on autopaint colorkey */
3894         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3895             (xvimagesink->autopaint_colorkey ? 1 : 0));
3896         todo--;
3897         xvimagesink->have_autopaint_colorkey = TRUE;
3898       } else if (!strcmp (attr[i].name, dbl_buffer)) {
3899         const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3900
3901         XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3902             (xvimagesink->double_buffer ? 1 : 0));
3903         todo--;
3904         xvimagesink->have_double_buffer = TRUE;
3905       } else if (!strcmp (attr[i].name, colorkey)) {
3906         /* Set the colorkey, default is something that is dark but hopefully
3907          * won't randomly appear on the screen elsewhere (ie not black or greys)
3908          * can be overridden by setting "colorkey" property
3909          */
3910         const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3911         guint32 ckey = 0;
3912         gboolean set_attr = TRUE;
3913         guint cr, cg, cb;
3914
3915         /* set a colorkey in the right format RGB565/RGB888
3916          * We only handle these 2 cases, because they're the only types of
3917          * devices we've encountered. If we don't recognise it, leave it alone
3918          */
3919         cr = (xvimagesink->colorkey >> 16);
3920         cg = (xvimagesink->colorkey >> 8) & 0xFF;
3921         cb = (xvimagesink->colorkey) & 0xFF;
3922         switch (xcontext->depth) {
3923           case 16:             /* RGB 565 */
3924             cr >>= 3;
3925             cg >>= 2;
3926             cb >>= 3;
3927             ckey = (cr << 11) | (cg << 5) | cb;
3928             break;
3929           case 24:
3930           case 32:             /* RGB 888 / ARGB 8888 */
3931             ckey = (cr << 16) | (cg << 8) | cb;
3932             break;
3933           default:
3934             GST_DEBUG_OBJECT (xvimagesink,
3935                 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3936                 xcontext->depth);
3937             set_attr = FALSE;
3938             break;
3939         }
3940
3941         if (set_attr) {
3942           ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3943               (guint32) attr[i].max_value);
3944           GST_LOG_OBJECT (xvimagesink,
3945               "Setting color key for display depth %d to 0x%x",
3946               xcontext->depth, ckey);
3947
3948           XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3949               (gint) ckey);
3950         }
3951         todo--;
3952         xvimagesink->have_colorkey = TRUE;
3953       }
3954
3955     XFree (attr);
3956   }
3957
3958   /* Get the list of encodings supported by the adapter and look for the
3959    * XV_IMAGE encoding so we can determine the maximum width and height
3960    * supported */
3961   XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3962       &encodings);
3963
3964   for (i = 0; i < nb_encodings; i++) {
3965     GST_LOG_OBJECT (xvimagesink,
3966         "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3967         i, encodings[i].name, encodings[i].width, encodings[i].height,
3968         encodings[i].rate.numerator, encodings[i].rate.denominator);
3969     if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3970       max_w = encodings[i].width;
3971       max_h = encodings[i].height;
3972 #ifdef GST_EXT_XV_ENHANCEMENT
3973       xvimagesink->scr_w = max_w;
3974       xvimagesink->scr_h = max_h;
3975 #endif /* GST_EXT_XV_ENHANCEMENT */
3976     }
3977   }
3978
3979   XvFreeEncodingInfo (encodings);
3980 #ifdef GST_EXT_XV_ENHANCEMENT
3981 if (!xvimagesink->subpicture) {
3982 #endif
3983   /* We get all image formats supported by our port */
3984   formats = XvListImageFormats (xcontext->disp,
3985       xcontext->xv_port_id, &nb_formats);
3986   caps = gst_caps_new_empty ();
3987   for (i = 0; i < nb_formats; i++) {
3988     GstCaps *format_caps = NULL;
3989     gboolean is_rgb_format = FALSE;
3990
3991     /* We set the image format of the xcontext to an existing one. This
3992        is just some valid image format for making our xshm calls check before
3993        caps negotiation really happens. */
3994     xcontext->im_format = formats[i].id;
3995
3996     switch (formats[i].type) {
3997       case XvRGB:
3998       {
3999         XvImageFormatValues *fmt = &(formats[i]);
4000         gint endianness = G_BIG_ENDIAN;
4001
4002         if (fmt->byte_order == LSBFirst) {
4003           /* our caps system handles 24/32bpp RGB as big-endian. */
4004           if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
4005             fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
4006             fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
4007             fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
4008
4009             if (fmt->bits_per_pixel == 24) {
4010               fmt->red_mask >>= 8;
4011               fmt->green_mask >>= 8;
4012               fmt->blue_mask >>= 8;
4013             }
4014           } else
4015             endianness = G_LITTLE_ENDIAN;
4016         }
4017
4018         format_caps = gst_caps_new_simple ("video/x-raw-rgb",
4019 #ifdef GST_EXT_XV_ENHANCEMENT
4020             "format", GST_TYPE_FOURCC, formats[i].id,
4021 #endif /* GST_EXT_XV_ENHANCEMENT */
4022             "endianness", G_TYPE_INT, endianness,
4023             "depth", G_TYPE_INT, fmt->depth,
4024             "bpp", G_TYPE_INT, fmt->bits_per_pixel,
4025             "red_mask", G_TYPE_INT, fmt->red_mask,
4026             "green_mask", G_TYPE_INT, fmt->green_mask,
4027             "blue_mask", G_TYPE_INT, fmt->blue_mask,
4028             "width", GST_TYPE_INT_RANGE, 1, max_w,
4029             "height", GST_TYPE_INT_RANGE, 1, max_h,
4030             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4031
4032         is_rgb_format = TRUE;
4033         break;
4034       }
4035       case XvYUV:
4036         format_caps = gst_caps_new_simple ("video/x-raw-yuv",
4037             "format", GST_TYPE_FOURCC, formats[i].id,
4038             "width", GST_TYPE_INT_RANGE, 1, max_w,
4039             "height", GST_TYPE_INT_RANGE, 1, max_h,
4040             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4041         break;
4042       default:
4043         g_assert_not_reached ();
4044         break;
4045     }
4046
4047     if (format_caps) {
4048       GstXvImageFormat *format = NULL;
4049
4050       format = g_new0 (GstXvImageFormat, 1);
4051       if (format) {
4052         format->format = formats[i].id;
4053         format->caps = gst_caps_copy (format_caps);
4054         xcontext->formats_list = g_list_append (xcontext->formats_list, format);
4055       }
4056
4057       if (is_rgb_format) {
4058         if (rgb_caps == NULL)
4059           rgb_caps = format_caps;
4060         else
4061           gst_caps_append (rgb_caps, format_caps);
4062       } else
4063         gst_caps_append (caps, format_caps);
4064     }
4065   }
4066
4067   /* Collected all caps into either the caps or rgb_caps structures.
4068    * Append rgb_caps on the end of YUV, so that YUV is always preferred */
4069   if (rgb_caps)
4070     gst_caps_append (caps, rgb_caps);
4071
4072   if (formats)
4073     XFree (formats);
4074
4075   GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
4076
4077   if (gst_caps_is_empty (caps)) {
4078     gst_caps_unref (caps);
4079     XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4080     GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
4081         ("No supported format found"));
4082     return NULL;
4083   }
4084 #ifdef GST_EXT_XV_ENHANCEMENT
4085 } //subpicture
4086 #endif
4087
4088   return caps;
4089 }
4090
4091 static gpointer
4092 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
4093 {
4094   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4095
4096   GST_OBJECT_LOCK (xvimagesink);
4097   while (xvimagesink->running) {
4098     GST_OBJECT_UNLOCK (xvimagesink);
4099
4100     if (xvimagesink->xwindow) {
4101       gst_xvimagesink_handle_xevents (xvimagesink);
4102     }
4103
4104 #ifdef GST_EXT_XV_ENHANCEMENT
4105     g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
4106 #else /* GST_EXT_XV_ENHANCEMENT */
4107     /* FIXME: do we want to align this with the framerate or anything else? */
4108     g_usleep (G_USEC_PER_SEC / 20);
4109 #endif /* GST_EXT_XV_ENHANCEMENT */
4110
4111     GST_OBJECT_LOCK (xvimagesink);
4112   }
4113   GST_OBJECT_UNLOCK (xvimagesink);
4114
4115   return NULL;
4116 }
4117
4118 static void
4119 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
4120 {
4121   GThread *thread = NULL;
4122
4123   /* don't start the thread too early */
4124   if (xvimagesink->xcontext == NULL) {
4125     return;
4126   }
4127
4128   GST_OBJECT_LOCK (xvimagesink);
4129   if (xvimagesink->handle_expose || xvimagesink->handle_events) {
4130     if (!xvimagesink->event_thread) {
4131       /* Setup our event listening thread */
4132       GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
4133           xvimagesink->handle_expose, xvimagesink->handle_events);
4134       xvimagesink->running = TRUE;
4135 #if !GLIB_CHECK_VERSION (2, 31, 0)
4136       xvimagesink->event_thread = g_thread_create (
4137           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
4138 #else
4139       xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
4140           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
4141 #endif
4142     }
4143   } else {
4144     if (xvimagesink->event_thread) {
4145       GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
4146           xvimagesink->handle_expose, xvimagesink->handle_events);
4147       xvimagesink->running = FALSE;
4148       /* grab thread and mark it as NULL */
4149       thread = xvimagesink->event_thread;
4150       xvimagesink->event_thread = NULL;
4151     }
4152   }
4153   GST_OBJECT_UNLOCK (xvimagesink);
4154
4155   /* Wait for our event thread to finish */
4156   if (thread)
4157     g_thread_join (thread);
4158
4159 }
4160
4161
4162 #ifdef GST_EXT_XV_ENHANCEMENT
4163 /**
4164  * gst_xvimagesink_prepare_xid:
4165  * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
4166  *
4167  * This will post a "prepare-xid" element message with video size and display size on the bus
4168  * to give applications an opportunity to call
4169  * gst_x_overlay_set_xwindow_id() before a plugin creates its own
4170  * window or pixmap.
4171  *
4172  * This function should only be used by video overlay plugin developers.
4173  */
4174 static void
4175 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
4176 {
4177   GstStructure *s;
4178   GstMessage *msg;
4179
4180   g_return_if_fail (overlay != NULL);
4181   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
4182
4183   GstXvImageSink *xvimagesink;
4184   xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
4185
4186   GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
4187         GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
4188
4189   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
4190   s = gst_structure_new ("prepare-xid",
4191         "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
4192         "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
4193         "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
4194         "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
4195         NULL);
4196   msg = gst_message_new_element (GST_OBJECT (overlay), s);
4197   gst_element_post_message (GST_ELEMENT (overlay), msg);
4198 }
4199 #endif /* GST_EXT_XV_ENHANCEMENT */
4200
4201
4202 /* This function calculates the pixel aspect ratio based on the properties
4203  * in the xcontext structure and stores it there. */
4204 static void
4205 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
4206 {
4207   static const gint par[][2] = {
4208     {1, 1},                     /* regular screen */
4209     {16, 15},                   /* PAL TV */
4210     {11, 10},                   /* 525 line Rec.601 video */
4211 #ifdef GST_EXT_XV_ENHANCEMENT
4212     {44, 46},                   /* Gear S Curved Display */
4213 #endif
4214     {54, 59},                   /* 625 line Rec.601 video */
4215     {64, 45},                   /* 1280x1024 on 16:9 display */
4216     {5, 3},                     /* 1280x1024 on 4:3 display */
4217     {4, 3}                      /*  800x600 on 16:9 display */
4218   };
4219   gint i;
4220   gint index;
4221   gdouble ratio;
4222   gdouble delta;
4223
4224 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
4225
4226   /* first calculate the "real" ratio based on the X values;
4227    * which is the "physical" w/h divided by the w/h in pixels of the display */
4228   ratio = (gdouble) (xcontext->widthmm * xcontext->height)
4229       / (xcontext->heightmm * xcontext->width);
4230
4231   /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
4232    * override here */
4233   if (xcontext->width == 720 && xcontext->height == 576) {
4234     ratio = 4.0 * 576 / (3.0 * 720);
4235   }
4236   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
4237   /* now find the one from par[][2] with the lowest delta to the real one */
4238   delta = DELTA (0);
4239   index = 0;
4240
4241   for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
4242     gdouble this_delta = DELTA (i);
4243
4244     if (this_delta < delta) {
4245       index = i;
4246       delta = this_delta;
4247     }
4248   }
4249
4250   GST_DEBUG ("Decided on index %d (%d/%d)", index,
4251       par[index][0], par[index][1]);
4252
4253   g_free (xcontext->par);
4254   xcontext->par = g_new0 (GValue, 1);
4255   g_value_init (xcontext->par, GST_TYPE_FRACTION);
4256   gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
4257   GST_DEBUG ("set xcontext PAR to %d/%d",
4258       gst_value_get_fraction_numerator (xcontext->par),
4259       gst_value_get_fraction_denominator (xcontext->par));
4260 }
4261
4262 /* This function gets the X Display and global info about it. Everything is
4263    stored in our object and will be cleaned when the object is disposed. Note
4264    here that caps for supported format are generated without any window or
4265    image creation */
4266 static GstXContext *
4267 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
4268 {
4269   GstXContext *xcontext = NULL;
4270   XPixmapFormatValues *px_formats = NULL;
4271   gint nb_formats = 0, i, j, N_attr;
4272   XvAttribute *xv_attr = NULL;
4273   Atom prop_atom;
4274   const char *channels[4] = { "XV_HUE", "XV_SATURATION",
4275     "XV_BRIGHTNESS", "XV_CONTRAST"
4276   };
4277
4278   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4279
4280   xcontext = g_new0 (GstXContext, 1);
4281   xcontext->im_format = 0;
4282
4283   g_mutex_lock (xvimagesink->x_lock);
4284
4285   xcontext->disp = XOpenDisplay (xvimagesink->display_name);
4286   if (!xcontext->disp) {
4287     g_mutex_unlock (xvimagesink->x_lock);
4288     g_free (xcontext);
4289     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4290         ("Could not initialise Xv output"), ("Could not open display"));
4291     return NULL;
4292   }
4293
4294 #ifdef GST_EXT_XV_ENHANCEMENT
4295   {
4296     int i = 0;
4297     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4298       if (g_display_id[i] == NULL) {
4299         g_display_id[i] = xcontext->disp;
4300         GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
4301         break;
4302       }
4303     }
4304     if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
4305       GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
4306     }
4307   }
4308 #endif
4309
4310   xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
4311   xcontext->screen_num = DefaultScreen (xcontext->disp);
4312   xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
4313   xcontext->root = DefaultRootWindow (xcontext->disp);
4314   xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
4315   xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
4316   xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
4317
4318   xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
4319   xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
4320   xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
4321   xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
4322
4323   GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
4324       xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
4325
4326   gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
4327   /* We get supported pixmap formats at supported depth */
4328   px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
4329
4330   if (!px_formats) {
4331 #ifdef GST_EXT_XV_ENHANCEMENT
4332   {
4333     int i = 0;
4334     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4335       if (g_display_id[i] == xcontext->disp) {
4336         g_display_id[i] = NULL;
4337       }
4338     }
4339   }
4340 #endif
4341     XCloseDisplay (xcontext->disp);
4342     g_mutex_unlock (xvimagesink->x_lock);
4343     g_free (xcontext->par);
4344     g_free (xcontext);
4345     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
4346         ("Could not initialise Xv output"), ("Could not get pixel formats"));
4347     return NULL;
4348   }
4349
4350   /* We get bpp value corresponding to our running depth */
4351   for (i = 0; i < nb_formats; i++) {
4352     if (px_formats[i].depth == xcontext->depth)
4353       xcontext->bpp = px_formats[i].bits_per_pixel;
4354   }
4355
4356   XFree (px_formats);
4357
4358   xcontext->endianness =
4359       (ImageByteOrder (xcontext->disp) ==
4360       LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
4361
4362   /* our caps system handles 24/32bpp RGB as big-endian. */
4363   if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
4364       xcontext->endianness == G_LITTLE_ENDIAN) {
4365     xcontext->endianness = G_BIG_ENDIAN;
4366     xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
4367     xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
4368     xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
4369     if (xcontext->bpp == 24) {
4370       xcontext->visual->red_mask >>= 8;
4371       xcontext->visual->green_mask >>= 8;
4372       xcontext->visual->blue_mask >>= 8;
4373     }
4374   }
4375
4376   xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
4377
4378   if (!xcontext->caps
4379 #ifdef GST_EXT_XV_ENHANCEMENT
4380     && !xvimagesink->subpicture
4381 #endif
4382     ) {
4383 #ifdef GST_EXT_XV_ENHANCEMENT
4384   {
4385     int i = 0;
4386     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4387       if (g_display_id[i] == xcontext->disp) {
4388         g_display_id[i] = NULL;
4389       }
4390     }
4391   }
4392 #endif
4393     XCloseDisplay (xcontext->disp);
4394     g_mutex_unlock (xvimagesink->x_lock);
4395     g_free (xcontext->par);
4396     g_free (xcontext);
4397     /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
4398     return NULL;
4399   }
4400 #ifdef HAVE_XSHM
4401 #ifdef GST_EXT_XV_ENHANCEMENT
4402   if (!xvimagesink->subpicture) {
4403 #endif //GST_EXT_XV_ENHANCEMENT
4404     /* Search for XShm extension support */
4405     if (XShmQueryExtension (xcontext->disp) &&
4406         gst_xvimagesink_check_xshm_calls (xcontext)) {
4407       xcontext->use_xshm = TRUE;
4408       GST_DEBUG ("xvimagesink is using XShm extension");
4409     } else
4410 #endif /* HAVE_XSHM */
4411     {
4412       xcontext->use_xshm = FALSE;
4413       GST_DEBUG ("xvimagesink is not using XShm extension");
4414     }
4415
4416     xv_attr = XvQueryPortAttributes (xcontext->disp,
4417         xcontext->xv_port_id, &N_attr);
4418 #ifdef GST_EXT_XV_ENHANCEMENT
4419   }
4420 #endif //GST_EXT_XV_ENHANCEMENT
4421
4422   /* Generate the channels list */
4423   for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
4424     XvAttribute *matching_attr = NULL;
4425
4426     /* Retrieve the property atom if it exists. If it doesn't exist,
4427      * the attribute itself must not either, so we can skip */
4428     prop_atom = XInternAtom (xcontext->disp, channels[i], True);
4429     if (prop_atom == None)
4430       continue;
4431
4432     if (xv_attr != NULL) {
4433       for (j = 0; j < N_attr && matching_attr == NULL; ++j)
4434         if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
4435           matching_attr = xv_attr + j;
4436     }
4437
4438     if (matching_attr) {
4439       GstColorBalanceChannel *channel;
4440
4441       channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
4442       channel->label = g_strdup (channels[i]);
4443       channel->min_value = matching_attr->min_value;
4444       channel->max_value = matching_attr->max_value;
4445
4446       xcontext->channels_list = g_list_append (xcontext->channels_list,
4447           channel);
4448
4449       /* If the colorbalance settings have not been touched we get Xv values
4450          as defaults and update our internal variables */
4451       if (!xvimagesink->cb_changed) {
4452         gint val;
4453
4454         XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
4455             prop_atom, &val);
4456         /* Normalize val to [-1000, 1000] */
4457         val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
4458             (double) (channel->max_value - channel->min_value));
4459
4460         if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
4461           xvimagesink->hue = val;
4462         else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
4463           xvimagesink->saturation = val;
4464         else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
4465           xvimagesink->brightness = val;
4466         else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
4467           xvimagesink->contrast = val;
4468       }
4469     }
4470   }
4471 #ifdef GST_EXT_XV_ENHANCEMENT
4472   if (!xvimagesink->subpicture) {
4473 #endif
4474   if (xv_attr)
4475     XFree (xv_attr);
4476 #ifdef GST_EXT_XV_ENHANCEMENT
4477   }
4478   if(!xvimagesink->subpicture) {
4479     set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
4480     set_csc_range(xcontext, xvimagesink->csc_range);
4481   }
4482 #endif /* GST_EXT_XV_ENHANCEMENT */
4483
4484   g_mutex_unlock (xvimagesink->x_lock);
4485
4486   return xcontext;
4487 }
4488
4489 /* This function cleans the X context. Closing the Display, releasing the XV
4490    port and unrefing the caps for supported formats. */
4491 static void
4492 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
4493 {
4494   GList *formats_list, *channels_list = NULL;
4495   GstXContext *xcontext;
4496   gint i = 0;
4497
4498   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4499
4500   GST_OBJECT_LOCK (xvimagesink);
4501   if (xvimagesink->xcontext == NULL) {
4502     GST_OBJECT_UNLOCK (xvimagesink);
4503     return;
4504   }
4505
4506   /* Take the XContext from the sink and clean it up */
4507   xcontext = xvimagesink->xcontext;
4508   xvimagesink->xcontext = NULL;
4509
4510   GST_OBJECT_UNLOCK (xvimagesink);
4511
4512 #ifdef GST_EXT_XV_ENHANCEMENT
4513   if (!xvimagesink->subpicture)  {
4514 #endif
4515   formats_list = xcontext->formats_list;
4516
4517   while (formats_list) {
4518     GstXvImageFormat *format = formats_list->data;
4519
4520     gst_caps_unref (format->caps);
4521     g_free (format);
4522     formats_list = g_list_next (formats_list);
4523   }
4524
4525   if (xcontext->formats_list)
4526     g_list_free (xcontext->formats_list);
4527
4528   channels_list = xcontext->channels_list;
4529 #ifdef GST_EXT_XV_ENHANCEMENT
4530   }
4531 #endif
4532   while (channels_list) {
4533     GstColorBalanceChannel *channel = channels_list->data;
4534
4535     g_object_unref (channel);
4536     channels_list = g_list_next (channels_list);
4537   }
4538
4539   if (xcontext->channels_list)
4540     g_list_free (xcontext->channels_list);
4541
4542   gst_caps_unref (xcontext->caps);
4543   if (xcontext->last_caps)
4544     gst_caps_replace (&xcontext->last_caps, NULL);
4545
4546   for (i = 0; i < xcontext->nb_adaptors; i++) {
4547     g_free (xcontext->adaptors[i]);
4548   }
4549
4550   g_free (xcontext->adaptors);
4551
4552   g_free (xcontext->par);
4553
4554   g_mutex_lock (xvimagesink->x_lock);
4555
4556   GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
4557
4558   XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4559
4560 #ifdef GST_EXT_XV_ENHANCEMENT
4561   {
4562     int i = 0;
4563     for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4564       if (g_display_id[i] == xcontext->disp) {
4565         g_display_id[i] = NULL;
4566       }
4567     }
4568   }
4569 #endif
4570   XCloseDisplay (xcontext->disp);
4571   g_mutex_unlock (xvimagesink->x_lock);
4572
4573   g_free (xcontext);
4574 }
4575
4576 static void
4577 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
4578 {
4579   g_mutex_lock (xvimagesink->pool_lock);
4580
4581   while (xvimagesink->image_pool) {
4582     GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
4583
4584     xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4585         xvimagesink->image_pool);
4586     gst_xvimage_buffer_free (xvimage);
4587   }
4588
4589   g_mutex_unlock (xvimagesink->pool_lock);
4590 }
4591
4592 /* Element stuff */
4593
4594 /* This function tries to get a format matching with a given caps in the
4595    supported list of formats we generated in gst_xvimagesink_get_xv_support */
4596 static gint
4597 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
4598     GstCaps * caps)
4599 {
4600   GList *list = NULL;
4601
4602   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
4603
4604   list = xvimagesink->xcontext->formats_list;
4605
4606   while (list) {
4607     GstXvImageFormat *format = list->data;
4608
4609     if (format) {
4610       if (gst_caps_can_intersect (caps, format->caps)) {
4611         return format->format;
4612       }
4613     }
4614     list = g_list_next (list);
4615   }
4616
4617   return -1;
4618 }
4619
4620 static GstCaps *
4621 gst_xvimagesink_getcaps (GstBaseSink * bsink)
4622 {
4623   GstXvImageSink *xvimagesink;
4624
4625   xvimagesink = GST_XVIMAGESINK (bsink);
4626   if (xvimagesink->xcontext
4627 #ifdef GST_EXT_XV_ENHANCEMENT
4628     && !xvimagesink->subpicture
4629 #endif
4630 ) {
4631     return gst_caps_ref (xvimagesink->xcontext->caps);
4632   }
4633   return
4634       gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
4635           (xvimagesink)));
4636 }
4637
4638 static gboolean
4639 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
4640 {
4641   GstXvImageSink *xvimagesink;
4642   GstStructure *structure;
4643   guint32 im_format = 0;
4644   gboolean ret;
4645   gint video_width, video_height;
4646   gint disp_x, disp_y;
4647   gint disp_width, disp_height;
4648   gint video_par_n, video_par_d;        /* video's PAR */
4649   gint display_par_n, display_par_d;    /* display's PAR */
4650   const GValue *caps_par;
4651   const GValue *caps_disp_reg;
4652   const GValue *fps;
4653   guint num, den;
4654 #ifdef GST_EXT_XV_ENHANCEMENT
4655   gboolean subtitle;
4656   gchar *str_in = gst_caps_to_string(caps);
4657   if(str_in == NULL) {
4658     GST_ERROR("gst_caps_to_string() returns NULL...");
4659   }else{
4660     GST_INFO("In setcaps. incaps:%s", str_in);
4661     g_free (str_in);
4662     str_in = NULL;
4663   }
4664 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
4665
4666   xvimagesink = GST_XVIMAGESINK (bsink);
4667
4668   GST_DEBUG_OBJECT (xvimagesink,
4669       "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
4670       GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
4671
4672   if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)
4673 #ifdef GST_EXT_XV_ENHANCEMENT
4674     && !xvimagesink->subpicture
4675 #endif
4676     )
4677     goto incompatible_caps;
4678
4679   structure = gst_caps_get_structure (caps, 0);
4680   ret = gst_structure_get_int (structure, "width", &video_width);
4681   ret &= gst_structure_get_int (structure, "height", &video_height);
4682   fps = gst_structure_get_value (structure, "framerate");
4683   ret &= (fps != NULL);
4684 #ifdef GST_EXT_XV_ENHANCEMENT
4685   if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture)
4686   {
4687     xvimagesink->is_subpicture_format = TRUE;
4688     GST_LOG("It is type of subpicture and subtitle.");
4689   }
4690 #endif
4691   if (!ret)
4692     goto incomplete_caps;
4693
4694 #ifdef GST_EXT_XV_ENHANCEMENT
4695   xvimagesink->aligned_width = video_width;
4696   xvimagesink->aligned_height = video_height;
4697
4698 #ifdef GST_EXT_ENABLE_HEVC
4699   /*get combine prop of hevc*/
4700   if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
4701   {
4702     GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
4703   }
4704   else
4705   {
4706     /*Not need to combine data, just directly copy*/
4707     xvimagesink->need_combine_data = 0;
4708   }
4709 #endif
4710   _remove_last_buffer(xvimagesink);
4711 #endif /* GST_EXT_XV_ENHANCEMENT */
4712
4713   xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
4714   xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
4715
4716   xvimagesink->video_width = video_width;
4717   xvimagesink->video_height = video_height;
4718 #ifdef GST_EXT_XV_ENHANCEMENT
4719   if (!xvimagesink->subpicture) {
4720 #endif
4721   im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
4722   if (im_format == -1)
4723     goto invalid_format;
4724 #ifdef GST_EXT_XV_ENHANCEMENT
4725   }
4726 #endif
4727   /* get aspect ratio from caps if it's present, and
4728    * convert video width and height to a display width and height
4729    * using wd / hd = wv / hv * PARv / PARd */
4730
4731   /* get video's PAR */
4732   caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
4733   if (caps_par) {
4734     video_par_n = gst_value_get_fraction_numerator (caps_par);
4735     video_par_d = gst_value_get_fraction_denominator (caps_par);
4736   } else {
4737     video_par_n = 1;
4738     video_par_d = 1;
4739   }
4740   /* get display's PAR */
4741   if (xvimagesink->par) {
4742     display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
4743     display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
4744   } else {
4745     display_par_n = 1;
4746     display_par_d = 1;
4747   }
4748
4749   /* get the display region */
4750   caps_disp_reg = gst_structure_get_value (structure, "display-region");
4751   if (caps_disp_reg) {
4752     disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
4753     disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
4754     disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
4755     disp_height =
4756         g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
4757   } else {
4758     disp_x = disp_y = 0;
4759     disp_width = video_width;
4760     disp_height = video_height;
4761   }
4762
4763   if (!gst_video_calculate_display_ratio (&num, &den, video_width,
4764           video_height, video_par_n, video_par_d, display_par_n, display_par_d))
4765     goto no_disp_ratio;
4766
4767   xvimagesink->disp_x = disp_x;
4768   xvimagesink->disp_y = disp_y;
4769   xvimagesink->disp_width = disp_width;
4770   xvimagesink->disp_height = disp_height;
4771
4772   GST_DEBUG_OBJECT (xvimagesink,
4773       "video width/height: %dx%d, calculated display ratio: %d/%d",
4774       video_width, video_height, num, den);
4775
4776   /* now find a width x height that respects this display ratio.
4777    * prefer those that have one of w/h the same as the incoming video
4778    * using wd / hd = num / den */
4779
4780   /* start with same height, because of interlaced video */
4781   /* check hd / den is an integer scale factor, and scale wd with the PAR */
4782   if (video_height % den == 0) {
4783     GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
4784     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4785         gst_util_uint64_scale_int (video_height, num, den);
4786     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4787   } else if (video_width % num == 0) {
4788     GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
4789     GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
4790     GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
4791         gst_util_uint64_scale_int (video_width, den, num);
4792   } else {
4793     GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
4794     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4795         gst_util_uint64_scale_int (video_height, num, den);
4796     GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4797   }
4798   GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
4799       GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
4800
4801   /* Notify application to set xwindow id now */
4802   g_mutex_lock (xvimagesink->flow_lock);
4803 #ifdef GST_EXT_XV_ENHANCEMENT
4804   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4805     g_mutex_unlock (xvimagesink->flow_lock);
4806     gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
4807 #else
4808   if (!xvimagesink->xwindow) {
4809     g_mutex_unlock (xvimagesink->flow_lock);
4810     gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
4811 #endif
4812   } else {
4813     g_mutex_unlock (xvimagesink->flow_lock);
4814   }
4815 #ifdef GST_EXT_XV_ENHANCEMENT
4816 if (!xvimagesink->is_subpicture_format) {
4817 #endif
4818     /* Creating our window and our image with the display size in pixels */
4819     if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
4820         GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
4821       goto no_display_size;
4822
4823     g_mutex_lock (xvimagesink->flow_lock);
4824 #ifdef GST_EXT_XV_ENHANCEMENT
4825     if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4826       GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
4827 #else
4828     if (!xvimagesink->xwindow) {
4829 #endif
4830       xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
4831           GST_VIDEO_SINK_WIDTH (xvimagesink),
4832           GST_VIDEO_SINK_HEIGHT (xvimagesink));
4833     }
4834   }
4835
4836   /* After a resize, we want to redraw the borders in case the new frame size
4837    * doesn't cover the same area */
4838   xvimagesink->redraw_border = TRUE;
4839
4840   /* We renew our xvimage only if size or format changed;
4841    * the xvimage is the same size as the video pixel size */
4842   if ((xvimagesink->xvimage) &&
4843       ((im_format != xvimagesink->xvimage->im_format) ||
4844           (video_width != xvimagesink->xvimage->width) ||
4845           (video_height != xvimagesink->xvimage->height)) &&
4846           (!xvimagesink->subpicture)) {
4847     GST_DEBUG_OBJECT (xvimagesink,
4848         "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4849         GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4850         GST_FOURCC_ARGS (im_format));
4851     GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4852     gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4853     xvimagesink->xvimage = NULL;
4854   }
4855
4856 #ifdef GST_EXT_XV_ENHANCEMENT
4857   /* In case of starting player with connecting external display, we have to check status.
4858    * It will be unconditionally executed. */
4859   if(!xvimagesink->is_subpicture_format)
4860     check_hdmi_connected(xvimagesink);
4861 #endif
4862   g_mutex_unlock (xvimagesink->flow_lock);
4863
4864   return TRUE;
4865
4866   /* ERRORS */
4867 incompatible_caps:
4868   {
4869     GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4870     return FALSE;
4871   }
4872 incomplete_caps:
4873   {
4874     GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4875         "height or framerate from intersected caps");
4876     return FALSE;
4877   }
4878 invalid_format:
4879   {
4880     GST_DEBUG_OBJECT (xvimagesink,
4881         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4882     return FALSE;
4883   }
4884 no_disp_ratio:
4885   {
4886     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4887         ("Error calculating the output display ratio of the video."));
4888     return FALSE;
4889   }
4890 no_display_size:
4891   {
4892     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4893         ("Error calculating the output display ratio of the video."));
4894     return FALSE;
4895   }
4896 #ifdef GST_EXT_XV_ENHANCEMENT
4897 }
4898 #endif
4899
4900 static GstStateChangeReturn
4901 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4902 {
4903   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4904   GstXvImageSink *xvimagesink;
4905   GstXContext *xcontext = NULL;
4906 #ifdef GST_EXT_XV_ENHANCEMENT
4907   Atom atom_preemption = None;
4908 #endif /* GST_EXT_XV_ENHANCEMENT */
4909
4910   xvimagesink = GST_XVIMAGESINK (element);
4911
4912   switch (transition) {
4913     case GST_STATE_CHANGE_NULL_TO_READY:
4914 #ifdef GST_EXT_XV_ENHANCEMENT
4915       GST_WARNING("NULL_TO_READY start");
4916 #endif /* GST_EXT_XV_ENHANCEMENT */
4917       /* Initializing the XContext */
4918       if (xvimagesink->xcontext == NULL) {
4919         xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4920         if (xcontext == NULL)
4921           return GST_STATE_CHANGE_FAILURE;
4922         GST_OBJECT_LOCK (xvimagesink);
4923         if (xcontext)
4924           xvimagesink->xcontext = xcontext;
4925         GST_OBJECT_UNLOCK (xvimagesink);
4926       }
4927
4928       /* update object's par with calculated one if not set yet */
4929       if (!xvimagesink->par) {
4930         xvimagesink->par = g_new0 (GValue, 1);
4931         gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4932         GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4933       }
4934       /* call XSynchronize with the current value of synchronous */
4935       GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4936           xvimagesink->synchronous ? "TRUE" : "FALSE");
4937       XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4938       gst_xvimagesink_update_colorbalance (xvimagesink);
4939       gst_xvimagesink_manage_event_thread (xvimagesink);
4940 #ifdef GST_EXT_XV_ENHANCEMENT
4941       GST_WARNING("NULL_TO_READY done");
4942 #endif /* GST_EXT_XV_ENHANCEMENT */
4943       break;
4944     case GST_STATE_CHANGE_READY_TO_PAUSED:
4945 #ifdef GST_EXT_XV_ENHANCEMENT
4946       GST_WARNING("READY_TO_PAUSED start");
4947 #endif /* GST_EXT_XV_ENHANCEMENT */
4948       g_mutex_lock (xvimagesink->pool_lock);
4949       xvimagesink->pool_invalid = FALSE;
4950       g_mutex_unlock (xvimagesink->pool_lock);
4951 #ifdef GST_EXT_XV_ENHANCEMENT
4952       GST_WARNING("READY_TO_PAUSED done");
4953 #endif /* GST_EXT_XV_ENHANCEMENT */
4954       break;
4955     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4956 #ifdef GST_EXT_XV_ENHANCEMENT
4957       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING))
4958         GST_WARNING("vconf set fail");
4959       GST_WARNING("PAUSED_TO_PLAYING done");
4960       xvimagesink->is_during_seek = FALSE;
4961       xvimagesink->keep_external_fullscreen_prev = FALSE;
4962 #endif /* GST_EXT_XV_ENHANCEMENT */
4963       break;
4964     case GST_STATE_CHANGE_PAUSED_TO_READY:
4965 #ifdef GST_EXT_XV_ENHANCEMENT
4966       GST_WARNING("PAUSED_TO_READY start");
4967 #endif /* GST_EXT_XV_ENHANCEMENT */
4968       g_mutex_lock (xvimagesink->pool_lock);
4969       xvimagesink->pool_invalid = TRUE;
4970       g_mutex_unlock (xvimagesink->pool_lock);
4971 #ifdef GST_EXT_XV_ENHANCEMENT
4972 #endif /* GST_EXT_XV_ENHANCEMENT */
4973       break;
4974     default:
4975       break;
4976   }
4977
4978   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4979
4980   switch (transition) {
4981     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4982 #ifdef GST_EXT_XV_ENHANCEMENT
4983       GST_WARNING("PLAYING_TO_PAUSED start");
4984       g_mutex_lock (xvimagesink->flow_lock);
4985       /* init displayed buffer count */
4986       xvimagesink->displayed_buffer_count = 0;
4987
4988       g_mutex_lock (xvimagesink->x_lock);
4989       if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) {
4990         GST_WARNING_OBJECT(xvimagesink, "release external display mode");
4991         XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
4992                      xvimagesink->xwindow->win);
4993         XSync(xvimagesink->xcontext->disp, FALSE);
4994         xvimagesink->skip_frame_due_to_external_dev = TRUE;
4995       }
4996       if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture)
4997         && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
4998         GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4999         XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
5000         XSync(xvimagesink->xcontext->disp, FALSE);
5001       }
5002       g_mutex_unlock (xvimagesink->x_lock);
5003       g_mutex_unlock (xvimagesink->flow_lock);
5004       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED))
5005         GST_WARNING("vconf set fail");
5006       GST_WARNING("PLAYING_TO_PAUSED done");
5007 #endif /* GST_EXT_XV_ENHANCEMENT */
5008       break;
5009     case GST_STATE_CHANGE_PAUSED_TO_READY:
5010 #ifdef GST_EXT_XV_ENHANCEMENT
5011       GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
5012                                       xvimagesink->is_zero_copy_format,
5013                                       xvimagesink->enable_flush_buffer,
5014                                       xvimagesink->secure_path,
5015                                       xvimagesink->get_pixmap_cb);
5016
5017       if ((xvimagesink->enable_flush_buffer == FALSE ||
5018            xvimagesink->secure_path == SECURE_PATH_ON) &&
5019           xvimagesink->xcontext && xvimagesink->xwindow) {
5020         GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
5021         g_mutex_lock(xvimagesink->x_lock);
5022         XvStopVideo(xvimagesink->xcontext->disp,
5023                     xvimagesink->xcontext->xv_port_id,
5024                     xvimagesink->xwindow->win);
5025         XSync(xvimagesink->xcontext->disp, FALSE);
5026         g_mutex_unlock(xvimagesink->x_lock);
5027         _remove_last_buffer(xvimagesink);
5028       } else if (xvimagesink->is_zero_copy_format &&
5029                  xvimagesink->xvimage &&
5030                  xvimagesink->xvimage->xvimage &&
5031                  !xvimagesink->get_pixmap_cb) {
5032         if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5033           int i = 0;
5034           XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5035           memset(img_data, 0x0, sizeof(XV_DATA));
5036           XV_INIT_DATA(img_data);
5037
5038           img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5039           img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5040           img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5041
5042           gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5043
5044           GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
5045
5046           /* check whether putimage is succeeded or not */
5047           g_mutex_lock(xvimagesink->display_buffer_lock);
5048
5049           for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5050             if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
5051               if ((img_data->dmabuf_fd[0] > 0 &&
5052                    xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
5053                    xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
5054                    xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
5055                   (img_data->bo[0] &&
5056                    xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
5057                    xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
5058                    xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
5059                 GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
5060                 break;
5061               }
5062             }
5063           }
5064
5065           if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
5066             GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
5067             _release_flush_buffer(xvimagesink);
5068           } else {
5069             _remove_last_buffer(xvimagesink);
5070           }
5071
5072           g_mutex_unlock(xvimagesink->display_buffer_lock);
5073         }
5074       }
5075 #endif /* GST_EXT_XV_ENHANCEMENT */
5076       xvimagesink->fps_n = 0;
5077       xvimagesink->fps_d = 1;
5078       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
5079       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
5080 #ifdef GST_EXT_XV_ENHANCEMENT
5081       GST_WARNING("PAUSED_TO_READY done");
5082 #endif /* GST_EXT_XV_ENHANCEMENT */
5083       break;
5084     case GST_STATE_CHANGE_READY_TO_NULL:
5085 #ifdef GST_EXT_XV_ENHANCEMENT
5086       GST_WARNING("READY_TO_NULL start");
5087 #endif /* GST_EXT_XV_ENHANCEMENT */
5088       gst_xvimagesink_reset (xvimagesink);
5089 #ifdef GST_EXT_XV_ENHANCEMENT
5090       /* close drm */
5091       drm_fini(xvimagesink);
5092       /* init displaying_buffer_count */
5093       xvimagesink->displaying_buffer_count = 0;
5094       GST_WARNING("READY_TO_NULL done");
5095 #endif /* GST_EXT_XV_ENHANCEMENT */
5096       break;
5097     default:
5098       break;
5099   }
5100
5101   return ret;
5102 }
5103
5104 static void
5105 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
5106     GstClockTime * start, GstClockTime * end)
5107 {
5108   GstXvImageSink *xvimagesink;
5109
5110   xvimagesink = GST_XVIMAGESINK (bsink);
5111
5112   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
5113     *start = GST_BUFFER_TIMESTAMP (buf);
5114     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
5115       *end = *start + GST_BUFFER_DURATION (buf);
5116     } else {
5117       if (xvimagesink->fps_n > 0) {
5118         *end = *start +
5119             gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
5120             xvimagesink->fps_n);
5121       }
5122     }
5123   }
5124 }
5125
5126 #ifdef GST_EXT_ENABLE_HEVC
5127 static void
5128 gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
5129 {
5130     unsigned int outsize = 0;
5131     unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
5132     int cnt = 0, j = 0;
5133     unsigned char *temp_imgb;
5134     SCMN_IMGB *imgb = NULL;
5135     int stride, w, h, i;
5136
5137     GST_DEBUG("Begin");
5138     imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
5139     if(imgb == NULL || imgb->a[0] == NULL)
5140     {
5141         return;
5142     }
5143
5144     stride = GST_ROUND_UP_4 (imgb->w[0]);
5145     h = imgb->h[0];
5146     w = imgb->w[0];
5147     /*Y plane copy */
5148     for (i = 0; i < h; i++)
5149     {
5150         memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
5151     }
5152
5153     temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
5154
5155     stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
5156     h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
5157     w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
5158     /* Cb plane copy */
5159     for (i = 0; i < h; i++)
5160     {
5161         memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
5162     }
5163
5164     temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
5165     /* Same stride, height, width as above */
5166     /* Cr plane copy */
5167     for (i = 0; i < h; i++)
5168     {
5169         memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
5170     }
5171
5172     outsize  = imgb->w[0] * imgb->h[0]* 3 >> 1;
5173     xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
5174
5175     GST_DEBUG("End");
5176 }
5177 #endif
5178
5179 #ifdef GST_EXT_XV_ENHANCEMENT
5180 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
5181 {
5182   GstXvImageFlushBuffer *flush_buffer = NULL;
5183   GstXvImageDisplayingBuffer *display_buffer = NULL;
5184   tbm_bo bo = NULL;
5185   int size = 0;
5186   int i = 0;
5187   int ret = 0;
5188
5189   if (xvimagesink == NULL) {
5190     GST_ERROR("handle is NULL");
5191     return FALSE;
5192   }
5193
5194   if (xvimagesink->last_added_buffer_index == -1) {
5195     GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
5196     return FALSE;
5197   }
5198
5199   if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
5200     GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
5201                                   xvimagesink->drm_fd, xvimagesink->bufmgr);
5202     return FALSE;
5203   }
5204
5205   flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
5206   if (flush_buffer == NULL) {
5207     GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
5208     return FALSE;
5209   }
5210
5211   memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
5212
5213   display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
5214   GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
5215                                   xvimagesink->last_added_buffer_index);
5216
5217   for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5218     if (display_buffer->bo[i]) {
5219       tbm_bo_handle vaddr_src;
5220       tbm_bo_handle vaddr_dst;
5221
5222       /* get bo size */
5223       size = tbm_bo_size(display_buffer->bo[i]);
5224
5225       /* alloc bo */
5226       bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT);
5227       if (bo == NULL) {
5228         GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
5229         goto FLUSH_BUFFER_FAILED;
5230       }
5231
5232       GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
5233
5234       flush_buffer->gem_name[i] = tbm_bo_export(bo);
5235       flush_buffer->bo[i] = bo;
5236
5237       /* get virtual address */
5238       vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5239       vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5240       if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
5241         GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
5242                                         vaddr_src.ptr, vaddr_dst.ptr);
5243         if (vaddr_src.ptr) {
5244           tbm_bo_unmap(display_buffer->bo[i]);
5245         }
5246         if (vaddr_dst.ptr) {
5247           tbm_bo_unmap(bo);
5248         }
5249         goto FLUSH_BUFFER_FAILED;
5250       }
5251
5252       /* copy buffer */
5253       memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
5254
5255       tbm_bo_unmap(display_buffer->bo[i]);
5256       tbm_bo_unmap(bo);
5257
5258       GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
5259
5260       xvimagesink->flush_buffer = flush_buffer;
5261
5262       ret = TRUE;
5263     }
5264   }
5265
5266   return ret;
5267
5268 FLUSH_BUFFER_FAILED:
5269   if (flush_buffer) {
5270     for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5271       if (flush_buffer->bo[i]) {
5272         tbm_bo_unref(flush_buffer->bo[i]);
5273         flush_buffer->bo[i] = NULL;
5274       }
5275     }
5276     free(flush_buffer);
5277     flush_buffer = NULL;
5278   }
5279
5280   return FALSE;
5281 }
5282 #endif /* GST_EXT_XV_ENHANCEMENT */
5283
5284
5285 static GstFlowReturn
5286 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
5287 {
5288   GstXvImageSink *xvimagesink;
5289
5290 #ifdef GST_EXT_XV_ENHANCEMENT
5291   XV_DATA_PTR img_data = NULL;
5292   SCMN_IMGB *scmn_imgb = NULL;
5293   gint format = 0;
5294   gboolean ret = FALSE;
5295   int res = -1;
5296   int (*handler) (Display *, XErrorEvent *) = NULL;
5297   Atom atom_overlay;
5298 #endif /* GST_EXT_XV_ENHANCEMENT */
5299
5300   xvimagesink = GST_XVIMAGESINK (vsink);
5301
5302 #ifdef GST_EXT_XV_ENHANCEMENT
5303   if (xvimagesink->stop_video) {
5304     GST_INFO( "Stop video is TRUE. so skip show frame..." );
5305     return GST_FLOW_OK;
5306   }
5307 #endif /* GST_EXT_XV_ENHANCEMENT */
5308
5309   /* If this buffer has been allocated using our buffer management we simply
5310      put the ximage which is in the PRIVATE pointer */
5311   if (GST_IS_XVIMAGE_BUFFER (buf)) {
5312     GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
5313 #ifdef GST_EXT_XV_ENHANCEMENT
5314     xvimagesink->xid_updated = FALSE;
5315 #endif /* GST_EXT_XV_ENHANCEMENT */
5316     if (!gst_xvimagesink_xvimage_put (xvimagesink,
5317             GST_XVIMAGE_BUFFER_CAST (buf)))
5318       goto no_window;
5319   } else {
5320     GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
5321         "slow copy into bufferpool buffer %p", buf);
5322     /* Else we have to copy the data into our private image, */
5323     /* if we have one... */
5324 #ifdef GST_EXT_XV_ENHANCEMENT
5325     g_mutex_lock (xvimagesink->flow_lock);
5326     if (xvimagesink->skip_frame_due_to_external_dev) {
5327       GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." );
5328       xvimagesink->skip_frame_due_to_external_dev = FALSE;
5329       g_mutex_unlock (xvimagesink->flow_lock);
5330       return GST_FLOW_OK;
5331     }
5332
5333 #endif /* GST_EXT_XV_ENHANCEMENT */
5334       if (!xvimagesink->xvimage
5335 #ifdef GST_EXT_XV_ENHANCEMENT
5336       && !xvimagesink->is_subpicture_format
5337 #endif
5338         ) {
5339         GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
5340
5341 #ifdef GST_EXT_XV_ENHANCEMENT
5342       format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
5343       switch (format) {
5344         case GST_MAKE_FOURCC('S', 'T', '1', '2'):
5345         case GST_MAKE_FOURCC('S', 'N', '1', '2'):
5346         case GST_MAKE_FOURCC('S', 'N', '2', '1'):
5347         case GST_MAKE_FOURCC('S', '4', '2', '0'):
5348         case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
5349         case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
5350         case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
5351         case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
5352         case GST_MAKE_FOURCC('S', 'R', '3', '2'):
5353         case GST_MAKE_FOURCC('S', 'V', '1', '2'):
5354           xvimagesink->is_zero_copy_format = TRUE;
5355           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5356           if(scmn_imgb == NULL) {
5357             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5358             g_mutex_unlock (xvimagesink->flow_lock);
5359             return GST_FLOW_OK;
5360           }
5361
5362           /* skip buffer if aligned size is smaller than size of caps */
5363           if (scmn_imgb->s[0] < xvimagesink->video_width ||
5364               scmn_imgb->e[0] < xvimagesink->video_height) {
5365             GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
5366                                             xvimagesink->video_width, xvimagesink->video_height,
5367                                             scmn_imgb->s[0], scmn_imgb->e[0]);
5368             g_mutex_unlock (xvimagesink->flow_lock);
5369             return GST_FLOW_OK;
5370           }
5371
5372           xvimagesink->aligned_width = scmn_imgb->s[0];
5373           xvimagesink->aligned_height = scmn_imgb->e[0];
5374           GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
5375                                        xvimagesink->aligned_width, xvimagesink->aligned_height);
5376           break;
5377         default:
5378           xvimagesink->is_zero_copy_format = FALSE;
5379           GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
5380           break;
5381       }
5382
5383       GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
5384 #endif /* GST_EXT_XV_ENHANCEMENT */
5385
5386       xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
5387           GST_BUFFER_CAPS (buf));
5388
5389       if (!xvimagesink->xvimage)
5390         /* The create method should have posted an informative error */
5391         goto no_image;
5392
5393 #ifdef GST_EXT_XV_ENHANCEMENT
5394       if ((xvimagesink->is_zero_copy_format == FALSE &&
5395            xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
5396           (xvimagesink->is_zero_copy_format &&
5397            xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
5398 #else /* GST_EXT_XV_ENHANCEMENT */
5399       if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
5400 #endif /* GST_EXT_XV_ENHANCEMENT */
5401         GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
5402             ("Failed to create output image buffer of %dx%d pixels",
5403                 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
5404             ("XServer allocated buffer size did not match input buffer"));
5405
5406         gst_xvimage_buffer_destroy (xvimagesink->xvimage);
5407         xvimagesink->xvimage = NULL;
5408         goto no_image;
5409       }
5410     }
5411
5412 #ifdef GST_EXT_XV_ENHANCEMENT
5413     if (xvimagesink->is_zero_copy_format) {
5414       /* Cases for specified formats of Samsung extension */
5415         GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
5416                 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
5417                 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
5418                 xvimagesink->display_mode, xvimagesink->rotate_angle);
5419
5420         if (xvimagesink->xvimage->xvimage->data) {
5421           int i = 0;
5422           img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5423           memset(img_data, 0x0, sizeof(XV_DATA));
5424           XV_INIT_DATA(img_data);
5425
5426           scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5427           if (scmn_imgb == NULL) {
5428             GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5429             g_mutex_unlock (xvimagesink->flow_lock);
5430             return GST_FLOW_OK;
5431           }
5432
5433           /* Keep the vaddr of current image for copying last image */
5434           if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
5435             for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
5436               xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
5437             }
5438             GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5439               xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
5440           }
5441
5442           if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
5443             img_data->YBuf = (unsigned int)scmn_imgb->p[0];
5444             img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
5445             img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
5446             img_data->BufType = XV_BUF_TYPE_LEGACY;
5447
5448             GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5449                       img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
5450           } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
5451                      scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
5452             gboolean do_set_secure = FALSE;
5453
5454             /* open drm to use gem */
5455             if (xvimagesink->drm_fd < 0) {
5456               drm_init(xvimagesink);
5457             }
5458
5459             if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
5460               /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
5461               img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
5462               img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
5463               img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
5464               img_data->BufType = XV_BUF_TYPE_DMABUF;
5465               GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
5466             } else {
5467               /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
5468               img_data->bo[0] = scmn_imgb->bo[0];
5469               img_data->bo[1] = scmn_imgb->bo[1];
5470               img_data->bo[2] = scmn_imgb->bo[2];
5471               GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
5472             }
5473
5474             /* check secure contents path */
5475             if (scmn_imgb->tz_enable) {
5476               if (xvimagesink->secure_path != SECURE_PATH_ON) {
5477                 xvimagesink->secure_path = SECURE_PATH_ON;
5478                 do_set_secure = TRUE;
5479               }
5480             } else {
5481               if (xvimagesink->secure_path != SECURE_PATH_OFF) {
5482                 xvimagesink->secure_path = SECURE_PATH_OFF;
5483                 do_set_secure = TRUE;
5484               }
5485             }
5486             static gboolean is_exist = FALSE;
5487             gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE");
5488             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5489             g_free(attr_name);
5490
5491             if (do_set_secure && is_exist) {
5492               Atom atom_secure = None;
5493               g_mutex_lock (xvimagesink->x_lock);
5494               atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
5495               if (atom_secure != None) {
5496                 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
5497                   GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
5498                 } else {
5499                   GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
5500                 }
5501                 XSync (xvimagesink->xcontext->disp, FALSE);
5502               } else {
5503                 GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
5504               }
5505               g_mutex_unlock (xvimagesink->x_lock);
5506             }
5507
5508             is_exist = FALSE;
5509             attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5510             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5511             g_free(attr_name);
5512
5513
5514             if (xvimagesink->drm_level && is_exist) {
5515               Atom atom_drm = None;
5516               g_mutex_lock (xvimagesink->x_lock);
5517               atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5518                                           "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5519               if (atom_drm != None) {
5520                 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5521                 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5522                                      xvimagesink->xcontext->xv_port_id,
5523                                      atom_drm, xvimagesink->drm_level ) != Success) {
5524                   GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5525                 }
5526                 XSync (xvimagesink->xcontext->disp, FALSE);
5527                 g_mutex_unlock (xvimagesink->x_lock);
5528                 xvimagesink->drm_level = DRM_LEVEL_0;
5529               }
5530             }
5531
5532             /* set current buffer */
5533             xvimagesink->xvimage->current_buffer = buf;
5534           } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) {
5535             /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
5536             GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
5537             if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5538               img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5539               img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5540               img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5541             } else {
5542               g_mutex_unlock(xvimagesink->flow_lock);
5543               return GST_FLOW_OK;
5544             }
5545           } else {
5546             GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
5547                         scmn_imgb->buf_share_method);
5548             g_mutex_unlock (xvimagesink->flow_lock);
5549             return GST_FLOW_OK;
5550           }
5551         } else {
5552           GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
5553           g_mutex_unlock (xvimagesink->flow_lock);
5554           return GST_FLOW_OK;
5555         }
5556     } else if (xvimagesink->is_subpicture_format) {
5557       GC gc;
5558       xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf);
5559       if(!xvimagesink->pixmap_for_subpicture) {
5560         GST_ERROR("no pixmap");
5561         g_mutex_unlock (xvimagesink->flow_lock);
5562         return GST_FLOW_OK;
5563       }
5564       if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) {
5565         GST_ERROR("pixmap's size and current resolution are different");
5566         g_mutex_unlock (xvimagesink->flow_lock);
5567         return GST_FLOW_OK;
5568       }
5569       gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0);
5570
5571       GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture,
5572         xvimagesink->xcontext->xv_port_id, gc);
5573
5574       /* set error handler */
5575       error_caught = FALSE;
5576       handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
5577
5578       if(!xvimagesink->set_overlay_for_subpicture_just_once)
5579       {
5580         GST_LOG("setting attribute overlay");
5581         atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE);
5582         XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1);
5583         XSync (xvimagesink->xcontext->disp, FALSE);
5584         xvimagesink->set_overlay_for_subpicture_just_once = TRUE;
5585       }
5586       res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
5587         xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height,
5588         0, 0, xvimagesink->external_width, xvimagesink->external_height);
5589       XSync (xvimagesink->xcontext->disp, FALSE);
5590
5591       GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n",
5592                           GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
5593                           GST_TIME_ARGS(GST_BUFFER_DURATION(buf)),
5594                           GST_BUFFER_SIZE(buf));
5595       if(gc) {
5596         GST_DEBUG("FreeGC");
5597         XFreeGC (xvimagesink->xcontext->disp, gc);
5598       }
5599       if (error_caught)
5600         GST_WARNING_OBJECT(xvimagesink, "XvGetStill error");
5601       else
5602         GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s  ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height);
5603
5604       /* Reset error handler */
5605       if (handler) {
5606         error_caught = FALSE;
5607         XSetErrorHandler (handler);
5608       }
5609     } else {
5610         GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
5611
5612 #ifdef GST_EXT_ENABLE_HEVC
5613         if(xvimagesink->need_combine_data == 1)
5614         {
5615             gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
5616         }
5617         else
5618 #endif
5619         {
5620             memcpy (xvimagesink->xvimage->xvimage->data,
5621             GST_BUFFER_DATA (buf),
5622             MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5623         }
5624     }
5625
5626     g_mutex_unlock (xvimagesink->flow_lock);
5627     ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5628     if (!ret && !xvimagesink->is_subpicture_format) {
5629       goto no_window;
5630     }
5631 #else /* GST_EXT_XV_ENHANCEMENT */
5632     memcpy (xvimagesink->xvimage->xvimage->data,
5633         GST_BUFFER_DATA (buf),
5634         MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5635
5636     if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
5637       goto no_window;
5638 #endif /* GST_EXT_XV_ENHANCEMENT */
5639   }
5640
5641   return GST_FLOW_OK;
5642
5643   /* ERRORS */
5644 no_image:
5645   {
5646     /* No image available. That's very bad ! */
5647     GST_WARNING_OBJECT (xvimagesink, "could not create image");
5648 #ifdef GST_EXT_XV_ENHANCEMENT
5649     g_mutex_unlock (xvimagesink->flow_lock);
5650 #endif
5651     return GST_FLOW_ERROR;
5652   }
5653 no_window:
5654   {
5655     /* No Window available to put our image into */
5656     GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
5657     return GST_FLOW_ERROR;
5658   }
5659 }
5660
5661 static gboolean
5662 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
5663 {
5664   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
5665   if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)
5666   {
5667       if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK))
5668         GST_WARNING("vconf set fail");
5669   }
5670
5671   switch (GST_EVENT_TYPE (event)) {
5672     case GST_EVENT_TAG:{
5673       GstTagList *l;
5674       gchar *title = NULL;
5675
5676       gst_event_parse_tag (event, &l);
5677       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
5678
5679       if (title) {
5680 #ifdef GST_EXT_XV_ENHANCEMENT
5681         if (!xvimagesink->get_pixmap_cb) {
5682 #endif
5683         GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
5684         gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
5685             title);
5686
5687         g_free (title);
5688 #ifdef GST_EXT_XV_ENHANCEMENT
5689         }
5690 #endif
5691       }
5692       break;
5693     }
5694 #ifdef GST_EXT_XV_ENHANCEMENT
5695     case GST_EVENT_FLUSH_START:
5696       GST_DEBUG_OBJECT (xvimagesink, "flush start");
5697       break;
5698     case GST_EVENT_FLUSH_STOP:
5699       GST_DEBUG_OBJECT (xvimagesink, "flush stop");
5700       xvimagesink->is_during_seek = TRUE;
5701       break;
5702     case GST_EVENT_CUSTOM_DOWNSTREAM:
5703     {
5704       const GstStructure *st = NULL;
5705       st = gst_event_get_structure (event);
5706       if(!st) {
5707         GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
5708       } else {
5709         if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
5710           GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
5711           xvimagesink->drm_level = DRM_LEVEL_1;
5712           if (xvimagesink->drm_level && xvimagesink->xcontext) {
5713             static gboolean is_exist = FALSE;
5714             gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5715             is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5716             g_free(attr_name);
5717
5718             if(is_exist)
5719             {
5720               Atom atom_drm = None;
5721               g_mutex_lock (xvimagesink->x_lock);
5722               atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5723                                           "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5724               if (atom_drm != None) {
5725                 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5726                 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5727                                      xvimagesink->xcontext->xv_port_id,
5728                                      atom_drm, xvimagesink->drm_level ) != Success) {
5729                   GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5730                 }
5731                 XSync (xvimagesink->xcontext->disp, FALSE);
5732                 xvimagesink->drm_level = DRM_LEVEL_0;
5733               }
5734               g_mutex_unlock (xvimagesink->x_lock);
5735             }
5736           }
5737         }
5738       }
5739       break;
5740     }
5741     case GST_EVENT_EOS:
5742       xvimagesink->eos_received = TRUE;
5743       GST_DEBUG_OBJECT(xvimagesink, "got eos");
5744       break;
5745     case GST_EVENT_NEWSEGMENT:
5746       xvimagesink->eos_received = FALSE;
5747       GST_DEBUG_OBJECT(xvimagesink, "got newsegment event");
5748       break;
5749 #endif
5750     default:
5751       break;
5752   }
5753   if (GST_BASE_SINK_CLASS (parent_class)->event)
5754     return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
5755   else
5756     return TRUE;
5757 }
5758
5759 /* Buffer management */
5760
5761 static GstCaps *
5762 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
5763     GstCaps * caps)
5764 {
5765   GstCaps *intersection;
5766   GstCaps *new_caps;
5767   GstStructure *s;
5768   gint width, height;
5769   gint par_n = 1, par_d = 1;
5770   gint dar_n, dar_d;
5771   gint w, h;
5772
5773   new_caps = gst_caps_copy (caps);
5774
5775   s = gst_caps_get_structure (new_caps, 0);
5776
5777   gst_structure_get_int (s, "width", &width);
5778   gst_structure_get_int (s, "height", &height);
5779   gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
5780
5781   gst_structure_remove_field (s, "width");
5782   gst_structure_remove_field (s, "height");
5783   gst_structure_remove_field (s, "pixel-aspect-ratio");
5784
5785   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5786   gst_caps_unref (new_caps);
5787
5788   if (gst_caps_is_empty (intersection))
5789     return intersection;
5790
5791   s = gst_caps_get_structure (intersection, 0);
5792
5793   gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
5794
5795   /* xvimagesink supports all PARs */
5796
5797   gst_structure_fixate_field_nearest_int (s, "width", width);
5798   gst_structure_fixate_field_nearest_int (s, "height", height);
5799   gst_structure_get_int (s, "width", &w);
5800   gst_structure_get_int (s, "height", &h);
5801
5802   gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
5803   gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
5804       NULL);
5805
5806   return intersection;
5807 }
5808
5809 static GstFlowReturn
5810 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
5811     GstCaps * caps, GstBuffer ** buf)
5812 {
5813   GstFlowReturn ret = GST_FLOW_OK;
5814   GstXvImageSink *xvimagesink;
5815   GstXvImageBuffer *xvimage = NULL;
5816   GstCaps *intersection = NULL;
5817   GstStructure *structure = NULL;
5818   gint width, height, image_format;
5819
5820   xvimagesink = GST_XVIMAGESINK (bsink);
5821
5822   if (G_UNLIKELY (!caps))
5823     goto no_caps;
5824
5825   g_mutex_lock (xvimagesink->pool_lock);
5826   if (G_UNLIKELY (xvimagesink->pool_invalid))
5827     goto invalid;
5828
5829   if (G_LIKELY (xvimagesink->xcontext->last_caps &&
5830           gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
5831     GST_LOG_OBJECT (xvimagesink,
5832         "buffer alloc for same last_caps, reusing caps");
5833     intersection = gst_caps_ref (caps);
5834     image_format = xvimagesink->xcontext->last_format;
5835     width = xvimagesink->xcontext->last_width;
5836     height = xvimagesink->xcontext->last_height;
5837
5838     goto reuse_last_caps;
5839   }
5840
5841   GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
5842       GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
5843       caps, xvimagesink->xcontext->caps);
5844
5845   /* Check the caps against our xcontext */
5846   intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
5847
5848   GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
5849       GST_PTR_FORMAT, intersection);
5850
5851   if (gst_caps_is_empty (intersection)) {
5852     GstCaps *new_caps;
5853
5854     gst_caps_unref (intersection);
5855
5856     /* So we don't support this kind of buffer, let's define one we'd like */
5857     new_caps = gst_caps_copy (caps);
5858
5859     structure = gst_caps_get_structure (new_caps, 0);
5860     if (!gst_structure_has_field (structure, "width") ||
5861         !gst_structure_has_field (structure, "height")) {
5862       gst_caps_unref (new_caps);
5863       goto invalid;
5864     }
5865
5866     /* Try different dimensions */
5867     intersection =
5868         gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5869
5870     if (gst_caps_is_empty (intersection)) {
5871       /* Try with different YUV formats first */
5872       gst_structure_set_name (structure, "video/x-raw-yuv");
5873
5874       /* Remove format specific fields */
5875       gst_structure_remove_field (structure, "format");
5876       gst_structure_remove_field (structure, "endianness");
5877       gst_structure_remove_field (structure, "depth");
5878       gst_structure_remove_field (structure, "bpp");
5879       gst_structure_remove_field (structure, "red_mask");
5880       gst_structure_remove_field (structure, "green_mask");
5881       gst_structure_remove_field (structure, "blue_mask");
5882       gst_structure_remove_field (structure, "alpha_mask");
5883
5884       /* Reuse intersection with Xcontext */
5885       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5886     }
5887
5888     if (gst_caps_is_empty (intersection)) {
5889       /* Try with different dimensions and YUV formats */
5890       intersection =
5891           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5892     }
5893
5894     if (gst_caps_is_empty (intersection)) {
5895       /* Now try with RGB */
5896       gst_structure_set_name (structure, "video/x-raw-rgb");
5897       /* And interset again */
5898       gst_caps_unref (intersection);
5899       intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5900     }
5901
5902     if (gst_caps_is_empty (intersection)) {
5903       /* Try with different dimensions and RGB formats */
5904       intersection =
5905           gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5906     }
5907
5908     /* Clean this copy */
5909     gst_caps_unref (new_caps);
5910
5911     if (gst_caps_is_empty (intersection))
5912       goto incompatible;
5913   }
5914
5915   /* Ensure the returned caps are fixed */
5916   gst_caps_truncate (intersection);
5917
5918   GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
5919       GST_PTR_FORMAT, intersection);
5920   if (gst_caps_is_equal (intersection, caps)) {
5921     /* Things work better if we return a buffer with the same caps ptr
5922      * as was asked for when we can */
5923     gst_caps_replace (&intersection, caps);
5924   }
5925
5926   /* Get image format from caps */
5927   image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
5928       intersection);
5929
5930   /* Get geometry from caps */
5931   structure = gst_caps_get_structure (intersection, 0);
5932   if (!gst_structure_get_int (structure, "width", &width) ||
5933       !gst_structure_get_int (structure, "height", &height) ||
5934       image_format == -1)
5935     goto invalid_caps;
5936
5937   /* Store our caps and format as the last_caps to avoid expensive
5938    * caps intersection next time */
5939   gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
5940   xvimagesink->xcontext->last_format = image_format;
5941   xvimagesink->xcontext->last_width = width;
5942   xvimagesink->xcontext->last_height = height;
5943
5944 reuse_last_caps:
5945
5946   /* Walking through the pool cleaning unusable images and searching for a
5947      suitable one */
5948   while (xvimagesink->image_pool) {
5949     xvimage = xvimagesink->image_pool->data;
5950
5951     if (xvimage) {
5952       /* Removing from the pool */
5953       xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
5954           xvimagesink->image_pool);
5955
5956       /* We check for geometry or image format changes */
5957       if ((xvimage->width != width) ||
5958           (xvimage->height != height) || (xvimage->im_format != image_format)) {
5959         /* This image is unusable. Destroying... */
5960         gst_xvimage_buffer_free (xvimage);
5961         xvimage = NULL;
5962       } else {
5963         /* We found a suitable image */
5964         GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
5965         break;
5966       }
5967     }
5968   }
5969
5970   if (!xvimage) {
5971 #ifdef GST_EXT_XV_ENHANCEMENT
5972     /* init aligned size */
5973     xvimagesink->aligned_width = 0;
5974     xvimagesink->aligned_height = 0;
5975 #endif /* GST_EXT_XV_ENHANCEMENT */
5976
5977     /* We found no suitable image in the pool. Creating... */
5978     GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
5979     xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
5980   }
5981   g_mutex_unlock (xvimagesink->pool_lock);
5982
5983   if (xvimage) {
5984     /* Make sure the buffer is cleared of any previously used flags */
5985     GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
5986     gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
5987   }
5988
5989   *buf = GST_BUFFER_CAST (xvimage);
5990
5991 beach:
5992   if (intersection) {
5993     gst_caps_unref (intersection);
5994   }
5995
5996   return ret;
5997
5998   /* ERRORS */
5999 invalid:
6000   {
6001     GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
6002     ret = GST_FLOW_WRONG_STATE;
6003     g_mutex_unlock (xvimagesink->pool_lock);
6004     goto beach;
6005   }
6006 incompatible:
6007   {
6008     GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
6009         "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
6010         " are completely incompatible with those caps", caps,
6011         xvimagesink->xcontext->caps);
6012     ret = GST_FLOW_NOT_NEGOTIATED;
6013     g_mutex_unlock (xvimagesink->pool_lock);
6014     goto beach;
6015   }
6016 invalid_caps:
6017   {
6018     GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
6019         GST_PTR_FORMAT, intersection);
6020     ret = GST_FLOW_NOT_NEGOTIATED;
6021     g_mutex_unlock (xvimagesink->pool_lock);
6022     goto beach;
6023   }
6024 no_caps:
6025   {
6026     GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
6027     *buf = NULL;
6028     ret = GST_FLOW_OK;
6029     goto beach;
6030   }
6031 }
6032
6033 /* Interfaces stuff */
6034
6035 static gboolean
6036 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
6037 {
6038   if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
6039       type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
6040     return TRUE;
6041   else
6042     return FALSE;
6043 }
6044
6045 static void
6046 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
6047 {
6048   klass->supported = gst_xvimagesink_interface_supported;
6049 }
6050
6051 static void
6052 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
6053     GstStructure * structure)
6054 {
6055   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
6056   GstPad *peer;
6057
6058   if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
6059     GstEvent *event;
6060     GstVideoRectangle src, dst, result;
6061     gdouble x, y, xscale = 1.0, yscale = 1.0;
6062
6063     event = gst_event_new_navigation (structure);
6064
6065     /* We take the flow_lock while we look at the window */
6066     g_mutex_lock (xvimagesink->flow_lock);
6067
6068     if (!xvimagesink->xwindow) {
6069       g_mutex_unlock (xvimagesink->flow_lock);
6070       return;
6071     }
6072
6073     if (xvimagesink->keep_aspect) {
6074       /* We get the frame position using the calculated geometry from _setcaps
6075          that respect pixel aspect ratios */
6076       src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
6077       src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
6078       dst.w = xvimagesink->render_rect.w;
6079       dst.h = xvimagesink->render_rect.h;
6080
6081       gst_video_sink_center_rect (src, dst, &result, TRUE);
6082       result.x += xvimagesink->render_rect.x;
6083       result.y += xvimagesink->render_rect.y;
6084     } else {
6085       memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
6086     }
6087
6088     g_mutex_unlock (xvimagesink->flow_lock);
6089
6090     /* We calculate scaling using the original video frames geometry to include
6091        pixel aspect ratio scaling. */
6092     xscale = (gdouble) xvimagesink->video_width / result.w;
6093     yscale = (gdouble) xvimagesink->video_height / result.h;
6094
6095     /* Converting pointer coordinates to the non scaled geometry */
6096     if (gst_structure_get_double (structure, "pointer_x", &x)) {
6097       x = MIN (x, result.x + result.w);
6098       x = MAX (x - result.x, 0);
6099       gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
6100           (gdouble) x * xscale, NULL);
6101     }
6102     if (gst_structure_get_double (structure, "pointer_y", &y)) {
6103       y = MIN (y, result.y + result.h);
6104       y = MAX (y - result.y, 0);
6105       gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
6106           (gdouble) y * yscale, NULL);
6107     }
6108
6109     gst_pad_send_event (peer, event);
6110     gst_object_unref (peer);
6111   }
6112 }
6113
6114 static void
6115 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
6116 {
6117   iface->send_event = gst_xvimagesink_navigation_send_event;
6118 }
6119
6120 #ifdef GST_EXT_XV_ENHANCEMENT
6121 static void
6122 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
6123 {
6124   XID pixmap_id = id;
6125   int i = 0;
6126   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6127   GstXPixmap *xpixmap = NULL;
6128   int (*handler) (Display *, XErrorEvent *);
6129
6130   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6131
6132   if (xvimagesink->subpicture)
6133    return;
6134
6135   /* If the element has not initialized the X11 context try to do so */
6136   if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6137     /* we have thrown a GST_ELEMENT_ERROR now */
6138     return;
6139   }
6140
6141   gst_xvimagesink_update_colorbalance (xvimagesink);
6142
6143   GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
6144
6145   /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
6146   if (pixmap_id == 0) {
6147     xvimagesink->current_pixmap_idx = -2;
6148     return;
6149   }
6150
6151   g_mutex_lock (xvimagesink->x_lock);
6152
6153   for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6154     if (!xvimagesink->xpixmap[i]) {
6155       Window root_window;
6156       int cur_win_x = 0;
6157       int cur_win_y = 0;
6158       unsigned int cur_win_width = 0;
6159       unsigned int cur_win_height = 0;
6160       unsigned int cur_win_border_width = 0;
6161       unsigned int cur_win_depth = 0;
6162
6163       GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
6164
6165       xpixmap = g_new0 (GstXPixmap, 1);
6166       if (xpixmap) {
6167         xpixmap->pixmap = pixmap_id;
6168
6169         /* Get root window and size of current window */
6170         XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
6171                      &cur_win_x, &cur_win_y, /* relative x, y */
6172                      &cur_win_width, &cur_win_height,
6173                      &cur_win_border_width, &cur_win_depth);
6174         if (!cur_win_width || !cur_win_height) {
6175           GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
6176           g_mutex_unlock (xvimagesink->x_lock);
6177           return;
6178         }
6179         xpixmap->width = cur_win_width;
6180         xpixmap->height = cur_win_height;
6181
6182         if (!xvimagesink->render_rect.w)
6183           xvimagesink->render_rect.w = cur_win_width;
6184         if (!xvimagesink->render_rect.h)
6185           xvimagesink->render_rect.h = cur_win_height;
6186
6187         /* Setting an error handler to catch failure */
6188         error_caught = FALSE;
6189         handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6190
6191         /* Create a GC */
6192         xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
6193
6194         XSync(xvimagesink->xcontext->disp, FALSE);
6195         if (error_caught) {
6196           GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
6197         }
6198         if (handler) {
6199           error_caught = FALSE;
6200           XSetErrorHandler (handler);
6201         }
6202
6203         xvimagesink->xpixmap[i] = xpixmap;
6204         xvimagesink->current_pixmap_idx = i;
6205       } else {
6206         GST_ERROR("failed to create xpixmap errno: %d", errno);
6207       }
6208
6209       g_mutex_unlock (xvimagesink->x_lock);
6210       return;
6211
6212     } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
6213       GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
6214       xvimagesink->current_pixmap_idx = i;
6215
6216       g_mutex_unlock (xvimagesink->x_lock);
6217       return;
6218
6219     } else {
6220       continue;
6221     }
6222   }
6223
6224   GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
6225   xvimagesink->current_pixmap_idx = -1;
6226
6227   g_mutex_unlock (xvimagesink->x_lock);
6228   return;
6229 }
6230 #endif /* GST_EXT_XV_ENHANCEMENT */
6231
6232 static void
6233 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
6234 {
6235   XID xwindow_id = id;
6236   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6237   GstXWindow *xwindow = NULL;
6238 #ifdef GST_EXT_XV_ENHANCEMENT
6239   GstState current_state = GST_STATE_NULL;
6240   int (*handler) (Display *, XErrorEvent *);
6241 #endif /* GST_EXT_XV_ENHANCEMENT */
6242
6243   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6244
6245   g_mutex_lock (xvimagesink->flow_lock);
6246
6247 #ifdef GST_EXT_XV_ENHANCEMENT
6248   gst_element_get_state(GST_ELEMENT(xvimagesink), &current_state, NULL, 0);
6249   GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
6250                                   xwindow_id, current_state);
6251 #endif /* GST_EXT_XV_ENHANCEMENT */
6252
6253   /* If we already use that window return */
6254   if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
6255     g_mutex_unlock (xvimagesink->flow_lock);
6256     return;
6257   }
6258
6259   /* If the element has not initialized the X11 context try to do so */
6260   if (!xvimagesink->xcontext &&
6261       !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6262     g_mutex_unlock (xvimagesink->flow_lock);
6263     /* we have thrown a GST_ELEMENT_ERROR now */
6264     return;
6265   }
6266
6267   gst_xvimagesink_update_colorbalance (xvimagesink);
6268
6269   /* Clear image pool as the images are unusable anyway */
6270   gst_xvimagesink_imagepool_clear (xvimagesink);
6271
6272   /* Clear the xvimage */
6273   if (xvimagesink->xvimage) {
6274     gst_xvimage_buffer_free (xvimagesink->xvimage);
6275     xvimagesink->xvimage = NULL;
6276   }
6277
6278   /* If a window is there already we destroy it */
6279   if (xvimagesink->xwindow) {
6280     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
6281     xvimagesink->xwindow = NULL;
6282   }
6283
6284   /* If the xid is 0 we go back to an internal window */
6285   if (xwindow_id == 0) {
6286     /* If no width/height caps nego did not happen window will be created
6287        during caps nego then */
6288 #ifdef GST_EXT_XV_ENHANCEMENT
6289   GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
6290     GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
6291 #endif /* GST_EXT_XV_ENHANCEMENT */
6292     if (GST_VIDEO_SINK_WIDTH (xvimagesink)
6293         && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
6294       xwindow =
6295           gst_xvimagesink_xwindow_new (xvimagesink,
6296           GST_VIDEO_SINK_WIDTH (xvimagesink),
6297           GST_VIDEO_SINK_HEIGHT (xvimagesink));
6298     }
6299   } else {
6300     XWindowAttributes attr;
6301
6302     xwindow = g_new0 (GstXWindow, 1);
6303     xwindow->win = xwindow_id;
6304
6305     /* Set the event we want to receive and create a GC */
6306     g_mutex_lock (xvimagesink->x_lock);
6307
6308     if(!xvimagesink->is_pixmap)
6309       XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
6310
6311     xwindow->width = attr.width;
6312     xwindow->height = attr.height;
6313     xwindow->internal = FALSE;
6314     if (!xvimagesink->have_render_rect) {
6315       xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
6316       xvimagesink->render_rect.w = attr.width;
6317       xvimagesink->render_rect.h = attr.height;
6318     }
6319     if (xvimagesink->handle_events) {
6320 #ifdef GST_EXT_XV_ENHANCEMENT
6321       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6322       XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6323           StructureNotifyMask | PointerMotionMask | KeyPressMask |
6324           KeyReleaseMask | PropertyChangeMask);
6325 #else
6326       XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6327           StructureNotifyMask | PointerMotionMask | KeyPressMask |
6328           KeyReleaseMask);
6329 #endif
6330
6331     }
6332 #ifdef GST_EXT_XV_ENHANCEMENT
6333     /* Setting an error handler to catch failure */
6334     error_caught = FALSE;
6335     handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6336 #endif
6337     xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
6338         xwindow->win, 0, NULL);
6339 #ifdef GST_EXT_XV_ENHANCEMENT
6340     XSync(xvimagesink->xcontext->disp, FALSE);
6341     if (error_caught) {
6342       GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
6343     }
6344     if (handler) {
6345       error_caught = FALSE;
6346       XSetErrorHandler (handler);
6347     }
6348 #endif
6349     g_mutex_unlock (xvimagesink->x_lock);
6350   }
6351
6352   if (xwindow)
6353     xvimagesink->xwindow = xwindow;
6354
6355 #ifdef GST_EXT_XV_ENHANCEMENT
6356   xvimagesink->xid_updated = TRUE;
6357 #endif /* GST_EXT_XV_ENHANCEMENT */
6358
6359   g_mutex_unlock (xvimagesink->flow_lock);
6360
6361 #ifdef GST_EXT_XV_ENHANCEMENT
6362   if (current_state == GST_STATE_PAUSED) {
6363     GstBuffer *last_buffer = NULL;
6364     g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
6365     GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
6366     if (last_buffer) {
6367       gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
6368       gst_buffer_unref(last_buffer);
6369       last_buffer = NULL;
6370     }
6371   }
6372 #endif /* GST_EXT_XV_ENHANCEMENT */
6373 }
6374
6375 static void
6376 gst_xvimagesink_expose (GstXOverlay * overlay)
6377 {
6378   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6379
6380   gst_xvimagesink_xwindow_update_geometry (xvimagesink);
6381 #ifdef GST_EXT_XV_ENHANCEMENT
6382   GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
6383 #endif /* GST_EXT_XV_ENHANCEMENT */
6384   gst_xvimagesink_xvimage_put (xvimagesink, NULL);
6385 }
6386
6387 static void
6388 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
6389     gboolean handle_events)
6390 {
6391   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6392
6393   xvimagesink->handle_events = handle_events;
6394
6395   g_mutex_lock (xvimagesink->flow_lock);
6396
6397   if (G_UNLIKELY (!xvimagesink->xwindow)) {
6398     g_mutex_unlock (xvimagesink->flow_lock);
6399     return;
6400   }
6401
6402   g_mutex_lock (xvimagesink->x_lock);
6403
6404   if (handle_events) {
6405     if (xvimagesink->xwindow->internal) {
6406 #ifdef GST_EXT_XV_ENHANCEMENT
6407       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6408 #endif
6409       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6410 #ifdef GST_EXT_XV_ENHANCEMENT
6411           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6412 #else /* GST_EXT_XV_ENHANCEMENT */
6413           ExposureMask | StructureNotifyMask | PointerMotionMask |
6414 #endif /* GST_EXT_XV_ENHANCEMENT */
6415           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
6416     } else {
6417 #ifdef GST_EXT_XV_ENHANCEMENT
6418       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6419 #endif
6420       XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6421 #ifdef GST_EXT_XV_ENHANCEMENT
6422           ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6423 #else /* GST_EXT_XV_ENHANCEMENT */
6424           ExposureMask | StructureNotifyMask | PointerMotionMask |
6425 #endif /* GST_EXT_XV_ENHANCEMENT */
6426           KeyPressMask | KeyReleaseMask);
6427     }
6428   } else {
6429     XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
6430   }
6431
6432   g_mutex_unlock (xvimagesink->x_lock);
6433
6434   g_mutex_unlock (xvimagesink->flow_lock);
6435 }
6436
6437 static void
6438 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
6439     gint width, gint height)
6440 {
6441   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6442
6443   /* FIXME: how about some locking? */
6444   if (width >= 0 && height >= 0) {
6445     xvimagesink->render_rect.x = x;
6446     xvimagesink->render_rect.y = y;
6447     xvimagesink->render_rect.w = width;
6448     xvimagesink->render_rect.h = height;
6449     xvimagesink->have_render_rect = TRUE;
6450   } else {
6451     xvimagesink->render_rect.x = 0;
6452     xvimagesink->render_rect.y = 0;
6453     xvimagesink->render_rect.w = xvimagesink->xwindow->width;
6454     xvimagesink->render_rect.h = xvimagesink->xwindow->height;
6455     xvimagesink->have_render_rect = FALSE;
6456   }
6457 }
6458
6459 static void
6460 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
6461 {
6462   iface->set_window_handle = gst_xvimagesink_set_window_handle;
6463   iface->expose = gst_xvimagesink_expose;
6464   iface->handle_events = gst_xvimagesink_set_event_handling;
6465   iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
6466 }
6467
6468 static const GList *
6469 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
6470 {
6471   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6472
6473   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
6474
6475   if (xvimagesink->xcontext)
6476     return xvimagesink->xcontext->channels_list;
6477   else
6478     return NULL;
6479 }
6480
6481 static void
6482 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
6483     GstColorBalanceChannel * channel, gint value)
6484 {
6485   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6486
6487   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6488   g_return_if_fail (channel->label != NULL);
6489
6490   xvimagesink->cb_changed = TRUE;
6491
6492   /* Normalize val to [-1000, 1000] */
6493   value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
6494       (double) (channel->max_value - channel->min_value));
6495
6496   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6497     xvimagesink->hue = value;
6498   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6499     xvimagesink->saturation = value;
6500   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6501     xvimagesink->contrast = value;
6502   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6503     xvimagesink->brightness = value;
6504   } else {
6505     g_warning ("got an unknown channel %s", channel->label);
6506     return;
6507   }
6508
6509   gst_xvimagesink_update_colorbalance (xvimagesink);
6510 }
6511
6512 static gint
6513 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
6514     GstColorBalanceChannel * channel)
6515 {
6516   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6517   gint value = 0;
6518
6519   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
6520   g_return_val_if_fail (channel->label != NULL, 0);
6521
6522   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6523     value = xvimagesink->hue;
6524   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6525     value = xvimagesink->saturation;
6526   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6527     value = xvimagesink->contrast;
6528   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6529     value = xvimagesink->brightness;
6530   } else {
6531     g_warning ("got an unknown channel %s", channel->label);
6532   }
6533
6534   /* Normalize val to [channel->min_value, channel->max_value] */
6535   value = channel->min_value + (channel->max_value - channel->min_value) *
6536       (value + 1000) / 2000;
6537
6538   return value;
6539 }
6540
6541 static void
6542 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
6543 {
6544   GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
6545   iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
6546   iface->set_value = gst_xvimagesink_colorbalance_set_value;
6547   iface->get_value = gst_xvimagesink_colorbalance_get_value;
6548 }
6549
6550 static const GList *
6551 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
6552 {
6553   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
6554   static GList *list = NULL;
6555
6556   if (!list) {
6557     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
6558     list =
6559         g_list_append (list, g_object_class_find_property (klass,
6560             "autopaint-colorkey"));
6561     list =
6562         g_list_append (list, g_object_class_find_property (klass,
6563             "double-buffer"));
6564     list =
6565         g_list_append (list, g_object_class_find_property (klass, "colorkey"));
6566   }
6567
6568   return list;
6569 }
6570
6571 static void
6572 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
6573     guint prop_id, const GParamSpec * pspec)
6574 {
6575   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6576
6577   switch (prop_id) {
6578     case PROP_DEVICE:
6579     case PROP_AUTOPAINT_COLORKEY:
6580     case PROP_DOUBLE_BUFFER:
6581     case PROP_COLORKEY:
6582       GST_DEBUG_OBJECT (xvimagesink,
6583           "probing device list and get capabilities");
6584       if (!xvimagesink->xcontext) {
6585         GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
6586         xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
6587       }
6588       break;
6589     default:
6590       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6591       break;
6592   }
6593 }
6594
6595 static gboolean
6596 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
6597     guint prop_id, const GParamSpec * pspec)
6598 {
6599   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6600   gboolean ret = FALSE;
6601
6602   switch (prop_id) {
6603     case PROP_DEVICE:
6604     case PROP_AUTOPAINT_COLORKEY:
6605     case PROP_DOUBLE_BUFFER:
6606     case PROP_COLORKEY:
6607       if (xvimagesink->xcontext != NULL) {
6608         ret = FALSE;
6609       } else {
6610         ret = TRUE;
6611       }
6612       break;
6613     default:
6614       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6615       break;
6616   }
6617
6618   return ret;
6619 }
6620
6621 static GValueArray *
6622 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
6623     guint prop_id, const GParamSpec * pspec)
6624 {
6625   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6626   GValueArray *array = NULL;
6627
6628   if (G_UNLIKELY (!xvimagesink->xcontext)) {
6629     GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
6630         "get values");
6631     goto beach;
6632   }
6633
6634   switch (prop_id) {
6635     case PROP_DEVICE:
6636     {
6637       guint i;
6638       GValue value = { 0 };
6639
6640       array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
6641       g_value_init (&value, G_TYPE_STRING);
6642
6643       for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
6644         gchar *adaptor_id_s = g_strdup_printf ("%u", i);
6645
6646         g_value_set_string (&value, adaptor_id_s);
6647         g_value_array_append (array, &value);
6648         g_free (adaptor_id_s);
6649       }
6650       g_value_unset (&value);
6651       break;
6652     }
6653     case PROP_AUTOPAINT_COLORKEY:
6654       if (xvimagesink->have_autopaint_colorkey) {
6655         GValue value = { 0 };
6656
6657         array = g_value_array_new (2);
6658         g_value_init (&value, G_TYPE_BOOLEAN);
6659         g_value_set_boolean (&value, FALSE);
6660         g_value_array_append (array, &value);
6661         g_value_set_boolean (&value, TRUE);
6662         g_value_array_append (array, &value);
6663         g_value_unset (&value);
6664       }
6665       break;
6666     case PROP_DOUBLE_BUFFER:
6667       if (xvimagesink->have_double_buffer) {
6668         GValue value = { 0 };
6669
6670         array = g_value_array_new (2);
6671         g_value_init (&value, G_TYPE_BOOLEAN);
6672         g_value_set_boolean (&value, FALSE);
6673         g_value_array_append (array, &value);
6674         g_value_set_boolean (&value, TRUE);
6675         g_value_array_append (array, &value);
6676         g_value_unset (&value);
6677       }
6678       break;
6679     case PROP_COLORKEY:
6680       if (xvimagesink->have_colorkey) {
6681         GValue value = { 0 };
6682
6683         array = g_value_array_new (1);
6684         g_value_init (&value, GST_TYPE_INT_RANGE);
6685         gst_value_set_int_range (&value, 0, 0xffffff);
6686         g_value_array_append (array, &value);
6687         g_value_unset (&value);
6688       }
6689       break;
6690     default:
6691       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6692       break;
6693   }
6694
6695 beach:
6696   return array;
6697 }
6698
6699 static void
6700 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
6701     iface)
6702 {
6703   iface->get_properties = gst_xvimagesink_probe_get_properties;
6704   iface->probe_property = gst_xvimagesink_probe_probe_property;
6705   iface->needs_probe = gst_xvimagesink_probe_needs_probe;
6706   iface->get_values = gst_xvimagesink_probe_get_values;
6707 }
6708
6709 /* =========================================== */
6710 /*                                             */
6711 /*              Init & Class init              */
6712 /*                                             */
6713 /* =========================================== */
6714
6715 static void
6716 gst_xvimagesink_set_property (GObject * object, guint prop_id,
6717     const GValue * value, GParamSpec * pspec)
6718 {
6719   GstXvImageSink *xvimagesink;
6720
6721   g_return_if_fail (GST_IS_XVIMAGESINK (object));
6722
6723   xvimagesink = GST_XVIMAGESINK (object);
6724
6725   switch (prop_id) {
6726     case PROP_HUE:
6727       xvimagesink->hue = g_value_get_int (value);
6728       xvimagesink->cb_changed = TRUE;
6729       gst_xvimagesink_update_colorbalance (xvimagesink);
6730       break;
6731     case PROP_CONTRAST:
6732       xvimagesink->contrast = g_value_get_int (value);
6733       xvimagesink->cb_changed = TRUE;
6734       gst_xvimagesink_update_colorbalance (xvimagesink);
6735       break;
6736     case PROP_BRIGHTNESS:
6737       xvimagesink->brightness = g_value_get_int (value);
6738       xvimagesink->cb_changed = TRUE;
6739       gst_xvimagesink_update_colorbalance (xvimagesink);
6740       break;
6741     case PROP_SATURATION:
6742       xvimagesink->saturation = g_value_get_int (value);
6743       xvimagesink->cb_changed = TRUE;
6744       gst_xvimagesink_update_colorbalance (xvimagesink);
6745       break;
6746     case PROP_DISPLAY:
6747       xvimagesink->display_name = g_strdup (g_value_get_string (value));
6748       break;
6749     case PROP_SYNCHRONOUS:
6750       xvimagesink->synchronous = g_value_get_boolean (value);
6751       if (xvimagesink->xcontext) {
6752         XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
6753         GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
6754             xvimagesink->synchronous ? "TRUE" : "FALSE");
6755       }
6756       break;
6757     case PROP_PIXEL_ASPECT_RATIO:
6758       g_free (xvimagesink->par);
6759       xvimagesink->par = g_new0 (GValue, 1);
6760       g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
6761       if (!g_value_transform (value, xvimagesink->par)) {
6762         g_warning ("Could not transform string to aspect ratio");
6763         gst_value_set_fraction (xvimagesink->par, 1, 1);
6764       }
6765       GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
6766           gst_value_get_fraction_numerator (xvimagesink->par),
6767           gst_value_get_fraction_denominator (xvimagesink->par));
6768       break;
6769     case PROP_FORCE_ASPECT_RATIO:
6770       xvimagesink->keep_aspect = g_value_get_boolean (value);
6771       break;
6772     case PROP_HANDLE_EVENTS:
6773       gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
6774           g_value_get_boolean (value));
6775       gst_xvimagesink_manage_event_thread (xvimagesink);
6776       break;
6777     case PROP_DEVICE:
6778       xvimagesink->adaptor_no = atoi (g_value_get_string (value));
6779       break;
6780     case PROP_HANDLE_EXPOSE:
6781       xvimagesink->handle_expose = g_value_get_boolean (value);
6782       gst_xvimagesink_manage_event_thread (xvimagesink);
6783       break;
6784     case PROP_DOUBLE_BUFFER:
6785       xvimagesink->double_buffer = g_value_get_boolean (value);
6786       break;
6787     case PROP_AUTOPAINT_COLORKEY:
6788       xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
6789       break;
6790     case PROP_COLORKEY:
6791       xvimagesink->colorkey = g_value_get_int (value);
6792       break;
6793     case PROP_DRAW_BORDERS:
6794       xvimagesink->draw_borders = g_value_get_boolean (value);
6795       break;
6796 #ifdef GST_EXT_XV_ENHANCEMENT
6797     case PROP_DISPLAY_MODE:
6798     {
6799       int set_mode = g_value_get_enum (value);
6800       g_mutex_lock(xvimagesink->flow_lock);
6801       xvimagesink->display_mode = set_mode;
6802       if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) {
6803         if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) {
6804           if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) {
6805             set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6806           } else {
6807             GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6808           }
6809         } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){
6810           if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
6811             set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6812           } else {
6813             GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6814           }
6815         } else {
6816           GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode);
6817         }
6818       }
6819       g_mutex_unlock(xvimagesink->flow_lock);
6820     }
6821       break;
6822     case PROP_CSC_RANGE:
6823     {
6824       int set_range = g_value_get_enum (value);
6825
6826       g_mutex_lock(xvimagesink->flow_lock);
6827       g_mutex_lock(xvimagesink->x_lock);
6828
6829       if (xvimagesink->csc_range != set_range) {
6830         if (xvimagesink->xcontext && !xvimagesink->subpicture) {
6831           /* set color space range */
6832           if (set_csc_range(xvimagesink->xcontext, set_range)) {
6833             xvimagesink->csc_range = set_range;
6834           } else {
6835             GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
6836           }
6837         } else {
6838           /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6839           GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
6840           xvimagesink->csc_range = set_range;
6841         }
6842       } else if (xvimagesink->subpicture) {
6843         GST_WARNING("skip to set csc range, because it is subpicture format.");
6844       } else {
6845         GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
6846       }
6847
6848       g_mutex_unlock(xvimagesink->x_lock);
6849       g_mutex_unlock(xvimagesink->flow_lock);
6850     }
6851       break;
6852     case PROP_DISPLAY_GEOMETRY_METHOD:
6853       xvimagesink->display_geometry_method = g_value_get_enum (value);
6854       GST_LOG("Overlay geometry changed. update it");
6855       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6856         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6857       }
6858       break;
6859     case PROP_FLIP:
6860       xvimagesink->flip = g_value_get_enum(value);
6861       break;
6862     case PROP_ROTATE_ANGLE:
6863       xvimagesink->rotate_angle = g_value_get_enum (value);
6864       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6865         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6866       }
6867       break;
6868     case PROP_VISIBLE:
6869       g_mutex_lock( xvimagesink->flow_lock );
6870       g_mutex_lock( xvimagesink->x_lock );
6871
6872       GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
6873
6874       if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
6875         if (xvimagesink->xcontext) {
6876 #if 0
6877           Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
6878                                           "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
6879           if (atom_stream != None) {
6880             GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
6881             if (XvSetPortAttribute(xvimagesink->xcontext->disp,
6882                                    xvimagesink->xcontext->xv_port_id,
6883                                    atom_stream, 0 ) != Success) {
6884               GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
6885             }
6886           }
6887 #endif
6888           xvimagesink->visible = g_value_get_boolean (value);
6889           if ( xvimagesink->get_pixmap_cb ) {
6890             if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6891               XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6892               }
6893           } else {
6894             if(xvimagesink->xwindow->win)
6895               XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
6896           }
6897           XSync( xvimagesink->xcontext->disp, FALSE );
6898         } else {
6899           GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
6900           xvimagesink->visible = g_value_get_boolean (value);
6901         }
6902       } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
6903         xvimagesink->visible = g_value_get_boolean (value);
6904         g_mutex_unlock( xvimagesink->x_lock );
6905         g_mutex_unlock( xvimagesink->flow_lock );
6906         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6907         g_mutex_lock( xvimagesink->flow_lock );
6908         g_mutex_lock( xvimagesink->x_lock );
6909       }
6910
6911       GST_INFO("set visible(%d) done", xvimagesink->visible);
6912
6913       g_mutex_unlock( xvimagesink->x_lock );
6914       g_mutex_unlock( xvimagesink->flow_lock );
6915       break;
6916     case PROP_ZOOM:
6917       xvimagesink->zoom = g_value_get_float (value);
6918       break;
6919     case PROP_ZOOM_POS_X:
6920       xvimagesink->zoom_pos_x = g_value_get_int (value);
6921       break;
6922     case PROP_ZOOM_POS_Y:
6923       xvimagesink->zoom_pos_y = g_value_get_int (value);
6924       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6925         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6926       }
6927       break;
6928     case PROP_ORIENTATION:
6929       xvimagesink->orientation = g_value_get_enum (value);
6930       GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
6931       break;
6932     case PROP_DST_ROI_MODE:
6933       xvimagesink->dst_roi_mode = g_value_get_enum (value);
6934       GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
6935       break;
6936     case PROP_DST_ROI_X:
6937       xvimagesink->dst_roi.x = g_value_get_int (value);
6938       break;
6939     case PROP_DST_ROI_Y:
6940       xvimagesink->dst_roi.y = g_value_get_int (value);
6941       break;
6942     case PROP_DST_ROI_W:
6943       xvimagesink->dst_roi.w = g_value_get_int (value);
6944       break;
6945     case PROP_DST_ROI_H:
6946       xvimagesink->dst_roi.h = g_value_get_int (value);
6947       break;
6948     case PROP_SRC_CROP_X:
6949       xvimagesink->src_crop.x = g_value_get_int (value);
6950       break;
6951     case PROP_SRC_CROP_Y:
6952       xvimagesink->src_crop.y = g_value_get_int (value);
6953       break;
6954     case PROP_SRC_CROP_W:
6955       xvimagesink->src_crop.w = g_value_get_int (value);
6956       break;
6957     case PROP_SRC_CROP_H:
6958       xvimagesink->src_crop.h = g_value_get_int (value);
6959       break;
6960     case PROP_STOP_VIDEO:
6961       xvimagesink->stop_video = g_value_get_int (value);
6962       g_mutex_lock( xvimagesink->flow_lock );
6963
6964       if( xvimagesink->stop_video )
6965       {
6966         if ( xvimagesink->get_pixmap_cb ) {
6967           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6968             g_mutex_lock (xvimagesink->x_lock);
6969             GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6970             XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6971             g_mutex_unlock (xvimagesink->x_lock);
6972           }
6973         } else {
6974           GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
6975           gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6976         }
6977       }
6978
6979       g_mutex_unlock( xvimagesink->flow_lock );
6980       break;
6981     case PROP_PIXMAP_CB:
6982     {
6983       void *cb_func;
6984       cb_func = g_value_get_pointer(value);
6985       if (cb_func) {
6986         if (xvimagesink->get_pixmap_cb) {
6987           int i = 0;
6988           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6989             g_mutex_lock (xvimagesink->x_lock);
6990             GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6991             XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6992             g_mutex_unlock (xvimagesink->x_lock);
6993           }
6994           for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6995             if (xvimagesink->xpixmap[i]) {
6996               gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6997               xvimagesink->xpixmap[i] = NULL;
6998             }
6999           }
7000         }
7001         xvimagesink->get_pixmap_cb = cb_func;
7002         GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
7003       }
7004       break;
7005     }
7006     case PROP_PIXMAP_CB_USER_DATA:
7007     {
7008       void *user_data;
7009       user_data = g_value_get_pointer(value);
7010       if (user_data) {
7011         xvimagesink->get_pixmap_cb_user_data = user_data;
7012         GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
7013       }
7014       break;
7015     }
7016     case PROP_SUBPICTURE:
7017       xvimagesink->subpicture = g_value_get_boolean (value);
7018     break;
7019     case PROP_EXTERNAL_WIDTH:
7020     {
7021       xvimagesink->external_width = g_value_get_int (value);
7022       GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width);
7023       break;
7024     }
7025     case PROP_EXTERNAL_HEIGHT:
7026     {
7027       xvimagesink->external_height = g_value_get_int (value);
7028       GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height);
7029       break;
7030     }
7031     case PROP_ENABLE_FLUSH_BUFFER:
7032       xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
7033       break;
7034     case PROP_PIXMAP:
7035       xvimagesink->is_pixmap = g_value_get_boolean(value);
7036       break;
7037     case PROP_HIDED_WINDOW:
7038     {
7039       xvimagesink->is_hided_subpicture = g_value_get_boolean(value);
7040       GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture);
7041       break;
7042     }
7043     case PROP_QUICKPANEL_ON:
7044     {
7045       xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value);
7046       GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture);
7047       break;
7048     }
7049     case PROP_MULTIWINDOW_ACTIVE:
7050     {
7051       xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value);
7052       GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture);
7053       break;
7054     }
7055     case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7056     {
7057       xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value);
7058       GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post);
7059       if(xvimagesink->keep_external_fullscreen_post) {
7060         Atom atom_keep_ext;
7061         atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False);
7062         if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success)
7063         {
7064           GST_WARNING("set atom_keep_ext fail");
7065         }
7066       }
7067       break;
7068     }
7069     case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7070     {
7071       xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value);
7072       GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev);
7073       break;
7074     }
7075
7076 #endif /* GST_EXT_XV_ENHANCEMENT */
7077     default:
7078       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7079       break;
7080   }
7081 }
7082
7083 static void
7084 gst_xvimagesink_get_property (GObject * object, guint prop_id,
7085     GValue * value, GParamSpec * pspec)
7086 {
7087   GstXvImageSink *xvimagesink;
7088
7089   g_return_if_fail (GST_IS_XVIMAGESINK (object));
7090
7091   xvimagesink = GST_XVIMAGESINK (object);
7092
7093   switch (prop_id) {
7094     case PROP_HUE:
7095       g_value_set_int (value, xvimagesink->hue);
7096       break;
7097     case PROP_CONTRAST:
7098       g_value_set_int (value, xvimagesink->contrast);
7099       break;
7100     case PROP_BRIGHTNESS:
7101       g_value_set_int (value, xvimagesink->brightness);
7102       break;
7103     case PROP_SATURATION:
7104       g_value_set_int (value, xvimagesink->saturation);
7105       break;
7106     case PROP_DISPLAY:
7107       g_value_set_string (value, xvimagesink->display_name);
7108       break;
7109     case PROP_SYNCHRONOUS:
7110       g_value_set_boolean (value, xvimagesink->synchronous);
7111       break;
7112     case PROP_PIXEL_ASPECT_RATIO:
7113       if (xvimagesink->par)
7114         g_value_transform (xvimagesink->par, value);
7115       break;
7116     case PROP_FORCE_ASPECT_RATIO:
7117       g_value_set_boolean (value, xvimagesink->keep_aspect);
7118       break;
7119     case PROP_HANDLE_EVENTS:
7120       g_value_set_boolean (value, xvimagesink->handle_events);
7121       break;
7122     case PROP_DEVICE:
7123     {
7124       char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
7125
7126       g_value_set_string (value, adaptor_no_s);
7127       g_free (adaptor_no_s);
7128       break;
7129     }
7130     case PROP_DEVICE_NAME:
7131       if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
7132         g_value_set_string (value,
7133             xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
7134       } else {
7135         g_value_set_string (value, NULL);
7136       }
7137       break;
7138     case PROP_HANDLE_EXPOSE:
7139       g_value_set_boolean (value, xvimagesink->handle_expose);
7140       break;
7141     case PROP_DOUBLE_BUFFER:
7142       g_value_set_boolean (value, xvimagesink->double_buffer);
7143       break;
7144     case PROP_AUTOPAINT_COLORKEY:
7145       g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
7146       break;
7147     case PROP_COLORKEY:
7148       g_value_set_int (value, xvimagesink->colorkey);
7149       break;
7150     case PROP_DRAW_BORDERS:
7151       g_value_set_boolean (value, xvimagesink->draw_borders);
7152       break;
7153     case PROP_WINDOW_WIDTH:
7154       if (xvimagesink->xwindow)
7155         g_value_set_uint64 (value, xvimagesink->xwindow->width);
7156       else
7157         g_value_set_uint64 (value, 0);
7158       break;
7159     case PROP_WINDOW_HEIGHT:
7160       if (xvimagesink->xwindow)
7161         g_value_set_uint64 (value, xvimagesink->xwindow->height);
7162       else
7163         g_value_set_uint64 (value, 0);
7164       break;
7165 #ifdef GST_EXT_XV_ENHANCEMENT
7166     case PROP_DISPLAY_MODE:
7167       g_value_set_enum (value, xvimagesink->display_mode);
7168       break;
7169     case PROP_CSC_RANGE:
7170       g_value_set_enum (value, xvimagesink->csc_range);
7171       break;
7172     case PROP_DISPLAY_GEOMETRY_METHOD:
7173       g_value_set_enum (value, xvimagesink->display_geometry_method);
7174       break;
7175     case PROP_FLIP:
7176       g_value_set_enum(value, xvimagesink->flip);
7177       break;
7178     case PROP_ROTATE_ANGLE:
7179       g_value_set_enum (value, xvimagesink->rotate_angle);
7180       break;
7181     case PROP_VISIBLE:
7182       g_value_set_boolean (value, xvimagesink->visible);
7183       break;
7184     case PROP_ZOOM:
7185       g_value_set_float (value, xvimagesink->zoom);
7186       break;
7187     case PROP_ZOOM_POS_X:
7188       g_value_set_int (value, xvimagesink->zoom_pos_x);
7189       break;
7190     case PROP_ZOOM_POS_Y:
7191       g_value_set_int (value, xvimagesink->zoom_pos_y);
7192       break;
7193     case PROP_ORIENTATION:
7194       g_value_set_enum (value, xvimagesink->orientation);
7195       break;
7196     case PROP_DST_ROI_MODE:
7197       g_value_set_enum (value, xvimagesink->dst_roi_mode);
7198       break;
7199     case PROP_DST_ROI_X:
7200       g_value_set_int (value, xvimagesink->dst_roi.x);
7201       break;
7202     case PROP_DST_ROI_Y:
7203       g_value_set_int (value, xvimagesink->dst_roi.y);
7204       break;
7205     case PROP_DST_ROI_W:
7206       g_value_set_int (value, xvimagesink->dst_roi.w);
7207       break;
7208     case PROP_DST_ROI_H:
7209       g_value_set_int (value, xvimagesink->dst_roi.h);
7210       break;
7211     case PROP_SRC_CROP_X:
7212       g_value_set_int (value, xvimagesink->src_crop.x);
7213       break;
7214     case PROP_SRC_CROP_Y:
7215       g_value_set_int (value, xvimagesink->src_crop.y);
7216       break;
7217     case PROP_SRC_CROP_W:
7218       g_value_set_int (value, xvimagesink->src_crop.w);
7219       break;
7220     case PROP_SRC_CROP_H:
7221       g_value_set_int (value, xvimagesink->src_crop.h);
7222       break;
7223     case PROP_STOP_VIDEO:
7224       g_value_set_int (value, xvimagesink->stop_video);
7225       break;
7226     case PROP_PIXMAP_CB:
7227       g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
7228       break;
7229     case PROP_PIXMAP_CB_USER_DATA:
7230       g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
7231       break;
7232     case PROP_SUBPICTURE:
7233       g_value_set_boolean (value, xvimagesink->subpicture);
7234       break;
7235     case PROP_EXTERNAL_WIDTH:
7236       g_value_set_int (value, xvimagesink->external_width);
7237       break;
7238     case PROP_EXTERNAL_HEIGHT:
7239       g_value_set_int (value, xvimagesink->external_height);
7240       break;
7241     case PROP_ENABLE_FLUSH_BUFFER:
7242       g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
7243       break;
7244     case PROP_PIXMAP:
7245       g_value_set_boolean(value, xvimagesink->is_pixmap);
7246       break;
7247     case PROP_HIDED_WINDOW:
7248       g_value_set_boolean(value, xvimagesink->is_hided_subpicture);
7249       break;
7250     case PROP_QUICKPANEL_ON:
7251       g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture);
7252       break;
7253     case PROP_MULTIWINDOW_ACTIVE:
7254       g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture);
7255       break;
7256     case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7257       g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post);
7258      break;
7259     case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7260       g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev);
7261      break;
7262 #endif /* GST_EXT_XV_ENHANCEMENT */
7263     default:
7264       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7265       break;
7266   }
7267 }
7268
7269 static void
7270 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
7271 {
7272   GThread *thread;
7273
7274   GST_OBJECT_LOCK (xvimagesink);
7275   xvimagesink->running = FALSE;
7276   /* grab thread and mark it as NULL */
7277   thread = xvimagesink->event_thread;
7278   xvimagesink->event_thread = NULL;
7279   GST_OBJECT_UNLOCK (xvimagesink);
7280
7281   /* invalidate the pool, current allocations continue, new buffer_alloc fails
7282    * with wrong_state */
7283   g_mutex_lock (xvimagesink->pool_lock);
7284   xvimagesink->pool_invalid = TRUE;
7285   g_mutex_unlock (xvimagesink->pool_lock);
7286
7287   /* Wait for our event thread to finish before we clean up our stuff. */
7288   if (thread)
7289     g_thread_join (thread);
7290
7291   if (xvimagesink->cur_image) {
7292     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
7293     xvimagesink->cur_image = NULL;
7294   }
7295   if (xvimagesink->xvimage) {
7296     gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
7297     xvimagesink->xvimage = NULL;
7298   }
7299
7300   gst_xvimagesink_imagepool_clear (xvimagesink);
7301
7302   if (xvimagesink->xwindow) {
7303     gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
7304     gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
7305     xvimagesink->xwindow = NULL;
7306   }
7307 #ifdef GST_EXT_XV_ENHANCEMENT
7308   if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
7309       GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7310       XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7311       xvimagesink->pixmap_for_subpicture = 0;
7312   }
7313
7314   if (xvimagesink->get_pixmap_cb) {
7315     int i = 0;
7316     if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
7317       g_mutex_lock (xvimagesink->x_lock);
7318       GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
7319       XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
7320       g_mutex_unlock (xvimagesink->x_lock);
7321     }
7322     for (i = 0; i < MAX_PIXMAP_NUM; i++) {
7323       if (xvimagesink->xpixmap[i]) {
7324         gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
7325         xvimagesink->xpixmap[i] = NULL;
7326       }
7327     }
7328     xvimagesink->get_pixmap_cb = NULL;
7329     xvimagesink->get_pixmap_cb_user_data = NULL;
7330   }
7331 #endif /* GST_EXT_XV_ENHANCEMENT */
7332   xvimagesink->render_rect.x = xvimagesink->render_rect.y =
7333       xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
7334   xvimagesink->have_render_rect = FALSE;
7335
7336   gst_xvimagesink_xcontext_clear (xvimagesink);
7337 }
7338
7339 /* Finalize is called only once, dispose can be called multiple times.
7340  * We use mutexes and don't reset stuff to NULL here so let's register
7341  * as a finalize. */
7342 static void
7343 gst_xvimagesink_finalize (GObject * object)
7344 {
7345   GstXvImageSink *xvimagesink;
7346
7347   xvimagesink = GST_XVIMAGESINK (object);
7348
7349   gst_xvimagesink_reset (xvimagesink);
7350
7351   if (xvimagesink->display_name) {
7352     g_free (xvimagesink->display_name);
7353     xvimagesink->display_name = NULL;
7354   }
7355
7356   if (xvimagesink->par) {
7357     g_free (xvimagesink->par);
7358     xvimagesink->par = NULL;
7359   }
7360   if (xvimagesink->x_lock) {
7361     g_mutex_free (xvimagesink->x_lock);
7362     xvimagesink->x_lock = NULL;
7363   }
7364   if (xvimagesink->flow_lock) {
7365     g_mutex_free (xvimagesink->flow_lock);
7366     xvimagesink->flow_lock = NULL;
7367   }
7368   if (xvimagesink->pool_lock) {
7369     g_mutex_free (xvimagesink->pool_lock);
7370     xvimagesink->pool_lock = NULL;
7371   }
7372 #ifdef GST_EXT_XV_ENHANCEMENT
7373   if (xvimagesink->display_buffer_lock) {
7374     g_mutex_free (xvimagesink->display_buffer_lock);
7375     xvimagesink->display_buffer_lock = NULL;
7376   }
7377 #endif /* GST_EXT_XV_ENHANCEMENT */
7378
7379   g_free (xvimagesink->media_title);
7380
7381   G_OBJECT_CLASS (parent_class)->finalize (object);
7382 }
7383
7384 static void
7385 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
7386     GstXvImageSinkClass * xvimagesinkclass)
7387 {
7388 #ifdef GST_EXT_XV_ENHANCEMENT
7389   int i;
7390   int j;
7391 #endif /* GST_EXT_XV_ENHANCEMENT */
7392
7393   xvimagesink->display_name = NULL;
7394   xvimagesink->adaptor_no = 0;
7395   xvimagesink->xcontext = NULL;
7396   xvimagesink->xwindow = NULL;
7397   xvimagesink->xvimage = NULL;
7398   xvimagesink->cur_image = NULL;
7399
7400   xvimagesink->hue = xvimagesink->saturation = 0;
7401   xvimagesink->contrast = xvimagesink->brightness = 0;
7402   xvimagesink->cb_changed = FALSE;
7403
7404   xvimagesink->fps_n = 0;
7405   xvimagesink->fps_d = 0;
7406   xvimagesink->video_width = 0;
7407   xvimagesink->video_height = 0;
7408
7409   xvimagesink->x_lock = g_mutex_new ();
7410   xvimagesink->flow_lock = g_mutex_new ();
7411
7412   xvimagesink->image_pool = NULL;
7413   xvimagesink->pool_lock = g_mutex_new ();
7414
7415   xvimagesink->synchronous = FALSE;
7416   xvimagesink->double_buffer = TRUE;
7417   xvimagesink->running = FALSE;
7418   xvimagesink->keep_aspect = FALSE;
7419   xvimagesink->handle_events = TRUE;
7420   xvimagesink->par = NULL;
7421   xvimagesink->handle_expose = TRUE;
7422   xvimagesink->autopaint_colorkey = TRUE;
7423
7424   /* on 16bit displays this becomes r,g,b = 1,2,3
7425    * on 24bit displays this becomes r,g,b = 8,8,16
7426    * as a port atom value
7427    */
7428   xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
7429   xvimagesink->draw_borders = TRUE;
7430
7431 #ifdef GST_EXT_XV_ENHANCEMENT
7432   xvimagesink->xid_updated = FALSE;
7433   xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE;
7434   xvimagesink->csc_range = CSC_RANGE_NARROW;
7435   xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
7436   xvimagesink->flip = DEF_DISPLAY_FLIP;
7437   xvimagesink->rotate_angle = DEGREE_270;
7438   xvimagesink->visible = TRUE;
7439   xvimagesink->zoom = 1.0;
7440   xvimagesink->zoom_pos_x = -1;
7441   xvimagesink->zoom_pos_y = -1;
7442   xvimagesink->rotation = -1;
7443   xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
7444   xvimagesink->orientation = DEGREE_0;
7445   xvimagesink->dst_roi.x = 0;
7446   xvimagesink->dst_roi.y = 0;
7447   xvimagesink->dst_roi.w = 0;
7448   xvimagesink->dst_roi.h = 0;
7449   xvimagesink->src_crop.x = 0;
7450   xvimagesink->src_crop.y = 0;
7451   xvimagesink->src_crop.w = 0;
7452   xvimagesink->src_crop.h = 0;
7453   xvimagesink->xim_transparenter = NULL;
7454   xvimagesink->scr_w = 0;
7455   xvimagesink->scr_h = 0;
7456   xvimagesink->aligned_width = 0;
7457   xvimagesink->aligned_height = 0;
7458   xvimagesink->stop_video = FALSE;
7459   xvimagesink->is_hided = FALSE;
7460   xvimagesink->is_quick_panel_on = FALSE;
7461   xvimagesink->is_multi_window = FALSE;
7462   xvimagesink->drm_fd = -1;
7463   xvimagesink->current_pixmap_idx = -1;
7464   xvimagesink->get_pixmap_cb = NULL;
7465   xvimagesink->get_pixmap_cb_user_data = NULL;
7466
7467   for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
7468     xvimagesink->displaying_buffers[i].buffer = NULL;
7469     for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
7470       xvimagesink->displaying_buffers[i].gem_name[j] = 0;
7471       xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
7472       xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
7473       xvimagesink->displaying_buffers[i].ref_count = 0;
7474     }
7475   }
7476
7477   xvimagesink->display_buffer_lock = g_mutex_new ();
7478
7479   xvimagesink->displayed_buffer_count = 0;
7480   xvimagesink->displaying_buffer_count = 0;
7481   xvimagesink->is_zero_copy_format = FALSE;
7482   xvimagesink->secure_path = SECURE_PATH_INIT;
7483   xvimagesink->drm_level = DRM_LEVEL_0;
7484   xvimagesink->last_added_buffer_index = -1;
7485   xvimagesink->bufmgr = NULL;
7486   xvimagesink->flush_buffer = NULL;
7487   xvimagesink->enable_flush_buffer = TRUE;
7488   xvimagesink->pixmap_for_subpicture = 0;
7489   xvimagesink->is_subpicture_format = FALSE;
7490   xvimagesink->set_overlay_for_subpicture_just_once = FALSE;
7491   xvimagesink->subpicture = FALSE;
7492   xvimagesink->external_width = 0;
7493   xvimagesink->external_height = 0;
7494   xvimagesink->skip_frame_due_to_external_dev = FALSE;
7495   xvimagesink->is_hided_subpicture = FALSE;
7496   xvimagesink->is_quick_panel_on_subpicture = FALSE;
7497   xvimagesink->is_multi_window_subpicture = FALSE;
7498   xvimagesink->keep_external_fullscreen_post = FALSE;
7499   xvimagesink->keep_external_fullscreen_prev = FALSE;
7500   if(!XInitThreads())
7501     GST_WARNING("FAIL to call XInitThreads()");
7502   if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL))
7503     GST_WARNING("vconf set fail");
7504 #endif /* GST_EXT_XV_ENHANCEMENT */
7505 }
7506
7507 static void
7508 gst_xvimagesink_base_init (gpointer g_class)
7509 {
7510   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
7511
7512   gst_element_class_set_details_simple (element_class,
7513       "Video sink", "Sink/Video",
7514       "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
7515
7516   gst_element_class_add_static_pad_template (element_class,
7517       &gst_xvimagesink_sink_template_factory);
7518 }
7519
7520 static void
7521 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
7522 {
7523   GObjectClass *gobject_class;
7524   GstElementClass *gstelement_class;
7525   GstBaseSinkClass *gstbasesink_class;
7526   GstVideoSinkClass *videosink_class;
7527
7528   gobject_class = (GObjectClass *) klass;
7529   gstelement_class = (GstElementClass *) klass;
7530   gstbasesink_class = (GstBaseSinkClass *) klass;
7531   videosink_class = (GstVideoSinkClass *) klass;
7532
7533   gobject_class->set_property = gst_xvimagesink_set_property;
7534   gobject_class->get_property = gst_xvimagesink_get_property;
7535
7536   g_object_class_install_property (gobject_class, PROP_CONTRAST,
7537       g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
7538           -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7539   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
7540       g_param_spec_int ("brightness", "Brightness",
7541           "The brightness of the video", -1000, 1000, 0,
7542           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7543   g_object_class_install_property (gobject_class, PROP_HUE,
7544       g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
7545           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7546   g_object_class_install_property (gobject_class, PROP_SATURATION,
7547       g_param_spec_int ("saturation", "Saturation",
7548           "The saturation of the video", -1000, 1000, 0,
7549           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7550   g_object_class_install_property (gobject_class, PROP_DISPLAY,
7551       g_param_spec_string ("display", "Display", "X Display name", NULL,
7552           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7553   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
7554       g_param_spec_boolean ("synchronous", "Synchronous",
7555           "When enabled, runs the X display in synchronous mode. "
7556           "(unrelated to A/V sync, used only for debugging)", FALSE,
7557           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7558   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
7559       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
7560           "The pixel aspect ratio of the device", "1/1",
7561           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7562   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
7563       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
7564           "When enabled, scaling will respect original aspect ratio", FALSE,
7565           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7566   g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
7567       g_param_spec_boolean ("handle-events", "Handle XEvents",
7568           "When enabled, XEvents will be selected and handled", TRUE,
7569           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7570   g_object_class_install_property (gobject_class, PROP_DEVICE,
7571       g_param_spec_string ("device", "Adaptor number",
7572           "The number of the video adaptor", "0",
7573           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7574   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
7575       g_param_spec_string ("device-name", "Adaptor name",
7576           "The name of the video adaptor", NULL,
7577           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7578   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH,
7579       g_param_spec_int ("external-width", "external width",
7580           "width of external display", 0, G_MAXINT,
7581           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7582   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT,
7583       g_param_spec_int ("external-height", "external height",
7584           "height of external display", 0, G_MAXINT,
7585           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7586   /**
7587    * GstXvImageSink:handle-expose
7588    *
7589    * When enabled, the current frame will always be drawn in response to X
7590    * Expose.
7591    *
7592    * Since: 0.10.14
7593    */
7594   g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
7595       g_param_spec_boolean ("handle-expose", "Handle expose",
7596           "When enabled, "
7597           "the current frame will always be drawn in response to X Expose "
7598           "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7599
7600   /**
7601    * GstXvImageSink:double-buffer
7602    *
7603    * Whether to double-buffer the output.
7604    *
7605    * Since: 0.10.14
7606    */
7607   g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
7608       g_param_spec_boolean ("double-buffer", "Double-buffer",
7609           "Whether to double-buffer the output", TRUE,
7610           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7611   /**
7612    * GstXvImageSink:autopaint-colorkey
7613    *
7614    * Whether to autofill overlay with colorkey
7615    *
7616    * Since: 0.10.21
7617    */
7618   g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
7619       g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
7620           "Whether to autofill overlay with colorkey", TRUE,
7621           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7622   /**
7623    * GstXvImageSink:colorkey
7624    *
7625    * Color to use for the overlay mask.
7626    *
7627    * Since: 0.10.21
7628    */
7629   g_object_class_install_property (gobject_class, PROP_COLORKEY,
7630       g_param_spec_int ("colorkey", "Colorkey",
7631           "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
7632           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7633
7634   /**
7635    * GstXvImageSink:draw-borders
7636    *
7637    * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
7638    * unused parts of the video area.
7639    *
7640    * Since: 0.10.21
7641    */
7642   g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
7643       g_param_spec_boolean ("draw-borders", "Colorkey",
7644           "Draw black borders to fill unused area in force-aspect-ratio mode",
7645           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7646
7647   /**
7648    * GstXvImageSink:window-width
7649    *
7650    * Actual width of the video window.
7651    *
7652    * Since: 0.10.32
7653    */
7654   g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
7655       g_param_spec_uint64 ("window-width", "window-width",
7656           "Width of the window", 0, G_MAXUINT64, 0,
7657           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7658
7659   /**
7660    * GstXvImageSink:window-height
7661    *
7662    * Actual height of the video window.
7663    *
7664    * Since: 0.10.32
7665    */
7666   g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
7667       g_param_spec_uint64 ("window-height", "window-height",
7668           "Height of the window", 0, G_MAXUINT64, 0,
7669           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7670
7671 #ifdef GST_EXT_XV_ENHANCEMENT
7672   /**
7673    * GstXvImageSink:display-mode
7674    *
7675    * select display mode
7676    */
7677   g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
7678     g_param_spec_enum("display-mode", "Display Mode",
7679       "Display device setting",
7680       GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE,
7681       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7682
7683   /**
7684    * GstXvImageSink:csc-range
7685    *
7686    * select color space range
7687    */
7688   g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
7689     g_param_spec_enum("csc-range", "Color Space Range",
7690       "Color space range setting",
7691       GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
7692       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7693
7694   /**
7695    * GstXvImageSink:display-geometry-method
7696    *
7697    * Display geometrical method setting
7698    */
7699   g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
7700     g_param_spec_enum("display-geometry-method", "Display geometry method",
7701       "Geometrical method for display",
7702       GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
7703       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7704
7705   /**
7706    * GstXvImageSink:display-flip
7707    *
7708    * Display flip setting
7709    */
7710   g_object_class_install_property(gobject_class, PROP_FLIP,
7711     g_param_spec_enum("flip", "Display flip",
7712       "Flip for display",
7713       GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
7714       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7715
7716   /**
7717    * GstXvImageSink:rotate
7718    *
7719    * Draw rotation angle setting
7720    */
7721   g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
7722     g_param_spec_enum("rotate", "Rotate angle",
7723       "Rotate angle of display output",
7724       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
7725       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7726
7727   /**
7728    * GstXvImageSink:visible
7729    *
7730    * Whether reserve original src size or not
7731    */
7732   g_object_class_install_property (gobject_class, PROP_VISIBLE,
7733       g_param_spec_boolean ("visible", "Visible",
7734           "Draws screen or blacks out, true means visible, false blacks out",
7735           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7736
7737   /**
7738    * GstXvImageSink:zoom
7739    *
7740    * Scale small area of screen to 1X~ 9X
7741    */
7742   g_object_class_install_property (gobject_class, PROP_ZOOM,
7743       g_param_spec_float ("zoom", "Zoom",
7744           "Zooms screen as nX", 1.0, 9.0, 1.0,
7745           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7746
7747   /**
7748    * GstXvImageSink:zoom-pos-x
7749    *
7750    * Standard x-position of zoom
7751    */
7752   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
7753       g_param_spec_int ("zoom-pos-x", "Zoom Position X",
7754           "Standard x-position of zoom", -1, 3840, -1,
7755           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7756
7757   /**
7758    * GstXvImageSink:zoom-pos-y
7759    *
7760    * Standard y-position of zoom
7761    */
7762   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
7763       g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
7764           "Standard y-position of zoom", -1, 3840, -1,
7765           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7766
7767   /**
7768    * GstXvImageSink:dst-roi-mode
7769    *
7770    * Display geometrical method of ROI setting
7771    */
7772   g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
7773     g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
7774       "Geometrical method of ROI for display",
7775       GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
7776       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7777
7778   /**
7779    * GstXvImageSink:orientation
7780    *
7781    * Orientation information which will be used for ROI/ZOOM
7782    */
7783   g_object_class_install_property(gobject_class, PROP_ORIENTATION,
7784     g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
7785       "Orientation information for display",
7786       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
7787       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7788
7789   /**
7790    * GstXvImageSink:dst-roi-x
7791    *
7792    * X value of Destination ROI
7793    */
7794   g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
7795       g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
7796           "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7797           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7798
7799   /**
7800    * GstXvImageSink:dst-roi-y
7801    *
7802    * Y value of Destination ROI
7803    */
7804   g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
7805       g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
7806           "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7807           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7808
7809   /**
7810    * GstXvImageSink:dst-roi-w
7811    *
7812    * W value of Destination ROI
7813    */
7814   g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
7815       g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
7816           "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7817           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7818
7819   /**
7820    * GstXvImageSink:dst-roi-h
7821    *
7822    * H value of Destination ROI
7823    */
7824   g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
7825       g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
7826           "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7827           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7828
7829   /**
7830    * GstXvImageSink:stop-video
7831    *
7832    * Stop video for releasing video source buffer
7833    */
7834   g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
7835       g_param_spec_int ("stop-video", "Stop-Video",
7836           "Stop video for releasing video source buffer", 0, 1, 0,
7837           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7838
7839   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
7840       g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
7841           "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
7842
7843   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
7844       g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
7845           "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
7846
7847   g_object_class_install_property (gobject_class, PROP_SUBPICTURE,
7848       g_param_spec_boolean ("subpicture", "Subpicture",
7849           "identifier of player for supporting subpicture", FALSE,
7850           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7851
7852   /**
7853    * GstXvImageSink:src-crop-x
7854    *
7855    * X value of video source crop
7856    */
7857   g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
7858       g_param_spec_int ("src-crop-x", "Source Crop X",
7859           "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7860           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7861
7862   /**
7863    * GstXvImageSink:src-crop-y
7864    *
7865    * Y value of video source crop
7866    */
7867   g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
7868       g_param_spec_int ("src-crop-y", "Source Crop X",
7869           "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7870           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7871
7872   /**
7873    * GstXvImageSink:src-crop-w
7874    *
7875    * Width value of video source crop
7876    */
7877   g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
7878       g_param_spec_int ("src-crop-w", "Source Crop Width",
7879           "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7880           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7881
7882   /**
7883    * GstXvImageSink:src-crop-h
7884    *
7885    * Height value of video source crop
7886    */
7887   g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
7888       g_param_spec_int ("src-crop-h", "Source Crop Height",
7889           "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7890           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7891
7892   /**
7893    * GstXvImageSink:enable-flush-buffer
7894    *
7895    * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
7896    */
7897   g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
7898       g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
7899           "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
7900           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7901
7902   /**
7903    * GstXvImageSink:is-pixmap
7904    *
7905    * Check using pixmap id for blocking X api
7906    */
7907   g_object_class_install_property (gobject_class, PROP_PIXMAP,
7908       g_param_spec_boolean("is-pixmap", "Check if use pixmap",
7909           "Check using pixmap id for blocking X api",
7910           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7911
7912   /**
7913    * GstXvImageSink:hided-window
7914    *
7915    * check window status for hiding subtitle
7916    */
7917   g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW,
7918       g_param_spec_boolean("hided-window", "Hided window",
7919           "check window status for hiding subtitle",
7920           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7921
7922   /**
7923    * GstXvImageSink:quick-panel-on
7924    *
7925    * check quick-panel status for hiding subtitle
7926    */
7927   g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON,
7928       g_param_spec_boolean("quick-panel-on", "Quick panel On",
7929           "check quick-panel status for hiding subtitle",
7930           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7931
7932   /**
7933    * GstXvImageSink:multiwindow-activated
7934    *
7935    * check multiwindow-activated status for hiding subtitle
7936    */
7937   g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE,
7938       g_param_spec_boolean("multiwindow-active", "Multiwindow Activate",
7939           "check multiwindow status for hiding subtitle",
7940           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7941
7942   /**
7943    * GstXvImageSink:keep-external-fullscreen-post
7944    *
7945    * keep video-only mode for special case, it is set immediately.
7946    */
7947   g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
7948       g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen",
7949           "set video-only mode forcedly for special case",
7950           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7951
7952   /**
7953    * GstXvImageSink:keep-external-fullscreen-prev
7954    *
7955    * keep video-only mode for special case, it is set in advance.
7956    */
7957   g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
7958       g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen",
7959           "set video-only mode forcedly for special case",
7960           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7961
7962   /**
7963    * GstXvImageSink::frame-render-error
7964    */
7965   gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
7966           "frame-render-error",
7967           G_TYPE_FROM_CLASS (klass),
7968           G_SIGNAL_RUN_LAST,
7969           0,
7970           NULL,
7971           NULL,
7972           gst_xvimagesink_BOOLEAN__POINTER,
7973           G_TYPE_BOOLEAN,
7974           1,
7975           G_TYPE_POINTER);
7976   /**
7977    * GstXvImageSink::display-status
7978    */
7979     gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new (
7980           "display-status",
7981           G_TYPE_FROM_CLASS (klass),
7982           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7983           0,
7984           NULL,
7985           NULL,
7986           g_cclosure_marshal_VOID__INT,
7987           G_TYPE_NONE,
7988           1,
7989           G_TYPE_INT);
7990
7991   /**
7992    * GstXvImageSink::external-resolution
7993    */
7994   gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new (
7995           "external-resolution",
7996          G_TYPE_FROM_CLASS (klass),
7997          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7998          0,
7999          NULL,
8000          NULL,
8001          gst_marshal_VOID__INT_INT,
8002          G_TYPE_NONE,
8003          2,
8004          G_TYPE_INT,
8005          G_TYPE_INT);
8006
8007   /**
8008    * GstXvImageSink::hided-window
8009    */
8010     gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new (
8011           "hided-window",
8012           G_TYPE_FROM_CLASS (klass),
8013           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8014           0,
8015           NULL,
8016           NULL,
8017           g_cclosure_marshal_VOID__BOOLEAN,
8018           G_TYPE_NONE,
8019           1,
8020           G_TYPE_BOOLEAN);
8021
8022   /**
8023    * GstXvImageSink::quick-panel-on
8024    */
8025     gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new (
8026           "quick-panel-on",
8027           G_TYPE_FROM_CLASS (klass),
8028           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8029           0,
8030           NULL,
8031           NULL,
8032           g_cclosure_marshal_VOID__BOOLEAN,
8033           G_TYPE_NONE,
8034           1,
8035           G_TYPE_BOOLEAN);
8036
8037   /**
8038    * GstXvImageSink::multiwindow-active
8039    */
8040     gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new (
8041           "multiwindow-active",
8042           G_TYPE_FROM_CLASS (klass),
8043           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8044           0,
8045           NULL,
8046           NULL,
8047           g_cclosure_marshal_VOID__BOOLEAN,
8048           G_TYPE_NONE,
8049           1,
8050           G_TYPE_BOOLEAN);
8051
8052 #endif /* GST_EXT_XV_ENHANCEMENT */
8053
8054   gobject_class->finalize = gst_xvimagesink_finalize;
8055
8056   gstelement_class->change_state =
8057       GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
8058
8059   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
8060   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
8061   gstbasesink_class->buffer_alloc =
8062       GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
8063   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
8064   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
8065
8066   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
8067 }
8068
8069 /* ============================================================= */
8070 /*                                                               */
8071 /*                       Public Methods                          */
8072 /*                                                               */
8073 /* ============================================================= */
8074
8075 /* =========================================== */
8076 /*                                             */
8077 /*          Object typing & Creation           */
8078 /*                                             */
8079 /* =========================================== */
8080 static void
8081 gst_xvimagesink_init_interfaces (GType type)
8082 {
8083   static const GInterfaceInfo iface_info = {
8084     (GInterfaceInitFunc) gst_xvimagesink_interface_init,
8085     NULL,
8086     NULL,
8087   };
8088   static const GInterfaceInfo navigation_info = {
8089     (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
8090     NULL,
8091     NULL,
8092   };
8093   static const GInterfaceInfo overlay_info = {
8094     (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
8095     NULL,
8096     NULL,
8097   };
8098   static const GInterfaceInfo colorbalance_info = {
8099     (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
8100     NULL,
8101     NULL,
8102   };
8103   static const GInterfaceInfo propertyprobe_info = {
8104     (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
8105     NULL,
8106     NULL,
8107   };
8108
8109   g_type_add_interface_static (type,
8110       GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
8111   g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
8112   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
8113   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
8114       &colorbalance_info);
8115   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
8116       &propertyprobe_info);
8117
8118   /* register type and create class in a more safe place instead of at
8119    * runtime since the type registration and class creation is not
8120    * threadsafe. */
8121   g_type_class_ref (gst_xvimage_buffer_get_type ());
8122 }
8123
8124 static gboolean
8125 plugin_init (GstPlugin * plugin)
8126 {
8127   if (!gst_element_register (plugin, "xvimagesink",
8128           GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
8129     return FALSE;
8130
8131   GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
8132       "xvimagesink element");
8133   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
8134
8135   return TRUE;
8136 }
8137
8138 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
8139     GST_VERSION_MINOR,
8140     "xvimagesink",
8141     "XFree86 video output plugin using Xv extension",
8142     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
8143
8144