[xvimagesink] fix deadlock issue
[platform/upstream/gst-plugins-base.git] / sys / xvimage / xvimagesink.c
1 /* GStreamer
2  * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3  *               <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
4  * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, 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 #GstVideoOverlay interface and will then render
35  * video frames in this drawable. If no Window ID was provided by the
36  * application, the element will create its own internal window and render
37  * into it.
38  *
39  * <refsect2>
40  * <title>Scaling</title>
41  * <para>
42  * The XVideo extension, when it's available, handles hardware accelerated
43  * scaling of video frames. This means that the element will just accept
44  * incoming video frames no matter their geometry and will then put them to the
45  * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
46  * property it is possible to enforce scaling with a constant aspect ratio,
47  * which means drawing black borders around the video frame.
48  * </para>
49  * </refsect2>
50  * <refsect2>
51  * <title>Events</title>
52  * <para>
53  * XvImageSink creates a thread to handle events coming from the drawable. There
54  * are several kind of events that can be grouped in 2 big categories: input
55  * events and window state related events. Input events will be translated to
56  * navigation events and pushed upstream for other elements to react on them.
57  * This includes events such as pointer moves, key press/release, clicks etc...
58  * Other events are used to handle the drawable appearance even when the data
59  * is not flowing (GST_STATE_PAUSED). That means that even when the element is
60  * paused, it will receive expose events from the drawable and draw the latest
61  * frame with correct borders/aspect-ratio.
62  * </para>
63  * </refsect2>
64  * <refsect2>
65  * <title>Pixel aspect ratio</title>
66  * <para>
67  * When changing state to GST_STATE_READY, XvImageSink will open a connection to
68  * the display specified in the #GstXvImageSink:display property or the
69  * default display if nothing specified. Once this connection is open it will
70  * inspect the display configuration including the physical display geometry and
71  * then calculate the pixel aspect ratio. When receiving video frames with a
72  * different pixel aspect ratio, XvImageSink will use hardware scaling to
73  * display the video frames correctly on display's pixel aspect ratio.
74  * Sometimes the calculated pixel aspect ratio can be wrong, it is
75  * then possible to enforce a specific pixel aspect ratio using the
76  * #GstXvImageSink:pixel-aspect-ratio property.
77  * </para>
78  * </refsect2>
79  * <refsect2>
80  * <title>Examples</title>
81  * |[
82  * gst-launch -v videotestsrc ! xvimagesink
83  * ]| A pipeline to test hardware scaling.
84  * When the test video signal appears you can resize the window and see that
85  * video frames are scaled through hardware (no extra CPU cost).
86  * |[
87  * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
88  * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
89  * You can observe the borders drawn around the scaled image respecting aspect
90  * ratio.
91  * |[
92  * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
93  * ]| A pipeline to test navigation events.
94  * While moving the mouse pointer over the test signal you will see a black box
95  * following the mouse pointer. If you press the mouse button somewhere on the
96  * video and release it somewhere else a green box will appear where you pressed
97  * the button and a red one where you released it. (The navigationtest element
98  * is part of gst-plugins-good.) You can observe here that even if the images
99  * are scaled through hardware the pointer coordinates are converted back to the
100  * original video frame geometry so that the box can be drawn to the correct
101  * position. This also handles borders correctly, limiting coordinates to the
102  * image area
103  * |[
104  * gst-launch -v videotestsrc ! video/x-raw, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
105  * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
106  * videotestsrc, in most cases the pixel aspect ratio of the display will be
107  * 1/1. This means that XvImageSink will have to do the scaling to convert
108  * incoming frames to a size that will match the display pixel aspect ratio
109  * (from 320x240 to 320x180 in this case). Note that you might have to escape
110  * some characters for your shell like '\(fraction\)'.
111  * |[
112  * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
113  * ]| Demonstrates how to use the colorbalance interface.
114  * </refsect2>
115  */
116
117 /* for developers: there are two useful tools : xvinfo and xvattr */
118
119 #ifdef HAVE_CONFIG_H
120 #include "config.h"
121 #endif
122
123 /* Our interfaces */
124 #include <gst/video/navigation.h>
125 #include <gst/video/videooverlay.h>
126 #include <gst/video/colorbalance.h>
127 /* Helper functions */
128 #include <gst/video/gstvideometa.h>
129
130 /* Object header */
131 #include "xvimagesink.h"
132 #include "xvimageallocator.h"
133
134 #ifdef GST_EXT_XV_ENHANCEMENT
135 /* Samsung extension headers */
136 /* For xv extension header for buffer transfer (output) */
137 #include "xv_types.h"
138
139 /* for performance checking */
140 //#include <mm_ta.h>
141
142 typedef enum {
143         BUF_SHARE_METHOD_PADDR = 0,
144         BUF_SHARE_METHOD_FD,
145         BUF_SHARE_METHOD_TIZEN_BUFFER
146 } buf_share_method_t;
147
148 #define _EVENT_THREAD_CHECK_INTERVAL    15000   /* us */
149 #endif /* GST_EXT_XV_ENHANCEMENT */
150
151
152 /* Debugging category */
153 #include <gst/gstinfo.h>
154
155 /* for XkbKeycodeToKeysym */
156 #include <X11/XKBlib.h>
157
158 GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagesink);
159 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
160 #define GST_CAT_DEFAULT gst_debug_xvimagesink
161
162 #ifdef GST_EXT_XV_ENHANCEMENT
163 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
164
165 static GType
166 gst_xvimagesink_display_mode_get_type(void)
167 {
168    static GType xvimagesink_display_mode_type = 0;
169    static const GEnumValue display_mode_type[] = {
170        { 0, "Default mode", "DEFAULT"},
171        { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
172        { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
173        { 3, NULL, NULL},
174    };
175
176    if (!xvimagesink_display_mode_type) {
177        xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
178    }
179
180    return xvimagesink_display_mode_type;
181 }
182
183 enum {
184     DEGREE_0,
185     DEGREE_90,
186     DEGREE_180,
187     DEGREE_270,
188     DEGREE_NUM,
189 };
190
191 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
192
193 static GType
194 gst_xvimagesink_rotate_angle_get_type(void)
195 {
196    static GType xvimagesink_rotate_angle_type = 0;
197    static const GEnumValue rotate_angle_type[] = {
198        { 0, "No rotate", "DEGREE_0"},
199        { 1, "Rotate 90 degree", "DEGREE_90"},
200        { 2, "Rotate 180 degree", "DEGREE_180"},
201        { 3, "Rotate 270 degree", "DEGREE_270"},
202        { 4, NULL, NULL},
203    };
204
205    if (!xvimagesink_rotate_angle_type) {
206        xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
207    }
208
209    return xvimagesink_rotate_angle_type;
210 }
211
212 enum {
213     DISP_GEO_METHOD_LETTER_BOX = 0,
214     DISP_GEO_METHOD_ORIGIN_SIZE,
215     DISP_GEO_METHOD_FULL_SCREEN,
216     DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
217     DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
218     DISP_GEO_METHOD_CUSTOM_DST_ROI,
219     DISP_GEO_METHOD_NUM,
220 };
221
222 enum {
223     ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
224     ROI_DISP_GEO_METHOD_LETTER_BOX,
225     ROI_DISP_GEO_METHOD_NUM,
226 };
227
228 #define DEF_DISPLAY_GEOMETRY_METHOD         DISP_GEO_METHOD_LETTER_BOX
229 #define DEF_ROI_DISPLAY_GEOMETRY_METHOD     ROI_DISP_GEO_METHOD_FULL_SCREEN
230
231 enum {
232     FLIP_NONE = 0,
233     FLIP_HORIZONTAL,
234     FLIP_VERTICAL,
235     FLIP_BOTH,
236     FLIP_NUM,
237 };
238 #define DEF_DISPLAY_FLIP            FLIP_NONE
239
240 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
241 #define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
242 #define GST_TYPE_XVIMAGESINK_FLIP                    (gst_xvimagesink_flip_get_type())
243
244 static GType
245 gst_xvimagesink_display_geometry_method_get_type(void)
246 {
247    static GType xvimagesink_display_geometry_method_type = 0;
248    static const GEnumValue display_geometry_method_type[] = {
249        { 0, "Letter box", "LETTER_BOX"},
250        { 1, "Origin size", "ORIGIN_SIZE"},
251        { 2, "Full-screen", "FULL_SCREEN"},
252        { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
253        { 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"},
254        { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
255        { 6, NULL, NULL},
256    };
257
258    if (!xvimagesink_display_geometry_method_type) {
259        xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
260    }
261
262    return xvimagesink_display_geometry_method_type;
263 }
264
265 static GType
266 gst_xvimagesink_roi_display_geometry_method_get_type(void)
267 {
268        static GType xvimagesink_roi_display_geometry_method_type = 0;
269        static const GEnumValue roi_display_geometry_method_type[] = {
270                { 0, "ROI-Full-screen", "FULL_SCREEN"},
271                { 1, "ROI-Letter box", "LETTER_BOX"},
272                { 2, NULL, NULL},
273        };
274
275        if (!xvimagesink_roi_display_geometry_method_type) {
276                xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
277        }
278
279        return xvimagesink_roi_display_geometry_method_type;
280 }
281
282 static GType
283 gst_xvimagesink_flip_get_type(void)
284 {
285    static GType xvimagesink_flip_type = 0;
286    static const GEnumValue flip_type[] = {
287        { FLIP_NONE,       "Flip NONE", "FLIP_NONE"},
288        { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
289        { FLIP_VERTICAL,   "Flip VERTICAL", "FLIP_VERTICAL"},
290        { FLIP_BOTH,       "Flip BOTH", "FLIP_BOTH"},
291        { FLIP_NUM, NULL, NULL},
292    };
293
294    if (!xvimagesink_flip_type) {
295        xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
296    }
297
298    return xvimagesink_flip_type;
299 }
300
301 #define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
302 void
303 gst_xvimagesink_BOOLEAN__POINTER (GClosure         *closure,
304                                      GValue         *return_value G_GNUC_UNUSED,
305                                      guint          n_param_values,
306                                      const GValue   *param_values,
307                                      gpointer       invocation_hint G_GNUC_UNUSED,
308                                      gpointer       marshal_data)
309 {
310   typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer     data1,
311                                                      gpointer     arg_1,
312                                                      gpointer     data2);
313   register GMarshalFunc_BOOLEAN__POINTER callback;
314   register GCClosure *cc = (GCClosure*) closure;
315   register gpointer data1, data2;
316
317   gboolean v_return;
318
319   g_return_if_fail (return_value != NULL);
320   g_return_if_fail (n_param_values == 2);
321
322   if (G_CCLOSURE_SWAP_DATA (closure)) {
323     data1 = closure->data;
324     data2 = g_value_peek_pointer (param_values + 0);
325   } else {
326     data1 = g_value_peek_pointer (param_values + 0);
327     data2 = closure->data;
328   }
329   callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
330
331   v_return = callback (data1,
332                       g_marshal_value_peek_pointer (param_values + 1),
333                       data2);
334
335   g_value_set_boolean (return_value, v_return);
336 }
337
338 enum
339 {
340     SIGNAL_FRAME_RENDER_ERROR,
341     LAST_SIGNAL
342 };
343 #endif /* GST_EXT_XV_ENHANCEMENT */
344
345 typedef struct
346 {
347   unsigned long flags;
348   unsigned long functions;
349   unsigned long decorations;
350   long input_mode;
351   unsigned long status;
352 }
353 MotifWmHints, MwmHints;
354
355 #define MWM_HINTS_DECORATIONS   (1L << 1)
356
357 static gboolean gst_xvimagesink_open (GstXvImageSink * xvimagesink);
358 static void gst_xvimagesink_close (GstXvImageSink * xvimagesink);
359 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
360     xvimagesink);
361 static void gst_xvimagesink_expose (GstVideoOverlay * overlay);
362 #ifdef GST_EXT_XV_ENHANCEMENT
363 static void gst_xvimagesink_set_pixmap_handle (GstVideoOverlay * overlay, guintptr id);
364 static void gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,GstXPixmap * xpixmap);
365 static int gst_xvimage_pixmap_xerror (Display * display, XErrorEvent * xevent);
366 #endif
367
368 /* Default template - initiated with class struct to allow gst-register to work
369    without X running */
370 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
371 GST_STATIC_PAD_TEMPLATE ("sink",
372     GST_PAD_SINK,
373     GST_PAD_ALWAYS,
374     GST_STATIC_CAPS ("video/x-raw, "
375         "framerate = (fraction) [ 0, MAX ], "
376         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
377     );
378
379 enum
380 {
381   PROP_0,
382   PROP_CONTRAST,
383   PROP_BRIGHTNESS,
384   PROP_HUE,
385   PROP_SATURATION,
386   PROP_DISPLAY,
387   PROP_SYNCHRONOUS,
388   PROP_PIXEL_ASPECT_RATIO,
389   PROP_FORCE_ASPECT_RATIO,
390   PROP_HANDLE_EVENTS,
391   PROP_DEVICE,
392   PROP_DEVICE_NAME,
393   PROP_HANDLE_EXPOSE,
394   PROP_DOUBLE_BUFFER,
395   PROP_AUTOPAINT_COLORKEY,
396   PROP_COLORKEY,
397   PROP_DRAW_BORDERS,
398   PROP_WINDOW_WIDTH,
399   PROP_WINDOW_HEIGHT,
400 #ifdef GST_EXT_XV_ENHANCEMENT
401   PROP_DISPLAY_MODE,
402   PROP_ROTATE_ANGLE,
403   PROP_FLIP,
404   PROP_DISPLAY_GEOMETRY_METHOD,
405   PROP_VISIBLE,
406   PROP_ZOOM,
407   PROP_ZOOM_POS_X,
408   PROP_ZOOM_POS_Y,
409   PROP_ORIENTATION,
410   PROP_DST_ROI_MODE,
411   PROP_DST_ROI_X,
412   PROP_DST_ROI_Y,
413   PROP_DST_ROI_W,
414   PROP_DST_ROI_H,
415 #ifdef ENABLE_STOP_VIDEO
416   PROP_STOP_VIDEO,
417 #endif
418   PROP_PIXMAP_CB,
419   PROP_PIXMAP_CB_USER_DATA
420 #endif /* GST_EXT_XV_ENHANCEMENT */
421 };
422
423 /* ============================================================= */
424 /*                                                               */
425 /*                       Public Methods                          */
426 /*                                                               */
427 /* ============================================================= */
428
429 /* =========================================== */
430 /*                                             */
431 /*          Object typing & Creation           */
432 /*                                             */
433 /* =========================================== */
434 static void gst_xvimagesink_navigation_init (GstNavigationInterface * iface);
435 static void gst_xvimagesink_video_overlay_init (GstVideoOverlayInterface *
436     iface);
437 static void gst_xvimagesink_colorbalance_init (GstColorBalanceInterface *
438     iface);
439 #define gst_xvimagesink_parent_class parent_class
440 G_DEFINE_TYPE_WITH_CODE (GstXvImageSink, gst_xvimagesink, GST_TYPE_VIDEO_SINK,
441     G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
442         gst_xvimagesink_navigation_init);
443     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
444         gst_xvimagesink_video_overlay_init);
445     G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
446         gst_xvimagesink_colorbalance_init));
447
448
449 /* ============================================================= */
450 /*                                                               */
451 /*                       Private Methods                         */
452 /*                                                               */
453 /* ============================================================= */
454 #ifdef GST_EXT_XV_ENHANCEMENT
455 /* X11 stuff */
456 static gboolean error_caught = FALSE;
457
458 static int
459 gst_xvimage_pixmap_xerror (Display * display, XErrorEvent * xevent)
460 {
461   char error_msg[1024];
462
463   XGetErrorText (display, xevent->error_code, error_msg, 1024);
464   GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg);
465   error_caught = TRUE;
466   return 0;
467 }
468
469 static void
470 gst_xvimagesink_pixmap_render(GstXvImageMemory * mem, GstVideoRectangle * src_input,
471         GstVideoRectangle * result, gboolean draw_border, GstXvImageSink * xvimagesink)
472 {
473   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
474   g_return_if_fail (src_input != NULL);
475   g_return_if_fail (result != NULL);
476   g_return_if_fail (mem != NULL);
477
478   if (!xvimagesink->get_pixmap_cb) {
479         return;
480   }
481
482   XvImage *xvimage;
483   int ret                       = 0;
484   int idx                       = 0;
485   int (*handler) (Display *, XErrorEvent *) = NULL;
486   XV_DATA_PTR img_data = NULL;
487   g_mutex_lock (&xvimagesink->context->lock);
488   xvimage = gst_xvimage_memory_get_xvimage (mem);
489   idx = xvimagesink->current_pixmap_idx;
490
491 #ifdef HAVE_XSHM
492   if (xvimagesink->context->use_xshm) {
493
494     /* set error handler */
495         error_caught = FALSE;
496         handler = XSetErrorHandler(gst_xvimage_pixmap_xerror);
497
498         g_mutex_lock(xvimagesink->context->display_buffer_lock);
499         if (xvimagesink->context->displaying_buffer_count > 3) {
500           GST_WARNING("too many buffers are pushed. skip this... [displaying_buffer_count %d]",
501             xvimagesink->context->displaying_buffer_count);
502         }
503         g_mutex_unlock(xvimagesink->context->display_buffer_lock);
504
505         ret = XvShmPutImage (xvimagesink->context->disp,
506           xvimagesink->context->xv_port_id,
507           xvimagesink->xpixmap[idx]->pixmap,
508           xvimagesink->xpixmap[idx]->gc, xvimage,
509           src_input->x, src_input->y, src_input->w, src_input->h,
510           result->x, result->y, result->w, result->h, FALSE);
511           GST_LOG_OBJECT( mem, "XvShmPutImage return value [%d]", ret );
512   }
513   XSync (xvimagesink->context->disp, FALSE);
514 #endif
515   if (ret || error_caught) {
516     GST_WARNING("putimage error : ret %d, error_caught %d, displaying buffer count %d",
517           ret, error_caught, xvimagesink->context->displaying_buffer_count);
518
519     /* release gem handle */
520         img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage(mem)->data;
521         if (img_data) {
522           unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
523           gem_name[0] = img_data->YBuf;
524           gem_name[1] = img_data->CbBuf;
525           gem_name[2] = img_data->CrBuf;
526           gst_xvcontext_remove_displaying_buffer(xvimagesink->context, gem_name);
527         }
528   }
529
530   /* Reset error handler */
531   error_caught = FALSE;
532   XSetErrorHandler (handler);
533
534   g_mutex_unlock (&xvimagesink->context->lock);
535
536   return;
537 }
538
539 #endif
540 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
541  * if no window was available  */
542 static gboolean
543 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
544 {
545   GstXvImageMemory *mem;
546   GstVideoCropMeta *crop;
547   GstVideoRectangle result;
548   gboolean draw_border = FALSE;
549   GstVideoRectangle src, dst;
550   GstVideoRectangle mem_crop;
551   GstXWindow *xwindow;
552 #ifdef GST_EXT_XV_ENHANCEMENT
553   static Atom atom_rotation = None;
554   static Atom atom_hflip = None;
555   static Atom atom_vflip = None;
556   gboolean set_hflip = FALSE;
557   gboolean set_vflip = FALSE;
558
559   GstVideoRectangle src_origin = { 0, 0, 0, 0};
560   GstVideoRectangle src_input  = { 0, 0, 0, 0};
561
562   gint res_rotate_angle = 0;
563   int rotate        = 0;
564   int ret           = 0;
565   int idx                       = 0;
566
567   if (!xvimagesink->get_pixmap_cb){
568           gst_xvimagesink_xwindow_update_geometry( xvimagesink );
569   }
570 #endif /* GST_EXT_XV_ENHANCEMENT */
571
572   /* We take the flow_lock. If expose is in there we don't want to run
573      concurrently from the data flow thread */
574   g_mutex_lock (&xvimagesink->flow_lock);
575
576 #ifdef GST_EXT_XV_ENHANCEMENT
577   if (xvimagesink->xid_updated) {
578     if (xvimage) {
579       GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
580       xvimage = NULL;
581     }
582     xvimagesink->xid_updated = FALSE;
583   }
584 #endif /* GST_EXT_XV_ENHANCEMENT */
585
586 #ifdef GST_EXT_XV_ENHANCEMENT
587   if (G_UNLIKELY ((xwindow = xvimagesink->xwindow) == NULL)) {
588         if (xvimagesink->get_pixmap_cb){
589           GST_INFO("xwindow is NULL, but it has get_pixmap_cb(%p), keep going..",xvimagesink->get_pixmap_cb );
590         } else {
591           GST_INFO("xwindow is NULL. Skip xvimage_put.");
592           g_mutex_unlock (&xvimagesink->flow_lock);
593           return FALSE;
594         }
595   }
596 #else
597   if (G_UNLIKELY ((xwindow = xvimagesink->xwindow) == NULL)) {
598     g_mutex_unlock (&xvimagesink->flow_lock);
599     return FALSE;
600   }
601 #endif
602   /* Draw borders when displaying the first frame. After this
603      draw borders only on expose event or after a size change. */
604   if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
605     draw_border = xvimagesink->draw_borders;
606     xvimagesink->redraw_border = FALSE;
607   }
608
609   /* Store a reference to the last image we put, lose the previous one */
610   if (xvimage && xvimagesink->cur_image != xvimage) {
611     if (xvimagesink->cur_image) {
612       GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
613       gst_buffer_unref (xvimagesink->cur_image);
614     }
615     GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
616     xvimagesink->cur_image = gst_buffer_ref (xvimage);
617   }
618
619   /* Expose sends a NULL image, we take the latest frame */
620   if (!xvimage) {
621     if (xvimagesink->cur_image) {
622       draw_border = TRUE;
623       xvimage = xvimagesink->cur_image;
624     } else {
625 #ifdef GST_EXT_XV_ENHANCEMENT
626       GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
627       /* no need to release gem handle */
628 #endif /* GST_EXT_XV_ENHANCEMENT */
629       g_mutex_unlock (&xvimagesink->flow_lock);
630       return TRUE;
631     }
632   }
633
634   mem = (GstXvImageMemory *) gst_buffer_peek_memory (xvimage, 0);
635 #ifdef GST_EXT_XV_ENHANCEMENT
636   if (!xvimagesink->visible) {
637     GST_INFO("visible[%d]. Skip xvimage_put.",
638              xvimagesink->visible);
639     g_mutex_unlock(&xvimagesink->flow_lock);
640     return TRUE;
641   }
642
643   if (xvimagesink->get_pixmap_cb) {
644         gst_xvimagesink_set_pixmap_handle ((GstVideoOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
645     idx = xvimagesink->current_pixmap_idx;
646         if (idx == -1) {
647       g_mutex_unlock (&xvimagesink->flow_lock);
648       return FALSE;
649     } else if (idx == -2) {
650       GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
651       g_mutex_unlock (&xvimagesink->flow_lock);
652       return TRUE;
653     }
654   }
655
656   res_rotate_angle = xvimagesink->rotate_angle;
657
658   src.x = src.y = 0;
659   src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
660
661   src_input.w = src_origin.w = xvimagesink->video_width;
662   src_input.h = src_origin.h = xvimagesink->video_height;
663
664   if (xvimagesink->rotate_angle == DEGREE_0 ||
665       xvimagesink->rotate_angle == DEGREE_180) {
666     src.w = src_origin.w;
667     src.h = src_origin.h;
668   } else {
669     src.w = src_origin.h;
670     src.h = src_origin.w;
671   }
672   if (xvimagesink->get_pixmap_cb) {
673     dst.w = xvimagesink->xpixmap[idx]->width;
674         dst.h = xvimagesink->xpixmap[idx]->height;
675
676   } else {
677     dst.w = xwindow->render_rect.w;
678     dst.h = xwindow->render_rect.h;
679   }
680   switch (xvimagesink->display_geometry_method)
681   {
682     case DISP_GEO_METHOD_LETTER_BOX:
683       gst_video_sink_center_rect (src, dst, &result, TRUE);
684           if (xvimagesink->get_pixmap_cb) { //?
685                   result.x += xvimagesink->xpixmap[idx]->x;
686                   result.y += xvimagesink->xpixmap[idx]->y;
687           } else {
688         result.x += xwindow->render_rect.x;
689         result.y += xwindow->render_rect.y;
690           }
691       break;
692
693     case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
694       GST_WARNING_OBJECT(xvimagesink, "not supported API, set ORIGIN_SIZE mode");
695     case DISP_GEO_METHOD_ORIGIN_SIZE:
696       gst_video_sink_center_rect (src, dst, &result, FALSE);
697       gst_video_sink_center_rect (dst, src, &src_input, FALSE);
698
699       if (xvimagesink->rotate_angle == DEGREE_90 ||
700           xvimagesink->rotate_angle == DEGREE_270) {
701         src_input.x = src_input.x ^ src_input.y;
702         src_input.y = src_input.x ^ src_input.y;
703         src_input.x = src_input.x ^ src_input.y;
704
705         src_input.w = src_input.w ^ src_input.h;
706         src_input.h = src_input.w ^ src_input.h;
707         src_input.w = src_input.w ^ src_input.h;
708       }
709       break;
710
711    case DISP_GEO_METHOD_FULL_SCREEN:
712       result.x = result.y = 0;
713           if (xvimagesink->get_pixmap_cb) {
714             result.w = xvimagesink->xpixmap[idx]->width;
715                 result.h = xvimagesink->xpixmap[idx]->height;
716           } else {
717             result.w = xwindow->width;
718                 result.h = xwindow->height;
719           }
720       break;
721
722    case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
723       gst_video_sink_center_rect(dst, src, &src_input, TRUE);
724
725       result.x = result.y = 0;
726       result.w = dst.w;
727       result.h = dst.h;
728
729       if (xvimagesink->rotate_angle == DEGREE_90 ||
730           xvimagesink->rotate_angle == DEGREE_270) {
731         src_input.x = src_input.x ^ src_input.y;
732         src_input.y = src_input.x ^ src_input.y;
733         src_input.x = src_input.x ^ src_input.y;
734
735         src_input.w = src_input.w ^ src_input.h;
736         src_input.h = src_input.w ^ src_input.h;
737         src_input.w = src_input.w ^ src_input.h;
738       }
739       break;
740
741     case DISP_GEO_METHOD_CUSTOM_DST_ROI:
742     {
743       GstVideoRectangle dst_roi_cmpns;
744       dst_roi_cmpns.w = xvimagesink->dst_roi.w;
745       dst_roi_cmpns.h = xvimagesink->dst_roi.h;
746       dst_roi_cmpns.x = xvimagesink->dst_roi.x;
747       dst_roi_cmpns.y = xvimagesink->dst_roi.y;
748
749       /* setting for DST ROI mode */
750       switch (xvimagesink->dst_roi_mode) {
751       case ROI_DISP_GEO_METHOD_FULL_SCREEN:
752         break;
753       case ROI_DISP_GEO_METHOD_LETTER_BOX:
754        {
755         GstVideoRectangle roi_result;
756         if (xvimagesink->orientation == DEGREE_0 ||
757             xvimagesink->orientation == DEGREE_180) {
758           src.w = src_origin.w;
759           src.h = src_origin.h;
760         } else {
761           src.w = src_origin.h;
762           src.h = src_origin.w;
763         }
764         dst.w = xvimagesink->dst_roi.w;
765         dst.h = xvimagesink->dst_roi.h;
766
767         gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
768         dst_roi_cmpns.w = roi_result.w;
769         dst_roi_cmpns.h = roi_result.h;
770         dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
771         dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
772        }
773         break;
774       default:
775         break;
776       }
777
778       /* calculating coordinates according to rotation angle for DST ROI */
779       switch (xvimagesink->rotate_angle) {
780       case DEGREE_90:
781         result.w = dst_roi_cmpns.h;
782         result.h = dst_roi_cmpns.w;
783
784         result.x = dst_roi_cmpns.y;
785                 if (xvimagesink->get_pixmap_cb) {
786                   result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
787                 } else {
788           result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
789                 }
790         break;
791       case DEGREE_180:
792         result.w = dst_roi_cmpns.w;
793         result.h = dst_roi_cmpns.h;
794
795                 if (xvimagesink->get_pixmap_cb) {
796                   result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
797                   result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
798                 } else {
799           result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
800           result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
801                 }
802         break;
803       case DEGREE_270:
804         result.w = dst_roi_cmpns.h;
805         result.h = dst_roi_cmpns.w;
806                 if (xvimagesink->get_pixmap_cb) {
807                   result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
808                 } else {
809           result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
810                 }
811         result.y = dst_roi_cmpns.x;
812         break;
813       default:
814         result.x = dst_roi_cmpns.x;
815         result.y = dst_roi_cmpns.y;
816         result.w = dst_roi_cmpns.w;
817         result.h = dst_roi_cmpns.h;
818         break;
819       }
820
821       /* orientation setting for auto rotation in DST ROI */
822       if (xvimagesink->orientation) {
823         res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation);
824         if (res_rotate_angle < 0) {
825           res_rotate_angle += DEGREE_NUM;
826         }
827         GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
828                      xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle);
829       }
830
831       GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
832                      xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode,
833                      xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
834                      result.x, result.y, result.w, result.h);
835       break;
836     }
837     default:
838       break;
839   }
840
841   if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
842     GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]",
843                    xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
844     gint default_offset_x = 0;
845     gint default_offset_y = 0;
846     gfloat w = (gfloat)src_input.w;
847     gfloat h = (gfloat)src_input.h;
848     if (xvimagesink->orientation == DEGREE_0 ||
849         xvimagesink->orientation == DEGREE_180) {
850       default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
851       default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
852     } else {
853       default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1;
854       default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1;
855     }
856     GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation);
857     if (xvimagesink->zoom_pos_x == -1) {
858       src_input.x += default_offset_x;
859     } else {
860       if (xvimagesink->orientation == DEGREE_0 ||
861           xvimagesink->orientation == DEGREE_180) {
862         if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) {
863           xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom);
864         }
865         src_input.x += xvimagesink->zoom_pos_x;
866       } else {
867         if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) {
868           xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom);
869         }
870         src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x;
871       }
872     }
873     if (xvimagesink->zoom_pos_y == -1) {
874       src_input.y += default_offset_y;
875     } else {
876       if (xvimagesink->orientation == DEGREE_0 ||
877           xvimagesink->orientation == DEGREE_180) {
878         if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) {
879           xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom);
880         }
881         src_input.y += xvimagesink->zoom_pos_y;
882       } else {
883         if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) {
884           xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom);
885         }
886         src_input.x += (xvimagesink->zoom_pos_y);
887       }
888     }
889     src_input.w = (gint)(w/xvimagesink->zoom);
890     src_input.h = (gint)(h/xvimagesink->zoom);
891     GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
892                    xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
893   }
894
895   switch( res_rotate_angle )
896   {
897     /* There's slightly weired code (CCW? CW?) */
898     case DEGREE_0:
899       break;
900     case DEGREE_90:
901       rotate = 270;
902       break;
903     case DEGREE_180:
904       rotate = 180;
905       break;
906     case DEGREE_270:
907       rotate = 90;
908       break;
909     default:
910       GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
911           res_rotate_angle );
912       break;
913   }
914
915   /*fix top and left green pixel of video*/
916   gst_xvimage_memory_get_crop (mem, &mem_crop);
917   src_input.x += mem_crop.x;
918   src_input.y += mem_crop.y;
919
920   /* Trim as proper size */
921   if (src_input.w % 2 == 1) {
922       src_input.w += 1;
923   }
924   if (src_input.h % 2 == 1) {
925       src_input.h += 1;
926   }
927
928   if (xvimagesink->get_pixmap_cb) {
929           GST_LOG_OBJECT( xvimagesink, "pixmap[%dx%d],method[%d],rotate[%d],zoom[%lf],dp_mode[%d],src[%d,%d,%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
930                 xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
931                 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->config.display_mode,
932                 src_origin.x, src_origin.y, src_origin.w, src_origin.h,
933                 dst.x, dst.y, dst.w, dst.h,
934                 src_input.x, src_input.y, src_input.w, src_input.h,
935                 result.x, result.y, result.w, result.h );
936
937   } else {
938     GST_LOG_OBJECT( xvimagesink, "window[%dx%d],method[%d],rotate[%d],zoom[%lf],dp_mode[%d],src[%d,%d,%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
939       xwindow->width, xwindow->height,
940       xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->config.display_mode,
941       src_origin.x, src_origin.y, src_origin.w, src_origin.h,
942       dst.x, dst.y, dst.w, dst.h,
943       src_input.x, src_input.y, src_input.w, src_input.h,
944       result.x, result.y, result.w, result.h );
945   }
946
947 #ifdef HAVE_XSHM
948   /* set display rotation */
949   if (atom_rotation == None) {
950     atom_rotation = XInternAtom(xvimagesink->context->disp,
951                                 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
952   }
953
954   GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
955
956   ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_rotation, rotate);
957   if (ret != Success) {
958     GST_ERROR_OBJECT( mem, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
959       ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_rotation, rotate );
960     return ret;
961   }
962
963   /* set display flip */
964   if (atom_hflip == None) {
965     atom_hflip = XInternAtom(xvimagesink->context->disp,
966                              "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
967   }
968   if (atom_vflip == None) {
969     atom_vflip = XInternAtom(xvimagesink->context->disp,
970                              "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
971   }
972
973   switch (xvimagesink->flip) {
974   case FLIP_HORIZONTAL:
975     set_hflip = TRUE;
976     set_vflip = FALSE;
977     break;
978   case FLIP_VERTICAL:
979     set_hflip = FALSE;
980     set_vflip = TRUE;
981     break;
982   case FLIP_BOTH:
983     set_hflip = TRUE;
984     set_vflip = TRUE;
985     break;
986   case FLIP_NONE:
987   default:
988     set_hflip = FALSE;
989     set_vflip = FALSE;
990     break;
991   }
992
993   ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_hflip, set_hflip);
994   if (ret != Success) {
995     GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
996                 ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_hflip, set_hflip);
997   }
998   ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_vflip, set_vflip);
999   if (ret != Success) {
1000     GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1001                 ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_vflip, set_vflip);
1002   }
1003 #endif /* HAVE_XSHM */
1004
1005   if (xvimagesink->get_pixmap_cb) {
1006     gst_xvimagesink_pixmap_render(mem, &src_input, &result, draw_border, xvimagesink);
1007   } else {
1008     gst_xvimage_memory_render (mem, &src_input, xwindow, &result, draw_border);
1009   }
1010   g_mutex_unlock (&xvimagesink->flow_lock);
1011
1012   return TRUE;
1013
1014 #else /* GST_EXT_XV_ENHANCEMENT */
1015   gst_xvimage_memory_get_crop (mem, &mem_crop);
1016
1017   crop = gst_buffer_get_video_crop_meta (xvimage);
1018
1019   if (crop) {
1020     src.x = crop->x + mem_crop.x;
1021     src.y = crop->y + mem_crop.y;
1022     src.w = crop->width;
1023     src.h = crop->height;
1024     GST_LOG_OBJECT (xvimagesink,
1025         "crop %dx%d-%dx%d", crop->x, crop->y, crop->width, crop->height);
1026   } else {
1027     src = mem_crop;
1028   }
1029
1030   if (xvimagesink->keep_aspect) {
1031     GstVideoRectangle s;
1032
1033     /* We take the size of the source material as it was negotiated and
1034      * corrected for DAR. This size can be different from the cropped size in
1035      * which case the image will be scaled to fit the negotiated size. */
1036     s.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1037     s.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1038     dst.w = xwindow->render_rect.w;
1039     dst.h = xwindow->render_rect.h;
1040
1041     gst_video_sink_center_rect (s, dst, &result, TRUE);
1042     result.x += xwindow->render_rect.x;
1043     result.y += xwindow->render_rect.y;
1044   } else {
1045     memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle));
1046   }
1047   gst_xvimage_memory_render (mem, &src, xwindow, &result, draw_border);
1048   g_mutex_unlock (&xvimagesink->flow_lock);
1049
1050   return TRUE;
1051 #endif /* GST_EXT_XV_ENHANCEMENT */
1052 }
1053
1054 static void
1055 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1056     GstXWindow * xwindow, const gchar * media_title)
1057 {
1058   if (media_title) {
1059     g_free (xvimagesink->media_title);
1060     xvimagesink->media_title = g_strdup (media_title);
1061   }
1062   if (xwindow) {
1063     /* we have a window */
1064     const gchar *app_name;
1065     const gchar *title = NULL;
1066     gchar *title_mem = NULL;
1067
1068     /* set application name as a title */
1069     app_name = g_get_application_name ();
1070
1071     if (app_name && xvimagesink->media_title) {
1072       title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1073           app_name, NULL);
1074     } else if (app_name) {
1075       title = app_name;
1076     } else if (xvimagesink->media_title) {
1077       title = xvimagesink->media_title;
1078     }
1079
1080     gst_xwindow_set_title (xwindow, title);
1081     g_free (title_mem);
1082   }
1083 }
1084
1085 /* This function handles a GstXWindow creation
1086  * The width and height are the actual pixel size on the display */
1087 static GstXWindow *
1088 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
1089     gint width, gint height)
1090 {
1091   GstXWindow *xwindow = NULL;
1092   GstXvContext *context;
1093
1094   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1095
1096   context = xvimagesink->context;
1097
1098 #ifdef GST_EXT_XV_ENHANCEMENT
1099   /* 0 or 180 */
1100   if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
1101       xwindow = gst_xvcontext_create_xwindow (context, height, width);
1102   /* 90 or 270 */
1103   } else {
1104       xwindow = gst_xvcontext_create_xwindow (context, width, height);
1105   }
1106 #else
1107   xwindow = gst_xvcontext_create_xwindow (context, width, height);
1108 #endif /* GST_EXT_XV_ENHANCEMENT */
1109
1110   /* set application name as a title */
1111   gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
1112
1113   gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events);
1114
1115   gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (xvimagesink),
1116       xwindow->win);
1117
1118   return xwindow;
1119 }
1120
1121 static void
1122 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
1123 {
1124   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1125
1126   /* Update the window geometry */
1127   g_mutex_lock (&xvimagesink->flow_lock);
1128   if (G_LIKELY (xvimagesink->xwindow))
1129     gst_xwindow_update_geometry (xvimagesink->xwindow);
1130   g_mutex_unlock (&xvimagesink->flow_lock);
1131 }
1132
1133 /* This function commits our internal colorbalance settings to our grabbed Xv
1134    port. If the context is not initialized yet it simply returns */
1135 static void
1136 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
1137 {
1138   GstXvContext *context;
1139
1140   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1141
1142   /* If we haven't initialized the X context we can't update anything */
1143   if ((context = xvimagesink->context) == NULL)
1144     return;
1145
1146   gst_xvcontext_update_colorbalance (context, &xvimagesink->config);
1147 }
1148
1149 /* This function handles XEvents that might be in the queue. It generates
1150    GstEvent that will be sent upstream in the pipeline to handle interactivity
1151    and navigation. It will also listen for configure events on the window to
1152    trigger caps renegotiation so on the fly software scaling can work. */
1153 static void
1154 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
1155 {
1156   XEvent e;
1157   guint pointer_x = 0, pointer_y = 0;
1158   gboolean pointer_moved = FALSE;
1159   gboolean exposed = FALSE, configured = FALSE;
1160
1161   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1162
1163 #ifdef GST_EXT_XV_ENHANCEMENT
1164   GST_LOG("check x event");
1165 #endif /* GST_EXT_XV_ENHANCEMENT */
1166
1167   /* Handle Interaction, produces navigation events */
1168
1169   /* We get all pointer motion events, only the last position is
1170      interesting. */
1171   g_mutex_lock (&xvimagesink->flow_lock);
1172   g_mutex_lock (&xvimagesink->context->lock);
1173   while (XCheckWindowEvent (xvimagesink->context->disp,
1174           xvimagesink->xwindow->win, PointerMotionMask, &e)) {
1175     g_mutex_unlock (&xvimagesink->context->lock);
1176     g_mutex_unlock (&xvimagesink->flow_lock);
1177
1178     switch (e.type) {
1179       case MotionNotify:
1180         pointer_x = e.xmotion.x;
1181         pointer_y = e.xmotion.y;
1182         pointer_moved = TRUE;
1183         break;
1184       default:
1185         break;
1186     }
1187     g_mutex_lock (&xvimagesink->flow_lock);
1188     g_mutex_lock (&xvimagesink->context->lock);
1189   }
1190
1191   if (pointer_moved) {
1192     g_mutex_unlock (&xvimagesink->context->lock);
1193     g_mutex_unlock (&xvimagesink->flow_lock);
1194
1195     GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
1196         pointer_x, pointer_y);
1197     gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1198         "mouse-move", 0, e.xbutton.x, e.xbutton.y);
1199
1200     g_mutex_lock (&xvimagesink->flow_lock);
1201     g_mutex_lock (&xvimagesink->context->lock);
1202   }
1203
1204   /* We get all events on our window to throw them upstream */
1205   while (XCheckWindowEvent (xvimagesink->context->disp,
1206           xvimagesink->xwindow->win,
1207           KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
1208           &e)) {
1209     KeySym keysym;
1210     const char *key_str = NULL;
1211
1212     /* We lock only for the X function call */
1213     g_mutex_unlock (&xvimagesink->context->lock);
1214     g_mutex_unlock (&xvimagesink->flow_lock);
1215
1216     switch (e.type) {
1217       case ButtonPress:
1218         /* Mouse button pressed over our window. We send upstream
1219            events for interactivity/navigation */
1220         GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
1221             e.xbutton.button, e.xbutton.x, e.xbutton.y);
1222         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1223             "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1224         break;
1225       case ButtonRelease:
1226         /* Mouse button released over our window. We send upstream
1227            events for interactivity/navigation */
1228         GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
1229             e.xbutton.button, e.xbutton.x, e.xbutton.y);
1230         gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1231             "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1232         break;
1233       case KeyPress:
1234       case KeyRelease:
1235         /* Key pressed/released over our window. We send upstream
1236            events for interactivity/navigation */
1237         g_mutex_lock (&xvimagesink->context->lock);
1238         keysym = XkbKeycodeToKeysym (xvimagesink->context->disp,
1239             e.xkey.keycode, 0, 0);
1240         if (keysym != NoSymbol) {
1241           key_str = XKeysymToString (keysym);
1242         } else {
1243           key_str = "unknown";
1244         }
1245         g_mutex_unlock (&xvimagesink->context->lock);
1246         GST_DEBUG_OBJECT (xvimagesink,
1247             "key %d pressed over window at %d,%d (%s)",
1248             e.xkey.keycode, e.xkey.x, e.xkey.y, key_str);
1249         gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1250             e.type == KeyPress ? "key-press" : "key-release", key_str);
1251         break;
1252       default:
1253         GST_DEBUG_OBJECT (xvimagesink, "xvimagesink unhandled X event (%d)",
1254             e.type);
1255     }
1256     g_mutex_lock (&xvimagesink->flow_lock);
1257     g_mutex_lock (&xvimagesink->context->lock);
1258   }
1259
1260   /* Handle Expose */
1261   while (XCheckWindowEvent (xvimagesink->context->disp,
1262           xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
1263     switch (e.type) {
1264       case Expose:
1265         exposed = TRUE;
1266         break;
1267       case ConfigureNotify:
1268         g_mutex_unlock (&xvimagesink->context->lock);
1269         g_mutex_unlock (&xvimagesink->flow_lock);
1270
1271 #ifdef GST_EXT_XV_ENHANCEMENT
1272         GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
1273 #endif /* GST_EXT_XV_ENHANCEMENT */
1274         gst_xvimagesink_xwindow_update_geometry (xvimagesink);
1275 #ifdef GST_EXT_XV_ENHANCEMENT
1276         GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
1277 #endif /* GST_EXT_XV_ENHANCEMENT */
1278         g_mutex_lock (&xvimagesink->flow_lock);
1279         g_mutex_lock (&xvimagesink->context->lock);
1280         configured = TRUE;
1281         break;
1282       default:
1283         break;
1284     }
1285   }
1286
1287   if (xvimagesink->handle_expose && (exposed || configured)) {
1288     g_mutex_unlock (&xvimagesink->context->lock);
1289     g_mutex_unlock (&xvimagesink->flow_lock);
1290
1291     gst_xvimagesink_expose (GST_VIDEO_OVERLAY (xvimagesink));
1292
1293     g_mutex_lock (&xvimagesink->flow_lock);
1294     g_mutex_lock (&xvimagesink->context->lock);
1295   }
1296
1297   /* Handle Display events */
1298   while (XPending (xvimagesink->context->disp)) {
1299     XNextEvent (xvimagesink->context->disp, &e);
1300
1301     switch (e.type) {
1302       case ClientMessage:{
1303 #ifdef GST_EXT_XV_ENHANCEMENT
1304         XClientMessageEvent *cme = (XClientMessageEvent *)&e;
1305         Atom buffer_atom = XInternAtom(xvimagesink->context->disp, "XV_RETURN_BUFFER", False);
1306 #endif /* GST_EXT_XV_ENHANCEMENT */
1307         Atom wm_delete;
1308
1309 #ifdef GST_EXT_XV_ENHANCEMENT
1310         GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
1311         if (cme->message_type == buffer_atom) {
1312           unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
1313
1314           GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
1315                     cme->data.l[0], cme->data.l[1]);
1316
1317           gem_name[0] = cme->data.l[0];
1318           gem_name[1] = cme->data.l[1];
1319
1320                   g_mutex_unlock (&xvimagesink->context->lock);
1321           gst_xvcontext_remove_displaying_buffer(xvimagesink->context, gem_name);
1322                   g_mutex_lock (&xvimagesink->context->lock);
1323
1324           break;
1325         }
1326 #endif /* GST_EXT_XV_ENHANCEMENT */
1327
1328         wm_delete = XInternAtom (xvimagesink->context->disp,
1329             "WM_DELETE_WINDOW", True);
1330         if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
1331           /* Handle window deletion by posting an error on the bus */
1332           GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
1333               ("Output window was closed"), (NULL));
1334
1335           g_mutex_unlock (&xvimagesink->context->lock);
1336           gst_xwindow_destroy (xvimagesink->xwindow);
1337           xvimagesink->xwindow = NULL;
1338           g_mutex_lock (&xvimagesink->context->lock);
1339         }
1340         break;
1341       }
1342       default:
1343         break;
1344     }
1345   }
1346
1347   g_mutex_unlock (&xvimagesink->context->lock);
1348   g_mutex_unlock (&xvimagesink->flow_lock);
1349 }
1350
1351 static gpointer
1352 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
1353 {
1354   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1355
1356   GST_OBJECT_LOCK (xvimagesink);
1357   while (xvimagesink->running) {
1358     GST_OBJECT_UNLOCK (xvimagesink);
1359
1360     if (xvimagesink->xwindow) {
1361       gst_xvimagesink_handle_xevents (xvimagesink);
1362     }
1363
1364 #ifdef GST_EXT_XV_ENHANCEMENT
1365     g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
1366 #else /* GST_EXT_XV_ENHANCEMENT */
1367     /* FIXME: do we want to align this with the framerate or anything else? */
1368     g_usleep (G_USEC_PER_SEC / 20);
1369 #endif /* GST_EXT_XV_ENHANCEMENT */
1370
1371     GST_OBJECT_LOCK (xvimagesink);
1372   }
1373   GST_OBJECT_UNLOCK (xvimagesink);
1374
1375   return NULL;
1376 }
1377
1378 static void
1379 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
1380 {
1381   GThread *thread = NULL;
1382
1383   /* don't start the thread too early */
1384   if (xvimagesink->context == NULL) {
1385     return;
1386   }
1387
1388   GST_OBJECT_LOCK (xvimagesink);
1389   if (xvimagesink->handle_expose || xvimagesink->handle_events) {
1390     if (!xvimagesink->event_thread) {
1391       /* Setup our event listening thread */
1392       GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
1393           xvimagesink->handle_expose, xvimagesink->handle_events);
1394       xvimagesink->running = TRUE;
1395       xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
1396           (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
1397     }
1398   } else {
1399     if (xvimagesink->event_thread) {
1400       GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
1401           xvimagesink->handle_expose, xvimagesink->handle_events);
1402       xvimagesink->running = FALSE;
1403       /* grab thread and mark it as NULL */
1404       thread = xvimagesink->event_thread;
1405       xvimagesink->event_thread = NULL;
1406     }
1407   }
1408   GST_OBJECT_UNLOCK (xvimagesink);
1409
1410   /* Wait for our event thread to finish */
1411   if (thread)
1412     g_thread_join (thread);
1413
1414 }
1415
1416 /* Element stuff */
1417
1418 static GstCaps *
1419 gst_xvimagesink_getcaps (GstBaseSink * bsink, GstCaps * filter)
1420 {
1421   GstXvImageSink *xvimagesink;
1422   GstCaps *caps;
1423
1424   xvimagesink = GST_XVIMAGESINK (bsink);
1425
1426   if (xvimagesink->context) {
1427     if (filter)
1428       return gst_caps_intersect_full (filter, xvimagesink->context->caps,
1429           GST_CAPS_INTERSECT_FIRST);
1430     else
1431       return gst_caps_ref (xvimagesink->context->caps);
1432   }
1433
1434   caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (xvimagesink));
1435   if (filter) {
1436     GstCaps *intersection;
1437
1438     intersection =
1439         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1440     gst_caps_unref (caps);
1441     caps = intersection;
1442   }
1443   return caps;
1444 }
1445
1446 static gboolean
1447 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
1448 {
1449   GstXvImageSink *xvimagesink;
1450   GstXvContext *context;
1451   GstStructure *structure;
1452   GstBufferPool *newpool, *oldpool;
1453   GstVideoInfo info;
1454   guint32 im_format = 0;
1455   gint video_par_n, video_par_d;        /* video's PAR */
1456   gint display_par_n, display_par_d;    /* display's PAR */
1457   guint num, den;
1458   gint size;
1459
1460   xvimagesink = GST_XVIMAGESINK (bsink);
1461   context = xvimagesink->context;
1462
1463   GST_DEBUG_OBJECT (xvimagesink,
1464       "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
1465       GST_PTR_FORMAT, context->caps, caps);
1466
1467   if (!gst_caps_can_intersect (context->caps, caps))
1468     goto incompatible_caps;
1469
1470   if (!gst_video_info_from_caps (&info, caps))
1471     goto invalid_format;
1472
1473   xvimagesink->fps_n = info.fps_n;
1474   xvimagesink->fps_d = info.fps_d;
1475
1476   xvimagesink->video_width = info.width;
1477   xvimagesink->video_height = info.height;
1478
1479   im_format = gst_xvcontext_get_format_from_info (context, &info);
1480   if (im_format == -1)
1481     goto invalid_format;
1482
1483   gst_xvcontext_set_colorimetry (context, &info.colorimetry);
1484
1485   size = info.size;
1486   GST_INFO ("info.size = %d ",size);
1487   /* get aspect ratio from caps if it's present, and
1488    * convert video width and height to a display width and height
1489    * using wd / hd = wv / hv * PARv / PARd */
1490
1491   /* get video's PAR */
1492   video_par_n = info.par_n;
1493   video_par_d = info.par_d;
1494
1495   /* get display's PAR */
1496   if (xvimagesink->par) {
1497     display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
1498     display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
1499   } else {
1500     display_par_n = 1;
1501     display_par_d = 1;
1502   }
1503
1504   if (!gst_video_calculate_display_ratio (&num, &den, info.width,
1505           info.height, video_par_n, video_par_d, display_par_n, display_par_d))
1506     goto no_disp_ratio;
1507
1508   GST_DEBUG_OBJECT (xvimagesink,
1509       "video width/height: %dx%d, calculated display ratio: %d/%d",
1510       info.width, info.height, num, den);
1511
1512   /* now find a width x height that respects this display ratio.
1513    * prefer those that have one of w/h the same as the incoming video
1514    * using wd / hd = num / den */
1515
1516   /* start with same height, because of interlaced video */
1517   /* check hd / den is an integer scale factor, and scale wd with the PAR */
1518   if (info.height % den == 0) {
1519     GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
1520     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
1521         gst_util_uint64_scale_int (info.height, num, den);
1522     GST_VIDEO_SINK_HEIGHT (xvimagesink) = info.height;
1523   } else if (info.width % num == 0) {
1524     GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
1525     GST_VIDEO_SINK_WIDTH (xvimagesink) = info.width;
1526     GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
1527         gst_util_uint64_scale_int (info.width, den, num);
1528   } else {
1529     GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
1530     GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
1531         gst_util_uint64_scale_int (info.height, num, den);
1532     GST_VIDEO_SINK_HEIGHT (xvimagesink) = info.height;
1533   }
1534   GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
1535       GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
1536
1537   /* Notify application to set xwindow id now */
1538   g_mutex_lock (&xvimagesink->flow_lock);
1539 #ifdef GST_EXT_XV_ENHANCEMENT
1540   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
1541 #else
1542   if (!xvimagesink->xwindow) {
1543 #endif
1544     g_mutex_unlock (&xvimagesink->flow_lock);
1545     gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (xvimagesink));
1546   } else {
1547     g_mutex_unlock (&xvimagesink->flow_lock);
1548   }
1549
1550   /* Creating our window and our image with the display size in pixels */
1551   if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
1552       GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
1553     goto no_display_size;
1554
1555   g_mutex_lock (&xvimagesink->flow_lock);
1556 #ifdef GST_EXT_XV_ENHANCEMENT
1557   if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
1558 #else
1559   if (!xvimagesink->xwindow) {
1560 #endif
1561     xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
1562         GST_VIDEO_SINK_WIDTH (xvimagesink),
1563         GST_VIDEO_SINK_HEIGHT (xvimagesink));
1564   }
1565
1566   xvimagesink->info = info;
1567
1568   /* After a resize, we want to redraw the borders in case the new frame size
1569    * doesn't cover the same area */
1570   xvimagesink->redraw_border = TRUE;
1571
1572   /* create a new pool for the new configuration */
1573   newpool = gst_xvimage_buffer_pool_new (xvimagesink->allocator);
1574
1575   structure = gst_buffer_pool_get_config (newpool);
1576   gst_buffer_pool_config_set_params (structure, caps, size, 2, 0);
1577   if (!gst_buffer_pool_set_config (newpool, structure))
1578     goto config_failed;
1579
1580   oldpool = xvimagesink->pool;
1581   /* we don't activate the pool yet, this will be done by downstream after it
1582    * has configured the pool. If downstream does not want our pool we will
1583    * activate it when we render into it */
1584   xvimagesink->pool = newpool;
1585   g_mutex_unlock (&xvimagesink->flow_lock);
1586
1587   /* unref the old sink */
1588   if (oldpool) {
1589     /* we don't deactivate, some elements might still be using it, it will
1590      * be deactivated when the last ref is gone */
1591     gst_object_unref (oldpool);
1592   }
1593
1594   return TRUE;
1595
1596   /* ERRORS */
1597 incompatible_caps:
1598   {
1599     GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
1600     return FALSE;
1601   }
1602 invalid_format:
1603   {
1604     GST_DEBUG_OBJECT (xvimagesink,
1605         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1606     return FALSE;
1607   }
1608 no_disp_ratio:
1609   {
1610     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
1611         ("Error calculating the output display ratio of the video."));
1612     return FALSE;
1613   }
1614 no_display_size:
1615   {
1616     GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
1617         ("Error calculating the output display ratio of the video."));
1618     return FALSE;
1619   }
1620 config_failed:
1621   {
1622     GST_ERROR_OBJECT (xvimagesink, "failed to set config.");
1623     g_mutex_unlock (&xvimagesink->flow_lock);
1624     return FALSE;
1625   }
1626 }
1627
1628 static GstStateChangeReturn
1629 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
1630 {
1631   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1632   GstXvImageSink *xvimagesink;
1633
1634   xvimagesink = GST_XVIMAGESINK (element);
1635
1636   switch (transition) {
1637     case GST_STATE_CHANGE_NULL_TO_READY:
1638 #ifdef GST_EXT_XV_ENHANCEMENT
1639       GST_WARNING("NULL_TO_READY start");
1640 #endif /* GST_EXT_XV_ENHANCEMENT */
1641       if (!gst_xvimagesink_open (xvimagesink))
1642         goto error;
1643 #ifdef GST_EXT_XV_ENHANCEMENT
1644       GST_WARNING("NULL_TO_READY done");
1645 #endif /* GST_EXT_XV_ENHANCEMENT */
1646       break;
1647     case GST_STATE_CHANGE_READY_TO_PAUSED:
1648       break;
1649     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1650 #ifdef GST_EXT_XV_ENHANCEMENT
1651         GST_WARNING("PAUSED_TO_PLAYING done");
1652 #endif /* GST_EXT_XV_ENHANCEMENT */
1653       break;
1654     case GST_STATE_CHANGE_PAUSED_TO_READY:
1655       break;
1656     default:
1657       break;
1658   }
1659
1660   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1661
1662   switch (transition) {
1663     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1664 #ifdef GST_EXT_XV_ENHANCEMENT
1665       GST_WARNING("PLAYING_TO_PAUSED start");
1666       /* init displayed buffer count */
1667       xvimagesink->context->displayed_buffer_count = 0;
1668
1669       GST_WARNING("PLAYING_TO_PAUSED done");
1670 #endif /* GST_EXT_XV_ENHANCEMENT */
1671       break;
1672     case GST_STATE_CHANGE_PAUSED_TO_READY:
1673       xvimagesink->fps_n = 0;
1674       xvimagesink->fps_d = 1;
1675       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
1676       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
1677       g_mutex_lock (&xvimagesink->flow_lock);
1678       if (xvimagesink->pool)
1679         gst_buffer_pool_set_active (xvimagesink->pool, FALSE);
1680       g_mutex_unlock (&xvimagesink->flow_lock);
1681 #ifdef GST_EXT_XV_ENHANCEMENT
1682       /* close drm */
1683       gst_xvcontext_drm_fini(xvimagesink->context);
1684
1685       GST_WARNING("PAUSED_TO_READY done");
1686 #endif /* GST_EXT_XV_ENHANCEMENT */
1687       break;
1688     case GST_STATE_CHANGE_READY_TO_NULL:
1689 #ifdef GST_EXT_XV_ENHANCEMENT
1690       GST_WARNING("READY_TO_NULL start");
1691 #endif /* GST_EXT_XV_ENHANCEMENT */
1692       gst_xvimagesink_close (xvimagesink);
1693 #ifdef GST_EXT_XV_ENHANCEMENT
1694       GST_WARNING("READY_TO_NULL done");
1695 #endif /* GST_EXT_XV_ENHANCEMENT */
1696       break;
1697     default:
1698       break;
1699   }
1700   return ret;
1701
1702 error:
1703   {
1704     return GST_STATE_CHANGE_FAILURE;
1705   }
1706 }
1707
1708 static void
1709 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1710     GstClockTime * start, GstClockTime * end)
1711 {
1712   GstXvImageSink *xvimagesink;
1713
1714   xvimagesink = GST_XVIMAGESINK (bsink);
1715
1716   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1717     *start = GST_BUFFER_TIMESTAMP (buf);
1718     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1719       *end = *start + GST_BUFFER_DURATION (buf);
1720     } else {
1721       if (xvimagesink->fps_n > 0) {
1722         *end = *start +
1723             gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
1724             xvimagesink->fps_n);
1725       }
1726     }
1727   }
1728 }
1729
1730 static GstFlowReturn
1731 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
1732 {
1733   GstFlowReturn res;
1734   GstXvImageSink *xvimagesink;
1735   GstBuffer *to_put;
1736   GstMemory *mem;
1737   gboolean ret = FALSE;
1738 #ifdef GST_EXT_XV_ENHANCEMENT
1739   GstMapInfo mem_info = GST_MAP_INFO_INIT;
1740   SCMN_IMGB *scmn_imgb = NULL;
1741 #endif /* GST_EXT_XV_ENHANCEMENT */
1742
1743   xvimagesink = GST_XVIMAGESINK (vsink);
1744
1745 #ifdef ENABLE_STOP_VIDEO
1746         if (xvimagesink->stop_video) {
1747           GST_INFO( "Stop video is TRUE. so skip show frame..." );
1748           return GST_FLOW_OK;
1749         }
1750 #endif
1751
1752   if (gst_buffer_n_memory (buf) == 1 && (mem = gst_buffer_peek_memory (buf, 0))
1753       && gst_xvimage_memory_is_from_context (mem, xvimagesink->context)) {
1754     /* If this buffer has been allocated using our buffer management we simply
1755        put the ximage which is in the PRIVATE pointer */
1756     GST_LOG_OBJECT (xvimagesink, "buffer %p from our pool, writing directly",
1757         buf);
1758 #ifdef GST_EXT_XV_ENHANCEMENT
1759     xvimagesink->xid_updated = FALSE;
1760 #endif /* GST_EXT_XV_ENHANCEMENT */
1761     to_put = buf;
1762     res = GST_FLOW_OK;
1763   } else {
1764     GstVideoFrame src, dest;
1765     GstBufferPoolAcquireParams params = { 0, };
1766
1767     /* Else we have to copy the data into our private image, */
1768     /* if we have one... */
1769     GST_LOG_OBJECT (xvimagesink, "buffer %p not from our pool, copying", buf);
1770
1771     /* we should have a pool, configured in setcaps */
1772     if (xvimagesink->pool == NULL)
1773       goto no_pool;
1774
1775     if (!gst_buffer_pool_set_active (xvimagesink->pool, TRUE))
1776       goto activate_failed;
1777
1778     /* take a buffer from our pool, if there is no buffer in the pool something
1779      * is seriously wrong, waiting for the pool here might deadlock when we try
1780      * to go to PAUSED because we never flush the pool then. */
1781     params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
1782     res = gst_buffer_pool_acquire_buffer (xvimagesink->pool, &to_put, &params);
1783     if (res != GST_FLOW_OK)
1784       goto no_buffer;
1785
1786     GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
1787         "slow copy buffer %p into bufferpool buffer %p", buf, to_put);
1788 #ifdef GST_EXT_XV_ENHANCEMENT
1789     g_mutex_lock (&xvimagesink->flow_lock);
1790     switch (GST_VIDEO_INFO_FORMAT(&xvimagesink->info)) {
1791       /* Cases for specified formats of Samsung extension */
1792      case GST_VIDEO_FORMAT_SN12:
1793      case GST_VIDEO_FORMAT_ST12:
1794      case GST_VIDEO_FORMAT_ITLV:
1795      {
1796        GstXvImageMemory* img_mem = NULL;
1797        XV_DATA_PTR img_data = NULL;
1798
1799        GST_LOG("Samsung EXT format - name:%s, display mode:%d, Rotate angle:%d", GST_VIDEO_INFO_NAME(&xvimagesink->info),
1800                xvimagesink->config.display_mode, xvimagesink->rotate_angle);
1801
1802        img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage((GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0))->data;
1803        if (img_data) {
1804          memset(img_data, 0x0, sizeof(XV_DATA));
1805          XV_INIT_DATA(img_data);
1806
1807          mem = gst_buffer_peek_memory(buf, 1);
1808          gst_memory_map(mem, &mem_info, GST_MAP_READ);
1809          scmn_imgb = (SCMN_IMGB *)mem_info.data;
1810          gst_memory_unmap(mem, &mem_info);
1811          if (scmn_imgb == NULL) {
1812            GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
1813            g_mutex_unlock (&xvimagesink->flow_lock);
1814            return GST_FLOW_OK;
1815          }
1816
1817          /* store buffer */
1818          img_mem = (GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0);
1819          img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage(img_mem)->data;
1820
1821          if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
1822            img_data->YBuf = (unsigned int)scmn_imgb->p[0];
1823            img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
1824            img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
1825            img_data->BufType = XV_BUF_TYPE_LEGACY;
1826          } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD || scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
1827            /* open drm to use gem */
1828            if (xvimagesink->context->drm_fd < 0) {
1829                gst_xvcontext_drm_init(xvimagesink->context);
1830            }
1831
1832            if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
1833              /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
1834              img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
1835              img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
1836              img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
1837              img_data->BufType = XV_BUF_TYPE_DMABUF;
1838              GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
1839            } else {
1840              /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
1841              img_data->bo[0] = scmn_imgb->bo[0];
1842              img_data->bo[1] = scmn_imgb->bo[1];
1843              img_data->bo[2] = scmn_imgb->bo[2];
1844              GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
1845            }
1846
1847            /* check secure contents path */
1848            /* NOTE : does it need to set 0 during playing(recovery case)? */
1849            if (scmn_imgb->tz_enable) {
1850              if (!xvimagesink->is_secure_path) {
1851                Atom atom_secure = None;
1852                g_mutex_lock (&xvimagesink->context->lock);
1853                atom_secure = XInternAtom(xvimagesink->context->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
1854                if (atom_secure != None) {
1855                  if (XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_secure, 1) != Success) {
1856                    GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.\n", atom_secure);
1857                  } else {
1858                    GST_WARNING_OBJECT(xvimagesink, "secure contents path is enabled.\n");
1859                  }
1860                    XSync (xvimagesink->context->disp, FALSE);
1861                }
1862                g_mutex_unlock (&xvimagesink->context->lock);
1863                xvimagesink->is_secure_path = TRUE;
1864              }
1865            }
1866            /* set current buffer */
1867            gst_xvimage_memory_set_buffer((GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0), buf);
1868            if (img_data)
1869              gst_xvcontext_add_displaying_buffer(xvimagesink->context, img_data, gst_xvimage_memory_get_buffer(img_mem));
1870
1871         } else {
1872           GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
1873                       scmn_imgb->buf_share_method);
1874           g_mutex_unlock (&xvimagesink->flow_lock);
1875           return GST_FLOW_OK;
1876         }
1877
1878        } else {
1879           GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
1880           g_mutex_lock (&xvimagesink->flow_lock);
1881           return GST_FLOW_OK;
1882         }
1883         break;
1884       }
1885       default:
1886       {
1887         GST_DEBUG("Normal format activated. Name = %s", GST_VIDEO_INFO_NAME(&xvimagesink->info));
1888         if (!gst_video_frame_map (&src, &xvimagesink->info, buf, GST_MAP_READ))
1889           goto invalid_buffer;
1890
1891         if (!gst_video_frame_map (&dest, &xvimagesink->info, to_put, GST_MAP_WRITE)) {
1892           gst_video_frame_unmap (&src);
1893           goto invalid_buffer;
1894         }
1895
1896         gst_video_frame_copy (&dest, &src);
1897
1898         gst_video_frame_unmap (&dest);
1899         gst_video_frame_unmap (&src);
1900         break;
1901       }
1902     }
1903         g_mutex_unlock (&xvimagesink->flow_lock);
1904 #else /* GST_EXT_XV_ENHANCEMENT */
1905     if (!gst_video_frame_map (&src, &xvimagesink->info, buf, GST_MAP_READ))
1906       goto invalid_buffer;
1907     if (!gst_video_frame_map (&dest, &xvimagesink->info, to_put, GST_MAP_WRITE)) {
1908       gst_video_frame_unmap (&src);
1909       goto invalid_buffer;
1910     }
1911
1912     gst_video_frame_copy (&dest, &src);
1913
1914     gst_video_frame_unmap (&dest);
1915     gst_video_frame_unmap (&src);
1916 #endif /* GST_EXT_XV_ENHANCEMENT */
1917   }
1918
1919   ret = gst_xvimagesink_xvimage_put(xvimagesink, to_put);
1920
1921   if (!ret) {
1922     goto no_window;
1923   }
1924
1925 done:
1926   if (to_put != buf)
1927     gst_buffer_unref (to_put);
1928
1929   return res;
1930
1931   /* ERRORS */
1932 no_pool:
1933   {
1934     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1935         ("Internal error: can't allocate images"),
1936         ("We don't have a bufferpool negotiated"));
1937     return GST_FLOW_ERROR;
1938   }
1939 no_buffer:
1940   {
1941     /* No image available. That's very bad ! */
1942     GST_WARNING_OBJECT (xvimagesink, "could not create image");
1943     return GST_FLOW_OK;
1944   }
1945 invalid_buffer:
1946   {
1947     /* No Window available to put our image into */
1948     GST_WARNING_OBJECT (xvimagesink, "could not map image");
1949 #ifdef GST_EXT_XV_ENHANCEMENT
1950           g_mutex_unlock (&xvimagesink->flow_lock);
1951 #endif
1952     res = GST_FLOW_OK;
1953     goto done;
1954   }
1955 no_window:
1956   {
1957     /* No Window available to put our image into */
1958     GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
1959     res = GST_FLOW_ERROR;
1960     goto done;
1961   }
1962 activate_failed:
1963   {
1964     GST_ERROR_OBJECT (xvimagesink, "failed to activate bufferpool.");
1965     res = GST_FLOW_ERROR;
1966     goto done;
1967   }
1968 }
1969
1970 static gboolean
1971 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
1972 {
1973   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
1974
1975   switch (GST_EVENT_TYPE (event)) {
1976     case GST_EVENT_TAG:{
1977       GstTagList *l;
1978       gchar *title = NULL;
1979
1980       gst_event_parse_tag (event, &l);
1981       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
1982
1983       if (title) {
1984 #ifdef GST_EXT_XV_ENHANCEMENT
1985         if (!xvimagesink->get_pixmap_cb) {
1986 #endif
1987
1988         GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
1989         gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
1990             title);
1991
1992         g_free (title);
1993 #ifdef GST_EXT_XV_ENHANCEMENT
1994         }
1995 #endif
1996
1997       }
1998       break;
1999     }
2000     default:
2001       break;
2002   }
2003   return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2004 }
2005
2006 static gboolean
2007 gst_xvimagesink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
2008 {
2009   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (bsink);
2010   GstBufferPool *pool;
2011   GstStructure *config;
2012   GstCaps *caps;
2013   guint size;
2014   gboolean need_pool;
2015
2016   gst_query_parse_allocation (query, &caps, &need_pool);
2017
2018   if (caps == NULL)
2019     goto no_caps;
2020
2021   g_mutex_lock (&xvimagesink->flow_lock);
2022   if ((pool = xvimagesink->pool))
2023     gst_object_ref (pool);
2024   g_mutex_unlock (&xvimagesink->flow_lock);
2025
2026   if (pool != NULL) {
2027     GstCaps *pcaps;
2028
2029     /* we had a pool, check caps */
2030     GST_DEBUG_OBJECT (xvimagesink, "check existing pool caps");
2031     config = gst_buffer_pool_get_config (pool);
2032     gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
2033
2034     if (!gst_caps_is_equal (caps, pcaps)) {
2035       GST_DEBUG_OBJECT (xvimagesink, "pool has different caps");
2036       /* different caps, we can't use this pool */
2037       gst_object_unref (pool);
2038       pool = NULL;
2039     }
2040     gst_structure_free (config);
2041   }
2042   if (pool == NULL && need_pool) {
2043     GstVideoInfo info;
2044
2045     if (!gst_video_info_from_caps (&info, caps))
2046       goto invalid_caps;
2047
2048     GST_DEBUG_OBJECT (xvimagesink, "create new pool");
2049     pool = gst_xvimage_buffer_pool_new (xvimagesink->allocator);
2050
2051     /* the normal size of a frame */
2052     size = info.size;
2053
2054     config = gst_buffer_pool_get_config (pool);
2055     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
2056     if (!gst_buffer_pool_set_config (pool, config))
2057       goto config_failed;
2058   }
2059   if (pool) {
2060     /* we need at least 2 buffer because we hold on to the last one */
2061     gst_query_add_allocation_pool (query, pool, size, 2, 0);
2062     gst_object_unref (pool);
2063   }
2064
2065   /* we also support various metadata */
2066   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2067   gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
2068
2069   return TRUE;
2070
2071   /* ERRORS */
2072 no_caps:
2073   {
2074     GST_DEBUG_OBJECT (bsink, "no caps specified");
2075     return FALSE;
2076   }
2077 invalid_caps:
2078   {
2079     GST_DEBUG_OBJECT (bsink, "invalid caps specified");
2080     return FALSE;
2081   }
2082 config_failed:
2083   {
2084     GST_DEBUG_OBJECT (bsink, "failed setting config");
2085     gst_object_unref (pool);
2086     return FALSE;
2087   }
2088 }
2089
2090 /* Interfaces stuff */
2091 static void
2092 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
2093     GstStructure * structure)
2094 {
2095   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
2096   GstPad *peer;
2097
2098   if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
2099     GstEvent *event;
2100     GstVideoRectangle src, dst, result;
2101     gdouble x, y, xscale = 1.0, yscale = 1.0;
2102     GstXWindow *xwindow;
2103
2104     event = gst_event_new_navigation (structure);
2105
2106     /* We take the flow_lock while we look at the window */
2107     g_mutex_lock (&xvimagesink->flow_lock);
2108
2109     if (!(xwindow = xvimagesink->xwindow)) {
2110       g_mutex_unlock (&xvimagesink->flow_lock);
2111       return;
2112     }
2113
2114     if (xvimagesink->keep_aspect) {
2115       /* We get the frame position using the calculated geometry from _setcaps
2116          that respect pixel aspect ratios */
2117       src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
2118       src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
2119       dst.w = xwindow->render_rect.w;
2120       dst.h = xwindow->render_rect.h;
2121
2122       gst_video_sink_center_rect (src, dst, &result, TRUE);
2123       result.x += xwindow->render_rect.x;
2124       result.y += xwindow->render_rect.y;
2125     } else {
2126       memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle));
2127     }
2128
2129     g_mutex_unlock (&xvimagesink->flow_lock);
2130
2131     /* We calculate scaling using the original video frames geometry to include
2132        pixel aspect ratio scaling. */
2133     xscale = (gdouble) xvimagesink->video_width / result.w;
2134     yscale = (gdouble) xvimagesink->video_height / result.h;
2135
2136     /* Converting pointer coordinates to the non scaled geometry */
2137     if (gst_structure_get_double (structure, "pointer_x", &x)) {
2138       x = MIN (x, result.x + result.w);
2139       x = MAX (x - result.x, 0);
2140       gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2141           (gdouble) x * xscale, NULL);
2142     }
2143     if (gst_structure_get_double (structure, "pointer_y", &y)) {
2144       y = MIN (y, result.y + result.h);
2145       y = MAX (y - result.y, 0);
2146       gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2147           (gdouble) y * yscale, NULL);
2148     }
2149
2150     gst_pad_send_event (peer, event);
2151     gst_object_unref (peer);
2152   }
2153 }
2154
2155 static void
2156 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
2157 {
2158   iface->send_event = gst_xvimagesink_navigation_send_event;
2159 }
2160
2161 static void
2162 gst_xvimagesink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
2163 {
2164   XID xwindow_id = id;
2165   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2166   GstXWindow *xwindow = NULL;
2167   GstXvContext *context;
2168 #ifdef GST_EXT_XV_ENHANCEMENT
2169   GstState current_state = GST_STATE_NULL;
2170 #endif /* GST_EXT_XV_ENHANCEMENT */
2171
2172   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2173
2174   g_mutex_lock (&xvimagesink->flow_lock);
2175
2176 #ifdef GST_EXT_XV_ENHANCEMENT
2177   gst_element_get_state(GST_ELEMENT(xvimagesink), &current_state, NULL, 0);
2178   GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
2179                                   xwindow_id, current_state);
2180 #endif /* GST_EXT_XV_ENHANCEMENT */
2181
2182   /* If we already use that window return */
2183   if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
2184     g_mutex_unlock (&xvimagesink->flow_lock);
2185     return;
2186   }
2187
2188   /* If the element has not initialized the X11 context try to do so */
2189   if (!xvimagesink->context &&
2190       !(xvimagesink->context =
2191           gst_xvcontext_new (&xvimagesink->config, NULL))) {
2192     g_mutex_unlock (&xvimagesink->flow_lock);
2193     /* we have thrown a GST_ELEMENT_ERROR now */
2194     return;
2195   }
2196
2197   context = xvimagesink->context;
2198
2199   gst_xvimagesink_update_colorbalance (xvimagesink);
2200
2201   /* If a window is there already we destroy it */
2202   if (xvimagesink->xwindow) {
2203     gst_xwindow_destroy (xvimagesink->xwindow);
2204     xvimagesink->xwindow = NULL;
2205   }
2206
2207   /* If the xid is 0 we go back to an internal window */
2208   if (xwindow_id == 0) {
2209     /* If no width/height caps nego did not happen window will be created
2210        during caps nego then */
2211     if (GST_VIDEO_SINK_WIDTH (xvimagesink)
2212         && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
2213       xwindow =
2214           gst_xvimagesink_xwindow_new (xvimagesink,
2215           GST_VIDEO_SINK_WIDTH (xvimagesink),
2216           GST_VIDEO_SINK_HEIGHT (xvimagesink));
2217     }
2218   } else {
2219     xwindow = gst_xvcontext_create_xwindow_from_xid (context, xwindow_id);
2220     gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events);
2221   }
2222
2223   if (xwindow)
2224     xvimagesink->xwindow = xwindow;
2225
2226 #ifdef GST_EXT_XV_ENHANCEMENT
2227   xvimagesink->xid_updated = TRUE;
2228 #endif /* GST_EXT_XV_ENHANCEMENT */
2229
2230   g_mutex_unlock (&xvimagesink->flow_lock);
2231
2232 #ifdef GST_EXT_XV_ENHANCEMENT
2233   if (current_state == GST_STATE_PAUSED) {
2234     GstBuffer *last_buffer = NULL;
2235     g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
2236     GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
2237     if (last_buffer) {
2238       gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
2239       gst_buffer_unref(last_buffer);
2240       last_buffer = NULL;
2241     }
2242   }
2243 #endif /* GST_EXT_XV_ENHANCEMENT */
2244 }
2245
2246 #ifdef GST_EXT_XV_ENHANCEMENT
2247 /* This function destroys a GstXWindow */
2248 static void
2249 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
2250     GstXPixmap * xpixmap)
2251 {
2252   g_return_if_fail (xpixmap != NULL);
2253   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2254
2255   XSelectInput (xvimagesink->context->disp, xpixmap->pixmap, 0);
2256
2257   XFreeGC (xvimagesink->context->disp, xpixmap->gc);
2258
2259   XSync (xvimagesink->context->disp, FALSE);
2260
2261   g_free (xpixmap);
2262 }
2263
2264 static void
2265 gst_xvimagesink_set_pixmap_handle (GstVideoOverlay * overlay, guintptr id)
2266 {
2267   GST_INFO("gst_xvimagesink_set_pixmap_handle");
2268
2269   XID pixmap_id = id;
2270   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2271   GstXPixmap *xpixmap = NULL;
2272   int i = 0;
2273   int (*handler) (Display *, XErrorEvent *);
2274   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2275
2276   /* If the element has not initialized the X11 context try to do so */
2277   if (!xvimagesink->context && !(xvimagesink->context =
2278     gst_xvcontext_new (&xvimagesink->config, NULL))) {
2279         /* we have thrown a GST_ELEMENT_ERROR now */
2280         GST_ERROR("GST_ELEMENT_ERROR");
2281         return;
2282   }
2283   GST_INFO("call gst_xvimagesink_update_colorbalance ");
2284   gst_xvimagesink_update_colorbalance (xvimagesink);
2285
2286   GST_INFO("pixmap id : %d", pixmap_id );
2287
2288   /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
2289   if (pixmap_id == 0) {
2290     xvimagesink->current_pixmap_idx = -2;
2291         return;
2292   }
2293
2294   for (i = 0; i < MAX_PIXMAP_NUM; i++) {
2295     if (!xvimagesink->xpixmap[i]) {
2296           Window root_window;
2297           int cur_win_x = 0;
2298           int cur_win_y = 0;
2299           unsigned int cur_win_width = 0;
2300           unsigned int cur_win_height = 0;
2301           unsigned int cur_win_border_width = 0;
2302           unsigned int cur_win_depth = 0;
2303
2304           GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
2305
2306           xpixmap = g_new0 (GstXPixmap, 1);
2307           if (xpixmap) {
2308                 xpixmap->pixmap = pixmap_id;
2309
2310                 /* Get root window and size of current window */
2311                 XGetGeometry(xvimagesink->context->disp, xpixmap->pixmap, &root_window,
2312                                          &cur_win_x, &cur_win_y, /* relative x, y */
2313                                          &cur_win_width, &cur_win_height,
2314                                          &cur_win_border_width, &cur_win_depth);
2315                 if (!cur_win_width || !cur_win_height) {
2316                   GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
2317                   return;
2318                 }
2319                 GST_INFO("cur_win_x(%d) cur_win_y(%d) cur_win_width(%d)  cur_win_height(%d) cur_win_border_width(%d) cur_win_depth(%d)",
2320                         cur_win_x, cur_win_y, cur_win_width, cur_win_height, cur_win_border_width, cur_win_depth);
2321                         xpixmap->width = cur_win_width;
2322                         xpixmap->height = cur_win_height;
2323
2324                 /* Setting an error handler to catch failure */
2325                 error_caught = FALSE;
2326                 handler = XSetErrorHandler (gst_xvimage_pixmap_xerror);
2327
2328                 /* Create a GC */
2329                 xpixmap->gc = XCreateGC (xvimagesink->context->disp, xpixmap->pixmap, 0, NULL);
2330
2331                 XSync(xvimagesink->context->disp, FALSE);
2332                 if (error_caught) {
2333                   GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
2334                 }
2335                 if (handler) {
2336                   error_caught = FALSE;
2337                   XSetErrorHandler (handler);
2338                 }
2339
2340                 xvimagesink->xpixmap[i] = xpixmap;
2341                 xvimagesink->current_pixmap_idx = i;
2342           } else {
2343                 GST_ERROR("failed to create xpixmap errno: %d", errno);
2344           }
2345
2346           return;
2347
2348         } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
2349           GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
2350           xvimagesink->current_pixmap_idx = i;
2351           return;
2352         } else {
2353                   continue;
2354         }
2355   }
2356
2357   GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
2358     xvimagesink->current_pixmap_idx = -1;
2359
2360 }
2361 #endif /* GST_EXT_XV_ENHANCEMENT */
2362
2363
2364
2365 static void
2366 gst_xvimagesink_expose (GstVideoOverlay * overlay)
2367 {
2368   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2369
2370   GST_DEBUG ("doing expose");
2371   gst_xvimagesink_xwindow_update_geometry (xvimagesink);
2372   gst_xvimagesink_xvimage_put (xvimagesink, NULL);
2373 }
2374
2375 static void
2376 gst_xvimagesink_set_event_handling (GstVideoOverlay * overlay,
2377     gboolean handle_events)
2378 {
2379   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2380
2381   g_mutex_lock (&xvimagesink->flow_lock);
2382   xvimagesink->handle_events = handle_events;
2383   if (G_LIKELY (xvimagesink->xwindow))
2384     gst_xwindow_set_event_handling (xvimagesink->xwindow, handle_events);
2385   g_mutex_unlock (&xvimagesink->flow_lock);
2386 }
2387
2388 static void
2389 gst_xvimagesink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y,
2390     gint width, gint height)
2391 {
2392   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2393
2394   g_mutex_lock (&xvimagesink->flow_lock);
2395   if (G_LIKELY (xvimagesink->xwindow))
2396     gst_xwindow_set_render_rectangle (xvimagesink->xwindow, x, y, width,
2397         height);
2398   g_mutex_unlock (&xvimagesink->flow_lock);
2399 }
2400
2401 static void
2402 gst_xvimagesink_video_overlay_init (GstVideoOverlayInterface * iface)
2403 {
2404   iface->set_window_handle = gst_xvimagesink_set_window_handle;
2405   iface->expose = gst_xvimagesink_expose;
2406   iface->handle_events = gst_xvimagesink_set_event_handling;
2407   iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
2408 }
2409
2410 static const GList *
2411 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
2412 {
2413   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2414
2415   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2416
2417   if (xvimagesink->context)
2418     return xvimagesink->context->channels_list;
2419   else
2420     return NULL;
2421 }
2422
2423 static void
2424 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
2425     GstColorBalanceChannel * channel, gint value)
2426 {
2427   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2428
2429   g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2430   g_return_if_fail (channel->label != NULL);
2431
2432   xvimagesink->config.cb_changed = TRUE;
2433
2434   /* Normalize val to [-1000, 1000] */
2435   value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
2436       (double) (channel->max_value - channel->min_value));
2437
2438   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2439     xvimagesink->config.hue = value;
2440   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2441     xvimagesink->config.saturation = value;
2442   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2443     xvimagesink->config.contrast = value;
2444   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2445     xvimagesink->config.brightness = value;
2446   } else {
2447     g_warning ("got an unknown channel %s", channel->label);
2448     return;
2449   }
2450
2451   gst_xvimagesink_update_colorbalance (xvimagesink);
2452 }
2453
2454 static gint
2455 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
2456     GstColorBalanceChannel * channel)
2457 {
2458   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2459   gint value = 0;
2460
2461   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
2462   g_return_val_if_fail (channel->label != NULL, 0);
2463
2464   if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2465     value = xvimagesink->config.hue;
2466   } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2467     value = xvimagesink->config.saturation;
2468   } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2469     value = xvimagesink->config.contrast;
2470   } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2471     value = xvimagesink->config.brightness;
2472   } else {
2473     g_warning ("got an unknown channel %s", channel->label);
2474   }
2475
2476   /* Normalize val to [channel->min_value, channel->max_value] */
2477   value = channel->min_value + (channel->max_value - channel->min_value) *
2478       (value + 1000) / 2000;
2479
2480   return value;
2481 }
2482
2483 static GstColorBalanceType
2484 gst_xvimagesink_colorbalance_get_balance_type (GstColorBalance * balance)
2485 {
2486   return GST_COLOR_BALANCE_HARDWARE;
2487 }
2488
2489 static void
2490 gst_xvimagesink_colorbalance_init (GstColorBalanceInterface * iface)
2491 {
2492   iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
2493   iface->set_value = gst_xvimagesink_colorbalance_set_value;
2494   iface->get_value = gst_xvimagesink_colorbalance_get_value;
2495   iface->get_balance_type = gst_xvimagesink_colorbalance_get_balance_type;
2496 }
2497
2498 #if 0
2499 static const GList *
2500 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
2501 {
2502   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
2503   static GList *list = NULL;
2504
2505   if (!list) {
2506     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
2507     list =
2508         g_list_append (list, g_object_class_find_property (klass,
2509             "autopaint-colorkey"));
2510     list =
2511         g_list_append (list, g_object_class_find_property (klass,
2512             "double-buffer"));
2513     list =
2514         g_list_append (list, g_object_class_find_property (klass, "colorkey"));
2515   }
2516
2517   return list;
2518 }
2519
2520 static void
2521 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
2522     guint prop_id, const GParamSpec * pspec)
2523 {
2524   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2525
2526   switch (prop_id) {
2527     case PROP_DEVICE:
2528     case PROP_AUTOPAINT_COLORKEY:
2529     case PROP_DOUBLE_BUFFER:
2530     case PROP_COLORKEY:
2531       GST_DEBUG_OBJECT (xvimagesink,
2532           "probing device list and get capabilities");
2533       if (!xvimagesink->context) {
2534         GST_DEBUG_OBJECT (xvimagesink, "generating context");
2535         xvimagesink->context = gst_xvimagesink_context_get (xvimagesink);
2536       }
2537       break;
2538     default:
2539       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2540       break;
2541   }
2542 }
2543
2544 static gboolean
2545 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
2546     guint prop_id, const GParamSpec * pspec)
2547 {
2548   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2549   gboolean ret = FALSE;
2550
2551   switch (prop_id) {
2552     case PROP_DEVICE:
2553     case PROP_AUTOPAINT_COLORKEY:
2554     case PROP_DOUBLE_BUFFER:
2555     case PROP_COLORKEY:
2556       if (xvimagesink->context != NULL) {
2557         ret = FALSE;
2558       } else {
2559         ret = TRUE;
2560       }
2561       break;
2562     default:
2563       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2564       break;
2565   }
2566
2567   return ret;
2568 }
2569
2570 static GValueArray *
2571 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
2572     guint prop_id, const GParamSpec * pspec)
2573 {
2574   GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2575   GValueArray *array = NULL;
2576
2577   if (G_UNLIKELY (!xvimagesink->context)) {
2578     GST_WARNING_OBJECT (xvimagesink, "we don't have any context, can't "
2579         "get values");
2580     goto beach;
2581   }
2582
2583   switch (prop_id) {
2584     case PROP_DEVICE:
2585     {
2586       guint i;
2587       GValue value = { 0 };
2588
2589       array = g_value_array_new (xvimagesink->context->nb_adaptors);
2590       g_value_init (&value, G_TYPE_STRING);
2591
2592       for (i = 0; i < xvimagesink->context->nb_adaptors; i++) {
2593         gchar *adaptor_id_s = g_strdup_printf ("%u", i);
2594
2595         g_value_set_string (&value, adaptor_id_s);
2596         g_value_array_append (array, &value);
2597         g_free (adaptor_id_s);
2598       }
2599       g_value_unset (&value);
2600       break;
2601     }
2602     case PROP_AUTOPAINT_COLORKEY:
2603       if (xvimagesink->have_autopaint_colorkey) {
2604         GValue value = { 0 };
2605
2606         array = g_value_array_new (2);
2607         g_value_init (&value, G_TYPE_BOOLEAN);
2608         g_value_set_boolean (&value, FALSE);
2609         g_value_array_append (array, &value);
2610         g_value_set_boolean (&value, TRUE);
2611         g_value_array_append (array, &value);
2612         g_value_unset (&value);
2613       }
2614       break;
2615     case PROP_DOUBLE_BUFFER:
2616       if (xvimagesink->have_double_buffer) {
2617         GValue value = { 0 };
2618
2619         array = g_value_array_new (2);
2620         g_value_init (&value, G_TYPE_BOOLEAN);
2621         g_value_set_boolean (&value, FALSE);
2622         g_value_array_append (array, &value);
2623         g_value_set_boolean (&value, TRUE);
2624         g_value_array_append (array, &value);
2625         g_value_unset (&value);
2626       }
2627       break;
2628     case PROP_COLORKEY:
2629       if (xvimagesink->have_colorkey) {
2630         GValue value = { 0 };
2631
2632         array = g_value_array_new (1);
2633         g_value_init (&value, GST_TYPE_INT_RANGE);
2634         gst_value_set_int_range (&value, 0, 0xffffff);
2635         g_value_array_append (array, &value);
2636         g_value_unset (&value);
2637       }
2638       break;
2639     default:
2640       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2641       break;
2642   }
2643
2644 beach:
2645   return array;
2646 }
2647
2648 static void
2649 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
2650     iface)
2651 {
2652   iface->get_properties = gst_xvimagesink_probe_get_properties;
2653   iface->probe_property = gst_xvimagesink_probe_probe_property;
2654   iface->needs_probe = gst_xvimagesink_probe_needs_probe;
2655   iface->get_values = gst_xvimagesink_probe_get_values;
2656 }
2657 #endif
2658
2659 /* =========================================== */
2660 /*                                             */
2661 /*              Init & Class init              */
2662 /*                                             */
2663 /* =========================================== */
2664
2665 static void
2666 gst_xvimagesink_set_property (GObject * object, guint prop_id,
2667     const GValue * value, GParamSpec * pspec)
2668 {
2669   GstXvImageSink *xvimagesink;
2670
2671   g_return_if_fail (GST_IS_XVIMAGESINK (object));
2672
2673   xvimagesink = GST_XVIMAGESINK (object);
2674
2675   switch (prop_id) {
2676     case PROP_HUE:
2677       xvimagesink->config.hue = g_value_get_int (value);
2678       xvimagesink->config.cb_changed = TRUE;
2679       gst_xvimagesink_update_colorbalance (xvimagesink);
2680       break;
2681     case PROP_CONTRAST:
2682       xvimagesink->config.contrast = g_value_get_int (value);
2683       xvimagesink->config.cb_changed = TRUE;
2684       gst_xvimagesink_update_colorbalance (xvimagesink);
2685       break;
2686     case PROP_BRIGHTNESS:
2687       xvimagesink->config.brightness = g_value_get_int (value);
2688       xvimagesink->config.cb_changed = TRUE;
2689       gst_xvimagesink_update_colorbalance (xvimagesink);
2690       break;
2691     case PROP_SATURATION:
2692       xvimagesink->config.saturation = g_value_get_int (value);
2693       xvimagesink->config.cb_changed = TRUE;
2694       gst_xvimagesink_update_colorbalance (xvimagesink);
2695       break;
2696     case PROP_DISPLAY:
2697       g_free (xvimagesink->config.display_name);
2698       xvimagesink->config.display_name = g_strdup (g_value_get_string (value));
2699       break;
2700     case PROP_SYNCHRONOUS:
2701       xvimagesink->synchronous = g_value_get_boolean (value);
2702       if (xvimagesink->context) {
2703         gst_xvcontext_set_synchronous (xvimagesink->context,
2704             xvimagesink->synchronous);
2705       }
2706       break;
2707     case PROP_PIXEL_ASPECT_RATIO:
2708       g_free (xvimagesink->par);
2709       xvimagesink->par = g_new0 (GValue, 1);
2710       g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
2711       if (!g_value_transform (value, xvimagesink->par)) {
2712         g_warning ("Could not transform string to aspect ratio");
2713         gst_value_set_fraction (xvimagesink->par, 1, 1);
2714       }
2715       GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
2716           gst_value_get_fraction_numerator (xvimagesink->par),
2717           gst_value_get_fraction_denominator (xvimagesink->par));
2718       break;
2719     case PROP_FORCE_ASPECT_RATIO:
2720       xvimagesink->keep_aspect = g_value_get_boolean (value);
2721       break;
2722     case PROP_HANDLE_EVENTS:
2723       gst_xvimagesink_set_event_handling (GST_VIDEO_OVERLAY (xvimagesink),
2724           g_value_get_boolean (value));
2725       gst_xvimagesink_manage_event_thread (xvimagesink);
2726       break;
2727     case PROP_DEVICE:
2728       xvimagesink->config.adaptor_nr = atoi (g_value_get_string (value));
2729       break;
2730     case PROP_HANDLE_EXPOSE:
2731       xvimagesink->handle_expose = g_value_get_boolean (value);
2732       gst_xvimagesink_manage_event_thread (xvimagesink);
2733       break;
2734     case PROP_DOUBLE_BUFFER:
2735       xvimagesink->double_buffer = g_value_get_boolean (value);
2736       break;
2737     case PROP_AUTOPAINT_COLORKEY:
2738       xvimagesink->config.autopaint_colorkey = g_value_get_boolean (value);
2739       break;
2740     case PROP_COLORKEY:
2741       xvimagesink->config.colorkey = g_value_get_int (value);
2742       break;
2743     case PROP_DRAW_BORDERS:
2744       xvimagesink->draw_borders = g_value_get_boolean (value);
2745       break;
2746 #ifdef GST_EXT_XV_ENHANCEMENT
2747     case PROP_DISPLAY_MODE:
2748     {
2749       int set_mode = g_value_get_enum (value);
2750
2751       g_mutex_lock(&xvimagesink->flow_lock);
2752       g_mutex_lock(&xvimagesink->context->lock);
2753
2754       if (xvimagesink->config.display_mode != set_mode) {
2755         if (xvimagesink->context) {
2756           /* set display mode */
2757           if (gst_xvcontext_set_display_mode(xvimagesink->context, set_mode)) {
2758             xvimagesink->config.display_mode = set_mode;
2759           } else {
2760             GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
2761           }
2762         } else {
2763           /* "xcontext" is not created yet. It will be applied when xcontext is created. */
2764           GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
2765           xvimagesink->config.display_mode = set_mode;
2766         }
2767       } else {
2768         GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
2769       }
2770
2771       g_mutex_unlock(&xvimagesink->context->lock);
2772       g_mutex_unlock(&xvimagesink->flow_lock);
2773     }
2774       break;
2775     case PROP_DISPLAY_GEOMETRY_METHOD:
2776       xvimagesink->display_geometry_method = g_value_get_enum (value);
2777       GST_LOG("Overlay geometry changed. update it");
2778       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2779         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2780       }
2781       break;
2782     case PROP_FLIP:
2783       xvimagesink->flip = g_value_get_enum(value);
2784       break;
2785     case PROP_ROTATE_ANGLE:
2786       xvimagesink->rotate_angle = g_value_get_enum (value);
2787       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2788         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2789       }
2790       break;
2791     case PROP_VISIBLE:
2792       g_mutex_lock( &xvimagesink->flow_lock );
2793
2794       GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
2795
2796       if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
2797         if (xvimagesink->context) {
2798           g_mutex_lock( &xvimagesink->context->lock );
2799 #if 0
2800           Atom atom_stream = XInternAtom( xvimagesink->context->disp,
2801                                           "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
2802           if (atom_stream != None) {
2803             GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
2804             if (XvSetPortAttribute(xvimagesink->context->disp,
2805                                    xvimagesink->context->xv_port_id,
2806                                    atom_stream, 0 ) != Success) {
2807               GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
2808             }
2809           }
2810 #endif
2811           xvimagesink->visible = g_value_get_boolean (value);
2812
2813           if (GST_STATE (xvimagesink) > GST_STATE_READY) {
2814                     if (xvimagesink->get_pixmap_cb) {
2815                           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2816                                 XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2817                           }
2818                     } else {
2819                       XvStopVideo(xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xwindow->win);
2820                     }
2821           }
2822           XSync( xvimagesink->context->disp, FALSE );
2823           g_mutex_unlock( &xvimagesink->context->lock );
2824         } else {
2825           GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
2826           xvimagesink->visible = g_value_get_boolean (value);
2827         }
2828
2829       } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
2830         g_mutex_unlock( &xvimagesink->flow_lock );
2831         xvimagesink->visible = g_value_get_boolean (value);
2832         g_mutex_lock( &xvimagesink->flow_lock );
2833       }
2834
2835       GST_INFO("set visible(%d) done", xvimagesink->visible);
2836
2837       g_mutex_unlock( &xvimagesink->flow_lock );
2838       break;
2839     case PROP_ZOOM:
2840       xvimagesink->zoom = g_value_get_float (value);
2841       break;
2842     case PROP_ZOOM_POS_X:
2843       xvimagesink->zoom_pos_x = g_value_get_int (value);
2844       break;
2845     case PROP_ZOOM_POS_Y:
2846       xvimagesink->zoom_pos_y = g_value_get_int (value);
2847       if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2848         gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2849       }
2850       break;
2851     case PROP_ORIENTATION:
2852       xvimagesink->orientation = g_value_get_enum (value);
2853       GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
2854       break;
2855     case PROP_DST_ROI_MODE:
2856       xvimagesink->dst_roi_mode = g_value_get_enum (value);
2857       GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
2858       break;
2859     case PROP_DST_ROI_X:
2860       xvimagesink->dst_roi.x = g_value_get_int (value);
2861       break;
2862     case PROP_DST_ROI_Y:
2863       xvimagesink->dst_roi.y = g_value_get_int (value);
2864       break;
2865     case PROP_DST_ROI_W:
2866       xvimagesink->dst_roi.w = g_value_get_int (value);
2867       break;
2868     case PROP_DST_ROI_H:
2869       xvimagesink->dst_roi.h = g_value_get_int (value);
2870       break;
2871 #ifdef ENABLE_STOP_VIDEO
2872         case PROP_STOP_VIDEO:
2873           xvimagesink->stop_video = g_value_get_int (value);
2874       g_mutex_lock( &xvimagesink->flow_lock );
2875           if (xvimagesink->stop_video) {
2876             if (xvimagesink->get_pixmap_cb && xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2877                   GST_INFO("calling XvStopVideo()");
2878                   g_mutex_lock( &xvimagesink->context->lock );
2879           XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2880                   g_mutex_unlock( &xvimagesink->context->lock );
2881                 }
2882           } else {
2883             GST_INFO("Xwindow CLEAR when set video-stop property");
2884                 gst_xwindow_clear (xvimagesink->xwindow);
2885           }
2886       g_mutex_unlock( &xvimagesink->flow_lock );
2887           break;
2888 #endif
2889         case PROP_PIXMAP_CB:
2890     {
2891           void *cb_func;
2892           cb_func = g_value_get_pointer (value);
2893           if (cb_func){
2894                 if (xvimagesink->get_pixmap_cb) {
2895                   int i = 0;
2896                   if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2897                         g_mutex_lock( &xvimagesink->context->lock );
2898                         XvStopVideo(xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2899                         g_mutex_unlock( &xvimagesink->context->lock );
2900                   }
2901                   for (i = 0; i < MAX_PIXMAP_NUM; i++) {
2902             if (xvimagesink->xpixmap[i]) {
2903               gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
2904               xvimagesink->xpixmap[i] = NULL;
2905             }
2906           }
2907                 }
2908                 xvimagesink->get_pixmap_cb = cb_func;
2909                 GST_INFO("Set callback(%p) for getting pixmap id", xvimagesink->get_pixmap_cb);
2910           }
2911           break;
2912         }
2913         case PROP_PIXMAP_CB_USER_DATA:
2914         {
2915           void *user_data;
2916           user_data = g_value_get_pointer (value);
2917           if (user_data) {
2918         xvimagesink->get_pixmap_cb_user_data = user_data;
2919                 GST_INFO("Set user data(%p) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
2920           }
2921           break;
2922         }
2923 #endif /* GST_EXT_XV_ENHANCEMENT */
2924     default:
2925       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2926       break;
2927   }
2928 }
2929
2930 static void
2931 gst_xvimagesink_get_property (GObject * object, guint prop_id,
2932     GValue * value, GParamSpec * pspec)
2933 {
2934   GstXvImageSink *xvimagesink;
2935
2936   g_return_if_fail (GST_IS_XVIMAGESINK (object));
2937
2938   xvimagesink = GST_XVIMAGESINK (object);
2939
2940   switch (prop_id) {
2941     case PROP_HUE:
2942       g_value_set_int (value, xvimagesink->config.hue);
2943       break;
2944     case PROP_CONTRAST:
2945       g_value_set_int (value, xvimagesink->config.contrast);
2946       break;
2947     case PROP_BRIGHTNESS:
2948       g_value_set_int (value, xvimagesink->config.brightness);
2949       break;
2950     case PROP_SATURATION:
2951       g_value_set_int (value, xvimagesink->config.saturation);
2952       break;
2953     case PROP_DISPLAY:
2954       g_value_set_string (value, xvimagesink->config.display_name);
2955       break;
2956     case PROP_SYNCHRONOUS:
2957       g_value_set_boolean (value, xvimagesink->synchronous);
2958       break;
2959     case PROP_PIXEL_ASPECT_RATIO:
2960       if (xvimagesink->par)
2961         g_value_transform (xvimagesink->par, value);
2962       break;
2963     case PROP_FORCE_ASPECT_RATIO:
2964       g_value_set_boolean (value, xvimagesink->keep_aspect);
2965       break;
2966     case PROP_HANDLE_EVENTS:
2967       g_value_set_boolean (value, xvimagesink->handle_events);
2968       break;
2969     case PROP_DEVICE:
2970     {
2971       char *adaptor_nr_s =
2972           g_strdup_printf ("%u", xvimagesink->config.adaptor_nr);
2973
2974       g_value_set_string (value, adaptor_nr_s);
2975       g_free (adaptor_nr_s);
2976       break;
2977     }
2978     case PROP_DEVICE_NAME:
2979       if (xvimagesink->context && xvimagesink->context->adaptors) {
2980         g_value_set_string (value,
2981             xvimagesink->context->adaptors[xvimagesink->config.adaptor_nr]);
2982       } else {
2983         g_value_set_string (value, NULL);
2984       }
2985       break;
2986     case PROP_HANDLE_EXPOSE:
2987       g_value_set_boolean (value, xvimagesink->handle_expose);
2988       break;
2989     case PROP_DOUBLE_BUFFER:
2990       g_value_set_boolean (value, xvimagesink->double_buffer);
2991       break;
2992     case PROP_AUTOPAINT_COLORKEY:
2993       g_value_set_boolean (value, xvimagesink->config.autopaint_colorkey);
2994       break;
2995     case PROP_COLORKEY:
2996       g_value_set_int (value, xvimagesink->config.colorkey);
2997       break;
2998     case PROP_DRAW_BORDERS:
2999       g_value_set_boolean (value, xvimagesink->draw_borders);
3000       break;
3001     case PROP_WINDOW_WIDTH:
3002       if (xvimagesink->xwindow)
3003         g_value_set_uint64 (value, xvimagesink->xwindow->width);
3004       else
3005         g_value_set_uint64 (value, 0);
3006       break;
3007     case PROP_WINDOW_HEIGHT:
3008       if (xvimagesink->xwindow)
3009         g_value_set_uint64 (value, xvimagesink->xwindow->height);
3010       else
3011         g_value_set_uint64 (value, 0);
3012       break;
3013 #ifdef GST_EXT_XV_ENHANCEMENT
3014     case PROP_DISPLAY_MODE:
3015       g_value_set_enum (value, xvimagesink->config.display_mode);
3016       break;
3017     case PROP_DISPLAY_GEOMETRY_METHOD:
3018       g_value_set_enum (value, xvimagesink->display_geometry_method);
3019       break;
3020     case PROP_FLIP:
3021       g_value_set_enum(value, xvimagesink->flip);
3022       break;
3023     case PROP_ROTATE_ANGLE:
3024       g_value_set_enum (value, xvimagesink->rotate_angle);
3025       break;
3026     case PROP_VISIBLE:
3027       g_value_set_boolean (value, xvimagesink->visible);
3028       break;
3029     case PROP_ZOOM:
3030       g_value_set_float (value, xvimagesink->zoom);
3031       break;
3032     case PROP_ZOOM_POS_X:
3033       g_value_set_int (value, xvimagesink->zoom_pos_x);
3034       break;
3035     case PROP_ZOOM_POS_Y:
3036       g_value_set_int (value, xvimagesink->zoom_pos_y);
3037       break;
3038     case PROP_ORIENTATION:
3039       g_value_set_enum (value, xvimagesink->orientation);
3040       break;
3041     case PROP_DST_ROI_MODE:
3042       g_value_set_enum (value, xvimagesink->dst_roi_mode);
3043       break;
3044     case PROP_DST_ROI_X:
3045       g_value_set_int (value, xvimagesink->dst_roi.x);
3046       break;
3047     case PROP_DST_ROI_Y:
3048       g_value_set_int (value, xvimagesink->dst_roi.y);
3049       break;
3050     case PROP_DST_ROI_W:
3051       g_value_set_int (value, xvimagesink->dst_roi.w);
3052       break;
3053     case PROP_DST_ROI_H:
3054       g_value_set_int (value, xvimagesink->dst_roi.h);
3055       break;
3056 #ifdef ENABLE_STOP_VIDEO
3057         case PROP_STOP_VIDEO:
3058           g_value_set_int (value, xvimagesink->stop_video);
3059           break;
3060 #endif
3061     case PROP_PIXMAP_CB:
3062           g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
3063           break;
3064         case PROP_PIXMAP_CB_USER_DATA:
3065           g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
3066           break;
3067 #endif /* GST_EXT_XV_ENHANCEMENT */
3068     default:
3069       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3070       break;
3071   }
3072 }
3073
3074 static gboolean
3075 gst_xvimagesink_open (GstXvImageSink * xvimagesink)
3076 {
3077   GError *error = NULL;
3078
3079   /* Initializing the XvContext unless already done through GstVideoOverlay */
3080   if (!xvimagesink->context) {
3081     GstXvContext *context;
3082     if (!(context = gst_xvcontext_new (&xvimagesink->config, &error)))
3083       goto no_context;
3084
3085     GST_OBJECT_LOCK (xvimagesink);
3086     xvimagesink->context = context;
3087   } else
3088     GST_OBJECT_LOCK (xvimagesink);
3089   /* make an allocator for this context */
3090   xvimagesink->allocator = gst_xvimage_allocator_new (xvimagesink->context);
3091   GST_OBJECT_UNLOCK (xvimagesink);
3092
3093   /* update object's par with calculated one if not set yet */
3094   if (!xvimagesink->par) {
3095     xvimagesink->par = g_new0 (GValue, 1);
3096     gst_value_init_and_copy (xvimagesink->par, xvimagesink->context->par);
3097     GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
3098   }
3099   /* call XSynchronize with the current value of synchronous */
3100   gst_xvcontext_set_synchronous (xvimagesink->context,
3101       xvimagesink->synchronous);
3102   gst_xvimagesink_update_colorbalance (xvimagesink);
3103   gst_xvimagesink_manage_event_thread (xvimagesink);
3104
3105   return TRUE;
3106
3107 no_context:
3108   {
3109     gst_element_message_full (GST_ELEMENT (xvimagesink), GST_MESSAGE_ERROR,
3110         error->domain, error->code, g_strdup ("Could not initialise Xv output"),
3111         error->message, __FILE__, GST_FUNCTION, __LINE__);
3112     return FALSE;
3113   }
3114 }
3115
3116 static void
3117 gst_xvimagesink_close (GstXvImageSink * xvimagesink)
3118 {
3119   GThread *thread;
3120   GstXvContext *context;
3121
3122   GST_OBJECT_LOCK (xvimagesink);
3123   xvimagesink->running = FALSE;
3124   /* grab thread and mark it as NULL */
3125   thread = xvimagesink->event_thread;
3126   xvimagesink->event_thread = NULL;
3127   GST_OBJECT_UNLOCK (xvimagesink);
3128
3129   /* Wait for our event thread to finish before we clean up our stuff. */
3130   if (thread)
3131     g_thread_join (thread);
3132
3133   if (xvimagesink->cur_image) {
3134     gst_buffer_unref (xvimagesink->cur_image);
3135     xvimagesink->cur_image = NULL;
3136   }
3137   g_mutex_lock (&xvimagesink->flow_lock);
3138
3139 #ifdef GST_EXT_XV_ENHANCEMENT
3140         if (xvimagesink->get_pixmap_cb) {
3141           int i = 0;
3142           if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
3143                 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
3144                 XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
3145           }
3146           for (i = 0; i < MAX_PIXMAP_NUM; i++) {
3147                 if (xvimagesink->xpixmap[i]) {
3148                   gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
3149                   xvimagesink->xpixmap[i] = NULL;
3150                 }
3151           }
3152           xvimagesink->get_pixmap_cb = NULL;
3153           xvimagesink->get_pixmap_cb_user_data = NULL;
3154         }
3155 #endif /* GST_EXT_XV_ENHANCEMENT */
3156
3157   if (xvimagesink->pool) {
3158     gst_object_unref (xvimagesink->pool);
3159     xvimagesink->pool = NULL;
3160   }
3161
3162   if (xvimagesink->xwindow) {
3163     gst_xwindow_clear (xvimagesink->xwindow);
3164     gst_xwindow_destroy (xvimagesink->xwindow);
3165     xvimagesink->xwindow = NULL;
3166   }
3167   g_mutex_unlock (&xvimagesink->flow_lock);
3168
3169   if (xvimagesink->allocator) {
3170     gst_object_unref (xvimagesink->allocator);
3171     xvimagesink->allocator = NULL;
3172   }
3173
3174   GST_OBJECT_LOCK (xvimagesink);
3175   /* grab context and mark it as NULL */
3176   context = xvimagesink->context;
3177   xvimagesink->context = NULL;
3178   GST_OBJECT_UNLOCK (xvimagesink);
3179
3180   if (context)
3181     gst_xvcontext_unref (context);
3182 }
3183
3184 /* Finalize is called only once, dispose can be called multiple times.
3185  * We use mutexes and don't reset stuff to NULL here so let's register
3186  * as a finalize. */
3187 static void
3188 gst_xvimagesink_finalize (GObject * object)
3189 {
3190   GstXvImageSink *xvimagesink;
3191
3192   xvimagesink = GST_XVIMAGESINK (object);
3193
3194   gst_xvimagesink_close (xvimagesink);
3195
3196   gst_xvcontext_config_clear (&xvimagesink->config);
3197
3198   if (xvimagesink->par) {
3199     g_free (xvimagesink->par);
3200     xvimagesink->par = NULL;
3201   }
3202   g_mutex_clear (&xvimagesink->flow_lock);
3203   g_free (xvimagesink->media_title);
3204
3205   G_OBJECT_CLASS (parent_class)->finalize (object);
3206 }
3207
3208 static void
3209 gst_xvimagesink_init (GstXvImageSink * xvimagesink)
3210 {
3211   xvimagesink->config.display_name = NULL;
3212   xvimagesink->config.adaptor_nr = 0;
3213   xvimagesink->config.autopaint_colorkey = TRUE;
3214   xvimagesink->config.double_buffer = TRUE;
3215   /* on 16bit displays this becomes r,g,b = 1,2,3
3216    * on 24bit displays this becomes r,g,b = 8,8,16
3217    * as a port atom value */
3218   xvimagesink->config.colorkey = (8 << 16) | (8 << 8) | 16;
3219   xvimagesink->config.hue = xvimagesink->config.saturation = 0;
3220   xvimagesink->config.contrast = xvimagesink->config.brightness = 0;
3221   xvimagesink->config.cb_changed = FALSE;
3222 #ifdef GST_EXT_XV_ENHANCEMENT
3223   xvimagesink->config.display_mode = DISPLAY_MODE_DEFAULT;
3224 #endif /* GST_EXT_XV_ENHANCEMENT */
3225
3226   xvimagesink->context = NULL;
3227   xvimagesink->xwindow = NULL;
3228   xvimagesink->cur_image = NULL;
3229
3230   xvimagesink->fps_n = 0;
3231   xvimagesink->fps_d = 0;
3232   xvimagesink->video_width = 0;
3233   xvimagesink->video_height = 0;
3234
3235   g_mutex_init (&xvimagesink->flow_lock);
3236
3237   xvimagesink->pool = NULL;
3238
3239   xvimagesink->synchronous = FALSE;
3240   xvimagesink->running = FALSE;
3241   xvimagesink->keep_aspect = TRUE;
3242   xvimagesink->handle_events = TRUE;
3243   xvimagesink->par = NULL;
3244   xvimagesink->handle_expose = TRUE;
3245
3246   xvimagesink->draw_borders = TRUE;
3247 #ifdef GST_EXT_XV_ENHANCEMENT
3248   xvimagesink->xid_updated = FALSE;
3249   xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
3250   xvimagesink->flip = DEF_DISPLAY_FLIP;
3251   xvimagesink->rotate_angle = DEGREE_270;
3252   xvimagesink->visible = TRUE;
3253   xvimagesink->zoom = 1.0;
3254   xvimagesink->zoom_pos_x = -1;
3255   xvimagesink->zoom_pos_y = -1;
3256   xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
3257   xvimagesink->orientation = DEGREE_0;
3258   xvimagesink->dst_roi.x = 0;
3259   xvimagesink->dst_roi.y = 0;
3260   xvimagesink->dst_roi.w = 0;
3261   xvimagesink->dst_roi.h = 0;
3262
3263   xvimagesink->is_zero_copy_format = FALSE;
3264   xvimagesink->is_secure_path = FALSE;
3265
3266   xvimagesink->current_pixmap_idx = -1;
3267   xvimagesink->get_pixmap_cb = NULL;
3268   xvimagesink->get_pixmap_cb_user_data = NULL;
3269 #ifdef ENABLE_STOP_VIDEO
3270   xvimagesink->stop_video = FALSE;
3271 #endif
3272   /*X can't gurarantee thread  safe: sometimes, X can't render Video.
3273        Add XInitThread() before XOpenDisplay()*/
3274   if(!XInitThreads())
3275         GST_WARNING("FAIL to call XInitThreads()");
3276 #endif /* GST_EXT_XV_ENHANCEMENT */
3277 }
3278
3279 static void
3280 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
3281 {
3282   GObjectClass *gobject_class;
3283   GstElementClass *gstelement_class;
3284   GstBaseSinkClass *gstbasesink_class;
3285   GstVideoSinkClass *videosink_class;
3286
3287   gobject_class = (GObjectClass *) klass;
3288   gstelement_class = (GstElementClass *) klass;
3289   gstbasesink_class = (GstBaseSinkClass *) klass;
3290   videosink_class = (GstVideoSinkClass *) klass;
3291
3292   parent_class = g_type_class_peek_parent (klass);
3293
3294   gobject_class->set_property = gst_xvimagesink_set_property;
3295   gobject_class->get_property = gst_xvimagesink_get_property;
3296
3297   g_object_class_install_property (gobject_class, PROP_CONTRAST,
3298       g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
3299           -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3300   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
3301       g_param_spec_int ("brightness", "Brightness",
3302           "The brightness of the video", -1000, 1000, 0,
3303           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3304   g_object_class_install_property (gobject_class, PROP_HUE,
3305       g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
3306           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3307   g_object_class_install_property (gobject_class, PROP_SATURATION,
3308       g_param_spec_int ("saturation", "Saturation",
3309           "The saturation of the video", -1000, 1000, 0,
3310           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3311   g_object_class_install_property (gobject_class, PROP_DISPLAY,
3312       g_param_spec_string ("display", "Display", "X Display name", NULL,
3313           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3314   g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
3315       g_param_spec_boolean ("synchronous", "Synchronous",
3316           "When enabled, runs the X display in synchronous mode. "
3317           "(unrelated to A/V sync, used only for debugging)", FALSE,
3318           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3319   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
3320       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
3321           "The pixel aspect ratio of the device", "1/1",
3322           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3323   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
3324       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
3325           "When enabled, scaling will respect original aspect ratio", TRUE,
3326           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3327   g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
3328       g_param_spec_boolean ("handle-events", "Handle XEvents",
3329           "When enabled, XEvents will be selected and handled", TRUE,
3330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3331   g_object_class_install_property (gobject_class, PROP_DEVICE,
3332       g_param_spec_string ("device", "Adaptor number",
3333           "The number of the video adaptor", "0",
3334           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3335   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
3336       g_param_spec_string ("device-name", "Adaptor name",
3337           "The name of the video adaptor", NULL,
3338           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3339   /**
3340    * GstXvImageSink:handle-expose
3341    *
3342    * When enabled, the current frame will always be drawn in response to X
3343    * Expose.
3344    *
3345    * Since: 0.10.14
3346    */
3347   g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
3348       g_param_spec_boolean ("handle-expose", "Handle expose",
3349           "When enabled, "
3350           "the current frame will always be drawn in response to X Expose "
3351           "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3352
3353   /**
3354    * GstXvImageSink:double-buffer
3355    *
3356    * Whether to double-buffer the output.
3357    *
3358    * Since: 0.10.14
3359    */
3360   g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
3361       g_param_spec_boolean ("double-buffer", "Double-buffer",
3362           "Whether to double-buffer the output", TRUE,
3363           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3364   /**
3365    * GstXvImageSink:autopaint-colorkey
3366    *
3367    * Whether to autofill overlay with colorkey
3368    *
3369    * Since: 0.10.21
3370    */
3371   g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
3372       g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
3373           "Whether to autofill overlay with colorkey", TRUE,
3374           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3375   /**
3376    * GstXvImageSink:colorkey
3377    *
3378    * Color to use for the overlay mask.
3379    *
3380    * Since: 0.10.21
3381    */
3382   g_object_class_install_property (gobject_class, PROP_COLORKEY,
3383       g_param_spec_int ("colorkey", "Colorkey",
3384           "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
3385           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3386
3387   /**
3388    * GstXvImageSink:draw-borders
3389    *
3390    * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
3391    * unused parts of the video area.
3392    */
3393   g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
3394       g_param_spec_boolean ("draw-borders", "Draw Borders",
3395           "Draw black borders to fill unused area in force-aspect-ratio mode",
3396           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3397
3398   /**
3399    * GstXvImageSink:window-width
3400    *
3401    * Actual width of the video window.
3402    *
3403    * Since: 0.10.32
3404    */
3405   g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
3406       g_param_spec_uint64 ("window-width", "window-width",
3407           "Width of the window", 0, G_MAXUINT64, 0,
3408           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3409
3410   /**
3411    * GstXvImageSink:window-height
3412    *
3413    * Actual height of the video window.
3414    *
3415    * Since: 0.10.32
3416    */
3417   g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
3418       g_param_spec_uint64 ("window-height", "window-height",
3419           "Height of the window", 0, G_MAXUINT64, 0,
3420           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3421
3422 #ifdef GST_EXT_XV_ENHANCEMENT
3423   /**
3424    * GstXvImageSink:display-mode
3425    *
3426    * select display mode
3427    */
3428   g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
3429     g_param_spec_enum("display-mode", "Display Mode",
3430       "Display device setting",
3431       GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
3432       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3433
3434   /**
3435    * GstXvImageSink:display-geometry-method
3436    *
3437    * Display geometrical method setting
3438    */
3439   g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
3440     g_param_spec_enum("display-geometry-method", "Display geometry method",
3441       "Geometrical method for display",
3442       GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
3443       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3444
3445   /**
3446    * GstXvImageSink:display-flip
3447    *
3448    * Display flip setting
3449    */
3450   g_object_class_install_property(gobject_class, PROP_FLIP,
3451     g_param_spec_enum("flip", "Display flip",
3452       "Flip for display",
3453       GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
3454       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3455
3456   /**
3457    * GstXvImageSink:rotate
3458    *
3459    * Draw rotation angle setting
3460    */
3461   g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
3462     g_param_spec_enum("rotate", "Rotate angle",
3463       "Rotate angle of display output",
3464       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
3465       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3466
3467   /**
3468    * GstXvImageSink:visible
3469    *
3470    * Whether reserve original src size or not
3471    */
3472   g_object_class_install_property (gobject_class, PROP_VISIBLE,
3473       g_param_spec_boolean ("visible", "Visible",
3474           "Draws screen or blacks out, true means visible, false blacks out",
3475           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3476
3477   /**
3478    * GstXvImageSink:zoom
3479    *
3480    * Scale small area of screen to 1X~ 9
3481    */
3482   g_object_class_install_property (gobject_class, PROP_ZOOM,
3483       g_param_spec_float ("zoom", "Zoom",
3484           "Zooms screen as nX", 1.0, 9.0, 1.0,
3485           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3486
3487   /**
3488    * GstXvImageSink:zoom-pos-x
3489    *
3490    * Standard x-position of zoom
3491    */
3492   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
3493       g_param_spec_int ("zoom-pos-x", "Zoom Position X",
3494           "Standard x-position of zoom", 0, 3840, 0,
3495           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3496
3497   /**
3498    * GstXvImageSink:zoom-pos-y
3499    *
3500    * Standard y-position of zoom
3501    */
3502   g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
3503       g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
3504           "Standard y-position of zoom", 0, 3840, 0,
3505           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3506
3507   /**
3508    * GstXvImageSink:dst-roi-mode
3509    *
3510    * Display geometrical method of ROI setting
3511    */
3512   g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
3513     g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
3514       "Geometrical method of ROI for display",
3515       GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
3516       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3517
3518   /**
3519    * GstXvImageSink:orientation
3520    *
3521    * Orientation information which will be used for ROI/ZOOM
3522    */
3523   g_object_class_install_property(gobject_class, PROP_ORIENTATION,
3524     g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
3525       "Orientation information for display",
3526       GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
3527       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3528
3529   /**
3530    * GstXvImageSink:dst-roi-x
3531    *
3532    * X value of Destination ROI
3533    */
3534   g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
3535       g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
3536           "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3537           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3538
3539   /**
3540    * GstXvImageSink:dst-roi-y
3541    *
3542    * Y value of Destination ROI
3543    */
3544   g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
3545       g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
3546           "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3547           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3548
3549   /**
3550    * GstXvImageSink:dst-roi-w
3551    *
3552    * W value of Destination ROI
3553    */
3554   g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
3555       g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
3556           "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3557           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3558
3559   /**
3560    * GstXvImageSink:dst-roi-h
3561    *
3562    * H value of Destination ROI
3563    */
3564   g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
3565       g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
3566           "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3567           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3568 #ifdef ENABLE_STOP_VIDEO
3569   g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
3570       g_param_spec_int ("stop-video", "Stop-Video",
3571           "Stop video for releasing video source buffer", 0, 1, 0,
3572           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3573 #endif
3574   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
3575       g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
3576           "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
3577
3578   g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
3579       g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
3580           "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
3581
3582 #endif /* GST_EXT_XV_ENHANCEMENT */
3583
3584   gobject_class->finalize = gst_xvimagesink_finalize;
3585
3586   gst_element_class_set_static_metadata (gstelement_class,
3587       "Video sink", "Sink/Video",
3588       "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
3589
3590   gst_element_class_add_pad_template (gstelement_class,
3591       gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory));
3592
3593   gstelement_class->change_state =
3594       GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
3595
3596   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
3597   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
3598   gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
3599   gstbasesink_class->propose_allocation =
3600       GST_DEBUG_FUNCPTR (gst_xvimagesink_propose_allocation);
3601   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
3602
3603   videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
3604 }