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