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.
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.
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.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
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
28 * SECTION:element-xvimagesink
30 * XvImageSink renders video frames to a drawable (XWindow) on a local display
31 * using the XVideo extension. Rendering to a remote display is theoretically
32 * possible but i doubt that the XVideo extension is actually available when
33 * connecting to a remote display. This element can receive a Window ID from the
34 * application through the XOverlay interface and will then render video frames
35 * in this drawable. If no Window ID was provided by the application, the
36 * element will create its own internal window and render into it.
39 * <title>Scaling</title>
41 * The XVideo extension, when it's available, handles hardware accelerated
42 * scaling of video frames. This means that the element will just accept
43 * incoming video frames no matter their geometry and will then put them to the
44 * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
45 * property it is possible to enforce scaling with a constant aspect ratio,
46 * which means drawing black borders around the video frame.
50 * <title>Events</title>
52 * XvImageSink creates a thread to handle events coming from the drawable. There
53 * are several kind of events that can be grouped in 2 big categories: input
54 * events and window state related events. Input events will be translated to
55 * navigation events and pushed upstream for other elements to react on them.
56 * This includes events such as pointer moves, key press/release, clicks etc...
57 * Other events are used to handle the drawable appearance even when the data
58 * is not flowing (GST_STATE_PAUSED). That means that even when the element is
59 * paused, it will receive expose events from the drawable and draw the latest
60 * frame with correct borders/aspect-ratio.
64 * <title>Pixel aspect ratio</title>
66 * When changing state to GST_STATE_READY, XvImageSink will open a connection to
67 * the display specified in the #GstXvImageSink:display property or the
68 * default display if nothing specified. Once this connection is open it will
69 * inspect the display configuration including the physical display geometry and
70 * then calculate the pixel aspect ratio. When receiving video frames with a
71 * different pixel aspect ratio, XvImageSink will use hardware scaling to
72 * display the video frames correctly on display's pixel aspect ratio.
73 * Sometimes the calculated pixel aspect ratio can be wrong, it is
74 * then possible to enforce a specific pixel aspect ratio using the
75 * #GstXvImageSink:pixel-aspect-ratio property.
79 * <title>Examples</title>
81 * gst-launch -v videotestsrc ! xvimagesink
82 * ]| A pipeline to test hardware scaling.
83 * When the test video signal appears you can resize the window and see that
84 * video frames are scaled through hardware (no extra CPU cost).
86 * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
87 * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
88 * You can observe the borders drawn around the scaled image respecting aspect
91 * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
92 * ]| A pipeline to test navigation events.
93 * While moving the mouse pointer over the test signal you will see a black box
94 * following the mouse pointer. If you press the mouse button somewhere on the
95 * video and release it somewhere else a green box will appear where you pressed
96 * the button and a red one where you released it. (The navigationtest element
97 * is part of gst-plugins-good.) You can observe here that even if the images
98 * are scaled through hardware the pointer coordinates are converted back to the
99 * original video frame geometry so that the box can be drawn to the correct
100 * position. This also handles borders correctly, limiting coordinates to the
103 * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
104 * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
105 * videotestsrc, in most cases the pixel aspect ratio of the display will be
106 * 1/1. This means that XvImageSink will have to do the scaling to convert
107 * incoming frames to a size that will match the display pixel aspect ratio
108 * (from 320x240 to 320x180 in this case). Note that you might have to escape
109 * some characters for your shell like '\(fraction\)'.
111 * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
112 * ]| Demonstrates how to use the colorbalance interface.
116 /* for developers: there are two useful tools : xvinfo and xvattr */
123 #include <gst/interfaces/navigation.h>
124 #include <gst/interfaces/xoverlay.h>
125 #include <gst/interfaces/colorbalance.h>
126 #include <gst/interfaces/propertyprobe.h>
127 /* Helper functions */
128 #include <gst/video/video.h>
131 #include "xvimagesink.h"
133 #ifdef GST_EXT_XV_ENHANCEMENT
134 /* Samsung extension headers */
135 /* For xv extension header for buffer transfer (output) */
136 #include "xv_types.h"
138 /* headers for drm */
139 #include <sys/stat.h>
140 #include <sys/ioctl.h>
144 #include <xf86drmMode.h>
146 #include <dri2/dri2.h>
147 #include <tbm_bufmgr.h>
149 /* for setting vconf about xv state */
151 #include <vconf-internal-player-keys.h>
155 SECURE_PATH_INIT = -1,
167 DISPLAY_STATUS_NULL = 0,
168 DISPLAY_STATUS_HDMI_ACTIVE,
169 DISPLAY_STATUS_UNKNOWN_ACTIVE,
182 BUF_SHARE_METHOD_PADDR = 0,
184 BUF_SHARE_METHOD_TIZEN_BUFFER,
185 BUF_SHARE_METHOD_FLUSH_BUFFER
186 } buf_share_method_t;
188 #define _CHECK_DISPLAYED_BUFFER_COUNT 15
189 #define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */
191 /* max channel count *********************************************************/
192 #define SCMN_IMGB_MAX_PLANE (4)
194 /* image buffer definition ***************************************************
196 +------------------------------------------+ ---
199 | +---------------------------+ --- | |
201 | |<---------- w[] ---------->| | | |
209 | +---------------------------+ --- | |
211 +------------------------------------------+ ---
213 |<----------------- s[] ------------------>|
218 /* width of each image plane */
219 int w[SCMN_IMGB_MAX_PLANE];
220 /* height of each image plane */
221 int h[SCMN_IMGB_MAX_PLANE];
222 /* stride of each image plane */
223 int s[SCMN_IMGB_MAX_PLANE];
224 /* elevation of each image plane */
225 int e[SCMN_IMGB_MAX_PLANE];
226 /* user space address of each image plane */
227 void *a[SCMN_IMGB_MAX_PLANE];
228 /* physical address of each image plane, if needs */
229 void *p[SCMN_IMGB_MAX_PLANE];
230 /* color space type of image */
232 /* left postion, if needs */
234 /* top position, if needs */
236 /* to align memory */
241 int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
242 /* buffer share method */
243 int buf_share_method;
244 /* Y plane size in case of ST12 */
246 /* UV plane size in case of ST12 */
248 /* Tizen buffer object */
249 void *bo[SCMN_IMGB_MAX_PLANE];
254 /* TZ memory buffer */
258 static void _release_flush_buffer(GstXvImageSink *xvimagesink);
259 static void _remove_last_buffer(GstXvImageSink *xvimagesink);
260 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink);
261 #endif /* GST_EXT_XV_ENHANCEMENT */
263 /* Debugging category */
264 #include <gst/gstinfo.h>
266 #include "gst/glib-compat-private.h"
268 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
269 #define GST_CAT_DEFAULT gst_debug_xvimagesink
270 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
272 #ifdef GST_EXT_XV_ENHANCEMENT
273 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
274 #define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
277 gst_xvimagesink_display_mode_get_type(void)
279 static GType xvimagesink_display_mode_type = 0;
280 static const GEnumValue display_mode_type[] = {
281 { 0, "Default mode", "DEFAULT"},
282 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
283 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
287 if (!xvimagesink_display_mode_type) {
288 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
291 return xvimagesink_display_mode_type;
295 gst_xvimagesink_csc_range_get_type(void)
297 static GType xvimagesink_csc_range_type = 0;
298 static const GEnumValue csc_range_type[] = {
299 { 0, "Narrow range", "NARROW"},
300 { 1, "Wide range", "WIDE"},
304 if (!xvimagesink_csc_range_type) {
305 xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
308 return xvimagesink_csc_range_type;
319 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
322 gst_xvimagesink_rotate_angle_get_type(void)
324 static GType xvimagesink_rotate_angle_type = 0;
325 static const GEnumValue rotate_angle_type[] = {
326 { 0, "No rotate", "DEGREE_0"},
327 { 1, "Rotate 90 degree", "DEGREE_90"},
328 { 2, "Rotate 180 degree", "DEGREE_180"},
329 { 3, "Rotate 270 degree", "DEGREE_270"},
333 if (!xvimagesink_rotate_angle_type) {
334 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
337 return xvimagesink_rotate_angle_type;
341 DISP_GEO_METHOD_LETTER_BOX = 0,
342 DISP_GEO_METHOD_ORIGIN_SIZE,
343 DISP_GEO_METHOD_FULL_SCREEN,
344 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
345 DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
346 DISP_GEO_METHOD_CUSTOM_DST_ROI,
351 ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
352 ROI_DISP_GEO_METHOD_LETTER_BOX,
353 ROI_DISP_GEO_METHOD_NUM,
356 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
357 #define DEF_ROI_DISPLAY_GEOMETRY_METHOD ROI_DISP_GEO_METHOD_FULL_SCREEN
366 #define DEF_DISPLAY_FLIP FLIP_NONE
368 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
369 #define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
370 #define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type())
373 gst_xvimagesink_display_geometry_method_get_type(void)
375 static GType xvimagesink_display_geometry_method_type = 0;
376 static const GEnumValue display_geometry_method_type[] = {
377 { 0, "Letter box", "LETTER_BOX"},
378 { 1, "Origin size", "ORIGIN_SIZE"},
379 { 2, "Full-screen", "FULL_SCREEN"},
380 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
381 { 4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"},
382 { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
386 if (!xvimagesink_display_geometry_method_type) {
387 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
390 return xvimagesink_display_geometry_method_type;
394 gst_xvimagesink_roi_display_geometry_method_get_type(void)
396 static GType xvimagesink_roi_display_geometry_method_type = 0;
397 static const GEnumValue roi_display_geometry_method_type[] = {
398 { 0, "ROI-Full-screen", "FULL_SCREEN"},
399 { 1, "ROI-Letter box", "LETTER_BOX"},
403 if (!xvimagesink_roi_display_geometry_method_type) {
404 xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
407 return xvimagesink_roi_display_geometry_method_type;
411 gst_xvimagesink_flip_get_type(void)
413 static GType xvimagesink_flip_type = 0;
414 static const GEnumValue flip_type[] = {
415 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
416 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
417 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
418 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
419 { FLIP_NUM, NULL, NULL},
422 if (!xvimagesink_flip_type) {
423 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
426 return xvimagesink_flip_type;
429 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
431 gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure,
432 GValue *return_value G_GNUC_UNUSED,
433 guint n_param_values,
434 const GValue *param_values,
435 gpointer invocation_hint G_GNUC_UNUSED,
436 gpointer marshal_data)
438 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
441 register GMarshalFunc_BOOLEAN__POINTER callback;
442 register GCClosure *cc = (GCClosure*) closure;
443 register gpointer data1, data2;
447 g_return_if_fail (return_value != NULL);
448 g_return_if_fail (n_param_values == 2);
450 if (G_CCLOSURE_SWAP_DATA (closure)) {
451 data1 = closure->data;
452 data2 = g_value_peek_pointer (param_values + 0);
454 data1 = g_value_peek_pointer (param_values + 0);
455 data2 = closure->data;
457 callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
459 v_return = callback (data1,
460 g_marshal_value_peek_pointer (param_values + 1),
463 g_value_set_boolean (return_value, v_return);
468 SIGNAL_FRAME_RENDER_ERROR,
469 SIGNAL_DISPLAY_STATUS,
470 SIGNAL_EXTERNAL_RESOLUTION,
471 SIGNAL_WINDOW_STATUS,
472 SIGNAL_QUICKPANEL_STATUS,
473 SIGNAL_MULTIWINDOW_STATUS,
476 static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
478 #endif /* GST_EXT_XV_ENHANCEMENT */
483 unsigned long functions;
484 unsigned long decorations;
486 unsigned long status;
488 MotifWmHints, MwmHints;
490 #define MWM_HINTS_DECORATIONS (1L << 1)
492 #ifdef GST_EXT_XV_ENHANCEMENT
493 #define MAX_DISPLAY_IN_XVIMAGESINK 20
494 static Display *g_display_id[MAX_DISPLAY_IN_XVIMAGESINK] = {0};
497 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
499 static GstBufferClass *xvimage_buffer_parent_class = NULL;
500 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
502 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
504 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
506 static void gst_xvimagesink_expose (GstXOverlay * overlay);
508 #ifdef GST_EXT_XV_ENHANCEMENT
509 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
510 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
511 static gboolean set_csc_range(GstXContext *xcontext, int set_range);
512 static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
513 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
514 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
515 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
516 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
517 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
518 static void check_hdmi_connected(GstXvImageSink *xvimagesink);
519 static int get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type, unsigned int *val, unsigned int len);
520 static gboolean check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name);
521 #endif /* GST_EXT_XV_ENHANCEMENT */
523 /* Default template - initiated with class struct to allow gst-register to work
525 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
526 GST_STATIC_PAD_TEMPLATE ("sink",
529 GST_STATIC_CAPS ("video/x-raw-rgb, "
530 "framerate = (fraction) [ 0, MAX ], "
531 "width = (int) [ 1, MAX ], "
532 "height = (int) [ 1, MAX ]; "
534 "framerate = (fraction) [ 0, MAX ], "
535 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
547 PROP_PIXEL_ASPECT_RATIO,
548 PROP_FORCE_ASPECT_RATIO,
554 PROP_AUTOPAINT_COLORKEY,
559 #ifdef GST_EXT_XV_ENHANCEMENT
564 PROP_DISPLAY_GEOMETRY_METHOD,
581 PROP_PIXMAP_CB_USER_DATA,
584 PROP_EXTERNAL_HEIGHT,
585 PROP_ENABLE_FLUSH_BUFFER,
589 PROP_MULTIWINDOW_ACTIVE,
590 PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
591 PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
592 #endif /* GST_EXT_XV_ENHANCEMENT */
595 static void gst_xvimagesink_init_interfaces (GType type);
597 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
598 GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
601 /* ============================================================= */
603 /* Private Methods */
605 /* ============================================================= */
607 /* xvimage buffers */
609 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
611 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
612 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
613 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
615 /* This function destroys a GstXvImage handling XShm availability */
617 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
619 GstXvImageSink *xvimagesink;
621 GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
623 xvimagesink = xvimage->xvimagesink;
624 if (G_UNLIKELY (xvimagesink == NULL))
627 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
629 GST_OBJECT_LOCK (xvimagesink);
631 /* If the destroyed image is the current one we destroy our reference too */
632 if (xvimagesink->cur_image == xvimage)
633 xvimagesink->cur_image = NULL;
635 /* We might have some buffers destroyed after changing state to NULL */
636 if (xvimagesink->xcontext == NULL) {
637 GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
639 /* Need to free the shared memory segment even if the x context
640 * was already cleaned up */
641 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
642 shmdt (xvimage->SHMInfo.shmaddr);
648 g_mutex_lock (xvimagesink->x_lock);
651 if (xvimagesink->xcontext->use_xshm) {
652 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
653 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
654 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
655 XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
656 XSync (xvimagesink->xcontext->disp, FALSE);
658 shmdt (xvimage->SHMInfo.shmaddr);
660 if (xvimage->xvimage)
661 XFree (xvimage->xvimage);
663 #endif /* HAVE_XSHM */
665 if (xvimage->xvimage) {
666 if (xvimage->xvimage->data) {
667 g_free (xvimage->xvimage->data);
669 XFree (xvimage->xvimage);
673 XSync (xvimagesink->xcontext->disp, FALSE);
675 g_mutex_unlock (xvimagesink->x_lock);
678 GST_OBJECT_UNLOCK (xvimagesink);
679 xvimage->xvimagesink = NULL;
680 gst_object_unref (xvimagesink);
682 GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
689 GST_WARNING ("no sink found");
695 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
697 GstXvImageSink *xvimagesink;
700 xvimagesink = xvimage->xvimagesink;
701 if (G_UNLIKELY (xvimagesink == NULL))
704 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
706 GST_OBJECT_LOCK (xvimagesink);
707 running = xvimagesink->running;
708 GST_OBJECT_UNLOCK (xvimagesink);
710 /* If our geometry changed we can't reuse that image. */
711 if (running == FALSE) {
712 GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
713 gst_xvimage_buffer_destroy (xvimage);
714 } else if ((xvimage->width != xvimagesink->video_width) ||
715 (xvimage->height != xvimagesink->video_height)) {
716 GST_LOG_OBJECT (xvimage,
717 "destroy image as its size changed %dx%d vs current %dx%d",
718 xvimage->width, xvimage->height,
719 xvimagesink->video_width, xvimagesink->video_height);
720 gst_xvimage_buffer_destroy (xvimage);
722 /* In that case we can reuse the image and add it to our image pool. */
723 GST_LOG_OBJECT (xvimage, "recycling image in pool");
724 /* need to increment the refcount again to recycle */
725 gst_buffer_ref (GST_BUFFER_CAST (xvimage));
726 g_mutex_lock (xvimagesink->pool_lock);
727 xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
729 g_mutex_unlock (xvimagesink->pool_lock);
735 GST_WARNING ("no sink found");
741 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
743 /* make sure it is not recycled */
745 xvimage->height = -1;
746 gst_buffer_unref (GST_BUFFER (xvimage));
750 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
753 xvimage->SHMInfo.shmaddr = ((void *) -1);
754 xvimage->SHMInfo.shmid = -1;
759 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
761 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
763 xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
765 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
766 gst_xvimage_buffer_finalize;
770 gst_xvimage_buffer_get_type (void)
772 static GType _gst_xvimage_buffer_type;
774 if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
775 static const GTypeInfo xvimage_buffer_info = {
776 sizeof (GstBufferClass),
779 gst_xvimage_buffer_class_init,
782 sizeof (GstXvImageBuffer),
784 (GInstanceInitFunc) gst_xvimage_buffer_init,
787 _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
788 "GstXvImageBuffer", &xvimage_buffer_info, 0);
790 return _gst_xvimage_buffer_type;
795 static gboolean error_caught = FALSE;
798 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
800 char error_msg[1024];
802 XGetErrorText (display, xevent->error_code, error_msg, 1024);
803 #ifndef GST_EXT_XV_ENHANCEMENT
804 GST_DEBUG ("xvimagesink triggered an XError. error: %s, display(%p)", error_msg, display);
808 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
809 if (g_display_id[i] == display) {
810 GST_ERROR ("xvimagesink triggered an XError. error: %s, display(%p), xevent->request_code: %d", error_msg, display, xevent->request_code);
815 if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
816 GST_ERROR ("xvimagesink triggered an XError. error: %s, xevent->request_code: %d, but the display(%p) was not created in xvimagesink, skip it...", error_msg, xevent->request_code, display);
824 /* This function checks that it is actually really possible to create an image
827 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
830 XShmSegmentInfo SHMInfo;
832 int (*handler) (Display *, XErrorEvent *);
833 gboolean result = FALSE;
834 gboolean did_attach = FALSE;
836 g_return_val_if_fail (xcontext != NULL, FALSE);
838 /* Sync to ensure any older errors are already processed */
839 XSync (xcontext->disp, FALSE);
841 /* Set defaults so we don't free these later unnecessarily */
842 SHMInfo.shmaddr = ((void *) -1);
845 /* Setting an error handler to catch failure */
846 error_caught = FALSE;
847 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
849 /* Trying to create a 1x1 picture */
850 GST_DEBUG ("XvShmCreateImage of 1x1");
851 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
852 xcontext->im_format, NULL, 1, 1, &SHMInfo);
854 /* Might cause an error, sync to ensure it is noticed */
855 XSync (xcontext->disp, FALSE);
856 if (!xvimage || error_caught) {
857 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
860 size = xvimage->data_size;
862 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
863 if (SHMInfo.shmid == -1) {
864 GST_WARNING ("could not get shared memory of %d bytes", size);
868 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
869 if (SHMInfo.shmaddr == ((void *) -1)) {
870 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
871 /* Clean up the shared memory segment */
872 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
876 xvimage->data = SHMInfo.shmaddr;
877 SHMInfo.readOnly = FALSE;
879 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
880 GST_WARNING ("Failed to XShmAttach");
881 /* Clean up the shared memory segment */
882 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
886 /* Sync to ensure we see any errors we caused */
887 XSync (xcontext->disp, FALSE);
889 /* Delete the shared memory segment as soon as everyone is attached.
890 * This way, it will be deleted as soon as we detach later, and not
891 * leaked if we crash. */
892 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
895 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
899 /* store whether we succeeded in result */
902 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
903 "Not using shared memory.");
907 /* Sync to ensure we swallow any errors we caused and reset error_caught */
908 XSync (xcontext->disp, FALSE);
910 error_caught = FALSE;
911 XSetErrorHandler (handler);
914 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
915 SHMInfo.shmid, SHMInfo.shmseg);
916 XShmDetach (xcontext->disp, &SHMInfo);
917 XSync (xcontext->disp, FALSE);
919 if (SHMInfo.shmaddr != ((void *) -1))
920 shmdt (SHMInfo.shmaddr);
925 #endif /* HAVE_XSHM */
927 /* This function handles GstXvImage creation depending on XShm availability */
928 static GstXvImageBuffer *
929 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
931 GstXvImageBuffer *xvimage = NULL;
932 GstStructure *structure = NULL;
933 gboolean succeeded = FALSE;
934 int (*handler) (Display *, XErrorEvent *);
936 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
941 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
942 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
944 structure = gst_caps_get_structure (caps, 0);
946 if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
947 !gst_structure_get_int (structure, "height", &xvimage->height)) {
948 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
951 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
953 #ifdef GST_EXT_XV_ENHANCEMENT
954 GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
955 xvimagesink->aligned_width, xvimagesink->aligned_height);
956 if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
957 GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
958 xvimagesink->aligned_width = xvimage->width;
959 xvimagesink->aligned_height = xvimage->height;
961 if (xvimagesink->subpicture) {
962 GST_LOG("because of subpicture's format, pass xvimage_new");
965 #endif /* GST_EXT_XV_ENHANCEMENT */
967 xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
968 if (xvimage->im_format == -1) {
969 GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
970 GST_PTR_FORMAT, caps);
971 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
972 ("Failed to create output image buffer of %dx%d pixels",
973 xvimage->width, xvimage->height), ("Invalid input caps"));
976 xvimage->xvimagesink = gst_object_ref (xvimagesink);
978 g_mutex_lock (xvimagesink->x_lock);
980 #ifdef GST_EXT_XV_ENHANCEMENT
981 XSync (xvimagesink->xcontext->disp, FALSE);
982 #endif /* GST_EXT_XV_ENHANCEMENT */
983 /* Setting an error handler to catch failure */
984 error_caught = FALSE;
985 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
988 if (xvimagesink->xcontext->use_xshm) {
991 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
992 xvimagesink->xcontext->xv_port_id,
993 xvimage->im_format, NULL,
994 #ifdef GST_EXT_XV_ENHANCEMENT
995 xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
996 #else /* GST_EXT_XV_ENHANCEMENT */
997 xvimage->width, xvimage->height, &xvimage->SHMInfo);
998 #endif /* GST_EXT_XV_ENHANCEMENT */
999 if (!xvimage->xvimage || error_caught) {
1000 g_mutex_unlock (xvimagesink->x_lock);
1002 /* Reset error flag */
1003 error_caught = FALSE;
1005 /* Push a warning */
1006 GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
1007 ("Failed to create output image buffer of %dx%d pixels",
1008 xvimage->width, xvimage->height),
1009 ("could not XvShmCreateImage a %dx%d image",
1010 xvimage->width, xvimage->height));
1012 #ifdef GST_EXT_XV_ENHANCEMENT
1013 /* must not change "use_xshm",
1014 because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
1015 goto beach_unlocked;
1016 #else /* GST_EXT_XV_ENHANCEMENT */
1017 /* Retry without XShm */
1018 xvimagesink->xcontext->use_xshm = FALSE;
1020 /* Hold X mutex again to try without XShm */
1021 g_mutex_lock (xvimagesink->x_lock);
1023 #endif /* GST_EXT_XV_ENHANCEMENT */
1026 /* we have to use the returned data_size for our shm size */
1027 xvimage->size = xvimage->xvimage->data_size;
1028 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
1031 /* calculate the expected size. This is only for sanity checking the
1032 * number we get from X. */
1033 switch (xvimage->im_format) {
1034 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
1035 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
1042 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
1043 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
1044 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
1046 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
1047 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
1050 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
1052 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1053 GST_DEBUG_OBJECT (xvimagesink,
1054 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
1055 plane, pitches[plane], offsets[plane]);
1059 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
1060 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
1061 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
1064 #ifdef GST_EXT_XV_ENHANCEMENT
1065 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
1066 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
1067 case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
1068 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
1069 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
1070 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
1071 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
1072 expected_size = sizeof(SCMN_IMGB);
1074 #endif /* GST_EXT_XV_ENHANCEMENT */
1079 if (expected_size != 0 && xvimage->size != expected_size) {
1080 GST_WARNING_OBJECT (xvimagesink,
1081 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
1082 xvimage->size, expected_size);
1085 /* Be verbose about our XvImage stride */
1089 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1090 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
1091 "offset of %d", plane, xvimage->xvimage->pitches[plane],
1092 xvimage->xvimage->offsets[plane]);
1096 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
1098 if (xvimage->SHMInfo.shmid == -1) {
1099 g_mutex_unlock (xvimagesink->x_lock);
1100 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1101 ("Failed to create output image buffer of %dx%d pixels",
1102 xvimage->width, xvimage->height),
1103 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1105 goto beach_unlocked;
1108 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1109 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1110 g_mutex_unlock (xvimagesink->x_lock);
1111 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1112 ("Failed to create output image buffer of %dx%d pixels",
1113 xvimage->width, xvimage->height),
1114 ("Failed to shmat: %s", g_strerror (errno)));
1115 /* Clean up the shared memory segment */
1116 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1117 goto beach_unlocked;
1120 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1121 xvimage->SHMInfo.readOnly = FALSE;
1123 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1124 /* Clean up the shared memory segment */
1125 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1127 g_mutex_unlock (xvimagesink->x_lock);
1128 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1129 ("Failed to create output image buffer of %dx%d pixels",
1130 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1131 goto beach_unlocked;
1134 XSync (xvimagesink->xcontext->disp, FALSE);
1136 /* Delete the shared memory segment as soon as we everyone is attached.
1137 * This way, it will be deleted as soon as we detach later, and not
1138 * leaked if we crash. */
1139 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1141 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1142 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1144 #ifndef GST_EXT_XV_ENHANCEMENT
1146 #endif /* GST_EXT_XV_ENHANCEMENT */
1147 #endif /* HAVE_XSHM */
1149 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1150 xvimagesink->xcontext->xv_port_id,
1151 #ifdef GST_EXT_XV_ENHANCEMENT
1152 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1153 #else /* GST_EXT_XV_ENHANCEMENT */
1154 xvimage->im_format, NULL, xvimage->width, xvimage->height);
1155 #endif /* GST_EXT_XV_ENHANCEMENT */
1156 if (!xvimage->xvimage || error_caught) {
1157 g_mutex_unlock (xvimagesink->x_lock);
1158 /* Reset error handler */
1159 error_caught = FALSE;
1160 XSetErrorHandler (handler);
1162 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1163 ("Failed to create outputimage buffer of %dx%d pixels",
1164 xvimage->width, xvimage->height),
1165 ("could not XvCreateImage a %dx%d image",
1166 xvimage->width, xvimage->height));
1167 goto beach_unlocked;
1170 /* we have to use the returned data_size for our image size */
1171 xvimage->size = xvimage->xvimage->data_size;
1172 xvimage->xvimage->data = g_malloc (xvimage->size);
1174 XSync (xvimagesink->xcontext->disp, FALSE);
1177 /* Reset error handler */
1178 error_caught = FALSE;
1179 XSetErrorHandler (handler);
1183 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1184 GST_BUFFER_SIZE (xvimage) = xvimage->size;
1186 g_mutex_unlock (xvimagesink->x_lock);
1190 gst_xvimage_buffer_free (xvimage);
1197 /* We are called with the x_lock taken */
1199 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
1200 GstXWindow * xwindow, GstVideoRectangle rect)
1204 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1205 g_return_if_fail (xwindow != NULL);
1207 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1208 xvimagesink->xcontext->black);
1211 if (rect.x > xvimagesink->render_rect.x) {
1212 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1213 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1214 rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
1218 t1 = rect.x + rect.w;
1219 t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
1221 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1222 t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
1226 if (rect.y > xvimagesink->render_rect.y) {
1227 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1228 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1229 xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
1233 t1 = rect.y + rect.h;
1234 t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
1236 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1237 xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
1241 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
1242 * if no window was available */
1244 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
1245 GstXvImageBuffer * xvimage)
1247 GstVideoRectangle result;
1248 gboolean draw_border = FALSE;
1250 #ifdef GST_EXT_XV_ENHANCEMENT
1251 static Atom atom_rotation = None;
1252 static Atom atom_hflip = None;
1253 static Atom atom_vflip = None;
1254 static Atom atom_contents_rotation = None;
1255 gboolean set_hflip = FALSE;
1256 gboolean set_vflip = FALSE;
1257 XWindowAttributes map_attr;
1259 GstVideoRectangle src_origin = { 0, 0, 0, 0};
1260 GstVideoRectangle src_input = { 0, 0, 0, 0};
1261 GstVideoRectangle src = { 0, 0, 0, 0};
1262 GstVideoRectangle dst = { 0, 0, 0, 0};
1264 gint res_rotate_angle = 0;
1266 int orientation = 0;
1269 int (*handler) (Display *, XErrorEvent *) = NULL;
1270 gboolean res = FALSE;
1271 XV_DATA_PTR img_data = NULL;
1273 if (xvimagesink->is_subpicture_format)
1275 #endif /* GST_EXT_XV_ENHANCEMENT */
1277 /* We take the flow_lock. If expose is in there we don't want to run
1278 concurrently from the data flow thread */
1279 g_mutex_lock (xvimagesink->flow_lock);
1281 #ifdef GST_EXT_XV_ENHANCEMENT
1282 if (xvimagesink->xid_updated) {
1283 if (xvimage && xvimagesink->xvimage == NULL) {
1284 GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
1287 xvimagesink->xid_updated = FALSE;
1289 #endif /* GST_EXT_XV_ENHANCEMENT */
1291 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1292 #ifdef GST_EXT_XV_ENHANCEMENT
1293 if (xvimagesink->get_pixmap_cb) {
1294 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
1296 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
1297 g_mutex_unlock(xvimagesink->flow_lock);
1300 #else /* GST_EXT_XV_ENHANCEMENT */
1301 g_mutex_unlock (xvimagesink->flow_lock);
1303 #endif /* GST_EXT_XV_ENHANCEMENT */
1306 #ifdef GST_EXT_XV_ENHANCEMENT
1307 /* check map status of window */
1308 if(!xvimagesink->is_pixmap) {
1309 if (xvimagesink->xcontext && xvimagesink->xwindow) {
1310 if (XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &map_attr)) {
1311 if (map_attr.map_state != IsViewable) {
1312 GST_WARNING_OBJECT(xvimagesink, "window is unmapped, skip putimage");
1313 g_mutex_unlock(xvimagesink->flow_lock);
1317 GST_WARNING_OBJECT(xvimagesink, "XGetWindowAttributes failed");
1321 #endif /* GST_EXT_XV_ENHANCEMENT */
1323 /* Draw borders when displaying the first frame. After this
1324 draw borders only on expose event or after a size change. */
1325 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1329 /* Store a reference to the last image we put, lose the previous one */
1330 if (xvimage && xvimagesink->cur_image != xvimage) {
1331 if (xvimagesink->cur_image) {
1332 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1333 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1335 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1336 xvimagesink->cur_image =
1337 GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1340 /* Expose sends a NULL image, we take the latest frame */
1342 #ifdef GST_EXT_XV_ENHANCEMENT
1343 g_mutex_lock(xvimagesink->display_buffer_lock);
1344 if (xvimagesink->is_zero_copy_format &&
1345 xvimagesink->displaying_buffer_count < 1) {
1346 g_mutex_unlock(xvimagesink->display_buffer_lock);
1347 g_mutex_unlock (xvimagesink->flow_lock);
1348 GST_WARNING_OBJECT(xvimagesink, "no buffer to display. skip putimage");
1351 g_mutex_unlock(xvimagesink->display_buffer_lock);
1352 #endif /* GST_EXT_XV_ENHANCEMENT */
1353 if (xvimagesink->cur_image) {
1355 xvimage = xvimagesink->cur_image;
1357 #ifdef GST_EXT_XV_ENHANCEMENT
1358 GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1359 /* no need to release gem handle */
1360 #endif /* GST_EXT_XV_ENHANCEMENT */
1361 g_mutex_unlock (xvimagesink->flow_lock);
1366 #ifdef GST_EXT_XV_ENHANCEMENT
1367 gboolean enable_last_buffer;
1368 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
1369 if(enable_last_buffer) {
1370 if (xvimagesink->cur_image && xvimagesink->is_zero_copy_format) {
1371 GstBuffer *last_buffer= NULL;
1372 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
1374 if(last_buffer != xvimagesink->cur_image)
1376 GST_LOG("curimage : %p , last_buffer : %p", xvimagesink->cur_image, last_buffer);
1379 GST_WARNING_OBJECT(xvimagesink, "zero copy format and last buffer is NULL, so skip this putimage");
1380 g_mutex_unlock (xvimagesink->flow_lock);
1383 gst_buffer_unref(last_buffer);
1388 if (xvimagesink->visible == FALSE ||
1389 (xvimagesink->is_hided && GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
1390 GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
1391 xvimagesink->visible, xvimagesink->is_hided);
1392 g_mutex_unlock(xvimagesink->flow_lock);
1396 if (!xvimagesink->get_pixmap_cb) {
1397 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1398 if (!xvimagesink->subpicture && !xvimagesink->is_during_seek) {
1399 if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
1400 set_display_mode(xvimagesink->xcontext, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE);
1402 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
1406 /* for multi-pixmap usage for the video texture */
1407 gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
1408 idx = xvimagesink->current_pixmap_idx;
1410 g_mutex_unlock (xvimagesink->flow_lock);
1412 } else if (idx == -2) {
1413 GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
1414 g_mutex_unlock (xvimagesink->flow_lock);
1419 res_rotate_angle = xvimagesink->rotate_angle;
1422 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1424 src_input.w = src_origin.w = xvimagesink->video_width;
1425 src_input.h = src_origin.h = xvimagesink->video_height;
1427 if ((xvimagesink->display_geometry_method == DISP_GEO_METHOD_LETTER_BOX ||
1428 xvimagesink->display_geometry_method == DISP_GEO_METHOD_FULL_SCREEN ||
1429 xvimagesink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_DST_ROI) &&
1430 xvimagesink->src_crop.w && xvimagesink->src_crop.h) {
1431 GST_LOG_OBJECT(xvimagesink, "set src crop %d,%d,%dx%d -> %d,%d,%dx%d",
1432 src_input.x, src_input.y, src_input.w, src_input.h,
1433 xvimagesink->src_crop.x, xvimagesink->src_crop.y, xvimagesink->src_crop.w, xvimagesink->src_crop.h);
1434 src_input.x = src_origin.w = xvimagesink->src_crop.x;
1435 src_input.y = src_origin.y = xvimagesink->src_crop.y;
1436 src_input.w = src_origin.w = xvimagesink->src_crop.w;
1437 src_input.h = src_origin.h = xvimagesink->src_crop.h;
1440 if (xvimagesink->rotate_angle == DEGREE_0 ||
1441 xvimagesink->rotate_angle == DEGREE_180) {
1442 src.w = src_origin.w;
1443 src.h = src_origin.h;
1445 src.w = src_origin.h;
1446 src.h = src_origin.w;
1449 dst.w = xvimagesink->render_rect.w;
1450 dst.h = xvimagesink->render_rect.h;
1452 switch (xvimagesink->display_geometry_method)
1454 case DISP_GEO_METHOD_LETTER_BOX:
1455 gst_video_sink_center_rect (src, dst, &result, TRUE);
1456 result.x += xvimagesink->render_rect.x;
1457 result.y += xvimagesink->render_rect.y;
1460 case DISP_GEO_METHOD_ORIGIN_SIZE:
1461 gst_video_sink_center_rect (src, dst, &result, FALSE);
1462 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1464 if (xvimagesink->rotate_angle == DEGREE_90 ||
1465 xvimagesink->rotate_angle == DEGREE_270) {
1466 src_input.x = src_input.x ^ src_input.y;
1467 src_input.y = src_input.x ^ src_input.y;
1468 src_input.x = src_input.x ^ src_input.y;
1470 src_input.w = src_input.w ^ src_input.h;
1471 src_input.h = src_input.w ^ src_input.h;
1472 src_input.w = src_input.w ^ src_input.h;
1476 case DISP_GEO_METHOD_FULL_SCREEN:
1477 result.x = result.y = 0;
1478 if (!xvimagesink->get_pixmap_cb) {
1479 result.w = xvimagesink->xwindow->width;
1480 result.h = xvimagesink->xwindow->height;
1482 result.w = xvimagesink->xpixmap[idx]->width;
1483 result.h = xvimagesink->xpixmap[idx]->height;
1487 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1488 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1490 result.x = result.y = 0;
1494 if (xvimagesink->rotate_angle == DEGREE_90 ||
1495 xvimagesink->rotate_angle == DEGREE_270) {
1496 src_input.x = src_input.x ^ src_input.y;
1497 src_input.y = src_input.x ^ src_input.y;
1498 src_input.x = src_input.x ^ src_input.y;
1500 src_input.w = src_input.w ^ src_input.h;
1501 src_input.h = src_input.w ^ src_input.h;
1502 src_input.w = src_input.w ^ src_input.h;
1506 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
1507 if (src.w > dst.w || src.h > dst.h) {
1509 gst_video_sink_center_rect (src, dst, &result, TRUE);
1510 result.x += xvimagesink->render_rect.x;
1511 result.y += xvimagesink->render_rect.y;
1514 gst_video_sink_center_rect (src, dst, &result, FALSE);
1515 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1517 if (xvimagesink->rotate_angle == DEGREE_90 ||
1518 xvimagesink->rotate_angle == DEGREE_270) {
1519 src_input.x = src_input.x ^ src_input.y;
1520 src_input.y = src_input.x ^ src_input.y;
1521 src_input.x = src_input.x ^ src_input.y;
1523 src_input.w = src_input.w ^ src_input.h;
1524 src_input.h = src_input.w ^ src_input.h;
1525 src_input.w = src_input.w ^ src_input.h;
1530 case DISP_GEO_METHOD_CUSTOM_DST_ROI:
1532 GstVideoRectangle dst_roi_cmpns;
1533 dst_roi_cmpns.w = xvimagesink->dst_roi.w;
1534 dst_roi_cmpns.h = xvimagesink->dst_roi.h;
1535 dst_roi_cmpns.x = xvimagesink->dst_roi.x;
1536 dst_roi_cmpns.y = xvimagesink->dst_roi.y;
1538 /* setting for DST ROI mode */
1539 switch (xvimagesink->dst_roi_mode) {
1540 case ROI_DISP_GEO_METHOD_FULL_SCREEN:
1542 case ROI_DISP_GEO_METHOD_LETTER_BOX:
1544 GstVideoRectangle roi_result;
1545 if (xvimagesink->orientation == DEGREE_0 ||
1546 xvimagesink->orientation == DEGREE_180) {
1547 src.w = src_origin.w;
1548 src.h = src_origin.h;
1550 src.w = src_origin.h;
1551 src.h = src_origin.w;
1553 dst.w = xvimagesink->dst_roi.w;
1554 dst.h = xvimagesink->dst_roi.h;
1556 gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
1557 dst_roi_cmpns.w = roi_result.w;
1558 dst_roi_cmpns.h = roi_result.h;
1559 dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
1560 dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
1567 /* calculating coordinates according to rotation angle for DST ROI */
1568 switch (xvimagesink->rotate_angle) {
1570 result.w = dst_roi_cmpns.h;
1571 result.h = dst_roi_cmpns.w;
1573 result.x = dst_roi_cmpns.y;
1574 if (!xvimagesink->get_pixmap_cb) {
1575 result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1577 result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1581 result.w = dst_roi_cmpns.w;
1582 result.h = dst_roi_cmpns.h;
1584 if (!xvimagesink->get_pixmap_cb) {
1585 result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
1586 result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
1588 result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
1589 result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
1593 result.w = dst_roi_cmpns.h;
1594 result.h = dst_roi_cmpns.w;
1596 if (!xvimagesink->get_pixmap_cb) {
1597 result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1599 result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1601 result.y = dst_roi_cmpns.x;
1604 result.x = dst_roi_cmpns.x;
1605 result.y = dst_roi_cmpns.y;
1606 result.w = dst_roi_cmpns.w;
1607 result.h = dst_roi_cmpns.h;
1611 /* orientation setting for auto rotation in DST ROI */
1612 if (xvimagesink->orientation) {
1613 res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation);
1614 if (res_rotate_angle < 0) {
1615 res_rotate_angle += DEGREE_NUM;
1617 GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
1618 xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle);
1621 GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
1622 xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode,
1623 xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1624 result.x, result.y, result.w, result.h);
1631 if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
1632 GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]",
1633 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
1634 gint default_offset_x = 0;
1635 gint default_offset_y = 0;
1636 gfloat w = (gfloat)src_input.w;
1637 gfloat h = (gfloat)src_input.h;
1638 if (xvimagesink->orientation == DEGREE_0 ||
1639 xvimagesink->orientation == DEGREE_180) {
1640 default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
1641 default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
1643 default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1;
1644 default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1;
1646 GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation);
1647 if (xvimagesink->zoom_pos_x == -1) {
1648 src_input.x += default_offset_x;
1650 if (xvimagesink->orientation == DEGREE_0 ||
1651 xvimagesink->orientation == DEGREE_180) {
1652 if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) {
1653 xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom);
1655 src_input.x += xvimagesink->zoom_pos_x;
1657 if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) {
1658 xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom);
1660 src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x;
1663 if (xvimagesink->zoom_pos_y == -1) {
1664 src_input.y += default_offset_y;
1666 if (xvimagesink->orientation == DEGREE_0 ||
1667 xvimagesink->orientation == DEGREE_180) {
1668 if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) {
1669 xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom);
1671 src_input.y += xvimagesink->zoom_pos_y;
1673 if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) {
1674 xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom);
1676 src_input.x += (xvimagesink->zoom_pos_y);
1679 src_input.w = (gint)(w/xvimagesink->zoom);
1680 src_input.h = (gint)(h/xvimagesink->zoom);
1681 GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
1682 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
1685 #else /* GST_EXT_XV_ENHANCEMENT */
1686 if (xvimagesink->keep_aspect) {
1687 GstVideoRectangle src, dst;
1689 /* We use the calculated geometry from _setcaps as a source to respect
1690 source and screen pixel aspect ratios. */
1691 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1692 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1693 dst.w = xvimagesink->render_rect.w;
1694 dst.h = xvimagesink->render_rect.h;
1696 gst_video_sink_center_rect (src, dst, &result, TRUE);
1697 result.x += xvimagesink->render_rect.x;
1698 result.y += xvimagesink->render_rect.y;
1700 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1702 #endif /* GST_EXT_XV_ENHANCEMENT */
1704 g_mutex_lock (xvimagesink->x_lock);
1706 #ifdef GST_EXT_XV_ENHANCEMENT
1707 if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
1709 if (draw_border && xvimagesink->draw_borders) {
1710 #endif /* GST_EXT_XV_ENHANCEMENT */
1711 gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1713 xvimagesink->redraw_border = FALSE;
1716 /* We scale to the window's geometry */
1718 if (xvimagesink->xcontext->use_xshm) {
1719 GST_LOG_OBJECT (xvimagesink,
1720 "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1722 xvimage->width, xvimage->height,
1723 xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1725 #ifdef GST_EXT_XV_ENHANCEMENT
1726 switch( res_rotate_angle )
1728 /* There's slightly weired code (CCW? CW?) */
1741 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1746 /* Trim as proper size */
1747 if (src_input.w % 2 == 1) {
1750 if (src_input.h % 2 == 1) {
1754 if (!xvimagesink->get_pixmap_cb) {
1755 GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1756 xvimagesink->scr_w, xvimagesink->scr_h,
1757 xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1758 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1759 src_origin.w, src_origin.h,
1760 dst.x, dst.y, dst.w, dst.h,
1761 src_input.x, src_input.y, src_input.w, src_input.h,
1762 result.x, result.y, result.w, result.h );
1764 GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1765 xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
1766 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1767 src_origin.w, src_origin.h,
1768 dst.x, dst.y, dst.w, dst.h,
1769 src_input.x, src_input.y, src_input.w, src_input.h,
1770 result.x, result.y, result.w, result.h );
1772 /* skip request to render if dst rect is 0 */
1773 if (xvimagesink->is_zero_copy_format && (!result.w || !result.h)) {
1774 GST_WARNING_OBJECT(xvimagesink, "result.w[%d] or result.h[%d] is 0. Skip xvimage_put.", result.w, result.h);
1775 g_mutex_unlock(xvimagesink->x_lock);
1776 g_mutex_unlock(xvimagesink->flow_lock);
1780 static gboolean is_exist = FALSE;
1781 gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_ROTATION");
1782 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1786 /* set display rotation */
1787 if (atom_rotation == None) {
1788 atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1789 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1791 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1792 atom_rotation, rotate);
1793 if (ret != Success) {
1794 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1795 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1797 g_mutex_unlock(xvimagesink->x_lock);
1798 g_mutex_unlock(xvimagesink->flow_lock);
1802 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_ROTATION is not existed");
1805 switch( xvimagesink->orientation )
1820 GST_WARNING_OBJECT( xvimagesink, "Unsupported orientation [%d]...",
1821 xvimagesink->orientation );
1826 attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION");
1827 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1831 /* set contents rotation for connecting with external display */
1832 if (atom_contents_rotation == None) {
1833 atom_contents_rotation = XInternAtom(xvimagesink->xcontext->disp,
1834 "_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION", False);
1836 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1837 atom_contents_rotation, orientation);
1838 if (ret != Success) {
1839 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],orientation[%d]",
1840 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_contents_rotation, orientation );
1842 g_mutex_unlock(xvimagesink->x_lock);
1843 g_mutex_unlock(xvimagesink->flow_lock);
1847 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION is not existed");
1850 switch (xvimagesink->flip) {
1851 case FLIP_HORIZONTAL:
1870 GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
1873 attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_HFLIP");
1874 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1878 if (atom_hflip == None) {
1879 /* set display flip */
1880 atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
1881 "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1883 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1884 if (ret != Success) {
1885 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1886 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1891 attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_VFLIP");
1892 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
1896 if (atom_vflip == None) {
1897 /* set display flip */
1898 atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
1899 "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1901 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1902 if (ret != Success) {
1903 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1904 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1908 /* set error handler */
1909 error_caught = FALSE;
1910 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
1912 /* src input indicates the status when degree is 0 */
1913 /* dst input indicates the area that src will be shown regardless of rotate */
1914 if (xvimagesink->visible &&
1915 ((!xvimagesink->is_hided) || (xvimagesink->is_hided && (GST_STATE(xvimagesink) == GST_STATE_PLAYING)))) {
1916 if (xvimagesink->xim_transparenter) {
1917 GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1918 XPutImage(xvimagesink->xcontext->disp,
1919 xvimagesink->xwindow->win,
1920 xvimagesink->xwindow->gc,
1921 xvimagesink->xim_transparenter,
1923 result.x, result.y, result.w, result.h);
1927 if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) {
1928 img_data = (XV_DATA_PTR)xvimage->xvimage->data;
1929 if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
1930 _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
1931 xvimage->current_buffer = NULL;
1935 g_mutex_lock(xvimagesink->display_buffer_lock);
1936 if (xvimagesink->displaying_buffer_count > 3) {
1937 GST_WARNING("too many buffers are not released. [displaying_buffer_count %d]", xvimagesink->displaying_buffer_count);
1939 g_mutex_unlock(xvimagesink->display_buffer_lock);
1941 if (xvimagesink->get_pixmap_cb) {
1942 gint idx = xvimagesink->current_pixmap_idx;
1943 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1944 xvimagesink->xcontext->xv_port_id,
1945 xvimagesink->xpixmap[idx]->pixmap,
1946 xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
1947 src_input.x, src_input.y, src_input.w, src_input.h,
1948 result.x, result.y, result.w, result.h, FALSE);
1949 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], pixmap id[%d], idx[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xpixmap[idx]->gc, xvimagesink->xpixmap[idx]->pixmap, idx);
1951 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1952 xvimagesink->xcontext->xv_port_id,
1953 xvimagesink->xwindow->win,
1954 xvimagesink->xwindow->gc, xvimage->xvimage,
1955 src_input.x, src_input.y, src_input.w, src_input.h,
1956 result.x, result.y, result.w, result.h, FALSE);
1957 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], xid[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xwindow->gc, xvimagesink->xwindow->win);
1960 GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1962 #else /* GST_EXT_XV_ENHANCEMENT */
1963 XvShmPutImage (xvimagesink->xcontext->disp,
1964 xvimagesink->xcontext->xv_port_id,
1965 xvimagesink->xwindow->win,
1966 xvimagesink->xwindow->gc, xvimage->xvimage,
1967 xvimagesink->disp_x, xvimagesink->disp_y,
1968 xvimagesink->disp_width, xvimagesink->disp_height,
1969 result.x, result.y, result.w, result.h, FALSE);
1970 #endif /* GST_EXT_XV_ENHANCEMENT */
1972 #endif /* HAVE_XSHM */
1974 XvPutImage (xvimagesink->xcontext->disp,
1975 xvimagesink->xcontext->xv_port_id,
1976 xvimagesink->xwindow->win,
1977 xvimagesink->xwindow->gc, xvimage->xvimage,
1978 xvimagesink->disp_x, xvimagesink->disp_y,
1979 xvimagesink->disp_width, xvimagesink->disp_height,
1980 result.x, result.y, result.w, result.h);
1983 XSync (xvimagesink->xcontext->disp, FALSE);
1986 #ifdef GST_EXT_XV_ENHANCEMENT
1987 if (ret || error_caught || xvimagesink->get_pixmap_cb) {
1988 GST_DEBUG("error or pixmap_cb");
1990 if (ret || error_caught) {
1991 GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
1992 ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
1994 if (xvimagesink->get_pixmap_cb) {
1995 g_signal_emit (G_OBJECT (xvimagesink),
1996 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
1998 &xvimagesink->xpixmap[idx]->pixmap,
2003 /* release gem handle */
2004 if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
2005 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
2006 gem_name[0] = img_data->YBuf;
2007 gem_name[1] = img_data->CbBuf;
2008 gem_name[2] = img_data->CrBuf;
2009 _remove_displaying_buffer(xvimagesink, gem_name);
2013 /* Reset error handler */
2015 error_caught = FALSE;
2016 XSetErrorHandler (handler);
2018 #endif /* GST_EXT_XV_ENHANCEMENT */
2019 #endif /* HAVE_XSHM */
2021 g_mutex_unlock (xvimagesink->x_lock);
2023 g_mutex_unlock (xvimagesink->flow_lock);
2029 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
2030 GstXWindow * window)
2032 Atom hints_atom = None;
2033 MotifWmHints *hints;
2035 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
2036 g_return_val_if_fail (window != NULL, FALSE);
2038 g_mutex_lock (xvimagesink->x_lock);
2040 hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
2042 if (hints_atom == None) {
2043 g_mutex_unlock (xvimagesink->x_lock);
2047 hints = g_malloc0 (sizeof (MotifWmHints));
2049 hints->flags |= MWM_HINTS_DECORATIONS;
2050 hints->decorations = 1 << 0;
2052 XChangeProperty (xvimagesink->xcontext->disp, window->win,
2053 hints_atom, hints_atom, 32, PropModeReplace,
2054 (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
2056 XSync (xvimagesink->xcontext->disp, FALSE);
2058 g_mutex_unlock (xvimagesink->x_lock);
2066 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
2067 GstXWindow * xwindow, const gchar * media_title)
2070 g_free (xvimagesink->media_title);
2071 xvimagesink->media_title = g_strdup (media_title);
2074 /* we have a window */
2075 if (xwindow->internal) {
2076 XTextProperty xproperty;
2077 const gchar *app_name;
2078 const gchar *title = NULL;
2079 gchar *title_mem = NULL;
2081 /* set application name as a title */
2082 app_name = g_get_application_name ();
2084 if (app_name && xvimagesink->media_title) {
2085 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
2087 } else if (app_name) {
2089 } else if (xvimagesink->media_title) {
2090 title = xvimagesink->media_title;
2094 if ((XStringListToTextProperty (((char **) &title), 1,
2095 &xproperty)) != 0) {
2096 XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
2097 XFree (xproperty.value);
2106 #ifdef GST_EXT_XV_ENHANCEMENT
2107 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
2111 /* create a normal ximage */
2112 xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
2114 GST_INFO("ximage %p", xim);
2116 /* allocate data for it */
2118 xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
2120 memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
2123 GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
2129 GST_ERROR("failed to create Ximage");
2135 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
2138 static gboolean is_exist = FALSE;
2139 static XvPortID current_port_id = -1;
2140 Atom atom_output = None;
2142 if (xcontext == NULL) {
2143 GST_WARNING("xcontext is NULL");
2147 /* check once per one xv_port_id */
2148 if (current_port_id != xcontext->xv_port_id) {
2149 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2152 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2153 xcontext->xv_port_id, &count);
2155 current_port_id = xcontext->xv_port_id;
2156 for (i = 0 ; i < count ; i++) {
2157 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
2159 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2165 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2166 xcontext->disp, xcontext->xv_port_id);
2171 GST_DEBUG("set display mode %d", set_mode);
2172 atom_output = XInternAtom(xcontext->disp,
2173 "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
2174 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2175 atom_output, set_mode);
2176 if (ret == Success) {
2179 GST_WARNING("display mode[%d] set failed.", set_mode);
2182 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
2189 static gboolean set_csc_range(GstXContext *xcontext, int set_range)
2192 static gboolean is_exist = FALSE;
2193 static XvPortID current_port_id = -1;
2194 Atom atom_csc_range = None;
2196 if (xcontext == NULL) {
2197 GST_WARNING("xcontext is NULL");
2201 /* check once per one xv_port_id */
2202 if (current_port_id != xcontext->xv_port_id) {
2203 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2206 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2207 xcontext->xv_port_id, &count);
2209 current_port_id = xcontext->xv_port_id;
2210 for (i = 0 ; i < count ; i++) {
2211 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
2213 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2219 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2220 xcontext->disp, xcontext->xv_port_id);
2225 GST_WARNING("set csc range %d", set_range);
2226 atom_csc_range = XInternAtom(xcontext->disp,
2227 "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
2228 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2229 atom_csc_range, set_range);
2230 if (ret == Success) {
2233 GST_WARNING("csc range[%d] set failed.", set_range);
2236 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
2243 static void drm_init(GstXvImageSink *xvimagesink)
2250 char *driverName = NULL;
2251 char *deviceName = NULL;
2252 struct drm_auth auth_arg = {0};
2254 xvimagesink->drm_fd = -1;
2256 dpy = XOpenDisplay(0);
2258 GST_ERROR("XOpenDisplay failed errno:%d", errno);
2265 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
2266 GST_ERROR("DRI2QueryExtension !!");
2267 goto DRM_INIT_ERROR;
2270 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
2271 GST_ERROR("DRI2QueryVersion !!");
2272 goto DRM_INIT_ERROR;
2275 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
2276 GST_ERROR("DRI2Connect !!");
2277 goto DRM_INIT_ERROR;
2280 if (!driverName || !deviceName) {
2281 GST_ERROR("driverName or deviceName is not valid");
2282 goto DRM_INIT_ERROR;
2285 GST_INFO("Open drm device : %s", deviceName);
2287 /* get the drm_fd though opening the deviceName */
2288 xvimagesink->drm_fd = open(deviceName, O_RDWR);
2289 if (xvimagesink->drm_fd < 0) {
2290 GST_ERROR("cannot open drm device (%s)", deviceName);
2291 goto DRM_INIT_ERROR;
2294 /* get magic from drm to authentication */
2295 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
2296 GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd);
2297 goto DRM_INIT_ERROR;
2300 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
2301 GST_ERROR("cannot get drm authentication from X");
2302 goto DRM_INIT_ERROR;
2309 xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd);
2310 if (xvimagesink->bufmgr == NULL) {
2311 GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed");
2312 goto DRM_INIT_ERROR;
2320 if (xvimagesink->drm_fd >= 0) {
2321 close(xvimagesink->drm_fd);
2322 xvimagesink->drm_fd = -1;
2337 static void drm_fini(GstXvImageSink *xvimagesink)
2339 GST_WARNING_OBJECT(xvimagesink, "START");
2341 if (xvimagesink->drm_fd >= 0) {
2345 /* close remained gem handle */
2346 g_mutex_lock(xvimagesink->display_buffer_lock);
2347 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2348 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2349 GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u",
2350 xvimagesink->displaying_buffers[i].buffer,
2351 xvimagesink->displaying_buffers[i].gem_name[0],
2352 xvimagesink->displaying_buffers[i].gem_name[1],
2353 xvimagesink->displaying_buffers[i].gem_name[2],
2354 xvimagesink->displaying_buffers[i].gem_handle[0],
2355 xvimagesink->displaying_buffers[i].gem_handle[1],
2356 xvimagesink->displaying_buffers[i].gem_handle[2]);
2358 /* release flush buffer */
2359 if (xvimagesink->flush_buffer) {
2360 if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] &&
2361 xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] &&
2362 xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) {
2363 _release_flush_buffer(xvimagesink);
2366 GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer");
2369 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2370 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2371 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2373 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2374 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2375 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2378 if (xvimagesink->displaying_buffers[i].buffer) {
2379 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2380 xvimagesink->displaying_buffers[i].buffer = NULL;
2384 g_mutex_unlock(xvimagesink->display_buffer_lock);
2386 GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager");
2387 tbm_bufmgr_deinit(xvimagesink->bufmgr);
2388 xvimagesink->bufmgr = NULL;
2390 GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd);
2391 close(xvimagesink->drm_fd);
2392 xvimagesink->drm_fd = -1;
2394 GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened");
2397 GST_WARNING_OBJECT(xvimagesink, "DONE");
2400 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
2404 struct drm_prime_handle prime_arg = {0,};
2405 struct drm_gem_flink flink_arg = {0,};
2407 if (!xvimagesink || !gem_handle) {
2408 GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
2412 if (xvimagesink->drm_fd < 0) {
2413 GST_ERROR("DRM is not opened");
2417 if (dmabuf_fd <= 0) {
2418 GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
2422 prime_arg.fd = dmabuf_fd;
2423 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
2425 GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]",
2426 ret, dmabuf_fd, xvimagesink->drm_fd);
2430 *gem_handle = prime_arg.handle;
2431 flink_arg.handle = prime_arg.handle;
2432 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
2434 GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]",
2435 ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd);
2439 return flink_arg.name;
2442 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
2444 struct drm_gem_close close_arg = {0,};
2446 if (xvimagesink->drm_fd < 0 || !gem_handle) {
2447 GST_ERROR("DRM is not opened");
2451 if (*gem_handle <= 0) {
2452 GST_DEBUG("invalid gem handle %u", *gem_handle);
2456 GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
2458 close_arg.handle = *gem_handle;
2459 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
2460 GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd);
2470 static void _remove_last_buffer(GstXvImageSink *xvimagesink)
2472 gboolean enable_last_buffer = FALSE;
2474 if (xvimagesink == NULL) {
2475 GST_ERROR("handle is NULL");
2479 /* get enable-last-buffer */
2480 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
2482 GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
2484 /* flush if enable-last-buffer is TRUE */
2485 if (enable_last_buffer) {
2486 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
2487 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
2494 static void _release_flush_buffer(GstXvImageSink *xvimagesink)
2498 if (xvimagesink == NULL ||
2499 xvimagesink->flush_buffer == NULL) {
2500 GST_WARNING("handle is NULL");
2504 GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER");
2506 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
2507 if (xvimagesink->flush_buffer->bo[i]) {
2508 tbm_bo_unref(xvimagesink->flush_buffer->bo[i]);
2509 xvimagesink->flush_buffer->bo[i] = NULL;
2513 GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done");
2515 free(xvimagesink->flush_buffer);
2516 xvimagesink->flush_buffer = NULL;
2522 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
2527 if (!xvimagesink || !img_data) {
2528 GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
2532 /* lock display buffer mutex */
2533 g_mutex_lock(xvimagesink->display_buffer_lock);
2535 /* increase displaying buffer count */
2536 xvimagesink->displaying_buffer_count++;
2538 /* check duplicated */
2539 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2540 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2541 if ((img_data->dmabuf_fd[0] > 0 &&
2542 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
2543 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
2544 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
2546 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
2547 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
2548 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
2549 /* increase ref count */
2550 xvimagesink->displaying_buffers[i].ref_count++;
2552 /* set buffer info */
2553 img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
2554 img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
2555 img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
2557 if (img_data->dmabuf_fd[0] > 0) {
2558 GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
2559 img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
2560 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2562 GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
2563 img_data->bo[0], img_data->bo[1], img_data->bo[2],
2564 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2567 /* unlock display buffer mutex */
2568 g_mutex_unlock(xvimagesink->display_buffer_lock);
2574 /* store buffer temporarily */
2575 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2576 if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
2578 /* increase ref count of buffer */
2579 gst_buffer_ref(buffer);
2580 xvimagesink->displaying_buffers[i].buffer = buffer;
2583 if (img_data->dmabuf_fd[0] > 0) {
2584 /* convert fd to name */
2585 img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
2586 img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
2587 img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
2590 if (img_data->bo[0]) {
2591 img_data->YBuf = tbm_bo_export(img_data->bo[0]);
2593 if (img_data->bo[1]) {
2594 img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
2596 if (img_data->bo[2]) {
2597 img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
2601 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2602 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
2603 xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
2604 xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
2607 /* set buffer info */
2608 xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
2609 xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
2610 xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
2613 xvimagesink->displaying_buffers[i].ref_count = 1;
2615 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2616 GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2617 xvimagesink->displayed_buffer_count,
2618 i, xvimagesink->displaying_buffers[i].buffer,
2619 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2620 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2621 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2622 xvimagesink->displaying_buffers[i].gem_handle[0],
2623 xvimagesink->displaying_buffers[i].gem_handle[1],
2624 xvimagesink->displaying_buffers[i].gem_handle[2],
2625 xvimagesink->displaying_buffers[i].gem_name[0],
2626 xvimagesink->displaying_buffers[i].gem_name[1],
2627 xvimagesink->displaying_buffers[i].gem_name[2]);
2629 GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2630 i, xvimagesink->displaying_buffers[i].buffer,
2631 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2632 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2633 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2634 xvimagesink->displaying_buffers[i].gem_handle[0],
2635 xvimagesink->displaying_buffers[i].gem_handle[1],
2636 xvimagesink->displaying_buffers[i].gem_handle[2],
2637 xvimagesink->displaying_buffers[i].gem_name[0],
2638 xvimagesink->displaying_buffers[i].gem_name[1],
2639 xvimagesink->displaying_buffers[i].gem_name[2]);
2642 /* set last added buffer index */
2643 xvimagesink->last_added_buffer_index = i;
2644 GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i);
2646 /* unlock display buffer mutex */
2647 g_mutex_unlock(xvimagesink->display_buffer_lock);
2649 /* get current time */
2650 gettimeofday(&xvimagesink->request_time[i], NULL);
2655 /* decrease displaying buffer count */
2656 xvimagesink->displaying_buffer_count--;
2658 /* unlock display buffer mutex */
2659 g_mutex_unlock(xvimagesink->display_buffer_lock);
2661 GST_ERROR("should not be reached here. buffer slot is FULL...");
2667 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
2672 if (!xvimagesink || !gem_name) {
2673 GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name);
2677 /* lock display buffer mutex */
2678 g_mutex_lock(xvimagesink->display_buffer_lock);
2680 if (xvimagesink->displaying_buffer_count == 0) {
2681 GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer");
2682 /* unlock display buffer mutex */
2683 g_mutex_unlock(xvimagesink->display_buffer_lock);
2687 GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d",
2688 gem_name[0], gem_name[1], gem_name[2],
2689 xvimagesink->displaying_buffer_count);
2691 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2692 if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
2693 xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
2694 xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
2695 struct timeval current_time;
2697 /* get current time to calculate displaying time */
2698 gettimeofday(¤t_time, NULL);
2700 GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
2701 (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
2702 (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
2704 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2705 xvimagesink->displayed_buffer_count++;
2706 GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2707 xvimagesink->displayed_buffer_count,
2708 i, xvimagesink->displaying_buffers[i].buffer,
2709 xvimagesink->displaying_buffers[i].gem_handle[0],
2710 xvimagesink->displaying_buffers[i].gem_handle[1],
2711 xvimagesink->displaying_buffers[i].gem_handle[2],
2712 xvimagesink->displaying_buffers[i].gem_name[0],
2713 xvimagesink->displaying_buffers[i].gem_name[1],
2714 xvimagesink->displaying_buffers[i].gem_name[2]);
2716 GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2717 i, xvimagesink->displaying_buffers[i].buffer,
2718 xvimagesink->displaying_buffers[i].gem_handle[0],
2719 xvimagesink->displaying_buffers[i].gem_handle[1],
2720 xvimagesink->displaying_buffers[i].gem_handle[2],
2721 xvimagesink->displaying_buffers[i].gem_name[0],
2722 xvimagesink->displaying_buffers[i].gem_name[1],
2723 xvimagesink->displaying_buffers[i].gem_name[2]);
2726 /* decrease displaying buffer count */
2727 xvimagesink->displaying_buffer_count--;
2729 /* decrease ref count */
2730 xvimagesink->displaying_buffers[i].ref_count--;
2732 if (xvimagesink->displaying_buffers[i].ref_count > 0) {
2733 GST_WARNING("ref count not zero[%d], skip close gem handle",
2734 xvimagesink->displaying_buffers[i].ref_count);
2738 /* release flush buffer */
2739 if (xvimagesink->flush_buffer) {
2740 if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] &&
2741 xvimagesink->flush_buffer->gem_name[1] == gem_name[1] &&
2742 xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) {
2743 _release_flush_buffer(xvimagesink);
2747 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2748 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2749 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2751 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2752 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2753 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2756 /* reset last_added_buffer_index */
2757 if (xvimagesink->displaying_buffer_count < 1) {
2758 xvimagesink->last_added_buffer_index = -1;
2759 GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d",
2760 xvimagesink->displaying_buffer_count);
2763 if (xvimagesink->displaying_buffers[i].buffer) {
2764 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2765 xvimagesink->displaying_buffers[i].buffer = NULL;
2767 GST_WARNING("no buffer to unref");
2773 /* unlock display buffer mutex */
2774 g_mutex_unlock(xvimagesink->display_buffer_lock);
2780 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
2786 unsigned long num_ret = 0;
2787 unsigned long bytes = 0;
2788 unsigned char *prop_ret = NULL;
2789 unsigned int data = 0;
2790 int (*handler) (Display *, XErrorEvent *) = NULL;
2791 Atom atom_output_external;
2793 atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
2794 "XV_OUTPUT_EXTERNAL", False);
2795 if (atom_output_external != None) {
2796 /* set error handler */
2797 error_caught = FALSE;
2798 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
2800 ret = XGetWindowProperty(xvimagesink->xcontext->disp,
2801 xvimagesink->xwindow->win,
2802 atom_output_external, 0, 0x7fffffff,
2803 False, XA_CARDINAL, &type_ret, &size_ret,
2804 &num_ret, &bytes, &prop_ret);
2805 XSync(xvimagesink->xcontext->disp, FALSE);
2806 if (ret != Success || error_caught) {
2807 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
2812 GST_WARNING_OBJECT(xvimagesink, "error caught in XGetWindowProperty()");
2815 error_caught = FALSE;
2816 XSetErrorHandler (handler);
2822 error_caught = FALSE;
2823 XSetErrorHandler (handler);
2827 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
2837 for (i = 0 ; i < num_ret ; i++) {
2838 (&data)[i] = prop_ret[i];
2842 for (i = 0 ; i < num_ret ; i++) {
2843 ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
2847 for (i = 0 ; i < num_ret ; i++) {
2848 ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
2855 GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
2859 GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
2863 GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
2868 #endif /* GST_EXT_XV_ENHANCEMENT */
2870 /* This function handles a GstXWindow creation
2871 * The width and height are the actual pixel size on the display */
2873 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
2874 gint width, gint height)
2876 GstXWindow *xwindow = NULL;
2878 #ifdef GST_EXT_XV_ENHANCEMENT
2879 XSetWindowAttributes win_attr;
2880 XWindowAttributes root_attr = {0 , };
2881 #endif /* GST_EXT_XV_ENHANCEMENT */
2883 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2885 xwindow = g_new0 (GstXWindow, 1);
2887 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2888 #ifdef GST_EXT_XV_ENHANCEMENT
2890 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
2891 xvimagesink->render_rect.w = xwindow->width = width;
2892 xvimagesink->render_rect.h = xwindow->height = height;
2895 xvimagesink->render_rect.w = xwindow->width = height;
2896 xvimagesink->render_rect.h = xwindow->height = width;
2899 if(!xvimagesink->is_pixmap)
2900 XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
2902 if (xwindow->width > root_attr.width) {
2903 GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
2904 xwindow->width, root_attr.width);
2905 xvimagesink->render_rect.w = xwindow->width = root_attr.width;
2907 if (xwindow->height > root_attr.height) {
2908 GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
2909 xwindow->height, root_attr.height);
2910 xvimagesink->render_rect.h = xwindow->height = root_attr.height;
2912 xwindow->internal = TRUE;
2914 g_mutex_lock (xvimagesink->x_lock);
2916 GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
2918 xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
2919 xvimagesink->xcontext->root,
2920 0, 0, xwindow->width, xwindow->height,
2923 xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
2924 xvimagesink->xcontext->root,
2925 xwindow->width, xwindow->height);
2927 /* Make window manager not to change window size as Full screen */
2928 win_attr.override_redirect = True;
2929 if(!xvimagesink->is_pixmap)
2930 XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
2931 #else /* GST_EXT_XV_ENHANCEMENT */
2932 xvimagesink->render_rect.w = width;
2933 xvimagesink->render_rect.h = height;
2935 xwindow->width = width;
2936 xwindow->height = height;
2937 xwindow->internal = TRUE;
2939 g_mutex_lock (xvimagesink->x_lock);
2941 xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
2942 xvimagesink->xcontext->root,
2943 0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
2944 #endif /* GST_EXT_XV_ENHANCEMENT */
2946 /* We have to do that to prevent X from redrawing the background on
2947 * ConfigureNotify. This takes away flickering of video when resizing. */
2948 XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
2950 /* set application name as a title */
2951 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
2953 if (xvimagesink->handle_events) {
2955 #ifdef GST_EXT_XV_ENHANCEMENT
2956 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
2957 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2958 StructureNotifyMask | PointerMotionMask | KeyPressMask |
2959 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask);
2961 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2962 StructureNotifyMask | PointerMotionMask | KeyPressMask |
2963 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
2967 /* Tell the window manager we'd like delete client messages instead of
2969 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2970 "WM_DELETE_WINDOW", True);
2971 if (wm_delete != None) {
2972 (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
2977 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
2978 xwindow->win, 0, &values);
2980 XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
2982 XSync (xvimagesink->xcontext->disp, FALSE);
2984 g_mutex_unlock (xvimagesink->x_lock);
2986 gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
2988 gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
2993 /* This function destroys a GstXWindow */
2995 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
2996 GstXWindow * xwindow)
2998 g_return_if_fail (xwindow != NULL);
2999 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3001 g_mutex_lock (xvimagesink->x_lock);
3003 /* If we did not create that window we just free the GC and let it live */
3004 if (xwindow->internal) {
3005 XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
3006 if (xvimagesink->xim_transparenter) {
3007 XDestroyImage(xvimagesink->xim_transparenter);
3008 xvimagesink->xim_transparenter = NULL;
3011 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
3014 XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
3016 XSync (xvimagesink->xcontext->disp, FALSE);
3018 g_mutex_unlock (xvimagesink->x_lock);
3023 #ifdef GST_EXT_XV_ENHANCEMENT
3024 /* This function destroys a GstXWindow */
3026 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
3027 GstXPixmap * xpixmap)
3029 g_return_if_fail (xpixmap != NULL);
3030 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3032 g_mutex_lock (xvimagesink->x_lock);
3034 XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
3036 XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
3038 XSync (xvimagesink->xcontext->disp, FALSE);
3040 g_mutex_unlock (xvimagesink->x_lock);
3044 #endif /* GST_EXT_XV_ENHANCEMENT */
3047 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
3049 #ifdef GST_EXT_XV_ENHANCEMENT
3050 Window root_window, child_window;
3051 XWindowAttributes root_attr = {0 , };
3055 unsigned int cur_win_width = 0;
3056 unsigned int cur_win_height = 0;
3057 unsigned int cur_win_border_width = 0;
3058 unsigned int cur_win_depth = 0;
3059 #else /* GST_EXT_XV_ENHANCEMENT */
3060 XWindowAttributes attr;
3061 #endif /* GST_EXT_XV_ENHANCEMENT */
3063 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3065 /* Update the window geometry */
3066 g_mutex_lock (xvimagesink->x_lock);
3067 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
3068 g_mutex_unlock (xvimagesink->x_lock);
3072 #ifdef GST_EXT_XV_ENHANCEMENT
3073 /* Get root window and size of current window */
3074 XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
3075 &cur_win_x, &cur_win_y, /* relative x, y */
3076 &cur_win_width, &cur_win_height,
3077 &cur_win_border_width, &cur_win_depth );
3079 xvimagesink->xwindow->width = cur_win_width;
3080 xvimagesink->xwindow->height = cur_win_height;
3082 /* Get absolute coordinates of current window */
3083 if(!xvimagesink->is_pixmap) {
3084 XTranslateCoordinates( xvimagesink->xcontext->disp,
3085 xvimagesink->xwindow->win,
3088 &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
3092 xvimagesink->xwindow->x = cur_win_x;
3093 xvimagesink->xwindow->y = cur_win_y;
3095 /* Get size of root window == size of screen */
3096 if(!xvimagesink->is_pixmap)
3097 XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
3099 xvimagesink->scr_w = root_attr.width;
3100 xvimagesink->scr_h = root_attr.height;
3102 if (!xvimagesink->have_render_rect) {
3103 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3104 xvimagesink->render_rect.w = cur_win_width;
3105 xvimagesink->render_rect.h = cur_win_height;
3107 if (xvimagesink->scr_w != xvimagesink->xwindow->width ||
3108 xvimagesink->scr_h != xvimagesink->xwindow->height) {
3109 xvimagesink->is_multi_window = TRUE;
3110 g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
3111 GST_INFO_OBJECT(xvimagesink, "It may be multi-window scenario");
3113 xvimagesink->is_multi_window = FALSE;
3114 g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
3115 GST_INFO_OBJECT(xvimagesink, "It may be full-window scenario");
3118 GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
3119 xvimagesink->scr_w, xvimagesink->scr_h,
3120 xvimagesink->xwindow->x, xvimagesink->xwindow->y,
3121 xvimagesink->xwindow->width, xvimagesink->xwindow->height,
3122 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3123 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3124 #else /* GST_EXT_XV_ENHANCEMENT */
3125 XGetWindowAttributes (xvimagesink->xcontext->disp,
3126 xvimagesink->xwindow->win, &attr);
3128 xvimagesink->xwindow->width = attr.width;
3129 xvimagesink->xwindow->height = attr.height;
3131 if (!xvimagesink->have_render_rect) {
3132 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3133 xvimagesink->render_rect.w = attr.width;
3134 xvimagesink->render_rect.h = attr.height;
3136 #endif /* GST_EXT_XV_ENHANCEMENT */
3138 g_mutex_unlock (xvimagesink->x_lock);
3142 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
3143 GstXWindow * xwindow)
3145 #ifdef GST_EXT_XV_ENHANCEMENT
3146 if (xvimagesink->is_subpicture_format)
3149 g_return_if_fail (xwindow != NULL);
3150 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3152 g_mutex_lock (xvimagesink->x_lock);
3153 #ifdef GST_EXT_XV_ENHANCEMENT
3154 GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
3155 #endif /* GST_EXT_XV_ENHANCEMENT */
3157 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
3159 #ifdef GST_EXT_XV_ENHANCEMENT
3161 /* NOTE : it should be enabled in pixmap buffer case,
3162 if we can check whether if it is a pixmap or a window by X API */
3163 /* Preview area is not updated before other UI is updated in the screen. */
3164 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
3165 xvimagesink->xcontext->black);
3167 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
3168 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3169 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3171 #endif /* GST_EXT_XV_ENHANCEMENT */
3173 XSync (xvimagesink->xcontext->disp, FALSE);
3175 g_mutex_unlock (xvimagesink->x_lock);
3178 /* This function commits our internal colorbalance settings to our grabbed Xv
3179 port. If the xcontext is not initialized yet it simply returns */
3181 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
3183 GList *channels = NULL;
3185 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3187 /* If we haven't initialized the X context we can't update anything */
3188 if (xvimagesink->xcontext == NULL)
3191 /* Don't set the attributes if they haven't been changed, to avoid
3192 * rounding errors changing the values */
3193 if (!xvimagesink->cb_changed)
3196 /* For each channel of the colorbalance we calculate the correct value
3197 doing range conversion and then set the Xv port attribute to match our
3199 channels = xvimagesink->xcontext->channels_list;
3202 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
3203 GstColorBalanceChannel *channel = NULL;
3206 gdouble convert_coef;
3208 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
3209 g_object_ref (channel);
3211 /* Our range conversion coef */
3212 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
3214 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3215 value = xvimagesink->hue;
3216 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3217 value = xvimagesink->saturation;
3218 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3219 value = xvimagesink->contrast;
3220 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3221 value = xvimagesink->brightness;
3223 g_warning ("got an unknown channel %s", channel->label);
3224 g_object_unref (channel);
3228 /* Committing to Xv port */
3229 g_mutex_lock (xvimagesink->x_lock);
3231 XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
3232 if (prop_atom != None) {
3235 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
3236 XvSetPortAttribute (xvimagesink->xcontext->disp,
3237 xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
3239 g_mutex_unlock (xvimagesink->x_lock);
3241 g_object_unref (channel);
3243 channels = g_list_next (channels);
3247 /* This function handles XEvents that might be in the queue. It generates
3248 GstEvent that will be sent upstream in the pipeline to handle interactivity
3249 and navigation. It will also listen for configure events on the window to
3250 trigger caps renegotiation so on the fly software scaling can work. */
3252 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
3255 guint pointer_x = 0, pointer_y = 0;
3256 gboolean pointer_moved = FALSE;
3257 gboolean exposed = FALSE, configured = FALSE;
3259 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3261 #ifdef GST_EXT_XV_ENHANCEMENT
3262 GST_LOG("check x event");
3263 Atom sc_status_atom = XInternAtom (xvimagesink->xcontext->disp, STR_ATOM_SCRNCONF_STATUS, FALSE);
3264 Atom external_atom = XInternAtom (xvimagesink->xcontext->disp, "XV_OUTPUT_EXTERNAL", FALSE);
3265 #endif /* GST_EXT_XV_ENHANCEMENT */
3267 /* Handle Interaction, produces navigation events */
3269 /* We get all pointer motion events, only the last position is
3271 g_mutex_lock (xvimagesink->flow_lock);
3272 g_mutex_lock (xvimagesink->x_lock);
3273 #ifdef GST_EXT_XV_ENHANCEMENT
3274 if (xvimagesink->xcontext->disp) {
3275 #endif //GST_EXT_XV_ENHANCEMENT
3276 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3277 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
3278 g_mutex_unlock (xvimagesink->x_lock);
3279 g_mutex_unlock (xvimagesink->flow_lock);
3283 pointer_x = e.xmotion.x;
3284 pointer_y = e.xmotion.y;
3285 pointer_moved = TRUE;
3290 g_mutex_lock (xvimagesink->flow_lock);
3291 g_mutex_lock (xvimagesink->x_lock);
3293 #ifdef GST_EXT_XV_ENHANCEMENT
3295 #endif //GST_EXT_XV_ENHANCEMENT
3296 if (pointer_moved) {
3297 g_mutex_unlock (xvimagesink->x_lock);
3298 g_mutex_unlock (xvimagesink->flow_lock);
3300 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
3301 pointer_x, pointer_y);
3302 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3303 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
3305 g_mutex_lock (xvimagesink->flow_lock);
3306 g_mutex_lock (xvimagesink->x_lock);
3309 /* We get all events on our window to throw them upstream */
3310 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3311 xvimagesink->xwindow->win,
3312 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
3316 /* We lock only for the X function call */
3317 g_mutex_unlock (xvimagesink->x_lock);
3318 g_mutex_unlock (xvimagesink->flow_lock);
3322 /* Mouse button pressed over our window. We send upstream
3323 events for interactivity/navigation */
3324 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
3325 e.xbutton.button, e.xbutton.x, e.xbutton.y);
3326 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3327 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3330 /* Mouse button released over our window. We send upstream
3331 events for interactivity/navigation */
3332 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
3333 e.xbutton.button, e.xbutton.x, e.xbutton.y);
3334 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3335 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3339 /* Key pressed/released over our window. We send upstream
3340 events for interactivity/navigation */
3341 GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
3342 e.xkey.keycode, e.xkey.x, e.xkey.y);
3343 g_mutex_lock (xvimagesink->x_lock);
3344 keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
3346 g_mutex_unlock (xvimagesink->x_lock);
3347 if (keysym != NoSymbol) {
3348 char *key_str = NULL;
3350 g_mutex_lock (xvimagesink->x_lock);
3351 key_str = XKeysymToString (keysym);
3352 g_mutex_unlock (xvimagesink->x_lock);
3353 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3354 e.type == KeyPress ? "key-press" : "key-release", key_str);
3356 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3357 e.type == KeyPress ? "key-press" : "key-release", "unknown");
3361 GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
3363 g_mutex_lock (xvimagesink->flow_lock);
3364 g_mutex_lock (xvimagesink->x_lock);
3367 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3368 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
3373 case ConfigureNotify:
3374 g_mutex_unlock (xvimagesink->x_lock);
3375 #ifdef GST_EXT_XV_ENHANCEMENT
3376 GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
3377 #endif /* GST_EXT_XV_ENHANCEMENT */
3378 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
3379 #ifdef GST_EXT_XV_ENHANCEMENT
3380 GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
3381 #endif /* GST_EXT_XV_ENHANCEMENT */
3382 g_mutex_lock (xvimagesink->x_lock);
3390 if (xvimagesink->handle_expose && (exposed || configured)) {
3391 g_mutex_unlock (xvimagesink->x_lock);
3392 g_mutex_unlock (xvimagesink->flow_lock);
3394 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
3396 g_mutex_lock (xvimagesink->flow_lock);
3397 g_mutex_lock (xvimagesink->x_lock);
3400 /* Handle Display events */
3401 while (XPending (xvimagesink->xcontext->disp)) {
3402 XNextEvent (xvimagesink->xcontext->disp, &e);
3404 case ClientMessage:{
3405 #ifdef GST_EXT_XV_ENHANCEMENT
3406 XClientMessageEvent *cme = (XClientMessageEvent *)&e;
3407 Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
3408 Atom qp_state_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_STATE", False);
3409 Atom qp_on_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_ON", False);
3410 Atom qp_off_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_OFF", False);
3411 #endif /* GST_EXT_XV_ENHANCEMENT */
3414 #ifdef GST_EXT_XV_ENHANCEMENT
3415 GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
3416 if (cme->message_type == buffer_atom) {
3417 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
3419 GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
3420 cme->data.l[0], cme->data.l[1]);
3422 gem_name[0] = cme->data.l[0];
3423 gem_name[1] = cme->data.l[1];
3425 _remove_displaying_buffer(xvimagesink, gem_name);
3427 } else if (cme->message_type == sc_status_atom) {
3428 int stat = cme->data.s[0];
3429 if (stat == UTILX_SCRNCONF_STATUS_NULL) {
3430 GST_WARNING ("get UTILX_SCRNCONF_STATUS_NULL event\n");
3431 check_hdmi_connected(xvimagesink);
3432 } else if (stat == UTILX_SCRNCONF_STATUS_CONNECT) {
3433 GST_WARNING ("get UTILX_SCRNCONF_STATUS_CONNECT event\n");
3434 check_hdmi_connected(xvimagesink);
3435 } else if (stat == UTILX_SCRNCONF_STATUS_ACTIVE) {
3436 GST_WARNING ("get UTILX_SCRNCONF_STATUS_ACTIVE event\n");
3437 g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_HDMI_ACTIVE);
3438 check_hdmi_connected(xvimagesink);
3440 GST_INFO ("Wrong status\n");
3443 } else if (cme->message_type == qp_state_atom) {
3444 if ((Atom) cme->data.l[0] == qp_on_atom) {
3445 /* quick panel on */
3446 GST_WARNING_OBJECT(xvimagesink, "quick panel is ON");
3447 xvimagesink->is_quick_panel_on = TRUE;
3448 g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", TRUE);
3449 } else if ((Atom) cme->data.l[0] == qp_off_atom) {
3450 /* quick panel off */
3451 GST_WARNING_OBJECT(xvimagesink, "quick panel is OFF");
3452 xvimagesink->is_quick_panel_on = FALSE;
3453 g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", FALSE);
3457 #endif /* GST_EXT_XV_ENHANCEMENT */
3459 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
3460 "WM_DELETE_WINDOW", True);
3461 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
3462 /* Handle window deletion by posting an error on the bus */
3463 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
3464 ("Output window was closed"), (NULL));
3466 g_mutex_unlock (xvimagesink->x_lock);
3467 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
3468 xvimagesink->xwindow = NULL;
3469 g_mutex_lock (xvimagesink->x_lock);
3473 #ifdef GST_EXT_XV_ENHANCEMENT
3474 case VisibilityNotify:
3475 if (xvimagesink->xwindow &&
3476 (e.xvisibility.window == xvimagesink->xwindow->win)) {
3477 if (e.xvisibility.state == VisibilityFullyObscured) {
3480 GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
3482 xvimagesink->is_hided = TRUE;
3483 g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", TRUE);
3484 if (!_is_connected_to_external_display(xvimagesink)) {
3485 GST_WARNING_OBJECT(xvimagesink, "no external display, calling XvStopVideo()");
3486 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
3487 XSync(xvimagesink->xcontext->disp, FALSE);
3489 if (GST_STATE(xvimagesink) == GST_STATE_PLAYING || xvimagesink->keep_external_fullscreen_prev) {
3490 GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip XvStopVideo()");
3492 GST_WARNING_OBJECT(xvimagesink, "external display is enabled, but not in the middle of playing, calling XvStopVideo()");
3493 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
3494 XSync(xvimagesink->xcontext->disp, FALSE);
3498 GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
3500 if (xvimagesink->is_hided) {
3501 g_mutex_unlock(xvimagesink->x_lock);
3502 g_mutex_unlock(xvimagesink->flow_lock);
3504 xvimagesink->is_hided = FALSE;
3505 g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", FALSE);
3506 gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
3508 g_mutex_lock(xvimagesink->flow_lock);
3509 g_mutex_lock(xvimagesink->x_lock);
3511 GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
3517 case PropertyNotify:
3519 XPropertyEvent *noti = (XPropertyEvent *)&e;
3520 if(xvimagesink->xwindow) {
3521 if (noti->window == xvimagesink->xwindow->win && noti->atom == external_atom) {
3523 get_window_prop_card32_property (xvimagesink->xcontext->disp,
3524 xvimagesink->xwindow->win,
3525 external_atom, XA_CARDINAL,
3526 (unsigned int*)&value, 1);
3528 // If value is 1, video will be displayed only on external display.
3529 // video won't be displayed on LCD.
3530 g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_UNKNOWN_ACTIVE);
3531 if(xvimagesink->external_width==0 && xvimagesink->external_height==0) {
3532 xvimagesink->external_width = 1920;
3533 xvimagesink->external_height = 1080;
3534 GST_WARNING("connected unknown external display");
3537 g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_NULL); //NULL
3538 if(xvimagesink->external_width!=0 || xvimagesink->external_height!=0) {
3539 xvimagesink->external_width = 0;
3540 xvimagesink->external_height = 0;
3541 GST_WARNING("disconnected external display");
3545 g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3546 GST_INFO ("external device : %s\n", (value)?"on":"off");
3552 #endif /* GST_EXT_XV_ENHANCEMENT */
3557 g_mutex_unlock (xvimagesink->x_lock);
3558 g_mutex_unlock (xvimagesink->flow_lock);
3560 #ifdef GST_EXT_XV_ENHANCEMENT
3562 get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type,
3563 unsigned int *val, unsigned int len)
3565 unsigned char* prop_ret;
3567 unsigned long bytes_after, num_ret;
3572 int (*handler) (Display *, XErrorEvent *) = NULL;
3576 /* set error handler */
3577 error_caught = FALSE;
3578 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
3580 ret = XGetWindowProperty(dpy, win, atom, 0, 0x7fffffff, False,
3581 type, &type_ret, &format_ret, &num_ret,
3582 &bytes_after, &prop_ret);
3584 if (ret != Success || error_caught) {
3585 GST_WARNING("XGetWindowProperty failed [%d, %d]", ret, error_caught);
3587 error_caught = FALSE;
3588 XSetErrorHandler (handler);
3594 error_caught = FALSE;
3595 XSetErrorHandler(handler);
3598 if (type_ret != type || format_ret != 32)
3600 else if (num_ret == 0 || !prop_ret)
3606 for (i = 0; i < len; i++)
3607 val[i] = ((unsigned long *)prop_ret)[i];
3617 static void check_hdmi_connected(GstXvImageSink *xvimagesink)
3619 char *str_output = NULL;
3620 char str_status[10] = {0, };
3621 char *str_resolution = NULL;
3622 char str_dispmode[10] = {0, };
3628 UtilxScrnConf *scrnconf = utilx_scrnconf_allocate();
3631 GST_WARNING ("fail to allocate scrnconf");
3634 utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf);
3636 str_output = scrnconf->str_output;
3638 if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT)
3640 strcpy (str_status, "CONNECT");
3642 else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE)
3644 strcpy (str_status, "ACTIVE");
3646 list = g_strsplit(scrnconf->str_resolution, "x", 2);
3651 utilx_scrnconf_free (scrnconf);
3654 for(walk = list; *walk; walk++)
3656 external[cnt++] = atoi(*walk);
3659 GST_WARNING("data error");
3661 utilx_scrnconf_free (scrnconf);
3665 xvimagesink->external_width = external[0];
3666 xvimagesink->external_height = external[1];
3669 GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height);
3670 g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3674 strcpy (str_status, "null");
3677 str_resolution = scrnconf->str_resolution;
3679 if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE)
3681 strcpy (str_dispmode, "CLONE");
3683 else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED)
3685 strcpy (str_dispmode, "EXTENDED");
3689 strcpy (str_dispmode, "null");
3692 GST_INFO ("[Display status] : %s, %s, %s, %s\n", str_output, str_status, str_resolution, str_dispmode);
3695 utilx_scrnconf_free (scrnconf);
3700 check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name)
3705 XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp,
3706 xvimagesink->xcontext->xv_port_id, &count);
3708 for (i = 0 ; i < count ; i++) {
3709 if (!strcmp(attr[i].name, attr_name)) {
3710 GST_INFO("%s[index %d] found", attr_name, i);
3717 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
3718 xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id);
3722 #endif //GST_EXT_XV_ENHANCEMENT
3725 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3726 XvAdaptorInfo * adaptors, int adaptor_no)
3731 /* Do we support XvImageMask ? */
3732 if (!(adaptors[adaptor_no].type & XvImageMask)) {
3733 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3734 adaptors[adaptor_no].name);
3738 /* We found such an adaptor, looking for an available port */
3739 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3740 /* We try to grab the port */
3741 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3742 if (Success == res) {
3743 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3744 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3745 adaptors[adaptor_no].num_ports);
3747 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3748 adaptors[adaptor_no].name, res);
3753 #ifdef GST_EXT_XV_ENHANCEMENT
3755 gst_lookup_xv_port_for_subtitle (GstXContext * xcontext,
3756 XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors)
3761 for (i = 0; i < nb_adaptors; i++)
3764 if (!(adaptors[i].type & XvOutputMask) ||
3765 !(adaptors[i].type & XvStillMask))
3767 min = adaptors[i].base_id;
3768 max = adaptors[i].base_id + adaptors[i].num_ports;
3769 for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++)
3771 if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success)
3773 GST_INFO ("========================================");
3774 GST_INFO ("XvGrabPort success : %ld", adaptors[adaptor_no].num_ports);
3775 GST_INFO ("========================================");
3776 xcontext->xv_port_id = adaptors[adaptor_no].num_ports;
3779 GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports);
3787 /* This function generates a caps with all supported format by the first
3788 Xv grabable port we find. We store each one of the supported formats in a
3789 format list and append the format to a newly created caps that we return
3790 If this function does not return NULL because of an error, it also grabs
3791 the port via XvGrabPort */
3793 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3794 GstXContext * xcontext)
3797 XvAdaptorInfo *adaptors;
3799 XvImageFormatValues *formats = NULL;
3801 XvEncodingInfo *encodings = NULL;
3802 gulong max_w = G_MAXINT, max_h = G_MAXINT;
3803 GstCaps *caps = NULL;
3804 GstCaps *rgb_caps = NULL;
3806 g_return_val_if_fail (xcontext != NULL, NULL);
3808 /* First let's check that XVideo extension is available */
3809 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3810 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3811 ("Could not initialise Xv output"),
3812 ("XVideo extension is not available"));
3816 /* Then we get adaptors list */
3817 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3818 &xcontext->nb_adaptors, &adaptors)) {
3819 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3820 ("Could not initialise Xv output"),
3821 ("Failed getting XV adaptors list"));
3825 xcontext->xv_port_id = 0;
3827 GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
3829 xcontext->adaptors =
3830 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3832 /* Now fill up our adaptor name array */
3833 for (i = 0; i < xcontext->nb_adaptors; i++) {
3834 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3837 if (xvimagesink->adaptor_no >= 0 &&
3838 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3839 /* Find xv port from user defined adaptor */
3840 #ifdef GST_EXT_XV_ENHANCEMENT
3841 if(!xvimagesink->subpicture)
3843 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no);
3844 #ifdef GST_EXT_XV_ENHANCEMENT
3846 gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors);
3850 if (!xcontext->xv_port_id) {
3851 /* Now search for an adaptor that supports XvImageMask */
3852 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3853 #ifdef GST_EXT_XV_ENHANCEMENT
3854 if(!xvimagesink->subpicture)
3856 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3857 #ifdef GST_EXT_XV_ENHANCEMENT
3859 gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors);
3861 xvimagesink->adaptor_no = i;
3865 XvFreeAdaptorInfo (adaptors);
3867 if (!xcontext->xv_port_id) {
3868 xvimagesink->adaptor_no = -1;
3869 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3870 ("Could not initialise Xv output"), ("No port available"));
3874 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3876 int count, todo = 3;
3877 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3878 xcontext->xv_port_id, &count);
3879 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3880 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3881 static const char colorkey[] = "XV_COLORKEY";
3883 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3885 xvimagesink->have_autopaint_colorkey = FALSE;
3886 xvimagesink->have_double_buffer = FALSE;
3887 xvimagesink->have_colorkey = FALSE;
3889 for (i = 0; ((i < count) && todo); i++)
3890 if (!strcmp (attr[i].name, autopaint)) {
3891 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3893 /* turn on autopaint colorkey */
3894 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3895 (xvimagesink->autopaint_colorkey ? 1 : 0));
3897 xvimagesink->have_autopaint_colorkey = TRUE;
3898 } else if (!strcmp (attr[i].name, dbl_buffer)) {
3899 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3901 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3902 (xvimagesink->double_buffer ? 1 : 0));
3904 xvimagesink->have_double_buffer = TRUE;
3905 } else if (!strcmp (attr[i].name, colorkey)) {
3906 /* Set the colorkey, default is something that is dark but hopefully
3907 * won't randomly appear on the screen elsewhere (ie not black or greys)
3908 * can be overridden by setting "colorkey" property
3910 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3912 gboolean set_attr = TRUE;
3915 /* set a colorkey in the right format RGB565/RGB888
3916 * We only handle these 2 cases, because they're the only types of
3917 * devices we've encountered. If we don't recognise it, leave it alone
3919 cr = (xvimagesink->colorkey >> 16);
3920 cg = (xvimagesink->colorkey >> 8) & 0xFF;
3921 cb = (xvimagesink->colorkey) & 0xFF;
3922 switch (xcontext->depth) {
3923 case 16: /* RGB 565 */
3927 ckey = (cr << 11) | (cg << 5) | cb;
3930 case 32: /* RGB 888 / ARGB 8888 */
3931 ckey = (cr << 16) | (cg << 8) | cb;
3934 GST_DEBUG_OBJECT (xvimagesink,
3935 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3942 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3943 (guint32) attr[i].max_value);
3944 GST_LOG_OBJECT (xvimagesink,
3945 "Setting color key for display depth %d to 0x%x",
3946 xcontext->depth, ckey);
3948 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3952 xvimagesink->have_colorkey = TRUE;
3958 /* Get the list of encodings supported by the adapter and look for the
3959 * XV_IMAGE encoding so we can determine the maximum width and height
3961 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3964 for (i = 0; i < nb_encodings; i++) {
3965 GST_LOG_OBJECT (xvimagesink,
3966 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3967 i, encodings[i].name, encodings[i].width, encodings[i].height,
3968 encodings[i].rate.numerator, encodings[i].rate.denominator);
3969 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3970 max_w = encodings[i].width;
3971 max_h = encodings[i].height;
3972 #ifdef GST_EXT_XV_ENHANCEMENT
3973 xvimagesink->scr_w = max_w;
3974 xvimagesink->scr_h = max_h;
3975 #endif /* GST_EXT_XV_ENHANCEMENT */
3979 XvFreeEncodingInfo (encodings);
3980 #ifdef GST_EXT_XV_ENHANCEMENT
3981 if (!xvimagesink->subpicture) {
3983 /* We get all image formats supported by our port */
3984 formats = XvListImageFormats (xcontext->disp,
3985 xcontext->xv_port_id, &nb_formats);
3986 caps = gst_caps_new_empty ();
3987 for (i = 0; i < nb_formats; i++) {
3988 GstCaps *format_caps = NULL;
3989 gboolean is_rgb_format = FALSE;
3991 /* We set the image format of the xcontext to an existing one. This
3992 is just some valid image format for making our xshm calls check before
3993 caps negotiation really happens. */
3994 xcontext->im_format = formats[i].id;
3996 switch (formats[i].type) {
3999 XvImageFormatValues *fmt = &(formats[i]);
4000 gint endianness = G_BIG_ENDIAN;
4002 if (fmt->byte_order == LSBFirst) {
4003 /* our caps system handles 24/32bpp RGB as big-endian. */
4004 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
4005 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
4006 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
4007 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
4009 if (fmt->bits_per_pixel == 24) {
4010 fmt->red_mask >>= 8;
4011 fmt->green_mask >>= 8;
4012 fmt->blue_mask >>= 8;
4015 endianness = G_LITTLE_ENDIAN;
4018 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
4019 #ifdef GST_EXT_XV_ENHANCEMENT
4020 "format", GST_TYPE_FOURCC, formats[i].id,
4021 #endif /* GST_EXT_XV_ENHANCEMENT */
4022 "endianness", G_TYPE_INT, endianness,
4023 "depth", G_TYPE_INT, fmt->depth,
4024 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
4025 "red_mask", G_TYPE_INT, fmt->red_mask,
4026 "green_mask", G_TYPE_INT, fmt->green_mask,
4027 "blue_mask", G_TYPE_INT, fmt->blue_mask,
4028 "width", GST_TYPE_INT_RANGE, 1, max_w,
4029 "height", GST_TYPE_INT_RANGE, 1, max_h,
4030 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4032 is_rgb_format = TRUE;
4036 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
4037 "format", GST_TYPE_FOURCC, formats[i].id,
4038 "width", GST_TYPE_INT_RANGE, 1, max_w,
4039 "height", GST_TYPE_INT_RANGE, 1, max_h,
4040 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4043 g_assert_not_reached ();
4048 GstXvImageFormat *format = NULL;
4050 format = g_new0 (GstXvImageFormat, 1);
4052 format->format = formats[i].id;
4053 format->caps = gst_caps_copy (format_caps);
4054 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
4057 if (is_rgb_format) {
4058 if (rgb_caps == NULL)
4059 rgb_caps = format_caps;
4061 gst_caps_append (rgb_caps, format_caps);
4063 gst_caps_append (caps, format_caps);
4067 /* Collected all caps into either the caps or rgb_caps structures.
4068 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
4070 gst_caps_append (caps, rgb_caps);
4075 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
4077 if (gst_caps_is_empty (caps)) {
4078 gst_caps_unref (caps);
4079 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4080 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
4081 ("No supported format found"));
4084 #ifdef GST_EXT_XV_ENHANCEMENT
4092 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
4094 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4096 GST_OBJECT_LOCK (xvimagesink);
4097 while (xvimagesink->running) {
4098 GST_OBJECT_UNLOCK (xvimagesink);
4100 if (xvimagesink->xwindow) {
4101 gst_xvimagesink_handle_xevents (xvimagesink);
4104 #ifdef GST_EXT_XV_ENHANCEMENT
4105 g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
4106 #else /* GST_EXT_XV_ENHANCEMENT */
4107 /* FIXME: do we want to align this with the framerate or anything else? */
4108 g_usleep (G_USEC_PER_SEC / 20);
4109 #endif /* GST_EXT_XV_ENHANCEMENT */
4111 GST_OBJECT_LOCK (xvimagesink);
4113 GST_OBJECT_UNLOCK (xvimagesink);
4119 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
4121 GThread *thread = NULL;
4123 /* don't start the thread too early */
4124 if (xvimagesink->xcontext == NULL) {
4128 GST_OBJECT_LOCK (xvimagesink);
4129 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
4130 if (!xvimagesink->event_thread) {
4131 /* Setup our event listening thread */
4132 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
4133 xvimagesink->handle_expose, xvimagesink->handle_events);
4134 xvimagesink->running = TRUE;
4135 #if !GLIB_CHECK_VERSION (2, 31, 0)
4136 xvimagesink->event_thread = g_thread_create (
4137 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
4139 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
4140 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
4144 if (xvimagesink->event_thread) {
4145 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
4146 xvimagesink->handle_expose, xvimagesink->handle_events);
4147 xvimagesink->running = FALSE;
4148 /* grab thread and mark it as NULL */
4149 thread = xvimagesink->event_thread;
4150 xvimagesink->event_thread = NULL;
4153 GST_OBJECT_UNLOCK (xvimagesink);
4155 /* Wait for our event thread to finish */
4157 g_thread_join (thread);
4162 #ifdef GST_EXT_XV_ENHANCEMENT
4164 * gst_xvimagesink_prepare_xid:
4165 * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
4167 * This will post a "prepare-xid" element message with video size and display size on the bus
4168 * to give applications an opportunity to call
4169 * gst_x_overlay_set_xwindow_id() before a plugin creates its own
4172 * This function should only be used by video overlay plugin developers.
4175 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
4180 g_return_if_fail (overlay != NULL);
4181 g_return_if_fail (GST_IS_X_OVERLAY (overlay));
4183 GstXvImageSink *xvimagesink;
4184 xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
4186 GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
4187 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
4189 GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
4190 s = gst_structure_new ("prepare-xid",
4191 "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
4192 "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
4193 "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
4194 "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
4196 msg = gst_message_new_element (GST_OBJECT (overlay), s);
4197 gst_element_post_message (GST_ELEMENT (overlay), msg);
4199 #endif /* GST_EXT_XV_ENHANCEMENT */
4202 /* This function calculates the pixel aspect ratio based on the properties
4203 * in the xcontext structure and stores it there. */
4205 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
4207 static const gint par[][2] = {
4208 {1, 1}, /* regular screen */
4209 {16, 15}, /* PAL TV */
4210 {11, 10}, /* 525 line Rec.601 video */
4211 #ifdef GST_EXT_XV_ENHANCEMENT
4212 {44, 46}, /* Gear S Curved Display */
4214 {54, 59}, /* 625 line Rec.601 video */
4215 {64, 45}, /* 1280x1024 on 16:9 display */
4216 {5, 3}, /* 1280x1024 on 4:3 display */
4217 {4, 3} /* 800x600 on 16:9 display */
4224 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
4226 /* first calculate the "real" ratio based on the X values;
4227 * which is the "physical" w/h divided by the w/h in pixels of the display */
4228 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
4229 / (xcontext->heightmm * xcontext->width);
4231 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
4233 if (xcontext->width == 720 && xcontext->height == 576) {
4234 ratio = 4.0 * 576 / (3.0 * 720);
4236 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
4237 /* now find the one from par[][2] with the lowest delta to the real one */
4241 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
4242 gdouble this_delta = DELTA (i);
4244 if (this_delta < delta) {
4250 GST_DEBUG ("Decided on index %d (%d/%d)", index,
4251 par[index][0], par[index][1]);
4253 g_free (xcontext->par);
4254 xcontext->par = g_new0 (GValue, 1);
4255 g_value_init (xcontext->par, GST_TYPE_FRACTION);
4256 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
4257 GST_DEBUG ("set xcontext PAR to %d/%d",
4258 gst_value_get_fraction_numerator (xcontext->par),
4259 gst_value_get_fraction_denominator (xcontext->par));
4262 /* This function gets the X Display and global info about it. Everything is
4263 stored in our object and will be cleaned when the object is disposed. Note
4264 here that caps for supported format are generated without any window or
4266 static GstXContext *
4267 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
4269 GstXContext *xcontext = NULL;
4270 XPixmapFormatValues *px_formats = NULL;
4271 gint nb_formats = 0, i, j, N_attr;
4272 XvAttribute *xv_attr = NULL;
4274 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
4275 "XV_BRIGHTNESS", "XV_CONTRAST"
4278 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4280 xcontext = g_new0 (GstXContext, 1);
4281 xcontext->im_format = 0;
4283 g_mutex_lock (xvimagesink->x_lock);
4285 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
4286 if (!xcontext->disp) {
4287 g_mutex_unlock (xvimagesink->x_lock);
4289 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4290 ("Could not initialise Xv output"), ("Could not open display"));
4294 #ifdef GST_EXT_XV_ENHANCEMENT
4297 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4298 if (g_display_id[i] == NULL) {
4299 g_display_id[i] = xcontext->disp;
4300 GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
4304 if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
4305 GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
4310 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
4311 xcontext->screen_num = DefaultScreen (xcontext->disp);
4312 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
4313 xcontext->root = DefaultRootWindow (xcontext->disp);
4314 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
4315 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
4316 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
4318 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
4319 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
4320 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
4321 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
4323 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
4324 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
4326 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
4327 /* We get supported pixmap formats at supported depth */
4328 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
4331 #ifdef GST_EXT_XV_ENHANCEMENT
4334 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4335 if (g_display_id[i] == xcontext->disp) {
4336 g_display_id[i] = NULL;
4341 XCloseDisplay (xcontext->disp);
4342 g_mutex_unlock (xvimagesink->x_lock);
4343 g_free (xcontext->par);
4345 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
4346 ("Could not initialise Xv output"), ("Could not get pixel formats"));
4350 /* We get bpp value corresponding to our running depth */
4351 for (i = 0; i < nb_formats; i++) {
4352 if (px_formats[i].depth == xcontext->depth)
4353 xcontext->bpp = px_formats[i].bits_per_pixel;
4358 xcontext->endianness =
4359 (ImageByteOrder (xcontext->disp) ==
4360 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
4362 /* our caps system handles 24/32bpp RGB as big-endian. */
4363 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
4364 xcontext->endianness == G_LITTLE_ENDIAN) {
4365 xcontext->endianness = G_BIG_ENDIAN;
4366 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
4367 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
4368 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
4369 if (xcontext->bpp == 24) {
4370 xcontext->visual->red_mask >>= 8;
4371 xcontext->visual->green_mask >>= 8;
4372 xcontext->visual->blue_mask >>= 8;
4376 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
4379 #ifdef GST_EXT_XV_ENHANCEMENT
4380 && !xvimagesink->subpicture
4383 #ifdef GST_EXT_XV_ENHANCEMENT
4386 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4387 if (g_display_id[i] == xcontext->disp) {
4388 g_display_id[i] = NULL;
4393 XCloseDisplay (xcontext->disp);
4394 g_mutex_unlock (xvimagesink->x_lock);
4395 g_free (xcontext->par);
4397 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
4401 #ifdef GST_EXT_XV_ENHANCEMENT
4402 if (!xvimagesink->subpicture) {
4403 #endif //GST_EXT_XV_ENHANCEMENT
4404 /* Search for XShm extension support */
4405 if (XShmQueryExtension (xcontext->disp) &&
4406 gst_xvimagesink_check_xshm_calls (xcontext)) {
4407 xcontext->use_xshm = TRUE;
4408 GST_DEBUG ("xvimagesink is using XShm extension");
4410 #endif /* HAVE_XSHM */
4412 xcontext->use_xshm = FALSE;
4413 GST_DEBUG ("xvimagesink is not using XShm extension");
4416 xv_attr = XvQueryPortAttributes (xcontext->disp,
4417 xcontext->xv_port_id, &N_attr);
4418 #ifdef GST_EXT_XV_ENHANCEMENT
4420 #endif //GST_EXT_XV_ENHANCEMENT
4422 /* Generate the channels list */
4423 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
4424 XvAttribute *matching_attr = NULL;
4426 /* Retrieve the property atom if it exists. If it doesn't exist,
4427 * the attribute itself must not either, so we can skip */
4428 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
4429 if (prop_atom == None)
4432 if (xv_attr != NULL) {
4433 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
4434 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
4435 matching_attr = xv_attr + j;
4438 if (matching_attr) {
4439 GstColorBalanceChannel *channel;
4441 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
4442 channel->label = g_strdup (channels[i]);
4443 channel->min_value = matching_attr->min_value;
4444 channel->max_value = matching_attr->max_value;
4446 xcontext->channels_list = g_list_append (xcontext->channels_list,
4449 /* If the colorbalance settings have not been touched we get Xv values
4450 as defaults and update our internal variables */
4451 if (!xvimagesink->cb_changed) {
4454 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
4456 /* Normalize val to [-1000, 1000] */
4457 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
4458 (double) (channel->max_value - channel->min_value));
4460 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
4461 xvimagesink->hue = val;
4462 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
4463 xvimagesink->saturation = val;
4464 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
4465 xvimagesink->brightness = val;
4466 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
4467 xvimagesink->contrast = val;
4471 #ifdef GST_EXT_XV_ENHANCEMENT
4472 if (!xvimagesink->subpicture) {
4476 #ifdef GST_EXT_XV_ENHANCEMENT
4478 if(!xvimagesink->subpicture) {
4479 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
4480 set_csc_range(xcontext, xvimagesink->csc_range);
4482 #endif /* GST_EXT_XV_ENHANCEMENT */
4484 g_mutex_unlock (xvimagesink->x_lock);
4489 /* This function cleans the X context. Closing the Display, releasing the XV
4490 port and unrefing the caps for supported formats. */
4492 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
4494 GList *formats_list, *channels_list = NULL;
4495 GstXContext *xcontext;
4498 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4500 GST_OBJECT_LOCK (xvimagesink);
4501 if (xvimagesink->xcontext == NULL) {
4502 GST_OBJECT_UNLOCK (xvimagesink);
4506 /* Take the XContext from the sink and clean it up */
4507 xcontext = xvimagesink->xcontext;
4508 xvimagesink->xcontext = NULL;
4510 GST_OBJECT_UNLOCK (xvimagesink);
4512 #ifdef GST_EXT_XV_ENHANCEMENT
4513 if (!xvimagesink->subpicture) {
4515 formats_list = xcontext->formats_list;
4517 while (formats_list) {
4518 GstXvImageFormat *format = formats_list->data;
4520 gst_caps_unref (format->caps);
4522 formats_list = g_list_next (formats_list);
4525 if (xcontext->formats_list)
4526 g_list_free (xcontext->formats_list);
4528 channels_list = xcontext->channels_list;
4529 #ifdef GST_EXT_XV_ENHANCEMENT
4532 while (channels_list) {
4533 GstColorBalanceChannel *channel = channels_list->data;
4535 g_object_unref (channel);
4536 channels_list = g_list_next (channels_list);
4539 if (xcontext->channels_list)
4540 g_list_free (xcontext->channels_list);
4542 gst_caps_unref (xcontext->caps);
4543 if (xcontext->last_caps)
4544 gst_caps_replace (&xcontext->last_caps, NULL);
4546 for (i = 0; i < xcontext->nb_adaptors; i++) {
4547 g_free (xcontext->adaptors[i]);
4550 g_free (xcontext->adaptors);
4552 g_free (xcontext->par);
4554 g_mutex_lock (xvimagesink->x_lock);
4556 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
4558 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4560 #ifdef GST_EXT_XV_ENHANCEMENT
4563 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4564 if (g_display_id[i] == xcontext->disp) {
4565 g_display_id[i] = NULL;
4570 XCloseDisplay (xcontext->disp);
4571 g_mutex_unlock (xvimagesink->x_lock);
4577 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
4579 g_mutex_lock (xvimagesink->pool_lock);
4581 while (xvimagesink->image_pool) {
4582 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
4584 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4585 xvimagesink->image_pool);
4586 gst_xvimage_buffer_free (xvimage);
4589 g_mutex_unlock (xvimagesink->pool_lock);
4594 /* This function tries to get a format matching with a given caps in the
4595 supported list of formats we generated in gst_xvimagesink_get_xv_support */
4597 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
4602 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
4604 list = xvimagesink->xcontext->formats_list;
4607 GstXvImageFormat *format = list->data;
4610 if (gst_caps_can_intersect (caps, format->caps)) {
4611 return format->format;
4614 list = g_list_next (list);
4621 gst_xvimagesink_getcaps (GstBaseSink * bsink)
4623 GstXvImageSink *xvimagesink;
4625 xvimagesink = GST_XVIMAGESINK (bsink);
4626 if (xvimagesink->xcontext
4627 #ifdef GST_EXT_XV_ENHANCEMENT
4628 && !xvimagesink->subpicture
4631 return gst_caps_ref (xvimagesink->xcontext->caps);
4634 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
4639 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
4641 GstXvImageSink *xvimagesink;
4642 GstStructure *structure;
4643 guint32 im_format = 0;
4645 gint video_width, video_height;
4646 gint disp_x, disp_y;
4647 gint disp_width, disp_height;
4648 gint video_par_n, video_par_d; /* video's PAR */
4649 gint display_par_n, display_par_d; /* display's PAR */
4650 const GValue *caps_par;
4651 const GValue *caps_disp_reg;
4654 #ifdef GST_EXT_XV_ENHANCEMENT
4656 gchar *str_in = gst_caps_to_string(caps);
4657 if(str_in == NULL) {
4658 GST_ERROR("gst_caps_to_string() returns NULL...");
4660 GST_INFO("In setcaps. incaps:%s", str_in);
4664 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
4666 xvimagesink = GST_XVIMAGESINK (bsink);
4668 GST_DEBUG_OBJECT (xvimagesink,
4669 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
4670 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
4672 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)
4673 #ifdef GST_EXT_XV_ENHANCEMENT
4674 && !xvimagesink->subpicture
4677 goto incompatible_caps;
4679 structure = gst_caps_get_structure (caps, 0);
4680 ret = gst_structure_get_int (structure, "width", &video_width);
4681 ret &= gst_structure_get_int (structure, "height", &video_height);
4682 fps = gst_structure_get_value (structure, "framerate");
4683 ret &= (fps != NULL);
4684 #ifdef GST_EXT_XV_ENHANCEMENT
4685 if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture)
4687 xvimagesink->is_subpicture_format = TRUE;
4688 GST_LOG("It is type of subpicture and subtitle.");
4692 goto incomplete_caps;
4694 #ifdef GST_EXT_XV_ENHANCEMENT
4695 xvimagesink->aligned_width = video_width;
4696 xvimagesink->aligned_height = video_height;
4698 #ifdef GST_EXT_ENABLE_HEVC
4699 /*get combine prop of hevc*/
4700 if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
4702 GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
4706 /*Not need to combine data, just directly copy*/
4707 xvimagesink->need_combine_data = 0;
4710 _remove_last_buffer(xvimagesink);
4711 #endif /* GST_EXT_XV_ENHANCEMENT */
4713 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
4714 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
4716 xvimagesink->video_width = video_width;
4717 xvimagesink->video_height = video_height;
4718 #ifdef GST_EXT_XV_ENHANCEMENT
4719 if (!xvimagesink->subpicture) {
4721 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
4722 if (im_format == -1)
4723 goto invalid_format;
4724 #ifdef GST_EXT_XV_ENHANCEMENT
4727 /* get aspect ratio from caps if it's present, and
4728 * convert video width and height to a display width and height
4729 * using wd / hd = wv / hv * PARv / PARd */
4731 /* get video's PAR */
4732 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
4734 video_par_n = gst_value_get_fraction_numerator (caps_par);
4735 video_par_d = gst_value_get_fraction_denominator (caps_par);
4740 /* get display's PAR */
4741 if (xvimagesink->par) {
4742 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
4743 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
4749 /* get the display region */
4750 caps_disp_reg = gst_structure_get_value (structure, "display-region");
4751 if (caps_disp_reg) {
4752 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
4753 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
4754 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
4756 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
4758 disp_x = disp_y = 0;
4759 disp_width = video_width;
4760 disp_height = video_height;
4763 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
4764 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
4767 xvimagesink->disp_x = disp_x;
4768 xvimagesink->disp_y = disp_y;
4769 xvimagesink->disp_width = disp_width;
4770 xvimagesink->disp_height = disp_height;
4772 GST_DEBUG_OBJECT (xvimagesink,
4773 "video width/height: %dx%d, calculated display ratio: %d/%d",
4774 video_width, video_height, num, den);
4776 /* now find a width x height that respects this display ratio.
4777 * prefer those that have one of w/h the same as the incoming video
4778 * using wd / hd = num / den */
4780 /* start with same height, because of interlaced video */
4781 /* check hd / den is an integer scale factor, and scale wd with the PAR */
4782 if (video_height % den == 0) {
4783 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
4784 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4785 gst_util_uint64_scale_int (video_height, num, den);
4786 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4787 } else if (video_width % num == 0) {
4788 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
4789 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
4790 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
4791 gst_util_uint64_scale_int (video_width, den, num);
4793 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
4794 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4795 gst_util_uint64_scale_int (video_height, num, den);
4796 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4798 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
4799 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
4801 /* Notify application to set xwindow id now */
4802 g_mutex_lock (xvimagesink->flow_lock);
4803 #ifdef GST_EXT_XV_ENHANCEMENT
4804 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4805 g_mutex_unlock (xvimagesink->flow_lock);
4806 gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
4808 if (!xvimagesink->xwindow) {
4809 g_mutex_unlock (xvimagesink->flow_lock);
4810 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
4813 g_mutex_unlock (xvimagesink->flow_lock);
4815 #ifdef GST_EXT_XV_ENHANCEMENT
4816 if (!xvimagesink->is_subpicture_format) {
4818 /* Creating our window and our image with the display size in pixels */
4819 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
4820 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
4821 goto no_display_size;
4823 g_mutex_lock (xvimagesink->flow_lock);
4824 #ifdef GST_EXT_XV_ENHANCEMENT
4825 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4826 GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
4828 if (!xvimagesink->xwindow) {
4830 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
4831 GST_VIDEO_SINK_WIDTH (xvimagesink),
4832 GST_VIDEO_SINK_HEIGHT (xvimagesink));
4836 /* After a resize, we want to redraw the borders in case the new frame size
4837 * doesn't cover the same area */
4838 xvimagesink->redraw_border = TRUE;
4840 /* We renew our xvimage only if size or format changed;
4841 * the xvimage is the same size as the video pixel size */
4842 if ((xvimagesink->xvimage) &&
4843 ((im_format != xvimagesink->xvimage->im_format) ||
4844 (video_width != xvimagesink->xvimage->width) ||
4845 (video_height != xvimagesink->xvimage->height)) &&
4846 (!xvimagesink->subpicture)) {
4847 GST_DEBUG_OBJECT (xvimagesink,
4848 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4849 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4850 GST_FOURCC_ARGS (im_format));
4851 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4852 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4853 xvimagesink->xvimage = NULL;
4856 #ifdef GST_EXT_XV_ENHANCEMENT
4857 /* In case of starting player with connecting external display, we have to check status.
4858 * It will be unconditionally executed. */
4859 if(!xvimagesink->is_subpicture_format)
4860 check_hdmi_connected(xvimagesink);
4862 g_mutex_unlock (xvimagesink->flow_lock);
4869 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4874 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4875 "height or framerate from intersected caps");
4880 GST_DEBUG_OBJECT (xvimagesink,
4881 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4886 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4887 ("Error calculating the output display ratio of the video."));
4892 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4893 ("Error calculating the output display ratio of the video."));
4896 #ifdef GST_EXT_XV_ENHANCEMENT
4900 static GstStateChangeReturn
4901 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4903 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4904 GstXvImageSink *xvimagesink;
4905 GstXContext *xcontext = NULL;
4906 #ifdef GST_EXT_XV_ENHANCEMENT
4907 Atom atom_preemption = None;
4908 #endif /* GST_EXT_XV_ENHANCEMENT */
4910 xvimagesink = GST_XVIMAGESINK (element);
4912 switch (transition) {
4913 case GST_STATE_CHANGE_NULL_TO_READY:
4914 #ifdef GST_EXT_XV_ENHANCEMENT
4915 GST_WARNING("NULL_TO_READY start");
4916 #endif /* GST_EXT_XV_ENHANCEMENT */
4917 /* Initializing the XContext */
4918 if (xvimagesink->xcontext == NULL) {
4919 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4920 if (xcontext == NULL)
4921 return GST_STATE_CHANGE_FAILURE;
4922 GST_OBJECT_LOCK (xvimagesink);
4924 xvimagesink->xcontext = xcontext;
4925 GST_OBJECT_UNLOCK (xvimagesink);
4928 /* update object's par with calculated one if not set yet */
4929 if (!xvimagesink->par) {
4930 xvimagesink->par = g_new0 (GValue, 1);
4931 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4932 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4934 /* call XSynchronize with the current value of synchronous */
4935 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4936 xvimagesink->synchronous ? "TRUE" : "FALSE");
4937 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4938 gst_xvimagesink_update_colorbalance (xvimagesink);
4939 gst_xvimagesink_manage_event_thread (xvimagesink);
4940 #ifdef GST_EXT_XV_ENHANCEMENT
4941 GST_WARNING("NULL_TO_READY done");
4942 #endif /* GST_EXT_XV_ENHANCEMENT */
4944 case GST_STATE_CHANGE_READY_TO_PAUSED:
4945 #ifdef GST_EXT_XV_ENHANCEMENT
4946 GST_WARNING("READY_TO_PAUSED start");
4947 #endif /* GST_EXT_XV_ENHANCEMENT */
4948 g_mutex_lock (xvimagesink->pool_lock);
4949 xvimagesink->pool_invalid = FALSE;
4950 g_mutex_unlock (xvimagesink->pool_lock);
4951 #ifdef GST_EXT_XV_ENHANCEMENT
4952 GST_WARNING("READY_TO_PAUSED done");
4953 #endif /* GST_EXT_XV_ENHANCEMENT */
4955 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4956 #ifdef GST_EXT_XV_ENHANCEMENT
4957 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING))
4958 GST_WARNING("vconf set fail");
4959 GST_WARNING("PAUSED_TO_PLAYING done");
4960 xvimagesink->is_during_seek = FALSE;
4961 xvimagesink->keep_external_fullscreen_prev = FALSE;
4962 #endif /* GST_EXT_XV_ENHANCEMENT */
4964 case GST_STATE_CHANGE_PAUSED_TO_READY:
4965 #ifdef GST_EXT_XV_ENHANCEMENT
4966 GST_WARNING("PAUSED_TO_READY start");
4967 #endif /* GST_EXT_XV_ENHANCEMENT */
4968 g_mutex_lock (xvimagesink->pool_lock);
4969 xvimagesink->pool_invalid = TRUE;
4970 g_mutex_unlock (xvimagesink->pool_lock);
4971 #ifdef GST_EXT_XV_ENHANCEMENT
4972 #endif /* GST_EXT_XV_ENHANCEMENT */
4978 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4980 switch (transition) {
4981 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4982 #ifdef GST_EXT_XV_ENHANCEMENT
4983 GST_WARNING("PLAYING_TO_PAUSED start");
4984 g_mutex_lock (xvimagesink->flow_lock);
4985 /* init displayed buffer count */
4986 xvimagesink->displayed_buffer_count = 0;
4988 g_mutex_lock (xvimagesink->x_lock);
4989 if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) {
4990 GST_WARNING_OBJECT(xvimagesink, "release external display mode");
4991 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
4992 xvimagesink->xwindow->win);
4993 XSync(xvimagesink->xcontext->disp, FALSE);
4994 xvimagesink->skip_frame_due_to_external_dev = TRUE;
4996 if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture)
4997 && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
4998 GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4999 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
5000 XSync(xvimagesink->xcontext->disp, FALSE);
5002 g_mutex_unlock (xvimagesink->x_lock);
5003 g_mutex_unlock (xvimagesink->flow_lock);
5004 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED))
5005 GST_WARNING("vconf set fail");
5006 GST_WARNING("PLAYING_TO_PAUSED done");
5007 #endif /* GST_EXT_XV_ENHANCEMENT */
5009 case GST_STATE_CHANGE_PAUSED_TO_READY:
5010 #ifdef GST_EXT_XV_ENHANCEMENT
5011 GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
5012 xvimagesink->is_zero_copy_format,
5013 xvimagesink->enable_flush_buffer,
5014 xvimagesink->secure_path,
5015 xvimagesink->get_pixmap_cb);
5017 if ((xvimagesink->enable_flush_buffer == FALSE ||
5018 xvimagesink->secure_path == SECURE_PATH_ON) &&
5019 xvimagesink->xcontext && xvimagesink->xwindow) {
5020 GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
5021 g_mutex_lock(xvimagesink->x_lock);
5022 XvStopVideo(xvimagesink->xcontext->disp,
5023 xvimagesink->xcontext->xv_port_id,
5024 xvimagesink->xwindow->win);
5025 XSync(xvimagesink->xcontext->disp, FALSE);
5026 g_mutex_unlock(xvimagesink->x_lock);
5027 _remove_last_buffer(xvimagesink);
5028 } else if (xvimagesink->is_zero_copy_format &&
5029 xvimagesink->xvimage &&
5030 xvimagesink->xvimage->xvimage &&
5031 !xvimagesink->get_pixmap_cb) {
5032 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5034 XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5035 memset(img_data, 0x0, sizeof(XV_DATA));
5036 XV_INIT_DATA(img_data);
5038 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5039 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5040 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5042 gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5044 GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
5046 /* check whether putimage is succeeded or not */
5047 g_mutex_lock(xvimagesink->display_buffer_lock);
5049 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5050 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
5051 if ((img_data->dmabuf_fd[0] > 0 &&
5052 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
5053 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
5054 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
5056 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
5057 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
5058 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
5059 GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
5065 if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
5066 GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
5067 _release_flush_buffer(xvimagesink);
5069 _remove_last_buffer(xvimagesink);
5072 g_mutex_unlock(xvimagesink->display_buffer_lock);
5075 #endif /* GST_EXT_XV_ENHANCEMENT */
5076 xvimagesink->fps_n = 0;
5077 xvimagesink->fps_d = 1;
5078 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
5079 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
5080 #ifdef GST_EXT_XV_ENHANCEMENT
5081 GST_WARNING("PAUSED_TO_READY done");
5082 #endif /* GST_EXT_XV_ENHANCEMENT */
5084 case GST_STATE_CHANGE_READY_TO_NULL:
5085 #ifdef GST_EXT_XV_ENHANCEMENT
5086 GST_WARNING("READY_TO_NULL start");
5087 #endif /* GST_EXT_XV_ENHANCEMENT */
5088 gst_xvimagesink_reset (xvimagesink);
5089 #ifdef GST_EXT_XV_ENHANCEMENT
5091 drm_fini(xvimagesink);
5092 /* init displaying_buffer_count */
5093 xvimagesink->displaying_buffer_count = 0;
5094 GST_WARNING("READY_TO_NULL done");
5095 #endif /* GST_EXT_XV_ENHANCEMENT */
5105 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
5106 GstClockTime * start, GstClockTime * end)
5108 GstXvImageSink *xvimagesink;
5110 xvimagesink = GST_XVIMAGESINK (bsink);
5112 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
5113 *start = GST_BUFFER_TIMESTAMP (buf);
5114 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
5115 *end = *start + GST_BUFFER_DURATION (buf);
5117 if (xvimagesink->fps_n > 0) {
5119 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
5120 xvimagesink->fps_n);
5126 #ifdef GST_EXT_ENABLE_HEVC
5128 gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
5130 unsigned int outsize = 0;
5131 unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
5133 unsigned char *temp_imgb;
5134 SCMN_IMGB *imgb = NULL;
5135 int stride, w, h, i;
5138 imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
5139 if(imgb == NULL || imgb->a[0] == NULL)
5144 stride = GST_ROUND_UP_4 (imgb->w[0]);
5148 for (i = 0; i < h; i++)
5150 memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
5153 temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
5155 stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
5156 h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
5157 w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
5159 for (i = 0; i < h; i++)
5161 memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
5164 temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
5165 /* Same stride, height, width as above */
5167 for (i = 0; i < h; i++)
5169 memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
5172 outsize = imgb->w[0] * imgb->h[0]* 3 >> 1;
5173 xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
5179 #ifdef GST_EXT_XV_ENHANCEMENT
5180 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
5182 GstXvImageFlushBuffer *flush_buffer = NULL;
5183 GstXvImageDisplayingBuffer *display_buffer = NULL;
5189 if (xvimagesink == NULL) {
5190 GST_ERROR("handle is NULL");
5194 if (xvimagesink->last_added_buffer_index == -1) {
5195 GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
5199 if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
5200 GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
5201 xvimagesink->drm_fd, xvimagesink->bufmgr);
5205 flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
5206 if (flush_buffer == NULL) {
5207 GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
5211 memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
5213 display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
5214 GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
5215 xvimagesink->last_added_buffer_index);
5217 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5218 if (display_buffer->bo[i]) {
5219 tbm_bo_handle vaddr_src;
5220 tbm_bo_handle vaddr_dst;
5223 size = tbm_bo_size(display_buffer->bo[i]);
5226 bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT);
5228 GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
5229 goto FLUSH_BUFFER_FAILED;
5232 GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
5234 flush_buffer->gem_name[i] = tbm_bo_export(bo);
5235 flush_buffer->bo[i] = bo;
5237 /* get virtual address */
5238 vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5239 vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5240 if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
5241 GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
5242 vaddr_src.ptr, vaddr_dst.ptr);
5243 if (vaddr_src.ptr) {
5244 tbm_bo_unmap(display_buffer->bo[i]);
5246 if (vaddr_dst.ptr) {
5249 goto FLUSH_BUFFER_FAILED;
5253 memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
5255 tbm_bo_unmap(display_buffer->bo[i]);
5258 GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
5260 xvimagesink->flush_buffer = flush_buffer;
5268 FLUSH_BUFFER_FAILED:
5270 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5271 if (flush_buffer->bo[i]) {
5272 tbm_bo_unref(flush_buffer->bo[i]);
5273 flush_buffer->bo[i] = NULL;
5277 flush_buffer = NULL;
5282 #endif /* GST_EXT_XV_ENHANCEMENT */
5285 static GstFlowReturn
5286 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
5288 GstXvImageSink *xvimagesink;
5290 #ifdef GST_EXT_XV_ENHANCEMENT
5291 XV_DATA_PTR img_data = NULL;
5292 SCMN_IMGB *scmn_imgb = NULL;
5294 gboolean ret = FALSE;
5296 int (*handler) (Display *, XErrorEvent *) = NULL;
5298 #endif /* GST_EXT_XV_ENHANCEMENT */
5300 xvimagesink = GST_XVIMAGESINK (vsink);
5302 #ifdef GST_EXT_XV_ENHANCEMENT
5303 if (xvimagesink->stop_video) {
5304 GST_INFO( "Stop video is TRUE. so skip show frame..." );
5307 #endif /* GST_EXT_XV_ENHANCEMENT */
5309 /* If this buffer has been allocated using our buffer management we simply
5310 put the ximage which is in the PRIVATE pointer */
5311 if (GST_IS_XVIMAGE_BUFFER (buf)) {
5312 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
5313 #ifdef GST_EXT_XV_ENHANCEMENT
5314 xvimagesink->xid_updated = FALSE;
5315 #endif /* GST_EXT_XV_ENHANCEMENT */
5316 if (!gst_xvimagesink_xvimage_put (xvimagesink,
5317 GST_XVIMAGE_BUFFER_CAST (buf)))
5320 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
5321 "slow copy into bufferpool buffer %p", buf);
5322 /* Else we have to copy the data into our private image, */
5323 /* if we have one... */
5324 #ifdef GST_EXT_XV_ENHANCEMENT
5325 g_mutex_lock (xvimagesink->flow_lock);
5326 if (xvimagesink->skip_frame_due_to_external_dev) {
5327 GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." );
5328 xvimagesink->skip_frame_due_to_external_dev = FALSE;
5329 g_mutex_unlock (xvimagesink->flow_lock);
5333 #endif /* GST_EXT_XV_ENHANCEMENT */
5334 if (!xvimagesink->xvimage
5335 #ifdef GST_EXT_XV_ENHANCEMENT
5336 && !xvimagesink->is_subpicture_format
5339 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
5341 #ifdef GST_EXT_XV_ENHANCEMENT
5342 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
5344 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
5345 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
5346 case GST_MAKE_FOURCC('S', 'N', '2', '1'):
5347 case GST_MAKE_FOURCC('S', '4', '2', '0'):
5348 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
5349 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
5350 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
5351 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
5352 case GST_MAKE_FOURCC('S', 'R', '3', '2'):
5353 case GST_MAKE_FOURCC('S', 'V', '1', '2'):
5354 xvimagesink->is_zero_copy_format = TRUE;
5355 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5356 if(scmn_imgb == NULL) {
5357 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5358 g_mutex_unlock (xvimagesink->flow_lock);
5362 /* skip buffer if aligned size is smaller than size of caps */
5363 if (scmn_imgb->s[0] < xvimagesink->video_width ||
5364 scmn_imgb->e[0] < xvimagesink->video_height) {
5365 GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
5366 xvimagesink->video_width, xvimagesink->video_height,
5367 scmn_imgb->s[0], scmn_imgb->e[0]);
5368 g_mutex_unlock (xvimagesink->flow_lock);
5372 xvimagesink->aligned_width = scmn_imgb->s[0];
5373 xvimagesink->aligned_height = scmn_imgb->e[0];
5374 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
5375 xvimagesink->aligned_width, xvimagesink->aligned_height);
5378 xvimagesink->is_zero_copy_format = FALSE;
5379 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
5383 GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
5384 #endif /* GST_EXT_XV_ENHANCEMENT */
5386 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
5387 GST_BUFFER_CAPS (buf));
5389 if (!xvimagesink->xvimage)
5390 /* The create method should have posted an informative error */
5393 #ifdef GST_EXT_XV_ENHANCEMENT
5394 if ((xvimagesink->is_zero_copy_format == FALSE &&
5395 xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
5396 (xvimagesink->is_zero_copy_format &&
5397 xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
5398 #else /* GST_EXT_XV_ENHANCEMENT */
5399 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
5400 #endif /* GST_EXT_XV_ENHANCEMENT */
5401 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
5402 ("Failed to create output image buffer of %dx%d pixels",
5403 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
5404 ("XServer allocated buffer size did not match input buffer"));
5406 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
5407 xvimagesink->xvimage = NULL;
5412 #ifdef GST_EXT_XV_ENHANCEMENT
5413 if (xvimagesink->is_zero_copy_format) {
5414 /* Cases for specified formats of Samsung extension */
5415 GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
5416 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
5417 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
5418 xvimagesink->display_mode, xvimagesink->rotate_angle);
5420 if (xvimagesink->xvimage->xvimage->data) {
5422 img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5423 memset(img_data, 0x0, sizeof(XV_DATA));
5424 XV_INIT_DATA(img_data);
5426 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5427 if (scmn_imgb == NULL) {
5428 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5429 g_mutex_unlock (xvimagesink->flow_lock);
5433 /* Keep the vaddr of current image for copying last image */
5434 if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
5435 for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
5436 xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
5438 GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5439 xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
5442 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
5443 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
5444 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
5445 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
5446 img_data->BufType = XV_BUF_TYPE_LEGACY;
5448 GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5449 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
5450 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
5451 scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
5452 gboolean do_set_secure = FALSE;
5454 /* open drm to use gem */
5455 if (xvimagesink->drm_fd < 0) {
5456 drm_init(xvimagesink);
5459 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
5460 /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
5461 img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
5462 img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
5463 img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
5464 img_data->BufType = XV_BUF_TYPE_DMABUF;
5465 GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
5467 /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
5468 img_data->bo[0] = scmn_imgb->bo[0];
5469 img_data->bo[1] = scmn_imgb->bo[1];
5470 img_data->bo[2] = scmn_imgb->bo[2];
5471 GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
5474 /* check secure contents path */
5475 if (scmn_imgb->tz_enable) {
5476 if (xvimagesink->secure_path != SECURE_PATH_ON) {
5477 xvimagesink->secure_path = SECURE_PATH_ON;
5478 do_set_secure = TRUE;
5481 if (xvimagesink->secure_path != SECURE_PATH_OFF) {
5482 xvimagesink->secure_path = SECURE_PATH_OFF;
5483 do_set_secure = TRUE;
5486 static gboolean is_exist = FALSE;
5487 gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE");
5488 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5491 if (do_set_secure && is_exist) {
5492 Atom atom_secure = None;
5493 g_mutex_lock (xvimagesink->x_lock);
5494 atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
5495 if (atom_secure != None) {
5496 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
5497 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
5499 GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
5501 XSync (xvimagesink->xcontext->disp, FALSE);
5503 GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
5505 g_mutex_unlock (xvimagesink->x_lock);
5509 attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5510 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5514 if (xvimagesink->drm_level && is_exist) {
5515 Atom atom_drm = None;
5516 g_mutex_lock (xvimagesink->x_lock);
5517 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5518 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5519 if (atom_drm != None) {
5520 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5521 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5522 xvimagesink->xcontext->xv_port_id,
5523 atom_drm, xvimagesink->drm_level ) != Success) {
5524 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5526 XSync (xvimagesink->xcontext->disp, FALSE);
5527 g_mutex_unlock (xvimagesink->x_lock);
5528 xvimagesink->drm_level = DRM_LEVEL_0;
5532 /* set current buffer */
5533 xvimagesink->xvimage->current_buffer = buf;
5534 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) {
5535 /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
5536 GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
5537 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5538 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5539 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5540 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5542 g_mutex_unlock(xvimagesink->flow_lock);
5546 GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
5547 scmn_imgb->buf_share_method);
5548 g_mutex_unlock (xvimagesink->flow_lock);
5552 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
5553 g_mutex_unlock (xvimagesink->flow_lock);
5556 } else if (xvimagesink->is_subpicture_format) {
5558 xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf);
5559 if(!xvimagesink->pixmap_for_subpicture) {
5560 GST_ERROR("no pixmap");
5561 g_mutex_unlock (xvimagesink->flow_lock);
5564 if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) {
5565 GST_ERROR("pixmap's size and current resolution are different");
5566 g_mutex_unlock (xvimagesink->flow_lock);
5569 gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0);
5571 GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture,
5572 xvimagesink->xcontext->xv_port_id, gc);
5574 /* set error handler */
5575 error_caught = FALSE;
5576 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
5578 if(!xvimagesink->set_overlay_for_subpicture_just_once)
5580 GST_LOG("setting attribute overlay");
5581 atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE);
5582 XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1);
5583 XSync (xvimagesink->xcontext->disp, FALSE);
5584 xvimagesink->set_overlay_for_subpicture_just_once = TRUE;
5586 res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
5587 xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height,
5588 0, 0, xvimagesink->external_width, xvimagesink->external_height);
5589 XSync (xvimagesink->xcontext->disp, FALSE);
5591 GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n",
5592 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
5593 GST_TIME_ARGS(GST_BUFFER_DURATION(buf)),
5594 GST_BUFFER_SIZE(buf));
5596 GST_DEBUG("FreeGC");
5597 XFreeGC (xvimagesink->xcontext->disp, gc);
5600 GST_WARNING_OBJECT(xvimagesink, "XvGetStill error");
5602 GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height);
5604 /* Reset error handler */
5606 error_caught = FALSE;
5607 XSetErrorHandler (handler);
5610 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
5612 #ifdef GST_EXT_ENABLE_HEVC
5613 if(xvimagesink->need_combine_data == 1)
5615 gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
5620 memcpy (xvimagesink->xvimage->xvimage->data,
5621 GST_BUFFER_DATA (buf),
5622 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5626 g_mutex_unlock (xvimagesink->flow_lock);
5627 ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5628 if (!ret && !xvimagesink->is_subpicture_format) {
5631 #else /* GST_EXT_XV_ENHANCEMENT */
5632 memcpy (xvimagesink->xvimage->xvimage->data,
5633 GST_BUFFER_DATA (buf),
5634 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5636 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
5638 #endif /* GST_EXT_XV_ENHANCEMENT */
5646 /* No image available. That's very bad ! */
5647 GST_WARNING_OBJECT (xvimagesink, "could not create image");
5648 #ifdef GST_EXT_XV_ENHANCEMENT
5649 g_mutex_unlock (xvimagesink->flow_lock);
5651 return GST_FLOW_ERROR;
5655 /* No Window available to put our image into */
5656 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
5657 return GST_FLOW_ERROR;
5662 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
5664 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
5665 if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)
5667 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK))
5668 GST_WARNING("vconf set fail");
5671 switch (GST_EVENT_TYPE (event)) {
5672 case GST_EVENT_TAG:{
5674 gchar *title = NULL;
5676 gst_event_parse_tag (event, &l);
5677 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
5680 #ifdef GST_EXT_XV_ENHANCEMENT
5681 if (!xvimagesink->get_pixmap_cb) {
5683 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
5684 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
5688 #ifdef GST_EXT_XV_ENHANCEMENT
5694 #ifdef GST_EXT_XV_ENHANCEMENT
5695 case GST_EVENT_FLUSH_START:
5696 GST_DEBUG_OBJECT (xvimagesink, "flush start");
5698 case GST_EVENT_FLUSH_STOP:
5699 GST_DEBUG_OBJECT (xvimagesink, "flush stop");
5700 xvimagesink->is_during_seek = TRUE;
5702 case GST_EVENT_CUSTOM_DOWNSTREAM:
5704 const GstStructure *st = NULL;
5705 st = gst_event_get_structure (event);
5707 GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
5709 if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
5710 GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
5711 xvimagesink->drm_level = DRM_LEVEL_1;
5712 if (xvimagesink->drm_level && xvimagesink->xcontext) {
5713 static gboolean is_exist = FALSE;
5714 gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5715 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5720 Atom atom_drm = None;
5721 g_mutex_lock (xvimagesink->x_lock);
5722 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5723 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5724 if (atom_drm != None) {
5725 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5726 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5727 xvimagesink->xcontext->xv_port_id,
5728 atom_drm, xvimagesink->drm_level ) != Success) {
5729 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5731 XSync (xvimagesink->xcontext->disp, FALSE);
5732 xvimagesink->drm_level = DRM_LEVEL_0;
5734 g_mutex_unlock (xvimagesink->x_lock);
5742 xvimagesink->eos_received = TRUE;
5743 GST_DEBUG_OBJECT(xvimagesink, "got eos");
5745 case GST_EVENT_NEWSEGMENT:
5746 xvimagesink->eos_received = FALSE;
5747 GST_DEBUG_OBJECT(xvimagesink, "got newsegment event");
5753 if (GST_BASE_SINK_CLASS (parent_class)->event)
5754 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
5759 /* Buffer management */
5762 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
5765 GstCaps *intersection;
5769 gint par_n = 1, par_d = 1;
5773 new_caps = gst_caps_copy (caps);
5775 s = gst_caps_get_structure (new_caps, 0);
5777 gst_structure_get_int (s, "width", &width);
5778 gst_structure_get_int (s, "height", &height);
5779 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
5781 gst_structure_remove_field (s, "width");
5782 gst_structure_remove_field (s, "height");
5783 gst_structure_remove_field (s, "pixel-aspect-ratio");
5785 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5786 gst_caps_unref (new_caps);
5788 if (gst_caps_is_empty (intersection))
5789 return intersection;
5791 s = gst_caps_get_structure (intersection, 0);
5793 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
5795 /* xvimagesink supports all PARs */
5797 gst_structure_fixate_field_nearest_int (s, "width", width);
5798 gst_structure_fixate_field_nearest_int (s, "height", height);
5799 gst_structure_get_int (s, "width", &w);
5800 gst_structure_get_int (s, "height", &h);
5802 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
5803 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
5806 return intersection;
5809 static GstFlowReturn
5810 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
5811 GstCaps * caps, GstBuffer ** buf)
5813 GstFlowReturn ret = GST_FLOW_OK;
5814 GstXvImageSink *xvimagesink;
5815 GstXvImageBuffer *xvimage = NULL;
5816 GstCaps *intersection = NULL;
5817 GstStructure *structure = NULL;
5818 gint width, height, image_format;
5820 xvimagesink = GST_XVIMAGESINK (bsink);
5822 if (G_UNLIKELY (!caps))
5825 g_mutex_lock (xvimagesink->pool_lock);
5826 if (G_UNLIKELY (xvimagesink->pool_invalid))
5829 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
5830 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
5831 GST_LOG_OBJECT (xvimagesink,
5832 "buffer alloc for same last_caps, reusing caps");
5833 intersection = gst_caps_ref (caps);
5834 image_format = xvimagesink->xcontext->last_format;
5835 width = xvimagesink->xcontext->last_width;
5836 height = xvimagesink->xcontext->last_height;
5838 goto reuse_last_caps;
5841 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
5842 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
5843 caps, xvimagesink->xcontext->caps);
5845 /* Check the caps against our xcontext */
5846 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
5848 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
5849 GST_PTR_FORMAT, intersection);
5851 if (gst_caps_is_empty (intersection)) {
5854 gst_caps_unref (intersection);
5856 /* So we don't support this kind of buffer, let's define one we'd like */
5857 new_caps = gst_caps_copy (caps);
5859 structure = gst_caps_get_structure (new_caps, 0);
5860 if (!gst_structure_has_field (structure, "width") ||
5861 !gst_structure_has_field (structure, "height")) {
5862 gst_caps_unref (new_caps);
5866 /* Try different dimensions */
5868 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5870 if (gst_caps_is_empty (intersection)) {
5871 /* Try with different YUV formats first */
5872 gst_structure_set_name (structure, "video/x-raw-yuv");
5874 /* Remove format specific fields */
5875 gst_structure_remove_field (structure, "format");
5876 gst_structure_remove_field (structure, "endianness");
5877 gst_structure_remove_field (structure, "depth");
5878 gst_structure_remove_field (structure, "bpp");
5879 gst_structure_remove_field (structure, "red_mask");
5880 gst_structure_remove_field (structure, "green_mask");
5881 gst_structure_remove_field (structure, "blue_mask");
5882 gst_structure_remove_field (structure, "alpha_mask");
5884 /* Reuse intersection with Xcontext */
5885 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5888 if (gst_caps_is_empty (intersection)) {
5889 /* Try with different dimensions and YUV formats */
5891 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5894 if (gst_caps_is_empty (intersection)) {
5895 /* Now try with RGB */
5896 gst_structure_set_name (structure, "video/x-raw-rgb");
5897 /* And interset again */
5898 gst_caps_unref (intersection);
5899 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5902 if (gst_caps_is_empty (intersection)) {
5903 /* Try with different dimensions and RGB formats */
5905 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5908 /* Clean this copy */
5909 gst_caps_unref (new_caps);
5911 if (gst_caps_is_empty (intersection))
5915 /* Ensure the returned caps are fixed */
5916 gst_caps_truncate (intersection);
5918 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
5919 GST_PTR_FORMAT, intersection);
5920 if (gst_caps_is_equal (intersection, caps)) {
5921 /* Things work better if we return a buffer with the same caps ptr
5922 * as was asked for when we can */
5923 gst_caps_replace (&intersection, caps);
5926 /* Get image format from caps */
5927 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
5930 /* Get geometry from caps */
5931 structure = gst_caps_get_structure (intersection, 0);
5932 if (!gst_structure_get_int (structure, "width", &width) ||
5933 !gst_structure_get_int (structure, "height", &height) ||
5937 /* Store our caps and format as the last_caps to avoid expensive
5938 * caps intersection next time */
5939 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
5940 xvimagesink->xcontext->last_format = image_format;
5941 xvimagesink->xcontext->last_width = width;
5942 xvimagesink->xcontext->last_height = height;
5946 /* Walking through the pool cleaning unusable images and searching for a
5948 while (xvimagesink->image_pool) {
5949 xvimage = xvimagesink->image_pool->data;
5952 /* Removing from the pool */
5953 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
5954 xvimagesink->image_pool);
5956 /* We check for geometry or image format changes */
5957 if ((xvimage->width != width) ||
5958 (xvimage->height != height) || (xvimage->im_format != image_format)) {
5959 /* This image is unusable. Destroying... */
5960 gst_xvimage_buffer_free (xvimage);
5963 /* We found a suitable image */
5964 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
5971 #ifdef GST_EXT_XV_ENHANCEMENT
5972 /* init aligned size */
5973 xvimagesink->aligned_width = 0;
5974 xvimagesink->aligned_height = 0;
5975 #endif /* GST_EXT_XV_ENHANCEMENT */
5977 /* We found no suitable image in the pool. Creating... */
5978 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
5979 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
5981 g_mutex_unlock (xvimagesink->pool_lock);
5984 /* Make sure the buffer is cleared of any previously used flags */
5985 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
5986 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
5989 *buf = GST_BUFFER_CAST (xvimage);
5993 gst_caps_unref (intersection);
6001 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
6002 ret = GST_FLOW_WRONG_STATE;
6003 g_mutex_unlock (xvimagesink->pool_lock);
6008 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
6009 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
6010 " are completely incompatible with those caps", caps,
6011 xvimagesink->xcontext->caps);
6012 ret = GST_FLOW_NOT_NEGOTIATED;
6013 g_mutex_unlock (xvimagesink->pool_lock);
6018 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
6019 GST_PTR_FORMAT, intersection);
6020 ret = GST_FLOW_NOT_NEGOTIATED;
6021 g_mutex_unlock (xvimagesink->pool_lock);
6026 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
6033 /* Interfaces stuff */
6036 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
6038 if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
6039 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
6046 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
6048 klass->supported = gst_xvimagesink_interface_supported;
6052 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
6053 GstStructure * structure)
6055 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
6058 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
6060 GstVideoRectangle src, dst, result;
6061 gdouble x, y, xscale = 1.0, yscale = 1.0;
6063 event = gst_event_new_navigation (structure);
6065 /* We take the flow_lock while we look at the window */
6066 g_mutex_lock (xvimagesink->flow_lock);
6068 if (!xvimagesink->xwindow) {
6069 g_mutex_unlock (xvimagesink->flow_lock);
6073 if (xvimagesink->keep_aspect) {
6074 /* We get the frame position using the calculated geometry from _setcaps
6075 that respect pixel aspect ratios */
6076 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
6077 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
6078 dst.w = xvimagesink->render_rect.w;
6079 dst.h = xvimagesink->render_rect.h;
6081 gst_video_sink_center_rect (src, dst, &result, TRUE);
6082 result.x += xvimagesink->render_rect.x;
6083 result.y += xvimagesink->render_rect.y;
6085 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
6088 g_mutex_unlock (xvimagesink->flow_lock);
6090 /* We calculate scaling using the original video frames geometry to include
6091 pixel aspect ratio scaling. */
6092 xscale = (gdouble) xvimagesink->video_width / result.w;
6093 yscale = (gdouble) xvimagesink->video_height / result.h;
6095 /* Converting pointer coordinates to the non scaled geometry */
6096 if (gst_structure_get_double (structure, "pointer_x", &x)) {
6097 x = MIN (x, result.x + result.w);
6098 x = MAX (x - result.x, 0);
6099 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
6100 (gdouble) x * xscale, NULL);
6102 if (gst_structure_get_double (structure, "pointer_y", &y)) {
6103 y = MIN (y, result.y + result.h);
6104 y = MAX (y - result.y, 0);
6105 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
6106 (gdouble) y * yscale, NULL);
6109 gst_pad_send_event (peer, event);
6110 gst_object_unref (peer);
6115 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
6117 iface->send_event = gst_xvimagesink_navigation_send_event;
6120 #ifdef GST_EXT_XV_ENHANCEMENT
6122 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
6126 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6127 GstXPixmap *xpixmap = NULL;
6128 int (*handler) (Display *, XErrorEvent *);
6130 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6132 if (xvimagesink->subpicture)
6135 /* If the element has not initialized the X11 context try to do so */
6136 if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6137 /* we have thrown a GST_ELEMENT_ERROR now */
6141 gst_xvimagesink_update_colorbalance (xvimagesink);
6143 GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
6145 /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
6146 if (pixmap_id == 0) {
6147 xvimagesink->current_pixmap_idx = -2;
6151 g_mutex_lock (xvimagesink->x_lock);
6153 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6154 if (!xvimagesink->xpixmap[i]) {
6158 unsigned int cur_win_width = 0;
6159 unsigned int cur_win_height = 0;
6160 unsigned int cur_win_border_width = 0;
6161 unsigned int cur_win_depth = 0;
6163 GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
6165 xpixmap = g_new0 (GstXPixmap, 1);
6167 xpixmap->pixmap = pixmap_id;
6169 /* Get root window and size of current window */
6170 XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
6171 &cur_win_x, &cur_win_y, /* relative x, y */
6172 &cur_win_width, &cur_win_height,
6173 &cur_win_border_width, &cur_win_depth);
6174 if (!cur_win_width || !cur_win_height) {
6175 GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
6176 g_mutex_unlock (xvimagesink->x_lock);
6179 xpixmap->width = cur_win_width;
6180 xpixmap->height = cur_win_height;
6182 if (!xvimagesink->render_rect.w)
6183 xvimagesink->render_rect.w = cur_win_width;
6184 if (!xvimagesink->render_rect.h)
6185 xvimagesink->render_rect.h = cur_win_height;
6187 /* Setting an error handler to catch failure */
6188 error_caught = FALSE;
6189 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6192 xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
6194 XSync(xvimagesink->xcontext->disp, FALSE);
6196 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
6199 error_caught = FALSE;
6200 XSetErrorHandler (handler);
6203 xvimagesink->xpixmap[i] = xpixmap;
6204 xvimagesink->current_pixmap_idx = i;
6206 GST_ERROR("failed to create xpixmap errno: %d", errno);
6209 g_mutex_unlock (xvimagesink->x_lock);
6212 } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
6213 GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
6214 xvimagesink->current_pixmap_idx = i;
6216 g_mutex_unlock (xvimagesink->x_lock);
6224 GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
6225 xvimagesink->current_pixmap_idx = -1;
6227 g_mutex_unlock (xvimagesink->x_lock);
6230 #endif /* GST_EXT_XV_ENHANCEMENT */
6233 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
6235 XID xwindow_id = id;
6236 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6237 GstXWindow *xwindow = NULL;
6238 #ifdef GST_EXT_XV_ENHANCEMENT
6239 GstState current_state = GST_STATE_NULL;
6240 int (*handler) (Display *, XErrorEvent *);
6241 #endif /* GST_EXT_XV_ENHANCEMENT */
6243 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6245 g_mutex_lock (xvimagesink->flow_lock);
6247 #ifdef GST_EXT_XV_ENHANCEMENT
6248 gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
6249 GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
6250 xwindow_id, current_state);
6251 #endif /* GST_EXT_XV_ENHANCEMENT */
6253 /* If we already use that window return */
6254 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
6255 g_mutex_unlock (xvimagesink->flow_lock);
6259 /* If the element has not initialized the X11 context try to do so */
6260 if (!xvimagesink->xcontext &&
6261 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6262 g_mutex_unlock (xvimagesink->flow_lock);
6263 /* we have thrown a GST_ELEMENT_ERROR now */
6267 gst_xvimagesink_update_colorbalance (xvimagesink);
6269 /* Clear image pool as the images are unusable anyway */
6270 gst_xvimagesink_imagepool_clear (xvimagesink);
6272 /* Clear the xvimage */
6273 if (xvimagesink->xvimage) {
6274 gst_xvimage_buffer_free (xvimagesink->xvimage);
6275 xvimagesink->xvimage = NULL;
6278 /* If a window is there already we destroy it */
6279 if (xvimagesink->xwindow) {
6280 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
6281 xvimagesink->xwindow = NULL;
6284 /* If the xid is 0 we go back to an internal window */
6285 if (xwindow_id == 0) {
6286 /* If no width/height caps nego did not happen window will be created
6287 during caps nego then */
6288 #ifdef GST_EXT_XV_ENHANCEMENT
6289 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
6290 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
6291 #endif /* GST_EXT_XV_ENHANCEMENT */
6292 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
6293 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
6295 gst_xvimagesink_xwindow_new (xvimagesink,
6296 GST_VIDEO_SINK_WIDTH (xvimagesink),
6297 GST_VIDEO_SINK_HEIGHT (xvimagesink));
6300 XWindowAttributes attr;
6302 xwindow = g_new0 (GstXWindow, 1);
6303 xwindow->win = xwindow_id;
6305 /* Set the event we want to receive and create a GC */
6306 g_mutex_lock (xvimagesink->x_lock);
6308 if(!xvimagesink->is_pixmap)
6309 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
6311 xwindow->width = attr.width;
6312 xwindow->height = attr.height;
6313 xwindow->internal = FALSE;
6314 if (!xvimagesink->have_render_rect) {
6315 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
6316 xvimagesink->render_rect.w = attr.width;
6317 xvimagesink->render_rect.h = attr.height;
6319 if (xvimagesink->handle_events) {
6320 #ifdef GST_EXT_XV_ENHANCEMENT
6321 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6322 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6323 StructureNotifyMask | PointerMotionMask | KeyPressMask |
6324 KeyReleaseMask | PropertyChangeMask);
6326 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6327 StructureNotifyMask | PointerMotionMask | KeyPressMask |
6332 #ifdef GST_EXT_XV_ENHANCEMENT
6333 /* Setting an error handler to catch failure */
6334 error_caught = FALSE;
6335 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6337 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
6338 xwindow->win, 0, NULL);
6339 #ifdef GST_EXT_XV_ENHANCEMENT
6340 XSync(xvimagesink->xcontext->disp, FALSE);
6342 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
6345 error_caught = FALSE;
6346 XSetErrorHandler (handler);
6349 g_mutex_unlock (xvimagesink->x_lock);
6353 xvimagesink->xwindow = xwindow;
6355 #ifdef GST_EXT_XV_ENHANCEMENT
6356 xvimagesink->xid_updated = TRUE;
6357 #endif /* GST_EXT_XV_ENHANCEMENT */
6359 g_mutex_unlock (xvimagesink->flow_lock);
6361 #ifdef GST_EXT_XV_ENHANCEMENT
6362 if (current_state == GST_STATE_PAUSED) {
6363 GstBuffer *last_buffer = NULL;
6364 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
6365 GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
6367 gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
6368 gst_buffer_unref(last_buffer);
6372 #endif /* GST_EXT_XV_ENHANCEMENT */
6376 gst_xvimagesink_expose (GstXOverlay * overlay)
6378 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6380 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
6381 #ifdef GST_EXT_XV_ENHANCEMENT
6382 GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
6383 #endif /* GST_EXT_XV_ENHANCEMENT */
6384 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
6388 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
6389 gboolean handle_events)
6391 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6393 xvimagesink->handle_events = handle_events;
6395 g_mutex_lock (xvimagesink->flow_lock);
6397 if (G_UNLIKELY (!xvimagesink->xwindow)) {
6398 g_mutex_unlock (xvimagesink->flow_lock);
6402 g_mutex_lock (xvimagesink->x_lock);
6404 if (handle_events) {
6405 if (xvimagesink->xwindow->internal) {
6406 #ifdef GST_EXT_XV_ENHANCEMENT
6407 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6409 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6410 #ifdef GST_EXT_XV_ENHANCEMENT
6411 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6412 #else /* GST_EXT_XV_ENHANCEMENT */
6413 ExposureMask | StructureNotifyMask | PointerMotionMask |
6414 #endif /* GST_EXT_XV_ENHANCEMENT */
6415 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
6417 #ifdef GST_EXT_XV_ENHANCEMENT
6418 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6420 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6421 #ifdef GST_EXT_XV_ENHANCEMENT
6422 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6423 #else /* GST_EXT_XV_ENHANCEMENT */
6424 ExposureMask | StructureNotifyMask | PointerMotionMask |
6425 #endif /* GST_EXT_XV_ENHANCEMENT */
6426 KeyPressMask | KeyReleaseMask);
6429 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
6432 g_mutex_unlock (xvimagesink->x_lock);
6434 g_mutex_unlock (xvimagesink->flow_lock);
6438 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
6439 gint width, gint height)
6441 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6443 /* FIXME: how about some locking? */
6444 if (width >= 0 && height >= 0) {
6445 xvimagesink->render_rect.x = x;
6446 xvimagesink->render_rect.y = y;
6447 xvimagesink->render_rect.w = width;
6448 xvimagesink->render_rect.h = height;
6449 xvimagesink->have_render_rect = TRUE;
6451 xvimagesink->render_rect.x = 0;
6452 xvimagesink->render_rect.y = 0;
6453 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
6454 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
6455 xvimagesink->have_render_rect = FALSE;
6460 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
6462 iface->set_window_handle = gst_xvimagesink_set_window_handle;
6463 iface->expose = gst_xvimagesink_expose;
6464 iface->handle_events = gst_xvimagesink_set_event_handling;
6465 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
6468 static const GList *
6469 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
6471 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6473 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
6475 if (xvimagesink->xcontext)
6476 return xvimagesink->xcontext->channels_list;
6482 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
6483 GstColorBalanceChannel * channel, gint value)
6485 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6487 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6488 g_return_if_fail (channel->label != NULL);
6490 xvimagesink->cb_changed = TRUE;
6492 /* Normalize val to [-1000, 1000] */
6493 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
6494 (double) (channel->max_value - channel->min_value));
6496 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6497 xvimagesink->hue = value;
6498 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6499 xvimagesink->saturation = value;
6500 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6501 xvimagesink->contrast = value;
6502 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6503 xvimagesink->brightness = value;
6505 g_warning ("got an unknown channel %s", channel->label);
6509 gst_xvimagesink_update_colorbalance (xvimagesink);
6513 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
6514 GstColorBalanceChannel * channel)
6516 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6519 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
6520 g_return_val_if_fail (channel->label != NULL, 0);
6522 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6523 value = xvimagesink->hue;
6524 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6525 value = xvimagesink->saturation;
6526 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6527 value = xvimagesink->contrast;
6528 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6529 value = xvimagesink->brightness;
6531 g_warning ("got an unknown channel %s", channel->label);
6534 /* Normalize val to [channel->min_value, channel->max_value] */
6535 value = channel->min_value + (channel->max_value - channel->min_value) *
6536 (value + 1000) / 2000;
6542 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
6544 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
6545 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
6546 iface->set_value = gst_xvimagesink_colorbalance_set_value;
6547 iface->get_value = gst_xvimagesink_colorbalance_get_value;
6550 static const GList *
6551 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
6553 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
6554 static GList *list = NULL;
6557 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
6559 g_list_append (list, g_object_class_find_property (klass,
6560 "autopaint-colorkey"));
6562 g_list_append (list, g_object_class_find_property (klass,
6565 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
6572 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
6573 guint prop_id, const GParamSpec * pspec)
6575 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6579 case PROP_AUTOPAINT_COLORKEY:
6580 case PROP_DOUBLE_BUFFER:
6582 GST_DEBUG_OBJECT (xvimagesink,
6583 "probing device list and get capabilities");
6584 if (!xvimagesink->xcontext) {
6585 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
6586 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
6590 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6596 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
6597 guint prop_id, const GParamSpec * pspec)
6599 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6600 gboolean ret = FALSE;
6604 case PROP_AUTOPAINT_COLORKEY:
6605 case PROP_DOUBLE_BUFFER:
6607 if (xvimagesink->xcontext != NULL) {
6614 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6621 static GValueArray *
6622 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
6623 guint prop_id, const GParamSpec * pspec)
6625 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6626 GValueArray *array = NULL;
6628 if (G_UNLIKELY (!xvimagesink->xcontext)) {
6629 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
6638 GValue value = { 0 };
6640 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
6641 g_value_init (&value, G_TYPE_STRING);
6643 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
6644 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
6646 g_value_set_string (&value, adaptor_id_s);
6647 g_value_array_append (array, &value);
6648 g_free (adaptor_id_s);
6650 g_value_unset (&value);
6653 case PROP_AUTOPAINT_COLORKEY:
6654 if (xvimagesink->have_autopaint_colorkey) {
6655 GValue value = { 0 };
6657 array = g_value_array_new (2);
6658 g_value_init (&value, G_TYPE_BOOLEAN);
6659 g_value_set_boolean (&value, FALSE);
6660 g_value_array_append (array, &value);
6661 g_value_set_boolean (&value, TRUE);
6662 g_value_array_append (array, &value);
6663 g_value_unset (&value);
6666 case PROP_DOUBLE_BUFFER:
6667 if (xvimagesink->have_double_buffer) {
6668 GValue value = { 0 };
6670 array = g_value_array_new (2);
6671 g_value_init (&value, G_TYPE_BOOLEAN);
6672 g_value_set_boolean (&value, FALSE);
6673 g_value_array_append (array, &value);
6674 g_value_set_boolean (&value, TRUE);
6675 g_value_array_append (array, &value);
6676 g_value_unset (&value);
6680 if (xvimagesink->have_colorkey) {
6681 GValue value = { 0 };
6683 array = g_value_array_new (1);
6684 g_value_init (&value, GST_TYPE_INT_RANGE);
6685 gst_value_set_int_range (&value, 0, 0xffffff);
6686 g_value_array_append (array, &value);
6687 g_value_unset (&value);
6691 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6700 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
6703 iface->get_properties = gst_xvimagesink_probe_get_properties;
6704 iface->probe_property = gst_xvimagesink_probe_probe_property;
6705 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
6706 iface->get_values = gst_xvimagesink_probe_get_values;
6709 /* =========================================== */
6711 /* Init & Class init */
6713 /* =========================================== */
6716 gst_xvimagesink_set_property (GObject * object, guint prop_id,
6717 const GValue * value, GParamSpec * pspec)
6719 GstXvImageSink *xvimagesink;
6721 g_return_if_fail (GST_IS_XVIMAGESINK (object));
6723 xvimagesink = GST_XVIMAGESINK (object);
6727 xvimagesink->hue = g_value_get_int (value);
6728 xvimagesink->cb_changed = TRUE;
6729 gst_xvimagesink_update_colorbalance (xvimagesink);
6732 xvimagesink->contrast = g_value_get_int (value);
6733 xvimagesink->cb_changed = TRUE;
6734 gst_xvimagesink_update_colorbalance (xvimagesink);
6736 case PROP_BRIGHTNESS:
6737 xvimagesink->brightness = g_value_get_int (value);
6738 xvimagesink->cb_changed = TRUE;
6739 gst_xvimagesink_update_colorbalance (xvimagesink);
6741 case PROP_SATURATION:
6742 xvimagesink->saturation = g_value_get_int (value);
6743 xvimagesink->cb_changed = TRUE;
6744 gst_xvimagesink_update_colorbalance (xvimagesink);
6747 xvimagesink->display_name = g_strdup (g_value_get_string (value));
6749 case PROP_SYNCHRONOUS:
6750 xvimagesink->synchronous = g_value_get_boolean (value);
6751 if (xvimagesink->xcontext) {
6752 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
6753 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
6754 xvimagesink->synchronous ? "TRUE" : "FALSE");
6757 case PROP_PIXEL_ASPECT_RATIO:
6758 g_free (xvimagesink->par);
6759 xvimagesink->par = g_new0 (GValue, 1);
6760 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
6761 if (!g_value_transform (value, xvimagesink->par)) {
6762 g_warning ("Could not transform string to aspect ratio");
6763 gst_value_set_fraction (xvimagesink->par, 1, 1);
6765 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
6766 gst_value_get_fraction_numerator (xvimagesink->par),
6767 gst_value_get_fraction_denominator (xvimagesink->par));
6769 case PROP_FORCE_ASPECT_RATIO:
6770 xvimagesink->keep_aspect = g_value_get_boolean (value);
6772 case PROP_HANDLE_EVENTS:
6773 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
6774 g_value_get_boolean (value));
6775 gst_xvimagesink_manage_event_thread (xvimagesink);
6778 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
6780 case PROP_HANDLE_EXPOSE:
6781 xvimagesink->handle_expose = g_value_get_boolean (value);
6782 gst_xvimagesink_manage_event_thread (xvimagesink);
6784 case PROP_DOUBLE_BUFFER:
6785 xvimagesink->double_buffer = g_value_get_boolean (value);
6787 case PROP_AUTOPAINT_COLORKEY:
6788 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
6791 xvimagesink->colorkey = g_value_get_int (value);
6793 case PROP_DRAW_BORDERS:
6794 xvimagesink->draw_borders = g_value_get_boolean (value);
6796 #ifdef GST_EXT_XV_ENHANCEMENT
6797 case PROP_DISPLAY_MODE:
6799 int set_mode = g_value_get_enum (value);
6800 g_mutex_lock(xvimagesink->flow_lock);
6801 xvimagesink->display_mode = set_mode;
6802 if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) {
6803 if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) {
6804 if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) {
6805 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6807 GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6809 } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){
6810 if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
6811 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6813 GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6816 GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode);
6819 g_mutex_unlock(xvimagesink->flow_lock);
6822 case PROP_CSC_RANGE:
6824 int set_range = g_value_get_enum (value);
6826 g_mutex_lock(xvimagesink->flow_lock);
6827 g_mutex_lock(xvimagesink->x_lock);
6829 if (xvimagesink->csc_range != set_range) {
6830 if (xvimagesink->xcontext && !xvimagesink->subpicture) {
6831 /* set color space range */
6832 if (set_csc_range(xvimagesink->xcontext, set_range)) {
6833 xvimagesink->csc_range = set_range;
6835 GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
6838 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6839 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
6840 xvimagesink->csc_range = set_range;
6842 } else if (xvimagesink->subpicture) {
6843 GST_WARNING("skip to set csc range, because it is subpicture format.");
6845 GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
6848 g_mutex_unlock(xvimagesink->x_lock);
6849 g_mutex_unlock(xvimagesink->flow_lock);
6852 case PROP_DISPLAY_GEOMETRY_METHOD:
6853 xvimagesink->display_geometry_method = g_value_get_enum (value);
6854 GST_LOG("Overlay geometry changed. update it");
6855 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6856 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6860 xvimagesink->flip = g_value_get_enum(value);
6862 case PROP_ROTATE_ANGLE:
6863 xvimagesink->rotate_angle = g_value_get_enum (value);
6864 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6865 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6869 g_mutex_lock( xvimagesink->flow_lock );
6870 g_mutex_lock( xvimagesink->x_lock );
6872 GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
6874 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
6875 if (xvimagesink->xcontext) {
6877 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
6878 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
6879 if (atom_stream != None) {
6880 GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
6881 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
6882 xvimagesink->xcontext->xv_port_id,
6883 atom_stream, 0 ) != Success) {
6884 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
6888 xvimagesink->visible = g_value_get_boolean (value);
6889 if ( xvimagesink->get_pixmap_cb ) {
6890 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6891 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6894 if(xvimagesink->xwindow->win)
6895 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
6897 XSync( xvimagesink->xcontext->disp, FALSE );
6899 GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
6900 xvimagesink->visible = g_value_get_boolean (value);
6902 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
6903 xvimagesink->visible = g_value_get_boolean (value);
6904 g_mutex_unlock( xvimagesink->x_lock );
6905 g_mutex_unlock( xvimagesink->flow_lock );
6906 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6907 g_mutex_lock( xvimagesink->flow_lock );
6908 g_mutex_lock( xvimagesink->x_lock );
6911 GST_INFO("set visible(%d) done", xvimagesink->visible);
6913 g_mutex_unlock( xvimagesink->x_lock );
6914 g_mutex_unlock( xvimagesink->flow_lock );
6917 xvimagesink->zoom = g_value_get_float (value);
6919 case PROP_ZOOM_POS_X:
6920 xvimagesink->zoom_pos_x = g_value_get_int (value);
6922 case PROP_ZOOM_POS_Y:
6923 xvimagesink->zoom_pos_y = g_value_get_int (value);
6924 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6925 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6928 case PROP_ORIENTATION:
6929 xvimagesink->orientation = g_value_get_enum (value);
6930 GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
6932 case PROP_DST_ROI_MODE:
6933 xvimagesink->dst_roi_mode = g_value_get_enum (value);
6934 GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
6936 case PROP_DST_ROI_X:
6937 xvimagesink->dst_roi.x = g_value_get_int (value);
6939 case PROP_DST_ROI_Y:
6940 xvimagesink->dst_roi.y = g_value_get_int (value);
6942 case PROP_DST_ROI_W:
6943 xvimagesink->dst_roi.w = g_value_get_int (value);
6945 case PROP_DST_ROI_H:
6946 xvimagesink->dst_roi.h = g_value_get_int (value);
6948 case PROP_SRC_CROP_X:
6949 xvimagesink->src_crop.x = g_value_get_int (value);
6951 case PROP_SRC_CROP_Y:
6952 xvimagesink->src_crop.y = g_value_get_int (value);
6954 case PROP_SRC_CROP_W:
6955 xvimagesink->src_crop.w = g_value_get_int (value);
6957 case PROP_SRC_CROP_H:
6958 xvimagesink->src_crop.h = g_value_get_int (value);
6960 case PROP_STOP_VIDEO:
6961 xvimagesink->stop_video = g_value_get_int (value);
6962 g_mutex_lock( xvimagesink->flow_lock );
6964 if( xvimagesink->stop_video )
6966 if ( xvimagesink->get_pixmap_cb ) {
6967 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6968 g_mutex_lock (xvimagesink->x_lock);
6969 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6970 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6971 g_mutex_unlock (xvimagesink->x_lock);
6974 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
6975 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6979 g_mutex_unlock( xvimagesink->flow_lock );
6981 case PROP_PIXMAP_CB:
6984 cb_func = g_value_get_pointer(value);
6986 if (xvimagesink->get_pixmap_cb) {
6988 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6989 g_mutex_lock (xvimagesink->x_lock);
6990 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6991 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6992 g_mutex_unlock (xvimagesink->x_lock);
6994 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6995 if (xvimagesink->xpixmap[i]) {
6996 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6997 xvimagesink->xpixmap[i] = NULL;
7001 xvimagesink->get_pixmap_cb = cb_func;
7002 GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
7006 case PROP_PIXMAP_CB_USER_DATA:
7009 user_data = g_value_get_pointer(value);
7011 xvimagesink->get_pixmap_cb_user_data = user_data;
7012 GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
7016 case PROP_SUBPICTURE:
7017 xvimagesink->subpicture = g_value_get_boolean (value);
7019 case PROP_EXTERNAL_WIDTH:
7021 xvimagesink->external_width = g_value_get_int (value);
7022 GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width);
7025 case PROP_EXTERNAL_HEIGHT:
7027 xvimagesink->external_height = g_value_get_int (value);
7028 GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height);
7031 case PROP_ENABLE_FLUSH_BUFFER:
7032 xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
7035 xvimagesink->is_pixmap = g_value_get_boolean(value);
7037 case PROP_HIDED_WINDOW:
7039 xvimagesink->is_hided_subpicture = g_value_get_boolean(value);
7040 GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture);
7043 case PROP_QUICKPANEL_ON:
7045 xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value);
7046 GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture);
7049 case PROP_MULTIWINDOW_ACTIVE:
7051 xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value);
7052 GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture);
7055 case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7057 xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value);
7058 GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post);
7059 if(xvimagesink->keep_external_fullscreen_post) {
7061 atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False);
7062 if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success)
7064 GST_WARNING("set atom_keep_ext fail");
7069 case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7071 xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value);
7072 GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev);
7076 #endif /* GST_EXT_XV_ENHANCEMENT */
7078 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7084 gst_xvimagesink_get_property (GObject * object, guint prop_id,
7085 GValue * value, GParamSpec * pspec)
7087 GstXvImageSink *xvimagesink;
7089 g_return_if_fail (GST_IS_XVIMAGESINK (object));
7091 xvimagesink = GST_XVIMAGESINK (object);
7095 g_value_set_int (value, xvimagesink->hue);
7098 g_value_set_int (value, xvimagesink->contrast);
7100 case PROP_BRIGHTNESS:
7101 g_value_set_int (value, xvimagesink->brightness);
7103 case PROP_SATURATION:
7104 g_value_set_int (value, xvimagesink->saturation);
7107 g_value_set_string (value, xvimagesink->display_name);
7109 case PROP_SYNCHRONOUS:
7110 g_value_set_boolean (value, xvimagesink->synchronous);
7112 case PROP_PIXEL_ASPECT_RATIO:
7113 if (xvimagesink->par)
7114 g_value_transform (xvimagesink->par, value);
7116 case PROP_FORCE_ASPECT_RATIO:
7117 g_value_set_boolean (value, xvimagesink->keep_aspect);
7119 case PROP_HANDLE_EVENTS:
7120 g_value_set_boolean (value, xvimagesink->handle_events);
7124 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
7126 g_value_set_string (value, adaptor_no_s);
7127 g_free (adaptor_no_s);
7130 case PROP_DEVICE_NAME:
7131 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
7132 g_value_set_string (value,
7133 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
7135 g_value_set_string (value, NULL);
7138 case PROP_HANDLE_EXPOSE:
7139 g_value_set_boolean (value, xvimagesink->handle_expose);
7141 case PROP_DOUBLE_BUFFER:
7142 g_value_set_boolean (value, xvimagesink->double_buffer);
7144 case PROP_AUTOPAINT_COLORKEY:
7145 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
7148 g_value_set_int (value, xvimagesink->colorkey);
7150 case PROP_DRAW_BORDERS:
7151 g_value_set_boolean (value, xvimagesink->draw_borders);
7153 case PROP_WINDOW_WIDTH:
7154 if (xvimagesink->xwindow)
7155 g_value_set_uint64 (value, xvimagesink->xwindow->width);
7157 g_value_set_uint64 (value, 0);
7159 case PROP_WINDOW_HEIGHT:
7160 if (xvimagesink->xwindow)
7161 g_value_set_uint64 (value, xvimagesink->xwindow->height);
7163 g_value_set_uint64 (value, 0);
7165 #ifdef GST_EXT_XV_ENHANCEMENT
7166 case PROP_DISPLAY_MODE:
7167 g_value_set_enum (value, xvimagesink->display_mode);
7169 case PROP_CSC_RANGE:
7170 g_value_set_enum (value, xvimagesink->csc_range);
7172 case PROP_DISPLAY_GEOMETRY_METHOD:
7173 g_value_set_enum (value, xvimagesink->display_geometry_method);
7176 g_value_set_enum(value, xvimagesink->flip);
7178 case PROP_ROTATE_ANGLE:
7179 g_value_set_enum (value, xvimagesink->rotate_angle);
7182 g_value_set_boolean (value, xvimagesink->visible);
7185 g_value_set_float (value, xvimagesink->zoom);
7187 case PROP_ZOOM_POS_X:
7188 g_value_set_int (value, xvimagesink->zoom_pos_x);
7190 case PROP_ZOOM_POS_Y:
7191 g_value_set_int (value, xvimagesink->zoom_pos_y);
7193 case PROP_ORIENTATION:
7194 g_value_set_enum (value, xvimagesink->orientation);
7196 case PROP_DST_ROI_MODE:
7197 g_value_set_enum (value, xvimagesink->dst_roi_mode);
7199 case PROP_DST_ROI_X:
7200 g_value_set_int (value, xvimagesink->dst_roi.x);
7202 case PROP_DST_ROI_Y:
7203 g_value_set_int (value, xvimagesink->dst_roi.y);
7205 case PROP_DST_ROI_W:
7206 g_value_set_int (value, xvimagesink->dst_roi.w);
7208 case PROP_DST_ROI_H:
7209 g_value_set_int (value, xvimagesink->dst_roi.h);
7211 case PROP_SRC_CROP_X:
7212 g_value_set_int (value, xvimagesink->src_crop.x);
7214 case PROP_SRC_CROP_Y:
7215 g_value_set_int (value, xvimagesink->src_crop.y);
7217 case PROP_SRC_CROP_W:
7218 g_value_set_int (value, xvimagesink->src_crop.w);
7220 case PROP_SRC_CROP_H:
7221 g_value_set_int (value, xvimagesink->src_crop.h);
7223 case PROP_STOP_VIDEO:
7224 g_value_set_int (value, xvimagesink->stop_video);
7226 case PROP_PIXMAP_CB:
7227 g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
7229 case PROP_PIXMAP_CB_USER_DATA:
7230 g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
7232 case PROP_SUBPICTURE:
7233 g_value_set_boolean (value, xvimagesink->subpicture);
7235 case PROP_EXTERNAL_WIDTH:
7236 g_value_set_int (value, xvimagesink->external_width);
7238 case PROP_EXTERNAL_HEIGHT:
7239 g_value_set_int (value, xvimagesink->external_height);
7241 case PROP_ENABLE_FLUSH_BUFFER:
7242 g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
7245 g_value_set_boolean(value, xvimagesink->is_pixmap);
7247 case PROP_HIDED_WINDOW:
7248 g_value_set_boolean(value, xvimagesink->is_hided_subpicture);
7250 case PROP_QUICKPANEL_ON:
7251 g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture);
7253 case PROP_MULTIWINDOW_ACTIVE:
7254 g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture);
7256 case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7257 g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post);
7259 case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7260 g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev);
7262 #endif /* GST_EXT_XV_ENHANCEMENT */
7264 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7270 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
7274 GST_OBJECT_LOCK (xvimagesink);
7275 xvimagesink->running = FALSE;
7276 /* grab thread and mark it as NULL */
7277 thread = xvimagesink->event_thread;
7278 xvimagesink->event_thread = NULL;
7279 GST_OBJECT_UNLOCK (xvimagesink);
7281 /* invalidate the pool, current allocations continue, new buffer_alloc fails
7282 * with wrong_state */
7283 g_mutex_lock (xvimagesink->pool_lock);
7284 xvimagesink->pool_invalid = TRUE;
7285 g_mutex_unlock (xvimagesink->pool_lock);
7287 /* Wait for our event thread to finish before we clean up our stuff. */
7289 g_thread_join (thread);
7291 if (xvimagesink->cur_image) {
7292 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
7293 xvimagesink->cur_image = NULL;
7295 if (xvimagesink->xvimage) {
7296 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
7297 xvimagesink->xvimage = NULL;
7300 gst_xvimagesink_imagepool_clear (xvimagesink);
7302 if (xvimagesink->xwindow) {
7303 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
7304 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
7305 xvimagesink->xwindow = NULL;
7307 #ifdef GST_EXT_XV_ENHANCEMENT
7308 if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
7309 GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7310 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7311 xvimagesink->pixmap_for_subpicture = 0;
7314 if (xvimagesink->get_pixmap_cb) {
7316 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
7317 g_mutex_lock (xvimagesink->x_lock);
7318 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
7319 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
7320 g_mutex_unlock (xvimagesink->x_lock);
7322 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
7323 if (xvimagesink->xpixmap[i]) {
7324 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
7325 xvimagesink->xpixmap[i] = NULL;
7328 xvimagesink->get_pixmap_cb = NULL;
7329 xvimagesink->get_pixmap_cb_user_data = NULL;
7331 #endif /* GST_EXT_XV_ENHANCEMENT */
7332 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
7333 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
7334 xvimagesink->have_render_rect = FALSE;
7336 gst_xvimagesink_xcontext_clear (xvimagesink);
7339 /* Finalize is called only once, dispose can be called multiple times.
7340 * We use mutexes and don't reset stuff to NULL here so let's register
7343 gst_xvimagesink_finalize (GObject * object)
7345 GstXvImageSink *xvimagesink;
7347 xvimagesink = GST_XVIMAGESINK (object);
7349 gst_xvimagesink_reset (xvimagesink);
7351 if (xvimagesink->display_name) {
7352 g_free (xvimagesink->display_name);
7353 xvimagesink->display_name = NULL;
7356 if (xvimagesink->par) {
7357 g_free (xvimagesink->par);
7358 xvimagesink->par = NULL;
7360 if (xvimagesink->x_lock) {
7361 g_mutex_free (xvimagesink->x_lock);
7362 xvimagesink->x_lock = NULL;
7364 if (xvimagesink->flow_lock) {
7365 g_mutex_free (xvimagesink->flow_lock);
7366 xvimagesink->flow_lock = NULL;
7368 if (xvimagesink->pool_lock) {
7369 g_mutex_free (xvimagesink->pool_lock);
7370 xvimagesink->pool_lock = NULL;
7372 #ifdef GST_EXT_XV_ENHANCEMENT
7373 if (xvimagesink->display_buffer_lock) {
7374 g_mutex_free (xvimagesink->display_buffer_lock);
7375 xvimagesink->display_buffer_lock = NULL;
7377 #endif /* GST_EXT_XV_ENHANCEMENT */
7379 g_free (xvimagesink->media_title);
7381 G_OBJECT_CLASS (parent_class)->finalize (object);
7385 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
7386 GstXvImageSinkClass * xvimagesinkclass)
7388 #ifdef GST_EXT_XV_ENHANCEMENT
7391 #endif /* GST_EXT_XV_ENHANCEMENT */
7393 xvimagesink->display_name = NULL;
7394 xvimagesink->adaptor_no = 0;
7395 xvimagesink->xcontext = NULL;
7396 xvimagesink->xwindow = NULL;
7397 xvimagesink->xvimage = NULL;
7398 xvimagesink->cur_image = NULL;
7400 xvimagesink->hue = xvimagesink->saturation = 0;
7401 xvimagesink->contrast = xvimagesink->brightness = 0;
7402 xvimagesink->cb_changed = FALSE;
7404 xvimagesink->fps_n = 0;
7405 xvimagesink->fps_d = 0;
7406 xvimagesink->video_width = 0;
7407 xvimagesink->video_height = 0;
7409 xvimagesink->x_lock = g_mutex_new ();
7410 xvimagesink->flow_lock = g_mutex_new ();
7412 xvimagesink->image_pool = NULL;
7413 xvimagesink->pool_lock = g_mutex_new ();
7415 xvimagesink->synchronous = FALSE;
7416 xvimagesink->double_buffer = TRUE;
7417 xvimagesink->running = FALSE;
7418 xvimagesink->keep_aspect = FALSE;
7419 xvimagesink->handle_events = TRUE;
7420 xvimagesink->par = NULL;
7421 xvimagesink->handle_expose = TRUE;
7422 xvimagesink->autopaint_colorkey = TRUE;
7424 /* on 16bit displays this becomes r,g,b = 1,2,3
7425 * on 24bit displays this becomes r,g,b = 8,8,16
7426 * as a port atom value
7428 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
7429 xvimagesink->draw_borders = TRUE;
7431 #ifdef GST_EXT_XV_ENHANCEMENT
7432 xvimagesink->xid_updated = FALSE;
7433 xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE;
7434 xvimagesink->csc_range = CSC_RANGE_NARROW;
7435 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
7436 xvimagesink->flip = DEF_DISPLAY_FLIP;
7437 xvimagesink->rotate_angle = DEGREE_270;
7438 xvimagesink->visible = TRUE;
7439 xvimagesink->zoom = 1.0;
7440 xvimagesink->zoom_pos_x = -1;
7441 xvimagesink->zoom_pos_y = -1;
7442 xvimagesink->rotation = -1;
7443 xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
7444 xvimagesink->orientation = DEGREE_0;
7445 xvimagesink->dst_roi.x = 0;
7446 xvimagesink->dst_roi.y = 0;
7447 xvimagesink->dst_roi.w = 0;
7448 xvimagesink->dst_roi.h = 0;
7449 xvimagesink->src_crop.x = 0;
7450 xvimagesink->src_crop.y = 0;
7451 xvimagesink->src_crop.w = 0;
7452 xvimagesink->src_crop.h = 0;
7453 xvimagesink->xim_transparenter = NULL;
7454 xvimagesink->scr_w = 0;
7455 xvimagesink->scr_h = 0;
7456 xvimagesink->aligned_width = 0;
7457 xvimagesink->aligned_height = 0;
7458 xvimagesink->stop_video = FALSE;
7459 xvimagesink->is_hided = FALSE;
7460 xvimagesink->is_quick_panel_on = FALSE;
7461 xvimagesink->is_multi_window = FALSE;
7462 xvimagesink->drm_fd = -1;
7463 xvimagesink->current_pixmap_idx = -1;
7464 xvimagesink->get_pixmap_cb = NULL;
7465 xvimagesink->get_pixmap_cb_user_data = NULL;
7467 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
7468 xvimagesink->displaying_buffers[i].buffer = NULL;
7469 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
7470 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
7471 xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
7472 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
7473 xvimagesink->displaying_buffers[i].ref_count = 0;
7477 xvimagesink->display_buffer_lock = g_mutex_new ();
7479 xvimagesink->displayed_buffer_count = 0;
7480 xvimagesink->displaying_buffer_count = 0;
7481 xvimagesink->is_zero_copy_format = FALSE;
7482 xvimagesink->secure_path = SECURE_PATH_INIT;
7483 xvimagesink->drm_level = DRM_LEVEL_0;
7484 xvimagesink->last_added_buffer_index = -1;
7485 xvimagesink->bufmgr = NULL;
7486 xvimagesink->flush_buffer = NULL;
7487 xvimagesink->enable_flush_buffer = TRUE;
7488 xvimagesink->pixmap_for_subpicture = 0;
7489 xvimagesink->is_subpicture_format = FALSE;
7490 xvimagesink->set_overlay_for_subpicture_just_once = FALSE;
7491 xvimagesink->subpicture = FALSE;
7492 xvimagesink->external_width = 0;
7493 xvimagesink->external_height = 0;
7494 xvimagesink->skip_frame_due_to_external_dev = FALSE;
7495 xvimagesink->is_hided_subpicture = FALSE;
7496 xvimagesink->is_quick_panel_on_subpicture = FALSE;
7497 xvimagesink->is_multi_window_subpicture = FALSE;
7498 xvimagesink->keep_external_fullscreen_post = FALSE;
7499 xvimagesink->keep_external_fullscreen_prev = FALSE;
7501 GST_WARNING("FAIL to call XInitThreads()");
7502 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL))
7503 GST_WARNING("vconf set fail");
7504 #endif /* GST_EXT_XV_ENHANCEMENT */
7508 gst_xvimagesink_base_init (gpointer g_class)
7510 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
7512 gst_element_class_set_details_simple (element_class,
7513 "Video sink", "Sink/Video",
7514 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
7516 gst_element_class_add_static_pad_template (element_class,
7517 &gst_xvimagesink_sink_template_factory);
7521 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
7523 GObjectClass *gobject_class;
7524 GstElementClass *gstelement_class;
7525 GstBaseSinkClass *gstbasesink_class;
7526 GstVideoSinkClass *videosink_class;
7528 gobject_class = (GObjectClass *) klass;
7529 gstelement_class = (GstElementClass *) klass;
7530 gstbasesink_class = (GstBaseSinkClass *) klass;
7531 videosink_class = (GstVideoSinkClass *) klass;
7533 gobject_class->set_property = gst_xvimagesink_set_property;
7534 gobject_class->get_property = gst_xvimagesink_get_property;
7536 g_object_class_install_property (gobject_class, PROP_CONTRAST,
7537 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
7538 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7539 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
7540 g_param_spec_int ("brightness", "Brightness",
7541 "The brightness of the video", -1000, 1000, 0,
7542 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7543 g_object_class_install_property (gobject_class, PROP_HUE,
7544 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
7545 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7546 g_object_class_install_property (gobject_class, PROP_SATURATION,
7547 g_param_spec_int ("saturation", "Saturation",
7548 "The saturation of the video", -1000, 1000, 0,
7549 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7550 g_object_class_install_property (gobject_class, PROP_DISPLAY,
7551 g_param_spec_string ("display", "Display", "X Display name", NULL,
7552 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7553 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
7554 g_param_spec_boolean ("synchronous", "Synchronous",
7555 "When enabled, runs the X display in synchronous mode. "
7556 "(unrelated to A/V sync, used only for debugging)", FALSE,
7557 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7558 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
7559 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
7560 "The pixel aspect ratio of the device", "1/1",
7561 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7562 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
7563 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
7564 "When enabled, scaling will respect original aspect ratio", FALSE,
7565 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7566 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
7567 g_param_spec_boolean ("handle-events", "Handle XEvents",
7568 "When enabled, XEvents will be selected and handled", TRUE,
7569 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7570 g_object_class_install_property (gobject_class, PROP_DEVICE,
7571 g_param_spec_string ("device", "Adaptor number",
7572 "The number of the video adaptor", "0",
7573 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7574 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
7575 g_param_spec_string ("device-name", "Adaptor name",
7576 "The name of the video adaptor", NULL,
7577 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7578 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH,
7579 g_param_spec_int ("external-width", "external width",
7580 "width of external display", 0, G_MAXINT,
7581 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7582 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT,
7583 g_param_spec_int ("external-height", "external height",
7584 "height of external display", 0, G_MAXINT,
7585 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7587 * GstXvImageSink:handle-expose
7589 * When enabled, the current frame will always be drawn in response to X
7594 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
7595 g_param_spec_boolean ("handle-expose", "Handle expose",
7597 "the current frame will always be drawn in response to X Expose "
7598 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7601 * GstXvImageSink:double-buffer
7603 * Whether to double-buffer the output.
7607 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
7608 g_param_spec_boolean ("double-buffer", "Double-buffer",
7609 "Whether to double-buffer the output", TRUE,
7610 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7612 * GstXvImageSink:autopaint-colorkey
7614 * Whether to autofill overlay with colorkey
7618 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
7619 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
7620 "Whether to autofill overlay with colorkey", TRUE,
7621 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7623 * GstXvImageSink:colorkey
7625 * Color to use for the overlay mask.
7629 g_object_class_install_property (gobject_class, PROP_COLORKEY,
7630 g_param_spec_int ("colorkey", "Colorkey",
7631 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
7632 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7635 * GstXvImageSink:draw-borders
7637 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
7638 * unused parts of the video area.
7642 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
7643 g_param_spec_boolean ("draw-borders", "Colorkey",
7644 "Draw black borders to fill unused area in force-aspect-ratio mode",
7645 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7648 * GstXvImageSink:window-width
7650 * Actual width of the video window.
7654 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
7655 g_param_spec_uint64 ("window-width", "window-width",
7656 "Width of the window", 0, G_MAXUINT64, 0,
7657 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7660 * GstXvImageSink:window-height
7662 * Actual height of the video window.
7666 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
7667 g_param_spec_uint64 ("window-height", "window-height",
7668 "Height of the window", 0, G_MAXUINT64, 0,
7669 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7671 #ifdef GST_EXT_XV_ENHANCEMENT
7673 * GstXvImageSink:display-mode
7675 * select display mode
7677 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
7678 g_param_spec_enum("display-mode", "Display Mode",
7679 "Display device setting",
7680 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE,
7681 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7684 * GstXvImageSink:csc-range
7686 * select color space range
7688 g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
7689 g_param_spec_enum("csc-range", "Color Space Range",
7690 "Color space range setting",
7691 GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
7692 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7695 * GstXvImageSink:display-geometry-method
7697 * Display geometrical method setting
7699 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
7700 g_param_spec_enum("display-geometry-method", "Display geometry method",
7701 "Geometrical method for display",
7702 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
7703 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7706 * GstXvImageSink:display-flip
7708 * Display flip setting
7710 g_object_class_install_property(gobject_class, PROP_FLIP,
7711 g_param_spec_enum("flip", "Display flip",
7713 GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
7714 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7717 * GstXvImageSink:rotate
7719 * Draw rotation angle setting
7721 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
7722 g_param_spec_enum("rotate", "Rotate angle",
7723 "Rotate angle of display output",
7724 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
7725 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7728 * GstXvImageSink:visible
7730 * Whether reserve original src size or not
7732 g_object_class_install_property (gobject_class, PROP_VISIBLE,
7733 g_param_spec_boolean ("visible", "Visible",
7734 "Draws screen or blacks out, true means visible, false blacks out",
7735 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7738 * GstXvImageSink:zoom
7740 * Scale small area of screen to 1X~ 9X
7742 g_object_class_install_property (gobject_class, PROP_ZOOM,
7743 g_param_spec_float ("zoom", "Zoom",
7744 "Zooms screen as nX", 1.0, 9.0, 1.0,
7745 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7748 * GstXvImageSink:zoom-pos-x
7750 * Standard x-position of zoom
7752 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
7753 g_param_spec_int ("zoom-pos-x", "Zoom Position X",
7754 "Standard x-position of zoom", -1, 3840, -1,
7755 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7758 * GstXvImageSink:zoom-pos-y
7760 * Standard y-position of zoom
7762 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
7763 g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
7764 "Standard y-position of zoom", -1, 3840, -1,
7765 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7768 * GstXvImageSink:dst-roi-mode
7770 * Display geometrical method of ROI setting
7772 g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
7773 g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
7774 "Geometrical method of ROI for display",
7775 GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
7776 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7779 * GstXvImageSink:orientation
7781 * Orientation information which will be used for ROI/ZOOM
7783 g_object_class_install_property(gobject_class, PROP_ORIENTATION,
7784 g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
7785 "Orientation information for display",
7786 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
7787 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7790 * GstXvImageSink:dst-roi-x
7792 * X value of Destination ROI
7794 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
7795 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
7796 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7797 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7800 * GstXvImageSink:dst-roi-y
7802 * Y value of Destination ROI
7804 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
7805 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
7806 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7807 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7810 * GstXvImageSink:dst-roi-w
7812 * W value of Destination ROI
7814 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
7815 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
7816 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7817 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7820 * GstXvImageSink:dst-roi-h
7822 * H value of Destination ROI
7824 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
7825 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
7826 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7827 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7830 * GstXvImageSink:stop-video
7832 * Stop video for releasing video source buffer
7834 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
7835 g_param_spec_int ("stop-video", "Stop-Video",
7836 "Stop video for releasing video source buffer", 0, 1, 0,
7837 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7839 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
7840 g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
7841 "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
7843 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
7844 g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
7845 "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
7847 g_object_class_install_property (gobject_class, PROP_SUBPICTURE,
7848 g_param_spec_boolean ("subpicture", "Subpicture",
7849 "identifier of player for supporting subpicture", FALSE,
7850 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7853 * GstXvImageSink:src-crop-x
7855 * X value of video source crop
7857 g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
7858 g_param_spec_int ("src-crop-x", "Source Crop X",
7859 "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7860 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7863 * GstXvImageSink:src-crop-y
7865 * Y value of video source crop
7867 g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
7868 g_param_spec_int ("src-crop-y", "Source Crop X",
7869 "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7870 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7873 * GstXvImageSink:src-crop-w
7875 * Width value of video source crop
7877 g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
7878 g_param_spec_int ("src-crop-w", "Source Crop Width",
7879 "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7880 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7883 * GstXvImageSink:src-crop-h
7885 * Height value of video source crop
7887 g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
7888 g_param_spec_int ("src-crop-h", "Source Crop Height",
7889 "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7890 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7893 * GstXvImageSink:enable-flush-buffer
7895 * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
7897 g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
7898 g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
7899 "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
7900 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7903 * GstXvImageSink:is-pixmap
7905 * Check using pixmap id for blocking X api
7907 g_object_class_install_property (gobject_class, PROP_PIXMAP,
7908 g_param_spec_boolean("is-pixmap", "Check if use pixmap",
7909 "Check using pixmap id for blocking X api",
7910 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7913 * GstXvImageSink:hided-window
7915 * check window status for hiding subtitle
7917 g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW,
7918 g_param_spec_boolean("hided-window", "Hided window",
7919 "check window status for hiding subtitle",
7920 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7923 * GstXvImageSink:quick-panel-on
7925 * check quick-panel status for hiding subtitle
7927 g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON,
7928 g_param_spec_boolean("quick-panel-on", "Quick panel On",
7929 "check quick-panel status for hiding subtitle",
7930 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7933 * GstXvImageSink:multiwindow-activated
7935 * check multiwindow-activated status for hiding subtitle
7937 g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE,
7938 g_param_spec_boolean("multiwindow-active", "Multiwindow Activate",
7939 "check multiwindow status for hiding subtitle",
7940 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7943 * GstXvImageSink:keep-external-fullscreen-post
7945 * keep video-only mode for special case, it is set immediately.
7947 g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
7948 g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen",
7949 "set video-only mode forcedly for special case",
7950 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7953 * GstXvImageSink:keep-external-fullscreen-prev
7955 * keep video-only mode for special case, it is set in advance.
7957 g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
7958 g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen",
7959 "set video-only mode forcedly for special case",
7960 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7963 * GstXvImageSink::frame-render-error
7965 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
7966 "frame-render-error",
7967 G_TYPE_FROM_CLASS (klass),
7972 gst_xvimagesink_BOOLEAN__POINTER,
7977 * GstXvImageSink::display-status
7979 gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new (
7981 G_TYPE_FROM_CLASS (klass),
7982 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7986 g_cclosure_marshal_VOID__INT,
7992 * GstXvImageSink::external-resolution
7994 gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new (
7995 "external-resolution",
7996 G_TYPE_FROM_CLASS (klass),
7997 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8001 gst_marshal_VOID__INT_INT,
8008 * GstXvImageSink::hided-window
8010 gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new (
8012 G_TYPE_FROM_CLASS (klass),
8013 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8017 g_cclosure_marshal_VOID__BOOLEAN,
8023 * GstXvImageSink::quick-panel-on
8025 gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new (
8027 G_TYPE_FROM_CLASS (klass),
8028 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8032 g_cclosure_marshal_VOID__BOOLEAN,
8038 * GstXvImageSink::multiwindow-active
8040 gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new (
8041 "multiwindow-active",
8042 G_TYPE_FROM_CLASS (klass),
8043 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8047 g_cclosure_marshal_VOID__BOOLEAN,
8052 #endif /* GST_EXT_XV_ENHANCEMENT */
8054 gobject_class->finalize = gst_xvimagesink_finalize;
8056 gstelement_class->change_state =
8057 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
8059 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
8060 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
8061 gstbasesink_class->buffer_alloc =
8062 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
8063 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
8064 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
8066 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
8069 /* ============================================================= */
8071 /* Public Methods */
8073 /* ============================================================= */
8075 /* =========================================== */
8077 /* Object typing & Creation */
8079 /* =========================================== */
8081 gst_xvimagesink_init_interfaces (GType type)
8083 static const GInterfaceInfo iface_info = {
8084 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
8088 static const GInterfaceInfo navigation_info = {
8089 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
8093 static const GInterfaceInfo overlay_info = {
8094 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
8098 static const GInterfaceInfo colorbalance_info = {
8099 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
8103 static const GInterfaceInfo propertyprobe_info = {
8104 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
8109 g_type_add_interface_static (type,
8110 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
8111 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
8112 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
8113 g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
8114 &colorbalance_info);
8115 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
8116 &propertyprobe_info);
8118 /* register type and create class in a more safe place instead of at
8119 * runtime since the type registration and class creation is not
8121 g_type_class_ref (gst_xvimage_buffer_get_type ());
8125 plugin_init (GstPlugin * plugin)
8127 if (!gst_element_register (plugin, "xvimagesink",
8128 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
8131 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
8132 "xvimagesink element");
8133 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
8138 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
8141 "XFree86 video output plugin using Xv extension",
8142 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)