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_resolution = NULL;
3626 UtilxScrnConf *scrnconf = utilx_scrnconf_allocate();
3629 GST_WARNING ("fail to allocate scrnconf");
3632 utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf);
3634 str_output = scrnconf->str_output;
3636 if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT)
3638 GST_INFO("CONNECT");
3640 else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE)
3644 list = g_strsplit(scrnconf->str_resolution, "x", 2);
3649 utilx_scrnconf_free (scrnconf);
3652 for(walk = list; *walk; walk++)
3654 external[cnt++] = atoi(*walk);
3657 GST_WARNING("data error");
3659 utilx_scrnconf_free (scrnconf);
3663 xvimagesink->external_width = external[0];
3664 xvimagesink->external_height = external[1];
3667 GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height);
3668 g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
3675 str_resolution = scrnconf->str_resolution;
3677 if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE)
3679 GST_INFO("CLONE mode");
3681 else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED)
3683 GST_INFO("EXTENDED mode");
3687 GST_INFO("NULL mode");
3690 GST_INFO ("[Display status] : %s, %s\n", str_output, str_resolution);
3693 utilx_scrnconf_free (scrnconf);
3698 check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name)
3703 XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp,
3704 xvimagesink->xcontext->xv_port_id, &count);
3706 for (i = 0 ; i < count ; i++) {
3707 if (!strcmp(attr[i].name, attr_name)) {
3708 GST_INFO("%s[index %d] found", attr_name, i);
3715 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
3716 xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id);
3720 #endif //GST_EXT_XV_ENHANCEMENT
3723 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3724 XvAdaptorInfo * adaptors, int adaptor_no)
3729 /* Do we support XvImageMask ? */
3730 if (!(adaptors[adaptor_no].type & XvImageMask)) {
3731 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3732 adaptors[adaptor_no].name);
3736 /* We found such an adaptor, looking for an available port */
3737 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3738 /* We try to grab the port */
3739 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3740 if (Success == res) {
3741 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3742 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3743 adaptors[adaptor_no].num_ports);
3745 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3746 adaptors[adaptor_no].name, res);
3751 #ifdef GST_EXT_XV_ENHANCEMENT
3753 gst_lookup_xv_port_for_subtitle (GstXContext * xcontext,
3754 XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors)
3759 for (i = 0; i < nb_adaptors; i++)
3762 if (!(adaptors[i].type & XvOutputMask) ||
3763 !(adaptors[i].type & XvStillMask))
3765 min = adaptors[i].base_id;
3766 max = adaptors[i].base_id + adaptors[i].num_ports;
3767 for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++)
3769 if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success)
3771 GST_INFO ("========================================");
3772 GST_INFO ("XvGrabPort success : %ld", adaptors[adaptor_no].num_ports);
3773 GST_INFO ("========================================");
3774 xcontext->xv_port_id = adaptors[adaptor_no].num_ports;
3777 GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports);
3785 /* This function generates a caps with all supported format by the first
3786 Xv grabable port we find. We store each one of the supported formats in a
3787 format list and append the format to a newly created caps that we return
3788 If this function does not return NULL because of an error, it also grabs
3789 the port via XvGrabPort */
3791 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3792 GstXContext * xcontext)
3795 XvAdaptorInfo *adaptors;
3797 XvImageFormatValues *formats = NULL;
3799 XvEncodingInfo *encodings = NULL;
3800 gulong max_w = G_MAXINT, max_h = G_MAXINT;
3801 GstCaps *caps = NULL;
3802 GstCaps *rgb_caps = NULL;
3804 g_return_val_if_fail (xcontext != NULL, NULL);
3806 /* First let's check that XVideo extension is available */
3807 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3808 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3809 ("Could not initialise Xv output"),
3810 ("XVideo extension is not available"));
3814 /* Then we get adaptors list */
3815 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3816 &xcontext->nb_adaptors, &adaptors)) {
3817 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3818 ("Could not initialise Xv output"),
3819 ("Failed getting XV adaptors list"));
3823 xcontext->xv_port_id = 0;
3825 GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
3827 xcontext->adaptors =
3828 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3830 /* Now fill up our adaptor name array */
3831 for (i = 0; i < xcontext->nb_adaptors; i++) {
3832 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3835 if (xvimagesink->adaptor_no >= 0 &&
3836 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3837 /* Find xv port from user defined adaptor */
3838 #ifdef GST_EXT_XV_ENHANCEMENT
3839 if(!xvimagesink->subpicture)
3841 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no);
3842 #ifdef GST_EXT_XV_ENHANCEMENT
3844 gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors);
3848 if (!xcontext->xv_port_id) {
3849 /* Now search for an adaptor that supports XvImageMask */
3850 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3851 #ifdef GST_EXT_XV_ENHANCEMENT
3852 if(!xvimagesink->subpicture)
3854 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3855 #ifdef GST_EXT_XV_ENHANCEMENT
3857 gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors);
3859 xvimagesink->adaptor_no = i;
3863 XvFreeAdaptorInfo (adaptors);
3865 if (!xcontext->xv_port_id) {
3866 xvimagesink->adaptor_no = -1;
3867 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3868 ("Could not initialise Xv output"), ("No port available"));
3872 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3874 int count, todo = 3;
3875 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3876 xcontext->xv_port_id, &count);
3877 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3878 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3879 static const char colorkey[] = "XV_COLORKEY";
3881 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3883 xvimagesink->have_autopaint_colorkey = FALSE;
3884 xvimagesink->have_double_buffer = FALSE;
3885 xvimagesink->have_colorkey = FALSE;
3887 for (i = 0; ((i < count) && todo); i++)
3888 if (!strcmp (attr[i].name, autopaint)) {
3889 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3891 /* turn on autopaint colorkey */
3892 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3893 (xvimagesink->autopaint_colorkey ? 1 : 0));
3895 xvimagesink->have_autopaint_colorkey = TRUE;
3896 } else if (!strcmp (attr[i].name, dbl_buffer)) {
3897 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3899 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3900 (xvimagesink->double_buffer ? 1 : 0));
3902 xvimagesink->have_double_buffer = TRUE;
3903 } else if (!strcmp (attr[i].name, colorkey)) {
3904 /* Set the colorkey, default is something that is dark but hopefully
3905 * won't randomly appear on the screen elsewhere (ie not black or greys)
3906 * can be overridden by setting "colorkey" property
3908 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3910 gboolean set_attr = TRUE;
3913 /* set a colorkey in the right format RGB565/RGB888
3914 * We only handle these 2 cases, because they're the only types of
3915 * devices we've encountered. If we don't recognise it, leave it alone
3917 cr = (xvimagesink->colorkey >> 16);
3918 cg = (xvimagesink->colorkey >> 8) & 0xFF;
3919 cb = (xvimagesink->colorkey) & 0xFF;
3920 switch (xcontext->depth) {
3921 case 16: /* RGB 565 */
3925 ckey = (cr << 11) | (cg << 5) | cb;
3928 case 32: /* RGB 888 / ARGB 8888 */
3929 ckey = (cr << 16) | (cg << 8) | cb;
3932 GST_DEBUG_OBJECT (xvimagesink,
3933 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3940 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3941 (guint32) attr[i].max_value);
3942 GST_LOG_OBJECT (xvimagesink,
3943 "Setting color key for display depth %d to 0x%x",
3944 xcontext->depth, ckey);
3946 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3950 xvimagesink->have_colorkey = TRUE;
3956 /* Get the list of encodings supported by the adapter and look for the
3957 * XV_IMAGE encoding so we can determine the maximum width and height
3959 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3962 for (i = 0; i < nb_encodings; i++) {
3963 GST_LOG_OBJECT (xvimagesink,
3964 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3965 i, encodings[i].name, encodings[i].width, encodings[i].height,
3966 encodings[i].rate.numerator, encodings[i].rate.denominator);
3967 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3968 max_w = encodings[i].width;
3969 max_h = encodings[i].height;
3970 #ifdef GST_EXT_XV_ENHANCEMENT
3971 xvimagesink->scr_w = max_w;
3972 xvimagesink->scr_h = max_h;
3973 #endif /* GST_EXT_XV_ENHANCEMENT */
3977 XvFreeEncodingInfo (encodings);
3978 #ifdef GST_EXT_XV_ENHANCEMENT
3979 if (!xvimagesink->subpicture) {
3981 /* We get all image formats supported by our port */
3982 formats = XvListImageFormats (xcontext->disp,
3983 xcontext->xv_port_id, &nb_formats);
3984 caps = gst_caps_new_empty ();
3985 for (i = 0; i < nb_formats; i++) {
3986 GstCaps *format_caps = NULL;
3987 gboolean is_rgb_format = FALSE;
3989 /* We set the image format of the xcontext to an existing one. This
3990 is just some valid image format for making our xshm calls check before
3991 caps negotiation really happens. */
3992 xcontext->im_format = formats[i].id;
3994 switch (formats[i].type) {
3997 XvImageFormatValues *fmt = &(formats[i]);
3998 gint endianness = G_BIG_ENDIAN;
4000 if (fmt->byte_order == LSBFirst) {
4001 /* our caps system handles 24/32bpp RGB as big-endian. */
4002 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
4003 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
4004 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
4005 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
4007 if (fmt->bits_per_pixel == 24) {
4008 fmt->red_mask >>= 8;
4009 fmt->green_mask >>= 8;
4010 fmt->blue_mask >>= 8;
4013 endianness = G_LITTLE_ENDIAN;
4016 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
4017 #ifdef GST_EXT_XV_ENHANCEMENT
4018 "format", GST_TYPE_FOURCC, formats[i].id,
4019 #endif /* GST_EXT_XV_ENHANCEMENT */
4020 "endianness", G_TYPE_INT, endianness,
4021 "depth", G_TYPE_INT, fmt->depth,
4022 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
4023 "red_mask", G_TYPE_INT, fmt->red_mask,
4024 "green_mask", G_TYPE_INT, fmt->green_mask,
4025 "blue_mask", G_TYPE_INT, fmt->blue_mask,
4026 "width", GST_TYPE_INT_RANGE, 1, max_w,
4027 "height", GST_TYPE_INT_RANGE, 1, max_h,
4028 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4030 is_rgb_format = TRUE;
4034 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
4035 "format", GST_TYPE_FOURCC, formats[i].id,
4036 "width", GST_TYPE_INT_RANGE, 1, max_w,
4037 "height", GST_TYPE_INT_RANGE, 1, max_h,
4038 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
4041 g_assert_not_reached ();
4046 GstXvImageFormat *format = NULL;
4048 format = g_new0 (GstXvImageFormat, 1);
4050 format->format = formats[i].id;
4051 format->caps = gst_caps_copy (format_caps);
4052 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
4055 if (is_rgb_format) {
4056 if (rgb_caps == NULL)
4057 rgb_caps = format_caps;
4059 gst_caps_append (rgb_caps, format_caps);
4061 gst_caps_append (caps, format_caps);
4065 /* Collected all caps into either the caps or rgb_caps structures.
4066 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
4068 gst_caps_append (caps, rgb_caps);
4073 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
4075 if (gst_caps_is_empty (caps)) {
4076 gst_caps_unref (caps);
4077 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4078 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
4079 ("No supported format found"));
4082 #ifdef GST_EXT_XV_ENHANCEMENT
4090 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
4092 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4094 GST_OBJECT_LOCK (xvimagesink);
4095 while (xvimagesink->running) {
4096 GST_OBJECT_UNLOCK (xvimagesink);
4098 if (xvimagesink->xwindow) {
4099 gst_xvimagesink_handle_xevents (xvimagesink);
4102 #ifdef GST_EXT_XV_ENHANCEMENT
4103 g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
4104 #else /* GST_EXT_XV_ENHANCEMENT */
4105 /* FIXME: do we want to align this with the framerate or anything else? */
4106 g_usleep (G_USEC_PER_SEC / 20);
4107 #endif /* GST_EXT_XV_ENHANCEMENT */
4109 GST_OBJECT_LOCK (xvimagesink);
4111 GST_OBJECT_UNLOCK (xvimagesink);
4117 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
4119 GThread *thread = NULL;
4121 /* don't start the thread too early */
4122 if (xvimagesink->xcontext == NULL) {
4126 GST_OBJECT_LOCK (xvimagesink);
4127 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
4128 if (!xvimagesink->event_thread) {
4129 /* Setup our event listening thread */
4130 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
4131 xvimagesink->handle_expose, xvimagesink->handle_events);
4132 xvimagesink->running = TRUE;
4133 #if !GLIB_CHECK_VERSION (2, 31, 0)
4134 xvimagesink->event_thread = g_thread_create (
4135 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
4137 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
4138 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
4142 if (xvimagesink->event_thread) {
4143 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
4144 xvimagesink->handle_expose, xvimagesink->handle_events);
4145 xvimagesink->running = FALSE;
4146 /* grab thread and mark it as NULL */
4147 thread = xvimagesink->event_thread;
4148 xvimagesink->event_thread = NULL;
4151 GST_OBJECT_UNLOCK (xvimagesink);
4153 /* Wait for our event thread to finish */
4155 g_thread_join (thread);
4160 #ifdef GST_EXT_XV_ENHANCEMENT
4162 * gst_xvimagesink_prepare_xid:
4163 * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
4165 * This will post a "prepare-xid" element message with video size and display size on the bus
4166 * to give applications an opportunity to call
4167 * gst_x_overlay_set_xwindow_id() before a plugin creates its own
4170 * This function should only be used by video overlay plugin developers.
4173 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
4178 g_return_if_fail (overlay != NULL);
4179 g_return_if_fail (GST_IS_X_OVERLAY (overlay));
4181 GstXvImageSink *xvimagesink;
4182 xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
4184 GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
4185 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
4187 GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
4188 s = gst_structure_new ("prepare-xid",
4189 "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
4190 "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
4191 "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
4192 "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
4194 msg = gst_message_new_element (GST_OBJECT (overlay), s);
4195 gst_element_post_message (GST_ELEMENT (overlay), msg);
4197 #endif /* GST_EXT_XV_ENHANCEMENT */
4200 /* This function calculates the pixel aspect ratio based on the properties
4201 * in the xcontext structure and stores it there. */
4203 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
4205 static const gint par[][2] = {
4206 {1, 1}, /* regular screen */
4207 {16, 15}, /* PAL TV */
4208 {11, 10}, /* 525 line Rec.601 video */
4209 #ifdef GST_EXT_XV_ENHANCEMENT
4210 {44, 46}, /* Gear S Curved Display */
4212 {54, 59}, /* 625 line Rec.601 video */
4213 {64, 45}, /* 1280x1024 on 16:9 display */
4214 {5, 3}, /* 1280x1024 on 4:3 display */
4215 {4, 3} /* 800x600 on 16:9 display */
4222 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
4224 /* first calculate the "real" ratio based on the X values;
4225 * which is the "physical" w/h divided by the w/h in pixels of the display */
4226 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
4227 / (xcontext->heightmm * xcontext->width);
4229 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
4231 if (xcontext->width == 720 && xcontext->height == 576) {
4232 ratio = 4.0 * 576 / (3.0 * 720);
4234 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
4235 /* now find the one from par[][2] with the lowest delta to the real one */
4239 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
4240 gdouble this_delta = DELTA (i);
4242 if (this_delta < delta) {
4248 GST_DEBUG ("Decided on index %d (%d/%d)", index,
4249 par[index][0], par[index][1]);
4251 g_free (xcontext->par);
4252 xcontext->par = g_new0 (GValue, 1);
4253 g_value_init (xcontext->par, GST_TYPE_FRACTION);
4254 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
4255 GST_DEBUG ("set xcontext PAR to %d/%d",
4256 gst_value_get_fraction_numerator (xcontext->par),
4257 gst_value_get_fraction_denominator (xcontext->par));
4260 /* This function gets the X Display and global info about it. Everything is
4261 stored in our object and will be cleaned when the object is disposed. Note
4262 here that caps for supported format are generated without any window or
4264 static GstXContext *
4265 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
4267 GstXContext *xcontext = NULL;
4268 XPixmapFormatValues *px_formats = NULL;
4269 gint nb_formats = 0, i, j, N_attr;
4270 XvAttribute *xv_attr = NULL;
4272 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
4273 "XV_BRIGHTNESS", "XV_CONTRAST"
4276 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4278 xcontext = g_new0 (GstXContext, 1);
4279 xcontext->im_format = 0;
4281 g_mutex_lock (xvimagesink->x_lock);
4283 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
4284 if (!xcontext->disp) {
4285 g_mutex_unlock (xvimagesink->x_lock);
4287 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4288 ("Could not initialise Xv output"), ("Could not open display"));
4292 #ifdef GST_EXT_XV_ENHANCEMENT
4295 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4296 if (g_display_id[i] == NULL) {
4297 g_display_id[i] = xcontext->disp;
4298 GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
4302 if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
4303 GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
4308 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
4309 xcontext->screen_num = DefaultScreen (xcontext->disp);
4310 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
4311 xcontext->root = DefaultRootWindow (xcontext->disp);
4312 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
4313 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
4314 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
4316 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
4317 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
4318 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
4319 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
4321 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
4322 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
4324 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
4325 /* We get supported pixmap formats at supported depth */
4326 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
4329 #ifdef GST_EXT_XV_ENHANCEMENT
4332 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4333 if (g_display_id[i] == xcontext->disp) {
4334 g_display_id[i] = NULL;
4339 XCloseDisplay (xcontext->disp);
4340 g_mutex_unlock (xvimagesink->x_lock);
4341 g_free (xcontext->par);
4343 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
4344 ("Could not initialise Xv output"), ("Could not get pixel formats"));
4348 /* We get bpp value corresponding to our running depth */
4349 for (i = 0; i < nb_formats; i++) {
4350 if (px_formats[i].depth == xcontext->depth)
4351 xcontext->bpp = px_formats[i].bits_per_pixel;
4356 xcontext->endianness =
4357 (ImageByteOrder (xcontext->disp) ==
4358 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
4360 /* our caps system handles 24/32bpp RGB as big-endian. */
4361 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
4362 xcontext->endianness == G_LITTLE_ENDIAN) {
4363 xcontext->endianness = G_BIG_ENDIAN;
4364 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
4365 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
4366 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
4367 if (xcontext->bpp == 24) {
4368 xcontext->visual->red_mask >>= 8;
4369 xcontext->visual->green_mask >>= 8;
4370 xcontext->visual->blue_mask >>= 8;
4374 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
4377 #ifdef GST_EXT_XV_ENHANCEMENT
4378 && !xvimagesink->subpicture
4381 #ifdef GST_EXT_XV_ENHANCEMENT
4384 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4385 if (g_display_id[i] == xcontext->disp) {
4386 g_display_id[i] = NULL;
4391 XCloseDisplay (xcontext->disp);
4392 g_mutex_unlock (xvimagesink->x_lock);
4393 g_free (xcontext->par);
4395 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
4399 #ifdef GST_EXT_XV_ENHANCEMENT
4400 if (!xvimagesink->subpicture) {
4401 #endif //GST_EXT_XV_ENHANCEMENT
4402 /* Search for XShm extension support */
4403 if (XShmQueryExtension (xcontext->disp) &&
4404 gst_xvimagesink_check_xshm_calls (xcontext)) {
4405 xcontext->use_xshm = TRUE;
4406 GST_DEBUG ("xvimagesink is using XShm extension");
4408 #endif /* HAVE_XSHM */
4410 xcontext->use_xshm = FALSE;
4411 GST_DEBUG ("xvimagesink is not using XShm extension");
4414 xv_attr = XvQueryPortAttributes (xcontext->disp,
4415 xcontext->xv_port_id, &N_attr);
4416 #ifdef GST_EXT_XV_ENHANCEMENT
4418 #endif //GST_EXT_XV_ENHANCEMENT
4420 /* Generate the channels list */
4421 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
4422 XvAttribute *matching_attr = NULL;
4424 /* Retrieve the property atom if it exists. If it doesn't exist,
4425 * the attribute itself must not either, so we can skip */
4426 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
4427 if (prop_atom == None)
4430 if (xv_attr != NULL) {
4431 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
4432 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
4433 matching_attr = xv_attr + j;
4436 if (matching_attr) {
4437 GstColorBalanceChannel *channel;
4439 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
4440 channel->label = g_strdup (channels[i]);
4441 channel->min_value = matching_attr->min_value;
4442 channel->max_value = matching_attr->max_value;
4444 xcontext->channels_list = g_list_append (xcontext->channels_list,
4447 /* If the colorbalance settings have not been touched we get Xv values
4448 as defaults and update our internal variables */
4449 if (!xvimagesink->cb_changed) {
4452 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
4454 /* Normalize val to [-1000, 1000] */
4455 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
4456 (double) (channel->max_value - channel->min_value));
4458 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
4459 xvimagesink->hue = val;
4460 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
4461 xvimagesink->saturation = val;
4462 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
4463 xvimagesink->brightness = val;
4464 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
4465 xvimagesink->contrast = val;
4469 #ifdef GST_EXT_XV_ENHANCEMENT
4470 if (!xvimagesink->subpicture) {
4474 #ifdef GST_EXT_XV_ENHANCEMENT
4476 if(!xvimagesink->subpicture) {
4477 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
4478 set_csc_range(xcontext, xvimagesink->csc_range);
4480 #endif /* GST_EXT_XV_ENHANCEMENT */
4482 g_mutex_unlock (xvimagesink->x_lock);
4487 /* This function cleans the X context. Closing the Display, releasing the XV
4488 port and unrefing the caps for supported formats. */
4490 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
4492 GList *formats_list, *channels_list = NULL;
4493 GstXContext *xcontext;
4496 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4498 GST_OBJECT_LOCK (xvimagesink);
4499 if (xvimagesink->xcontext == NULL) {
4500 GST_OBJECT_UNLOCK (xvimagesink);
4504 /* Take the XContext from the sink and clean it up */
4505 xcontext = xvimagesink->xcontext;
4506 xvimagesink->xcontext = NULL;
4508 GST_OBJECT_UNLOCK (xvimagesink);
4510 #ifdef GST_EXT_XV_ENHANCEMENT
4511 if (!xvimagesink->subpicture) {
4513 formats_list = xcontext->formats_list;
4515 while (formats_list) {
4516 GstXvImageFormat *format = formats_list->data;
4518 gst_caps_unref (format->caps);
4520 formats_list = g_list_next (formats_list);
4523 if (xcontext->formats_list)
4524 g_list_free (xcontext->formats_list);
4526 channels_list = xcontext->channels_list;
4527 #ifdef GST_EXT_XV_ENHANCEMENT
4530 while (channels_list) {
4531 GstColorBalanceChannel *channel = channels_list->data;
4533 g_object_unref (channel);
4534 channels_list = g_list_next (channels_list);
4537 if (xcontext->channels_list)
4538 g_list_free (xcontext->channels_list);
4540 gst_caps_unref (xcontext->caps);
4541 if (xcontext->last_caps)
4542 gst_caps_replace (&xcontext->last_caps, NULL);
4544 for (i = 0; i < xcontext->nb_adaptors; i++) {
4545 g_free (xcontext->adaptors[i]);
4548 g_free (xcontext->adaptors);
4550 g_free (xcontext->par);
4552 g_mutex_lock (xvimagesink->x_lock);
4554 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
4556 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4558 #ifdef GST_EXT_XV_ENHANCEMENT
4561 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4562 if (g_display_id[i] == xcontext->disp) {
4563 g_display_id[i] = NULL;
4568 XCloseDisplay (xcontext->disp);
4569 g_mutex_unlock (xvimagesink->x_lock);
4575 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
4577 g_mutex_lock (xvimagesink->pool_lock);
4579 while (xvimagesink->image_pool) {
4580 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
4582 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4583 xvimagesink->image_pool);
4584 gst_xvimage_buffer_free (xvimage);
4587 g_mutex_unlock (xvimagesink->pool_lock);
4592 /* This function tries to get a format matching with a given caps in the
4593 supported list of formats we generated in gst_xvimagesink_get_xv_support */
4595 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
4600 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
4602 list = xvimagesink->xcontext->formats_list;
4605 GstXvImageFormat *format = list->data;
4608 if (gst_caps_can_intersect (caps, format->caps)) {
4609 return format->format;
4612 list = g_list_next (list);
4619 gst_xvimagesink_getcaps (GstBaseSink * bsink)
4621 GstXvImageSink *xvimagesink;
4623 xvimagesink = GST_XVIMAGESINK (bsink);
4624 if (xvimagesink->xcontext
4625 #ifdef GST_EXT_XV_ENHANCEMENT
4626 && !xvimagesink->subpicture
4629 return gst_caps_ref (xvimagesink->xcontext->caps);
4632 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
4637 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
4639 GstXvImageSink *xvimagesink;
4640 GstStructure *structure;
4641 guint32 im_format = 0;
4643 gint video_width, video_height;
4644 gint disp_x, disp_y;
4645 gint disp_width, disp_height;
4646 gint video_par_n, video_par_d; /* video's PAR */
4647 gint display_par_n, display_par_d; /* display's PAR */
4648 const GValue *caps_par;
4649 const GValue *caps_disp_reg;
4652 #ifdef GST_EXT_XV_ENHANCEMENT
4654 gchar *str_in = gst_caps_to_string(caps);
4655 if(str_in == NULL) {
4656 GST_ERROR("gst_caps_to_string() returns NULL...");
4658 GST_INFO("In setcaps. incaps:%s", str_in);
4662 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
4664 xvimagesink = GST_XVIMAGESINK (bsink);
4666 GST_DEBUG_OBJECT (xvimagesink,
4667 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
4668 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
4670 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)
4671 #ifdef GST_EXT_XV_ENHANCEMENT
4672 && !xvimagesink->subpicture
4675 goto incompatible_caps;
4677 structure = gst_caps_get_structure (caps, 0);
4678 ret = gst_structure_get_int (structure, "width", &video_width);
4679 ret &= gst_structure_get_int (structure, "height", &video_height);
4680 fps = gst_structure_get_value (structure, "framerate");
4681 ret &= (fps != NULL);
4682 #ifdef GST_EXT_XV_ENHANCEMENT
4683 if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture)
4685 xvimagesink->is_subpicture_format = TRUE;
4686 GST_LOG("It is type of subpicture and subtitle.");
4690 goto incomplete_caps;
4692 #ifdef GST_EXT_XV_ENHANCEMENT
4693 xvimagesink->aligned_width = video_width;
4694 xvimagesink->aligned_height = video_height;
4696 #ifdef GST_EXT_ENABLE_HEVC
4697 /*get combine prop of hevc*/
4698 if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
4700 GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
4704 /*Not need to combine data, just directly copy*/
4705 xvimagesink->need_combine_data = 0;
4708 _remove_last_buffer(xvimagesink);
4709 #endif /* GST_EXT_XV_ENHANCEMENT */
4711 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
4712 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
4714 xvimagesink->video_width = video_width;
4715 xvimagesink->video_height = video_height;
4716 #ifdef GST_EXT_XV_ENHANCEMENT
4717 if (!xvimagesink->subpicture) {
4719 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
4720 if (im_format == -1)
4721 goto invalid_format;
4722 #ifdef GST_EXT_XV_ENHANCEMENT
4725 /* get aspect ratio from caps if it's present, and
4726 * convert video width and height to a display width and height
4727 * using wd / hd = wv / hv * PARv / PARd */
4729 /* get video's PAR */
4730 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
4732 video_par_n = gst_value_get_fraction_numerator (caps_par);
4733 video_par_d = gst_value_get_fraction_denominator (caps_par);
4738 /* get display's PAR */
4739 if (xvimagesink->par) {
4740 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
4741 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
4747 /* get the display region */
4748 caps_disp_reg = gst_structure_get_value (structure, "display-region");
4749 if (caps_disp_reg) {
4750 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
4751 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
4752 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
4754 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
4756 disp_x = disp_y = 0;
4757 disp_width = video_width;
4758 disp_height = video_height;
4761 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
4762 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
4765 xvimagesink->disp_x = disp_x;
4766 xvimagesink->disp_y = disp_y;
4767 xvimagesink->disp_width = disp_width;
4768 xvimagesink->disp_height = disp_height;
4770 GST_DEBUG_OBJECT (xvimagesink,
4771 "video width/height: %dx%d, calculated display ratio: %d/%d",
4772 video_width, video_height, num, den);
4774 /* now find a width x height that respects this display ratio.
4775 * prefer those that have one of w/h the same as the incoming video
4776 * using wd / hd = num / den */
4778 /* start with same height, because of interlaced video */
4779 /* check hd / den is an integer scale factor, and scale wd with the PAR */
4780 if (video_height % den == 0) {
4781 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
4782 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4783 gst_util_uint64_scale_int (video_height, num, den);
4784 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4785 } else if (video_width % num == 0) {
4786 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
4787 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
4788 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
4789 gst_util_uint64_scale_int (video_width, den, num);
4791 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
4792 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4793 gst_util_uint64_scale_int (video_height, num, den);
4794 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4796 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
4797 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
4799 /* Notify application to set xwindow id now */
4800 g_mutex_lock (xvimagesink->flow_lock);
4801 #ifdef GST_EXT_XV_ENHANCEMENT
4802 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4803 g_mutex_unlock (xvimagesink->flow_lock);
4804 gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
4806 if (!xvimagesink->xwindow) {
4807 g_mutex_unlock (xvimagesink->flow_lock);
4808 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
4811 g_mutex_unlock (xvimagesink->flow_lock);
4813 #ifdef GST_EXT_XV_ENHANCEMENT
4814 if (!xvimagesink->is_subpicture_format) {
4816 /* Creating our window and our image with the display size in pixels */
4817 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
4818 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
4819 goto no_display_size;
4821 g_mutex_lock (xvimagesink->flow_lock);
4822 #ifdef GST_EXT_XV_ENHANCEMENT
4823 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4824 GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
4826 if (!xvimagesink->xwindow) {
4828 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
4829 GST_VIDEO_SINK_WIDTH (xvimagesink),
4830 GST_VIDEO_SINK_HEIGHT (xvimagesink));
4834 /* After a resize, we want to redraw the borders in case the new frame size
4835 * doesn't cover the same area */
4836 xvimagesink->redraw_border = TRUE;
4838 /* We renew our xvimage only if size or format changed;
4839 * the xvimage is the same size as the video pixel size */
4840 if ((xvimagesink->xvimage) &&
4841 ((im_format != xvimagesink->xvimage->im_format) ||
4842 (video_width != xvimagesink->xvimage->width) ||
4843 (video_height != xvimagesink->xvimage->height)) &&
4844 (!xvimagesink->subpicture)) {
4845 GST_DEBUG_OBJECT (xvimagesink,
4846 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4847 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4848 GST_FOURCC_ARGS (im_format));
4849 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4850 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4851 xvimagesink->xvimage = NULL;
4854 #ifdef GST_EXT_XV_ENHANCEMENT
4855 /* In case of starting player with connecting external display, we have to check status.
4856 * It will be unconditionally executed. */
4857 if(!xvimagesink->is_subpicture_format)
4858 check_hdmi_connected(xvimagesink);
4860 g_mutex_unlock (xvimagesink->flow_lock);
4867 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4872 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4873 "height or framerate from intersected caps");
4878 GST_DEBUG_OBJECT (xvimagesink,
4879 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4884 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4885 ("Error calculating the output display ratio of the video."));
4890 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4891 ("Error calculating the output display ratio of the video."));
4894 #ifdef GST_EXT_XV_ENHANCEMENT
4898 static GstStateChangeReturn
4899 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4901 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4902 GstXvImageSink *xvimagesink;
4903 GstXContext *xcontext = NULL;
4904 #ifdef GST_EXT_XV_ENHANCEMENT
4905 Atom atom_preemption = None;
4906 #endif /* GST_EXT_XV_ENHANCEMENT */
4908 xvimagesink = GST_XVIMAGESINK (element);
4910 switch (transition) {
4911 case GST_STATE_CHANGE_NULL_TO_READY:
4912 #ifdef GST_EXT_XV_ENHANCEMENT
4913 GST_WARNING("NULL_TO_READY start");
4914 #endif /* GST_EXT_XV_ENHANCEMENT */
4915 /* Initializing the XContext */
4916 if (xvimagesink->xcontext == NULL) {
4917 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4918 if (xcontext == NULL)
4919 return GST_STATE_CHANGE_FAILURE;
4920 GST_OBJECT_LOCK (xvimagesink);
4922 xvimagesink->xcontext = xcontext;
4923 GST_OBJECT_UNLOCK (xvimagesink);
4926 /* update object's par with calculated one if not set yet */
4927 if (!xvimagesink->par) {
4928 xvimagesink->par = g_new0 (GValue, 1);
4929 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4930 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4932 /* call XSynchronize with the current value of synchronous */
4933 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4934 xvimagesink->synchronous ? "TRUE" : "FALSE");
4935 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4936 gst_xvimagesink_update_colorbalance (xvimagesink);
4937 gst_xvimagesink_manage_event_thread (xvimagesink);
4938 #ifdef GST_EXT_XV_ENHANCEMENT
4939 GST_WARNING("NULL_TO_READY done");
4940 #endif /* GST_EXT_XV_ENHANCEMENT */
4942 case GST_STATE_CHANGE_READY_TO_PAUSED:
4943 #ifdef GST_EXT_XV_ENHANCEMENT
4944 GST_WARNING("READY_TO_PAUSED start");
4945 #endif /* GST_EXT_XV_ENHANCEMENT */
4946 g_mutex_lock (xvimagesink->pool_lock);
4947 xvimagesink->pool_invalid = FALSE;
4948 g_mutex_unlock (xvimagesink->pool_lock);
4949 #ifdef GST_EXT_XV_ENHANCEMENT
4950 GST_WARNING("READY_TO_PAUSED done");
4951 #endif /* GST_EXT_XV_ENHANCEMENT */
4953 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4954 #ifdef GST_EXT_XV_ENHANCEMENT
4955 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING))
4956 GST_WARNING("vconf set fail");
4957 GST_WARNING("PAUSED_TO_PLAYING done");
4958 xvimagesink->is_during_seek = FALSE;
4959 xvimagesink->keep_external_fullscreen_prev = FALSE;
4960 #endif /* GST_EXT_XV_ENHANCEMENT */
4962 case GST_STATE_CHANGE_PAUSED_TO_READY:
4963 #ifdef GST_EXT_XV_ENHANCEMENT
4964 GST_WARNING("PAUSED_TO_READY start");
4965 #endif /* GST_EXT_XV_ENHANCEMENT */
4966 g_mutex_lock (xvimagesink->pool_lock);
4967 xvimagesink->pool_invalid = TRUE;
4968 g_mutex_unlock (xvimagesink->pool_lock);
4969 #ifdef GST_EXT_XV_ENHANCEMENT
4970 #endif /* GST_EXT_XV_ENHANCEMENT */
4976 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4978 switch (transition) {
4979 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4980 #ifdef GST_EXT_XV_ENHANCEMENT
4981 GST_WARNING("PLAYING_TO_PAUSED start");
4982 g_mutex_lock (xvimagesink->flow_lock);
4983 /* init displayed buffer count */
4984 xvimagesink->displayed_buffer_count = 0;
4986 g_mutex_lock (xvimagesink->x_lock);
4987 if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) {
4988 GST_WARNING_OBJECT(xvimagesink, "release external display mode");
4989 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
4990 xvimagesink->xwindow->win);
4991 XSync(xvimagesink->xcontext->disp, FALSE);
4992 xvimagesink->skip_frame_due_to_external_dev = TRUE;
4994 if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture)
4995 && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
4996 GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4997 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
4998 XSync(xvimagesink->xcontext->disp, FALSE);
5000 g_mutex_unlock (xvimagesink->x_lock);
5001 g_mutex_unlock (xvimagesink->flow_lock);
5002 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED))
5003 GST_WARNING("vconf set fail");
5004 GST_WARNING("PLAYING_TO_PAUSED done");
5005 #endif /* GST_EXT_XV_ENHANCEMENT */
5007 case GST_STATE_CHANGE_PAUSED_TO_READY:
5008 #ifdef GST_EXT_XV_ENHANCEMENT
5009 GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
5010 xvimagesink->is_zero_copy_format,
5011 xvimagesink->enable_flush_buffer,
5012 xvimagesink->secure_path,
5013 xvimagesink->get_pixmap_cb);
5015 if ((xvimagesink->enable_flush_buffer == FALSE ||
5016 xvimagesink->secure_path == SECURE_PATH_ON) &&
5017 xvimagesink->xcontext && xvimagesink->xwindow) {
5018 GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
5019 g_mutex_lock(xvimagesink->x_lock);
5020 XvStopVideo(xvimagesink->xcontext->disp,
5021 xvimagesink->xcontext->xv_port_id,
5022 xvimagesink->xwindow->win);
5023 XSync(xvimagesink->xcontext->disp, FALSE);
5024 g_mutex_unlock(xvimagesink->x_lock);
5025 _remove_last_buffer(xvimagesink);
5026 } else if (xvimagesink->is_zero_copy_format &&
5027 xvimagesink->xvimage &&
5028 xvimagesink->xvimage->xvimage &&
5029 !xvimagesink->get_pixmap_cb) {
5030 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5032 XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5033 memset(img_data, 0x0, sizeof(XV_DATA));
5034 XV_INIT_DATA(img_data);
5036 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5037 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5038 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5040 gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5042 GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
5044 /* check whether putimage is succeeded or not */
5045 g_mutex_lock(xvimagesink->display_buffer_lock);
5047 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5048 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
5049 if ((img_data->dmabuf_fd[0] > 0 &&
5050 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
5051 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
5052 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
5054 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
5055 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
5056 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
5057 GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
5063 if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
5064 GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
5065 _release_flush_buffer(xvimagesink);
5067 _remove_last_buffer(xvimagesink);
5070 g_mutex_unlock(xvimagesink->display_buffer_lock);
5073 #endif /* GST_EXT_XV_ENHANCEMENT */
5074 xvimagesink->fps_n = 0;
5075 xvimagesink->fps_d = 1;
5076 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
5077 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
5078 #ifdef GST_EXT_XV_ENHANCEMENT
5079 GST_WARNING("PAUSED_TO_READY done");
5080 #endif /* GST_EXT_XV_ENHANCEMENT */
5082 case GST_STATE_CHANGE_READY_TO_NULL:
5083 #ifdef GST_EXT_XV_ENHANCEMENT
5084 GST_WARNING("READY_TO_NULL start");
5085 #endif /* GST_EXT_XV_ENHANCEMENT */
5086 gst_xvimagesink_reset (xvimagesink);
5087 #ifdef GST_EXT_XV_ENHANCEMENT
5089 drm_fini(xvimagesink);
5090 /* init displaying_buffer_count */
5091 xvimagesink->displaying_buffer_count = 0;
5092 GST_WARNING("READY_TO_NULL done");
5093 #endif /* GST_EXT_XV_ENHANCEMENT */
5103 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
5104 GstClockTime * start, GstClockTime * end)
5106 GstXvImageSink *xvimagesink;
5108 xvimagesink = GST_XVIMAGESINK (bsink);
5110 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
5111 *start = GST_BUFFER_TIMESTAMP (buf);
5112 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
5113 *end = *start + GST_BUFFER_DURATION (buf);
5115 if (xvimagesink->fps_n > 0) {
5117 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
5118 xvimagesink->fps_n);
5124 #ifdef GST_EXT_ENABLE_HEVC
5126 gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
5128 unsigned int outsize = 0;
5129 unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
5131 unsigned char *temp_imgb;
5132 SCMN_IMGB *imgb = NULL;
5133 int stride, w, h, i;
5136 imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
5137 if(imgb == NULL || imgb->a[0] == NULL)
5142 stride = GST_ROUND_UP_4 (imgb->w[0]);
5146 for (i = 0; i < h; i++)
5148 memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
5151 temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
5153 stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
5154 h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
5155 w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
5157 for (i = 0; i < h; i++)
5159 memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
5162 temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
5163 /* Same stride, height, width as above */
5165 for (i = 0; i < h; i++)
5167 memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
5170 outsize = imgb->w[0] * imgb->h[0]* 3 >> 1;
5171 xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
5177 #ifdef GST_EXT_XV_ENHANCEMENT
5178 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
5180 GstXvImageFlushBuffer *flush_buffer = NULL;
5181 GstXvImageDisplayingBuffer *display_buffer = NULL;
5187 if (xvimagesink == NULL) {
5188 GST_ERROR("handle is NULL");
5192 if (xvimagesink->last_added_buffer_index == -1) {
5193 GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
5197 if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
5198 GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
5199 xvimagesink->drm_fd, xvimagesink->bufmgr);
5203 flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
5204 if (flush_buffer == NULL) {
5205 GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
5209 memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
5211 display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
5212 GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
5213 xvimagesink->last_added_buffer_index);
5215 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5216 if (display_buffer->bo[i]) {
5217 tbm_bo_handle vaddr_src;
5218 tbm_bo_handle vaddr_dst;
5221 size = tbm_bo_size(display_buffer->bo[i]);
5224 bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT);
5226 GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
5227 goto FLUSH_BUFFER_FAILED;
5230 GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
5232 flush_buffer->gem_name[i] = tbm_bo_export(bo);
5233 flush_buffer->bo[i] = bo;
5235 /* get virtual address */
5236 vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5237 vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
5238 if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
5239 GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
5240 vaddr_src.ptr, vaddr_dst.ptr);
5241 if (vaddr_src.ptr) {
5242 tbm_bo_unmap(display_buffer->bo[i]);
5244 if (vaddr_dst.ptr) {
5247 goto FLUSH_BUFFER_FAILED;
5251 memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
5253 tbm_bo_unmap(display_buffer->bo[i]);
5256 GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
5258 xvimagesink->flush_buffer = flush_buffer;
5266 FLUSH_BUFFER_FAILED:
5268 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5269 if (flush_buffer->bo[i]) {
5270 tbm_bo_unref(flush_buffer->bo[i]);
5271 flush_buffer->bo[i] = NULL;
5275 flush_buffer = NULL;
5280 #endif /* GST_EXT_XV_ENHANCEMENT */
5283 static GstFlowReturn
5284 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
5286 GstXvImageSink *xvimagesink;
5288 #ifdef GST_EXT_XV_ENHANCEMENT
5289 XV_DATA_PTR img_data = NULL;
5290 SCMN_IMGB *scmn_imgb = NULL;
5292 gboolean ret = FALSE;
5294 int (*handler) (Display *, XErrorEvent *) = NULL;
5296 #endif /* GST_EXT_XV_ENHANCEMENT */
5298 xvimagesink = GST_XVIMAGESINK (vsink);
5300 #ifdef GST_EXT_XV_ENHANCEMENT
5301 if (xvimagesink->stop_video) {
5302 GST_INFO( "Stop video is TRUE. so skip show frame..." );
5305 #endif /* GST_EXT_XV_ENHANCEMENT */
5307 /* If this buffer has been allocated using our buffer management we simply
5308 put the ximage which is in the PRIVATE pointer */
5309 if (GST_IS_XVIMAGE_BUFFER (buf)) {
5310 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
5311 #ifdef GST_EXT_XV_ENHANCEMENT
5312 xvimagesink->xid_updated = FALSE;
5313 #endif /* GST_EXT_XV_ENHANCEMENT */
5314 if (!gst_xvimagesink_xvimage_put (xvimagesink,
5315 GST_XVIMAGE_BUFFER_CAST (buf)))
5318 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
5319 "slow copy into bufferpool buffer %p", buf);
5320 /* Else we have to copy the data into our private image, */
5321 /* if we have one... */
5322 #ifdef GST_EXT_XV_ENHANCEMENT
5323 g_mutex_lock (xvimagesink->flow_lock);
5324 if (xvimagesink->skip_frame_due_to_external_dev) {
5325 GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." );
5326 xvimagesink->skip_frame_due_to_external_dev = FALSE;
5327 g_mutex_unlock (xvimagesink->flow_lock);
5331 #endif /* GST_EXT_XV_ENHANCEMENT */
5332 if (!xvimagesink->xvimage
5333 #ifdef GST_EXT_XV_ENHANCEMENT
5334 && !xvimagesink->is_subpicture_format
5337 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
5339 #ifdef GST_EXT_XV_ENHANCEMENT
5340 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
5342 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
5343 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
5344 case GST_MAKE_FOURCC('S', 'N', '2', '1'):
5345 case GST_MAKE_FOURCC('S', '4', '2', '0'):
5346 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
5347 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
5348 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
5349 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
5350 case GST_MAKE_FOURCC('S', 'R', '3', '2'):
5351 case GST_MAKE_FOURCC('S', 'V', '1', '2'):
5352 xvimagesink->is_zero_copy_format = TRUE;
5353 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5354 if(scmn_imgb == NULL) {
5355 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5356 g_mutex_unlock (xvimagesink->flow_lock);
5360 /* skip buffer if aligned size is smaller than size of caps */
5361 if (scmn_imgb->s[0] < xvimagesink->video_width ||
5362 scmn_imgb->e[0] < xvimagesink->video_height) {
5363 GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
5364 xvimagesink->video_width, xvimagesink->video_height,
5365 scmn_imgb->s[0], scmn_imgb->e[0]);
5366 g_mutex_unlock (xvimagesink->flow_lock);
5370 xvimagesink->aligned_width = scmn_imgb->s[0];
5371 xvimagesink->aligned_height = scmn_imgb->e[0];
5372 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
5373 xvimagesink->aligned_width, xvimagesink->aligned_height);
5376 xvimagesink->is_zero_copy_format = FALSE;
5377 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
5381 GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
5382 #endif /* GST_EXT_XV_ENHANCEMENT */
5384 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
5385 GST_BUFFER_CAPS (buf));
5387 if (!xvimagesink->xvimage)
5388 /* The create method should have posted an informative error */
5391 #ifdef GST_EXT_XV_ENHANCEMENT
5392 if ((xvimagesink->is_zero_copy_format == FALSE &&
5393 xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
5394 (xvimagesink->is_zero_copy_format &&
5395 xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
5396 #else /* GST_EXT_XV_ENHANCEMENT */
5397 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
5398 #endif /* GST_EXT_XV_ENHANCEMENT */
5399 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
5400 ("Failed to create output image buffer of %dx%d pixels",
5401 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
5402 ("XServer allocated buffer size did not match input buffer"));
5404 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
5405 xvimagesink->xvimage = NULL;
5410 #ifdef GST_EXT_XV_ENHANCEMENT
5411 if (xvimagesink->is_zero_copy_format) {
5412 /* Cases for specified formats of Samsung extension */
5413 GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
5414 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
5415 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
5416 xvimagesink->display_mode, xvimagesink->rotate_angle);
5418 if (xvimagesink->xvimage->xvimage->data) {
5420 img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5421 memset(img_data, 0x0, sizeof(XV_DATA));
5422 XV_INIT_DATA(img_data);
5424 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5425 if (scmn_imgb == NULL) {
5426 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5427 g_mutex_unlock (xvimagesink->flow_lock);
5431 /* Keep the vaddr of current image for copying last image */
5432 if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
5433 for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
5434 xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
5436 GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5437 xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
5440 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
5441 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
5442 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
5443 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
5444 img_data->BufType = XV_BUF_TYPE_LEGACY;
5446 GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5447 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
5448 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
5449 scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
5450 gboolean do_set_secure = FALSE;
5452 /* open drm to use gem */
5453 if (xvimagesink->drm_fd < 0) {
5454 drm_init(xvimagesink);
5457 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
5458 /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
5459 img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
5460 img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
5461 img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
5462 img_data->BufType = XV_BUF_TYPE_DMABUF;
5463 GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
5465 /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
5466 img_data->bo[0] = scmn_imgb->bo[0];
5467 img_data->bo[1] = scmn_imgb->bo[1];
5468 img_data->bo[2] = scmn_imgb->bo[2];
5469 GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
5472 /* check secure contents path */
5473 if (scmn_imgb->tz_enable) {
5474 if (xvimagesink->secure_path != SECURE_PATH_ON) {
5475 xvimagesink->secure_path = SECURE_PATH_ON;
5476 do_set_secure = TRUE;
5479 if (xvimagesink->secure_path != SECURE_PATH_OFF) {
5480 xvimagesink->secure_path = SECURE_PATH_OFF;
5481 do_set_secure = TRUE;
5484 static gboolean is_exist = FALSE;
5485 gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE");
5486 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5489 if (do_set_secure && is_exist) {
5490 Atom atom_secure = None;
5491 g_mutex_lock (xvimagesink->x_lock);
5492 atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
5493 if (atom_secure != None) {
5494 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
5495 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
5497 GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
5499 XSync (xvimagesink->xcontext->disp, FALSE);
5501 GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
5503 g_mutex_unlock (xvimagesink->x_lock);
5507 attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5508 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5512 if (xvimagesink->drm_level && is_exist) {
5513 Atom atom_drm = None;
5514 g_mutex_lock (xvimagesink->x_lock);
5515 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5516 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5517 if (atom_drm != None) {
5518 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5519 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5520 xvimagesink->xcontext->xv_port_id,
5521 atom_drm, xvimagesink->drm_level ) != Success) {
5522 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5524 XSync (xvimagesink->xcontext->disp, FALSE);
5525 g_mutex_unlock (xvimagesink->x_lock);
5526 xvimagesink->drm_level = DRM_LEVEL_0;
5530 /* set current buffer */
5531 xvimagesink->xvimage->current_buffer = buf;
5532 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) {
5533 /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
5534 GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
5535 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5536 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5537 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5538 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5540 g_mutex_unlock(xvimagesink->flow_lock);
5544 GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
5545 scmn_imgb->buf_share_method);
5546 g_mutex_unlock (xvimagesink->flow_lock);
5550 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
5551 g_mutex_unlock (xvimagesink->flow_lock);
5554 } else if (xvimagesink->is_subpicture_format) {
5556 xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf);
5557 if(!xvimagesink->pixmap_for_subpicture) {
5558 GST_ERROR("no pixmap");
5559 g_mutex_unlock (xvimagesink->flow_lock);
5562 if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) {
5563 GST_ERROR("pixmap's size and current resolution are different");
5564 g_mutex_unlock (xvimagesink->flow_lock);
5567 gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0);
5569 GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture,
5570 xvimagesink->xcontext->xv_port_id, gc);
5572 /* set error handler */
5573 error_caught = FALSE;
5574 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
5576 if(!xvimagesink->set_overlay_for_subpicture_just_once)
5578 GST_LOG("setting attribute overlay");
5579 atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE);
5580 XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1);
5581 XSync (xvimagesink->xcontext->disp, FALSE);
5582 xvimagesink->set_overlay_for_subpicture_just_once = TRUE;
5584 res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
5585 xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height,
5586 0, 0, xvimagesink->external_width, xvimagesink->external_height);
5587 XSync (xvimagesink->xcontext->disp, FALSE);
5589 GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n",
5590 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
5591 GST_TIME_ARGS(GST_BUFFER_DURATION(buf)),
5592 GST_BUFFER_SIZE(buf));
5594 GST_DEBUG("FreeGC");
5595 XFreeGC (xvimagesink->xcontext->disp, gc);
5598 GST_WARNING_OBJECT(xvimagesink, "XvGetStill error");
5600 GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height);
5602 /* Reset error handler */
5604 error_caught = FALSE;
5605 XSetErrorHandler (handler);
5608 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
5610 #ifdef GST_EXT_ENABLE_HEVC
5611 if(xvimagesink->need_combine_data == 1)
5613 gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
5618 memcpy (xvimagesink->xvimage->xvimage->data,
5619 GST_BUFFER_DATA (buf),
5620 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5624 g_mutex_unlock (xvimagesink->flow_lock);
5625 ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5626 if (!ret && !xvimagesink->is_subpicture_format) {
5629 #else /* GST_EXT_XV_ENHANCEMENT */
5630 memcpy (xvimagesink->xvimage->xvimage->data,
5631 GST_BUFFER_DATA (buf),
5632 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5634 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
5636 #endif /* GST_EXT_XV_ENHANCEMENT */
5644 /* No image available. That's very bad ! */
5645 GST_WARNING_OBJECT (xvimagesink, "could not create image");
5646 #ifdef GST_EXT_XV_ENHANCEMENT
5647 g_mutex_unlock (xvimagesink->flow_lock);
5649 return GST_FLOW_ERROR;
5653 /* No Window available to put our image into */
5654 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
5655 return GST_FLOW_ERROR;
5660 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
5662 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
5663 if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)
5665 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK))
5666 GST_WARNING("vconf set fail");
5669 switch (GST_EVENT_TYPE (event)) {
5670 case GST_EVENT_TAG:{
5672 gchar *title = NULL;
5674 gst_event_parse_tag (event, &l);
5675 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
5678 #ifdef GST_EXT_XV_ENHANCEMENT
5679 if (!xvimagesink->get_pixmap_cb) {
5681 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
5682 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
5686 #ifdef GST_EXT_XV_ENHANCEMENT
5692 #ifdef GST_EXT_XV_ENHANCEMENT
5693 case GST_EVENT_FLUSH_START:
5694 GST_DEBUG_OBJECT (xvimagesink, "flush start");
5696 case GST_EVENT_FLUSH_STOP:
5697 GST_DEBUG_OBJECT (xvimagesink, "flush stop");
5698 xvimagesink->is_during_seek = TRUE;
5700 case GST_EVENT_CUSTOM_DOWNSTREAM:
5702 const GstStructure *st = NULL;
5703 st = gst_event_get_structure (event);
5705 GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
5707 if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
5708 GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
5709 xvimagesink->drm_level = DRM_LEVEL_1;
5710 if (xvimagesink->drm_level && xvimagesink->xcontext) {
5711 static gboolean is_exist = FALSE;
5712 gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
5713 is_exist = check_supportable_port_attr(xvimagesink, attr_name);
5718 Atom atom_drm = None;
5719 g_mutex_lock (xvimagesink->x_lock);
5720 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5721 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5722 if (atom_drm != None) {
5723 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5724 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5725 xvimagesink->xcontext->xv_port_id,
5726 atom_drm, xvimagesink->drm_level ) != Success) {
5727 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5729 XSync (xvimagesink->xcontext->disp, FALSE);
5730 xvimagesink->drm_level = DRM_LEVEL_0;
5732 g_mutex_unlock (xvimagesink->x_lock);
5740 xvimagesink->eos_received = TRUE;
5741 GST_DEBUG_OBJECT(xvimagesink, "got eos");
5743 case GST_EVENT_NEWSEGMENT:
5744 xvimagesink->eos_received = FALSE;
5745 GST_DEBUG_OBJECT(xvimagesink, "got newsegment event");
5751 if (GST_BASE_SINK_CLASS (parent_class)->event)
5752 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
5757 /* Buffer management */
5760 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
5763 GstCaps *intersection;
5767 gint par_n = 1, par_d = 1;
5771 new_caps = gst_caps_copy (caps);
5773 s = gst_caps_get_structure (new_caps, 0);
5775 gst_structure_get_int (s, "width", &width);
5776 gst_structure_get_int (s, "height", &height);
5777 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
5779 gst_structure_remove_field (s, "width");
5780 gst_structure_remove_field (s, "height");
5781 gst_structure_remove_field (s, "pixel-aspect-ratio");
5783 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5784 gst_caps_unref (new_caps);
5786 if (gst_caps_is_empty (intersection))
5787 return intersection;
5789 s = gst_caps_get_structure (intersection, 0);
5791 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
5793 /* xvimagesink supports all PARs */
5795 gst_structure_fixate_field_nearest_int (s, "width", width);
5796 gst_structure_fixate_field_nearest_int (s, "height", height);
5797 gst_structure_get_int (s, "width", &w);
5798 gst_structure_get_int (s, "height", &h);
5800 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
5801 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
5804 return intersection;
5807 static GstFlowReturn
5808 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
5809 GstCaps * caps, GstBuffer ** buf)
5811 GstFlowReturn ret = GST_FLOW_OK;
5812 GstXvImageSink *xvimagesink;
5813 GstXvImageBuffer *xvimage = NULL;
5814 GstCaps *intersection = NULL;
5815 GstStructure *structure = NULL;
5816 gint width, height, image_format;
5818 xvimagesink = GST_XVIMAGESINK (bsink);
5820 if (G_UNLIKELY (!caps))
5823 g_mutex_lock (xvimagesink->pool_lock);
5824 if (G_UNLIKELY (xvimagesink->pool_invalid))
5827 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
5828 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
5829 GST_LOG_OBJECT (xvimagesink,
5830 "buffer alloc for same last_caps, reusing caps");
5831 intersection = gst_caps_ref (caps);
5832 image_format = xvimagesink->xcontext->last_format;
5833 width = xvimagesink->xcontext->last_width;
5834 height = xvimagesink->xcontext->last_height;
5836 goto reuse_last_caps;
5839 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
5840 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
5841 caps, xvimagesink->xcontext->caps);
5843 /* Check the caps against our xcontext */
5844 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
5846 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
5847 GST_PTR_FORMAT, intersection);
5849 if (gst_caps_is_empty (intersection)) {
5852 gst_caps_unref (intersection);
5854 /* So we don't support this kind of buffer, let's define one we'd like */
5855 new_caps = gst_caps_copy (caps);
5857 structure = gst_caps_get_structure (new_caps, 0);
5858 if (!gst_structure_has_field (structure, "width") ||
5859 !gst_structure_has_field (structure, "height")) {
5860 gst_caps_unref (new_caps);
5864 /* Try different dimensions */
5866 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5868 if (gst_caps_is_empty (intersection)) {
5869 /* Try with different YUV formats first */
5870 gst_structure_set_name (structure, "video/x-raw-yuv");
5872 /* Remove format specific fields */
5873 gst_structure_remove_field (structure, "format");
5874 gst_structure_remove_field (structure, "endianness");
5875 gst_structure_remove_field (structure, "depth");
5876 gst_structure_remove_field (structure, "bpp");
5877 gst_structure_remove_field (structure, "red_mask");
5878 gst_structure_remove_field (structure, "green_mask");
5879 gst_structure_remove_field (structure, "blue_mask");
5880 gst_structure_remove_field (structure, "alpha_mask");
5882 /* Reuse intersection with Xcontext */
5883 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5886 if (gst_caps_is_empty (intersection)) {
5887 /* Try with different dimensions and YUV formats */
5889 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5892 if (gst_caps_is_empty (intersection)) {
5893 /* Now try with RGB */
5894 gst_structure_set_name (structure, "video/x-raw-rgb");
5895 /* And interset again */
5896 gst_caps_unref (intersection);
5897 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5900 if (gst_caps_is_empty (intersection)) {
5901 /* Try with different dimensions and RGB formats */
5903 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5906 /* Clean this copy */
5907 gst_caps_unref (new_caps);
5909 if (gst_caps_is_empty (intersection))
5913 /* Ensure the returned caps are fixed */
5914 gst_caps_truncate (intersection);
5916 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
5917 GST_PTR_FORMAT, intersection);
5918 if (gst_caps_is_equal (intersection, caps)) {
5919 /* Things work better if we return a buffer with the same caps ptr
5920 * as was asked for when we can */
5921 gst_caps_replace (&intersection, caps);
5924 /* Get image format from caps */
5925 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
5928 /* Get geometry from caps */
5929 structure = gst_caps_get_structure (intersection, 0);
5930 if (!gst_structure_get_int (structure, "width", &width) ||
5931 !gst_structure_get_int (structure, "height", &height) ||
5935 /* Store our caps and format as the last_caps to avoid expensive
5936 * caps intersection next time */
5937 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
5938 xvimagesink->xcontext->last_format = image_format;
5939 xvimagesink->xcontext->last_width = width;
5940 xvimagesink->xcontext->last_height = height;
5944 /* Walking through the pool cleaning unusable images and searching for a
5946 while (xvimagesink->image_pool) {
5947 xvimage = xvimagesink->image_pool->data;
5950 /* Removing from the pool */
5951 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
5952 xvimagesink->image_pool);
5954 /* We check for geometry or image format changes */
5955 if ((xvimage->width != width) ||
5956 (xvimage->height != height) || (xvimage->im_format != image_format)) {
5957 /* This image is unusable. Destroying... */
5958 gst_xvimage_buffer_free (xvimage);
5961 /* We found a suitable image */
5962 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
5969 #ifdef GST_EXT_XV_ENHANCEMENT
5970 /* init aligned size */
5971 xvimagesink->aligned_width = 0;
5972 xvimagesink->aligned_height = 0;
5973 #endif /* GST_EXT_XV_ENHANCEMENT */
5975 /* We found no suitable image in the pool. Creating... */
5976 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
5977 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
5979 g_mutex_unlock (xvimagesink->pool_lock);
5982 /* Make sure the buffer is cleared of any previously used flags */
5983 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
5984 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
5987 *buf = GST_BUFFER_CAST (xvimage);
5991 gst_caps_unref (intersection);
5999 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
6000 ret = GST_FLOW_WRONG_STATE;
6001 g_mutex_unlock (xvimagesink->pool_lock);
6006 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
6007 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
6008 " are completely incompatible with those caps", caps,
6009 xvimagesink->xcontext->caps);
6010 ret = GST_FLOW_NOT_NEGOTIATED;
6011 g_mutex_unlock (xvimagesink->pool_lock);
6016 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
6017 GST_PTR_FORMAT, intersection);
6018 ret = GST_FLOW_NOT_NEGOTIATED;
6019 g_mutex_unlock (xvimagesink->pool_lock);
6024 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
6031 /* Interfaces stuff */
6034 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
6036 if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
6037 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
6044 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
6046 klass->supported = gst_xvimagesink_interface_supported;
6050 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
6051 GstStructure * structure)
6053 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
6056 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
6058 GstVideoRectangle src, dst, result;
6059 gdouble x, y, xscale = 1.0, yscale = 1.0;
6061 event = gst_event_new_navigation (structure);
6063 /* We take the flow_lock while we look at the window */
6064 g_mutex_lock (xvimagesink->flow_lock);
6066 if (!xvimagesink->xwindow) {
6067 g_mutex_unlock (xvimagesink->flow_lock);
6071 if (xvimagesink->keep_aspect) {
6072 /* We get the frame position using the calculated geometry from _setcaps
6073 that respect pixel aspect ratios */
6074 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
6075 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
6076 dst.w = xvimagesink->render_rect.w;
6077 dst.h = xvimagesink->render_rect.h;
6079 gst_video_sink_center_rect (src, dst, &result, TRUE);
6080 result.x += xvimagesink->render_rect.x;
6081 result.y += xvimagesink->render_rect.y;
6083 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
6086 g_mutex_unlock (xvimagesink->flow_lock);
6088 /* We calculate scaling using the original video frames geometry to include
6089 pixel aspect ratio scaling. */
6090 xscale = (gdouble) xvimagesink->video_width / result.w;
6091 yscale = (gdouble) xvimagesink->video_height / result.h;
6093 /* Converting pointer coordinates to the non scaled geometry */
6094 if (gst_structure_get_double (structure, "pointer_x", &x)) {
6095 x = MIN (x, result.x + result.w);
6096 x = MAX (x - result.x, 0);
6097 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
6098 (gdouble) x * xscale, NULL);
6100 if (gst_structure_get_double (structure, "pointer_y", &y)) {
6101 y = MIN (y, result.y + result.h);
6102 y = MAX (y - result.y, 0);
6103 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
6104 (gdouble) y * yscale, NULL);
6107 gst_pad_send_event (peer, event);
6108 gst_object_unref (peer);
6113 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
6115 iface->send_event = gst_xvimagesink_navigation_send_event;
6118 #ifdef GST_EXT_XV_ENHANCEMENT
6120 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
6124 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6125 GstXPixmap *xpixmap = NULL;
6126 int (*handler) (Display *, XErrorEvent *);
6128 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6130 if (xvimagesink->subpicture)
6133 /* If the element has not initialized the X11 context try to do so */
6134 if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6135 /* we have thrown a GST_ELEMENT_ERROR now */
6139 gst_xvimagesink_update_colorbalance (xvimagesink);
6141 GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
6143 /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
6144 if (pixmap_id == 0) {
6145 xvimagesink->current_pixmap_idx = -2;
6149 g_mutex_lock (xvimagesink->x_lock);
6151 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6152 if (!xvimagesink->xpixmap[i]) {
6156 unsigned int cur_win_width = 0;
6157 unsigned int cur_win_height = 0;
6158 unsigned int cur_win_border_width = 0;
6159 unsigned int cur_win_depth = 0;
6161 GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
6163 xpixmap = g_new0 (GstXPixmap, 1);
6165 xpixmap->pixmap = pixmap_id;
6167 /* Get root window and size of current window */
6168 XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
6169 &cur_win_x, &cur_win_y, /* relative x, y */
6170 &cur_win_width, &cur_win_height,
6171 &cur_win_border_width, &cur_win_depth);
6172 if (!cur_win_width || !cur_win_height) {
6173 GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
6174 g_mutex_unlock (xvimagesink->x_lock);
6177 xpixmap->width = cur_win_width;
6178 xpixmap->height = cur_win_height;
6180 if (!xvimagesink->render_rect.w)
6181 xvimagesink->render_rect.w = cur_win_width;
6182 if (!xvimagesink->render_rect.h)
6183 xvimagesink->render_rect.h = cur_win_height;
6185 /* Setting an error handler to catch failure */
6186 error_caught = FALSE;
6187 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6190 xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
6192 XSync(xvimagesink->xcontext->disp, FALSE);
6194 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
6197 error_caught = FALSE;
6198 XSetErrorHandler (handler);
6201 xvimagesink->xpixmap[i] = xpixmap;
6202 xvimagesink->current_pixmap_idx = i;
6204 GST_ERROR("failed to create xpixmap errno: %d", errno);
6207 g_mutex_unlock (xvimagesink->x_lock);
6210 } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
6211 GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
6212 xvimagesink->current_pixmap_idx = i;
6214 g_mutex_unlock (xvimagesink->x_lock);
6222 GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
6223 xvimagesink->current_pixmap_idx = -1;
6225 g_mutex_unlock (xvimagesink->x_lock);
6228 #endif /* GST_EXT_XV_ENHANCEMENT */
6231 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
6233 XID xwindow_id = id;
6234 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6235 GstXWindow *xwindow = NULL;
6236 #ifdef GST_EXT_XV_ENHANCEMENT
6237 GstState current_state = GST_STATE_NULL;
6238 int (*handler) (Display *, XErrorEvent *);
6239 #endif /* GST_EXT_XV_ENHANCEMENT */
6241 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6243 g_mutex_lock (xvimagesink->flow_lock);
6245 #ifdef GST_EXT_XV_ENHANCEMENT
6246 gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
6247 GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
6248 xwindow_id, current_state);
6249 #endif /* GST_EXT_XV_ENHANCEMENT */
6251 /* If we already use that window return */
6252 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
6253 g_mutex_unlock (xvimagesink->flow_lock);
6257 /* If the element has not initialized the X11 context try to do so */
6258 if (!xvimagesink->xcontext &&
6259 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
6260 g_mutex_unlock (xvimagesink->flow_lock);
6261 /* we have thrown a GST_ELEMENT_ERROR now */
6265 gst_xvimagesink_update_colorbalance (xvimagesink);
6267 /* Clear image pool as the images are unusable anyway */
6268 gst_xvimagesink_imagepool_clear (xvimagesink);
6270 /* Clear the xvimage */
6271 if (xvimagesink->xvimage) {
6272 gst_xvimage_buffer_free (xvimagesink->xvimage);
6273 xvimagesink->xvimage = NULL;
6276 /* If a window is there already we destroy it */
6277 if (xvimagesink->xwindow) {
6278 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
6279 xvimagesink->xwindow = NULL;
6282 /* If the xid is 0 we go back to an internal window */
6283 if (xwindow_id == 0) {
6284 /* If no width/height caps nego did not happen window will be created
6285 during caps nego then */
6286 #ifdef GST_EXT_XV_ENHANCEMENT
6287 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
6288 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
6289 #endif /* GST_EXT_XV_ENHANCEMENT */
6290 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
6291 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
6293 gst_xvimagesink_xwindow_new (xvimagesink,
6294 GST_VIDEO_SINK_WIDTH (xvimagesink),
6295 GST_VIDEO_SINK_HEIGHT (xvimagesink));
6298 XWindowAttributes attr;
6300 xwindow = g_new0 (GstXWindow, 1);
6301 xwindow->win = xwindow_id;
6303 /* Set the event we want to receive and create a GC */
6304 g_mutex_lock (xvimagesink->x_lock);
6306 if(!xvimagesink->is_pixmap)
6307 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
6309 xwindow->width = attr.width;
6310 xwindow->height = attr.height;
6311 xwindow->internal = FALSE;
6312 if (!xvimagesink->have_render_rect) {
6313 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
6314 xvimagesink->render_rect.w = attr.width;
6315 xvimagesink->render_rect.h = attr.height;
6317 if (xvimagesink->handle_events) {
6318 #ifdef GST_EXT_XV_ENHANCEMENT
6319 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6320 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6321 StructureNotifyMask | PointerMotionMask | KeyPressMask |
6322 KeyReleaseMask | PropertyChangeMask);
6324 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6325 StructureNotifyMask | PointerMotionMask | KeyPressMask |
6330 #ifdef GST_EXT_XV_ENHANCEMENT
6331 /* Setting an error handler to catch failure */
6332 error_caught = FALSE;
6333 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6335 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
6336 xwindow->win, 0, NULL);
6337 #ifdef GST_EXT_XV_ENHANCEMENT
6338 XSync(xvimagesink->xcontext->disp, FALSE);
6340 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
6343 error_caught = FALSE;
6344 XSetErrorHandler (handler);
6347 g_mutex_unlock (xvimagesink->x_lock);
6351 xvimagesink->xwindow = xwindow;
6353 #ifdef GST_EXT_XV_ENHANCEMENT
6354 xvimagesink->xid_updated = TRUE;
6355 #endif /* GST_EXT_XV_ENHANCEMENT */
6357 g_mutex_unlock (xvimagesink->flow_lock);
6359 #ifdef GST_EXT_XV_ENHANCEMENT
6360 if (current_state == GST_STATE_PAUSED) {
6361 GstBuffer *last_buffer = NULL;
6362 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
6363 GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
6365 gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
6366 gst_buffer_unref(last_buffer);
6370 #endif /* GST_EXT_XV_ENHANCEMENT */
6374 gst_xvimagesink_expose (GstXOverlay * overlay)
6376 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6378 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
6379 #ifdef GST_EXT_XV_ENHANCEMENT
6380 GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
6381 #endif /* GST_EXT_XV_ENHANCEMENT */
6382 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
6386 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
6387 gboolean handle_events)
6389 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6391 xvimagesink->handle_events = handle_events;
6393 g_mutex_lock (xvimagesink->flow_lock);
6395 if (G_UNLIKELY (!xvimagesink->xwindow)) {
6396 g_mutex_unlock (xvimagesink->flow_lock);
6400 g_mutex_lock (xvimagesink->x_lock);
6402 if (handle_events) {
6403 if (xvimagesink->xwindow->internal) {
6404 #ifdef GST_EXT_XV_ENHANCEMENT
6405 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6407 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6408 #ifdef GST_EXT_XV_ENHANCEMENT
6409 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6410 #else /* GST_EXT_XV_ENHANCEMENT */
6411 ExposureMask | StructureNotifyMask | PointerMotionMask |
6412 #endif /* GST_EXT_XV_ENHANCEMENT */
6413 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
6415 #ifdef GST_EXT_XV_ENHANCEMENT
6416 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
6418 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6419 #ifdef GST_EXT_XV_ENHANCEMENT
6420 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
6421 #else /* GST_EXT_XV_ENHANCEMENT */
6422 ExposureMask | StructureNotifyMask | PointerMotionMask |
6423 #endif /* GST_EXT_XV_ENHANCEMENT */
6424 KeyPressMask | KeyReleaseMask);
6427 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
6430 g_mutex_unlock (xvimagesink->x_lock);
6432 g_mutex_unlock (xvimagesink->flow_lock);
6436 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
6437 gint width, gint height)
6439 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6441 /* FIXME: how about some locking? */
6442 if (width >= 0 && height >= 0) {
6443 xvimagesink->render_rect.x = x;
6444 xvimagesink->render_rect.y = y;
6445 xvimagesink->render_rect.w = width;
6446 xvimagesink->render_rect.h = height;
6447 xvimagesink->have_render_rect = TRUE;
6449 xvimagesink->render_rect.x = 0;
6450 xvimagesink->render_rect.y = 0;
6451 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
6452 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
6453 xvimagesink->have_render_rect = FALSE;
6458 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
6460 iface->set_window_handle = gst_xvimagesink_set_window_handle;
6461 iface->expose = gst_xvimagesink_expose;
6462 iface->handle_events = gst_xvimagesink_set_event_handling;
6463 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
6466 static const GList *
6467 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
6469 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6471 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
6473 if (xvimagesink->xcontext)
6474 return xvimagesink->xcontext->channels_list;
6480 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
6481 GstColorBalanceChannel * channel, gint value)
6483 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6485 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6486 g_return_if_fail (channel->label != NULL);
6488 xvimagesink->cb_changed = TRUE;
6490 /* Normalize val to [-1000, 1000] */
6491 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
6492 (double) (channel->max_value - channel->min_value));
6494 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6495 xvimagesink->hue = value;
6496 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6497 xvimagesink->saturation = value;
6498 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6499 xvimagesink->contrast = value;
6500 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6501 xvimagesink->brightness = value;
6503 g_warning ("got an unknown channel %s", channel->label);
6507 gst_xvimagesink_update_colorbalance (xvimagesink);
6511 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
6512 GstColorBalanceChannel * channel)
6514 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6517 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
6518 g_return_val_if_fail (channel->label != NULL, 0);
6520 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6521 value = xvimagesink->hue;
6522 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6523 value = xvimagesink->saturation;
6524 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6525 value = xvimagesink->contrast;
6526 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6527 value = xvimagesink->brightness;
6529 g_warning ("got an unknown channel %s", channel->label);
6532 /* Normalize val to [channel->min_value, channel->max_value] */
6533 value = channel->min_value + (channel->max_value - channel->min_value) *
6534 (value + 1000) / 2000;
6540 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
6542 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
6543 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
6544 iface->set_value = gst_xvimagesink_colorbalance_set_value;
6545 iface->get_value = gst_xvimagesink_colorbalance_get_value;
6548 static const GList *
6549 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
6551 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
6552 static GList *list = NULL;
6555 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
6557 g_list_append (list, g_object_class_find_property (klass,
6558 "autopaint-colorkey"));
6560 g_list_append (list, g_object_class_find_property (klass,
6563 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
6570 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
6571 guint prop_id, const GParamSpec * pspec)
6573 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6577 case PROP_AUTOPAINT_COLORKEY:
6578 case PROP_DOUBLE_BUFFER:
6580 GST_DEBUG_OBJECT (xvimagesink,
6581 "probing device list and get capabilities");
6582 if (!xvimagesink->xcontext) {
6583 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
6584 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
6588 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6594 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
6595 guint prop_id, const GParamSpec * pspec)
6597 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6598 gboolean ret = FALSE;
6602 case PROP_AUTOPAINT_COLORKEY:
6603 case PROP_DOUBLE_BUFFER:
6605 if (xvimagesink->xcontext != NULL) {
6612 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6619 static GValueArray *
6620 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
6621 guint prop_id, const GParamSpec * pspec)
6623 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6624 GValueArray *array = NULL;
6626 if (G_UNLIKELY (!xvimagesink->xcontext)) {
6627 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
6636 GValue value = { 0 };
6638 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
6639 g_value_init (&value, G_TYPE_STRING);
6641 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
6642 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
6644 g_value_set_string (&value, adaptor_id_s);
6645 g_value_array_append (array, &value);
6646 g_free (adaptor_id_s);
6648 g_value_unset (&value);
6651 case PROP_AUTOPAINT_COLORKEY:
6652 if (xvimagesink->have_autopaint_colorkey) {
6653 GValue value = { 0 };
6655 array = g_value_array_new (2);
6656 g_value_init (&value, G_TYPE_BOOLEAN);
6657 g_value_set_boolean (&value, FALSE);
6658 g_value_array_append (array, &value);
6659 g_value_set_boolean (&value, TRUE);
6660 g_value_array_append (array, &value);
6661 g_value_unset (&value);
6664 case PROP_DOUBLE_BUFFER:
6665 if (xvimagesink->have_double_buffer) {
6666 GValue value = { 0 };
6668 array = g_value_array_new (2);
6669 g_value_init (&value, G_TYPE_BOOLEAN);
6670 g_value_set_boolean (&value, FALSE);
6671 g_value_array_append (array, &value);
6672 g_value_set_boolean (&value, TRUE);
6673 g_value_array_append (array, &value);
6674 g_value_unset (&value);
6678 if (xvimagesink->have_colorkey) {
6679 GValue value = { 0 };
6681 array = g_value_array_new (1);
6682 g_value_init (&value, GST_TYPE_INT_RANGE);
6683 gst_value_set_int_range (&value, 0, 0xffffff);
6684 g_value_array_append (array, &value);
6685 g_value_unset (&value);
6689 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6698 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
6701 iface->get_properties = gst_xvimagesink_probe_get_properties;
6702 iface->probe_property = gst_xvimagesink_probe_probe_property;
6703 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
6704 iface->get_values = gst_xvimagesink_probe_get_values;
6707 /* =========================================== */
6709 /* Init & Class init */
6711 /* =========================================== */
6714 gst_xvimagesink_set_property (GObject * object, guint prop_id,
6715 const GValue * value, GParamSpec * pspec)
6717 GstXvImageSink *xvimagesink;
6719 g_return_if_fail (GST_IS_XVIMAGESINK (object));
6721 xvimagesink = GST_XVIMAGESINK (object);
6725 xvimagesink->hue = g_value_get_int (value);
6726 xvimagesink->cb_changed = TRUE;
6727 gst_xvimagesink_update_colorbalance (xvimagesink);
6730 xvimagesink->contrast = g_value_get_int (value);
6731 xvimagesink->cb_changed = TRUE;
6732 gst_xvimagesink_update_colorbalance (xvimagesink);
6734 case PROP_BRIGHTNESS:
6735 xvimagesink->brightness = g_value_get_int (value);
6736 xvimagesink->cb_changed = TRUE;
6737 gst_xvimagesink_update_colorbalance (xvimagesink);
6739 case PROP_SATURATION:
6740 xvimagesink->saturation = g_value_get_int (value);
6741 xvimagesink->cb_changed = TRUE;
6742 gst_xvimagesink_update_colorbalance (xvimagesink);
6745 xvimagesink->display_name = g_strdup (g_value_get_string (value));
6747 case PROP_SYNCHRONOUS:
6748 xvimagesink->synchronous = g_value_get_boolean (value);
6749 if (xvimagesink->xcontext) {
6750 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
6751 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
6752 xvimagesink->synchronous ? "TRUE" : "FALSE");
6755 case PROP_PIXEL_ASPECT_RATIO:
6756 g_free (xvimagesink->par);
6757 xvimagesink->par = g_new0 (GValue, 1);
6758 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
6759 if (!g_value_transform (value, xvimagesink->par)) {
6760 g_warning ("Could not transform string to aspect ratio");
6761 gst_value_set_fraction (xvimagesink->par, 1, 1);
6763 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
6764 gst_value_get_fraction_numerator (xvimagesink->par),
6765 gst_value_get_fraction_denominator (xvimagesink->par));
6767 case PROP_FORCE_ASPECT_RATIO:
6768 xvimagesink->keep_aspect = g_value_get_boolean (value);
6770 case PROP_HANDLE_EVENTS:
6771 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
6772 g_value_get_boolean (value));
6773 gst_xvimagesink_manage_event_thread (xvimagesink);
6776 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
6778 case PROP_HANDLE_EXPOSE:
6779 xvimagesink->handle_expose = g_value_get_boolean (value);
6780 gst_xvimagesink_manage_event_thread (xvimagesink);
6782 case PROP_DOUBLE_BUFFER:
6783 xvimagesink->double_buffer = g_value_get_boolean (value);
6785 case PROP_AUTOPAINT_COLORKEY:
6786 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
6789 xvimagesink->colorkey = g_value_get_int (value);
6791 case PROP_DRAW_BORDERS:
6792 xvimagesink->draw_borders = g_value_get_boolean (value);
6794 #ifdef GST_EXT_XV_ENHANCEMENT
6795 case PROP_DISPLAY_MODE:
6797 int set_mode = g_value_get_enum (value);
6798 g_mutex_lock(xvimagesink->flow_lock);
6799 xvimagesink->display_mode = set_mode;
6800 if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) {
6801 if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) {
6802 if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) {
6803 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6805 GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6807 } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){
6808 if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
6809 set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
6811 GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
6814 GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode);
6817 g_mutex_unlock(xvimagesink->flow_lock);
6820 case PROP_CSC_RANGE:
6822 int set_range = g_value_get_enum (value);
6824 g_mutex_lock(xvimagesink->flow_lock);
6825 g_mutex_lock(xvimagesink->x_lock);
6827 if (xvimagesink->csc_range != set_range) {
6828 if (xvimagesink->xcontext && !xvimagesink->subpicture) {
6829 /* set color space range */
6830 if (set_csc_range(xvimagesink->xcontext, set_range)) {
6831 xvimagesink->csc_range = set_range;
6833 GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
6836 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6837 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
6838 xvimagesink->csc_range = set_range;
6840 } else if (xvimagesink->subpicture) {
6841 GST_WARNING("skip to set csc range, because it is subpicture format.");
6843 GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
6846 g_mutex_unlock(xvimagesink->x_lock);
6847 g_mutex_unlock(xvimagesink->flow_lock);
6850 case PROP_DISPLAY_GEOMETRY_METHOD:
6851 xvimagesink->display_geometry_method = g_value_get_enum (value);
6852 GST_LOG("Overlay geometry changed. update it");
6853 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6854 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6858 xvimagesink->flip = g_value_get_enum(value);
6860 case PROP_ROTATE_ANGLE:
6861 xvimagesink->rotate_angle = g_value_get_enum (value);
6862 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6863 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6867 g_mutex_lock( xvimagesink->flow_lock );
6868 g_mutex_lock( xvimagesink->x_lock );
6870 GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
6872 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
6873 if (xvimagesink->xcontext) {
6875 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
6876 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
6877 if (atom_stream != None) {
6878 GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
6879 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
6880 xvimagesink->xcontext->xv_port_id,
6881 atom_stream, 0 ) != Success) {
6882 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
6886 xvimagesink->visible = g_value_get_boolean (value);
6887 if ( xvimagesink->get_pixmap_cb ) {
6888 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6889 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6892 if(xvimagesink->xwindow->win)
6893 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
6895 XSync( xvimagesink->xcontext->disp, FALSE );
6897 GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
6898 xvimagesink->visible = g_value_get_boolean (value);
6900 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
6901 xvimagesink->visible = g_value_get_boolean (value);
6902 g_mutex_unlock( xvimagesink->x_lock );
6903 g_mutex_unlock( xvimagesink->flow_lock );
6904 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6905 g_mutex_lock( xvimagesink->flow_lock );
6906 g_mutex_lock( xvimagesink->x_lock );
6909 GST_INFO("set visible(%d) done", xvimagesink->visible);
6911 g_mutex_unlock( xvimagesink->x_lock );
6912 g_mutex_unlock( xvimagesink->flow_lock );
6915 xvimagesink->zoom = g_value_get_float (value);
6917 case PROP_ZOOM_POS_X:
6918 xvimagesink->zoom_pos_x = g_value_get_int (value);
6920 case PROP_ZOOM_POS_Y:
6921 xvimagesink->zoom_pos_y = g_value_get_int (value);
6922 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
6923 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6926 case PROP_ORIENTATION:
6927 xvimagesink->orientation = g_value_get_enum (value);
6928 GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
6930 case PROP_DST_ROI_MODE:
6931 xvimagesink->dst_roi_mode = g_value_get_enum (value);
6932 GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
6934 case PROP_DST_ROI_X:
6935 xvimagesink->dst_roi.x = g_value_get_int (value);
6937 case PROP_DST_ROI_Y:
6938 xvimagesink->dst_roi.y = g_value_get_int (value);
6940 case PROP_DST_ROI_W:
6941 xvimagesink->dst_roi.w = g_value_get_int (value);
6943 case PROP_DST_ROI_H:
6944 xvimagesink->dst_roi.h = g_value_get_int (value);
6946 case PROP_SRC_CROP_X:
6947 xvimagesink->src_crop.x = g_value_get_int (value);
6949 case PROP_SRC_CROP_Y:
6950 xvimagesink->src_crop.y = g_value_get_int (value);
6952 case PROP_SRC_CROP_W:
6953 xvimagesink->src_crop.w = g_value_get_int (value);
6955 case PROP_SRC_CROP_H:
6956 xvimagesink->src_crop.h = g_value_get_int (value);
6958 case PROP_STOP_VIDEO:
6959 xvimagesink->stop_video = g_value_get_int (value);
6960 g_mutex_lock( xvimagesink->flow_lock );
6962 if( xvimagesink->stop_video )
6964 if ( xvimagesink->get_pixmap_cb ) {
6965 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6966 g_mutex_lock (xvimagesink->x_lock);
6967 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6968 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6969 g_mutex_unlock (xvimagesink->x_lock);
6972 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
6973 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6977 g_mutex_unlock( xvimagesink->flow_lock );
6979 case PROP_PIXMAP_CB:
6982 cb_func = g_value_get_pointer(value);
6984 if (xvimagesink->get_pixmap_cb) {
6986 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6987 g_mutex_lock (xvimagesink->x_lock);
6988 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6989 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6990 g_mutex_unlock (xvimagesink->x_lock);
6992 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6993 if (xvimagesink->xpixmap[i]) {
6994 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6995 xvimagesink->xpixmap[i] = NULL;
6999 xvimagesink->get_pixmap_cb = cb_func;
7000 GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
7004 case PROP_PIXMAP_CB_USER_DATA:
7007 user_data = g_value_get_pointer(value);
7009 xvimagesink->get_pixmap_cb_user_data = user_data;
7010 GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
7014 case PROP_SUBPICTURE:
7015 xvimagesink->subpicture = g_value_get_boolean (value);
7017 case PROP_EXTERNAL_WIDTH:
7019 xvimagesink->external_width = g_value_get_int (value);
7020 GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width);
7023 case PROP_EXTERNAL_HEIGHT:
7025 xvimagesink->external_height = g_value_get_int (value);
7026 GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height);
7029 case PROP_ENABLE_FLUSH_BUFFER:
7030 xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
7033 xvimagesink->is_pixmap = g_value_get_boolean(value);
7035 case PROP_HIDED_WINDOW:
7037 xvimagesink->is_hided_subpicture = g_value_get_boolean(value);
7038 GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture);
7041 case PROP_QUICKPANEL_ON:
7043 xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value);
7044 GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture);
7047 case PROP_MULTIWINDOW_ACTIVE:
7049 xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value);
7050 GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture);
7053 case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7055 xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value);
7056 GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post);
7057 if(xvimagesink->keep_external_fullscreen_post) {
7059 atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False);
7060 if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success)
7062 GST_WARNING("set atom_keep_ext fail");
7067 case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7069 xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value);
7070 GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev);
7074 #endif /* GST_EXT_XV_ENHANCEMENT */
7076 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7082 gst_xvimagesink_get_property (GObject * object, guint prop_id,
7083 GValue * value, GParamSpec * pspec)
7085 GstXvImageSink *xvimagesink;
7087 g_return_if_fail (GST_IS_XVIMAGESINK (object));
7089 xvimagesink = GST_XVIMAGESINK (object);
7093 g_value_set_int (value, xvimagesink->hue);
7096 g_value_set_int (value, xvimagesink->contrast);
7098 case PROP_BRIGHTNESS:
7099 g_value_set_int (value, xvimagesink->brightness);
7101 case PROP_SATURATION:
7102 g_value_set_int (value, xvimagesink->saturation);
7105 g_value_set_string (value, xvimagesink->display_name);
7107 case PROP_SYNCHRONOUS:
7108 g_value_set_boolean (value, xvimagesink->synchronous);
7110 case PROP_PIXEL_ASPECT_RATIO:
7111 if (xvimagesink->par)
7112 g_value_transform (xvimagesink->par, value);
7114 case PROP_FORCE_ASPECT_RATIO:
7115 g_value_set_boolean (value, xvimagesink->keep_aspect);
7117 case PROP_HANDLE_EVENTS:
7118 g_value_set_boolean (value, xvimagesink->handle_events);
7122 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
7124 g_value_set_string (value, adaptor_no_s);
7125 g_free (adaptor_no_s);
7128 case PROP_DEVICE_NAME:
7129 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
7130 g_value_set_string (value,
7131 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
7133 g_value_set_string (value, NULL);
7136 case PROP_HANDLE_EXPOSE:
7137 g_value_set_boolean (value, xvimagesink->handle_expose);
7139 case PROP_DOUBLE_BUFFER:
7140 g_value_set_boolean (value, xvimagesink->double_buffer);
7142 case PROP_AUTOPAINT_COLORKEY:
7143 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
7146 g_value_set_int (value, xvimagesink->colorkey);
7148 case PROP_DRAW_BORDERS:
7149 g_value_set_boolean (value, xvimagesink->draw_borders);
7151 case PROP_WINDOW_WIDTH:
7152 if (xvimagesink->xwindow)
7153 g_value_set_uint64 (value, xvimagesink->xwindow->width);
7155 g_value_set_uint64 (value, 0);
7157 case PROP_WINDOW_HEIGHT:
7158 if (xvimagesink->xwindow)
7159 g_value_set_uint64 (value, xvimagesink->xwindow->height);
7161 g_value_set_uint64 (value, 0);
7163 #ifdef GST_EXT_XV_ENHANCEMENT
7164 case PROP_DISPLAY_MODE:
7165 g_value_set_enum (value, xvimagesink->display_mode);
7167 case PROP_CSC_RANGE:
7168 g_value_set_enum (value, xvimagesink->csc_range);
7170 case PROP_DISPLAY_GEOMETRY_METHOD:
7171 g_value_set_enum (value, xvimagesink->display_geometry_method);
7174 g_value_set_enum(value, xvimagesink->flip);
7176 case PROP_ROTATE_ANGLE:
7177 g_value_set_enum (value, xvimagesink->rotate_angle);
7180 g_value_set_boolean (value, xvimagesink->visible);
7183 g_value_set_float (value, xvimagesink->zoom);
7185 case PROP_ZOOM_POS_X:
7186 g_value_set_int (value, xvimagesink->zoom_pos_x);
7188 case PROP_ZOOM_POS_Y:
7189 g_value_set_int (value, xvimagesink->zoom_pos_y);
7191 case PROP_ORIENTATION:
7192 g_value_set_enum (value, xvimagesink->orientation);
7194 case PROP_DST_ROI_MODE:
7195 g_value_set_enum (value, xvimagesink->dst_roi_mode);
7197 case PROP_DST_ROI_X:
7198 g_value_set_int (value, xvimagesink->dst_roi.x);
7200 case PROP_DST_ROI_Y:
7201 g_value_set_int (value, xvimagesink->dst_roi.y);
7203 case PROP_DST_ROI_W:
7204 g_value_set_int (value, xvimagesink->dst_roi.w);
7206 case PROP_DST_ROI_H:
7207 g_value_set_int (value, xvimagesink->dst_roi.h);
7209 case PROP_SRC_CROP_X:
7210 g_value_set_int (value, xvimagesink->src_crop.x);
7212 case PROP_SRC_CROP_Y:
7213 g_value_set_int (value, xvimagesink->src_crop.y);
7215 case PROP_SRC_CROP_W:
7216 g_value_set_int (value, xvimagesink->src_crop.w);
7218 case PROP_SRC_CROP_H:
7219 g_value_set_int (value, xvimagesink->src_crop.h);
7221 case PROP_STOP_VIDEO:
7222 g_value_set_int (value, xvimagesink->stop_video);
7224 case PROP_PIXMAP_CB:
7225 g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
7227 case PROP_PIXMAP_CB_USER_DATA:
7228 g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
7230 case PROP_SUBPICTURE:
7231 g_value_set_boolean (value, xvimagesink->subpicture);
7233 case PROP_EXTERNAL_WIDTH:
7234 g_value_set_int (value, xvimagesink->external_width);
7236 case PROP_EXTERNAL_HEIGHT:
7237 g_value_set_int (value, xvimagesink->external_height);
7239 case PROP_ENABLE_FLUSH_BUFFER:
7240 g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
7243 g_value_set_boolean(value, xvimagesink->is_pixmap);
7245 case PROP_HIDED_WINDOW:
7246 g_value_set_boolean(value, xvimagesink->is_hided_subpicture);
7248 case PROP_QUICKPANEL_ON:
7249 g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture);
7251 case PROP_MULTIWINDOW_ACTIVE:
7252 g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture);
7254 case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
7255 g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post);
7257 case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
7258 g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev);
7260 #endif /* GST_EXT_XV_ENHANCEMENT */
7262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
7268 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
7272 GST_OBJECT_LOCK (xvimagesink);
7273 xvimagesink->running = FALSE;
7274 /* grab thread and mark it as NULL */
7275 thread = xvimagesink->event_thread;
7276 xvimagesink->event_thread = NULL;
7277 GST_OBJECT_UNLOCK (xvimagesink);
7279 /* invalidate the pool, current allocations continue, new buffer_alloc fails
7280 * with wrong_state */
7281 g_mutex_lock (xvimagesink->pool_lock);
7282 xvimagesink->pool_invalid = TRUE;
7283 g_mutex_unlock (xvimagesink->pool_lock);
7285 /* Wait for our event thread to finish before we clean up our stuff. */
7287 g_thread_join (thread);
7289 if (xvimagesink->cur_image) {
7290 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
7291 xvimagesink->cur_image = NULL;
7293 if (xvimagesink->xvimage) {
7294 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
7295 xvimagesink->xvimage = NULL;
7298 gst_xvimagesink_imagepool_clear (xvimagesink);
7300 if (xvimagesink->xwindow) {
7301 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
7302 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
7303 xvimagesink->xwindow = NULL;
7305 #ifdef GST_EXT_XV_ENHANCEMENT
7306 if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
7307 GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7308 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
7309 xvimagesink->pixmap_for_subpicture = 0;
7312 if (xvimagesink->get_pixmap_cb) {
7314 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
7315 g_mutex_lock (xvimagesink->x_lock);
7316 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
7317 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
7318 g_mutex_unlock (xvimagesink->x_lock);
7320 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
7321 if (xvimagesink->xpixmap[i]) {
7322 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
7323 xvimagesink->xpixmap[i] = NULL;
7326 xvimagesink->get_pixmap_cb = NULL;
7327 xvimagesink->get_pixmap_cb_user_data = NULL;
7329 #endif /* GST_EXT_XV_ENHANCEMENT */
7330 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
7331 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
7332 xvimagesink->have_render_rect = FALSE;
7334 gst_xvimagesink_xcontext_clear (xvimagesink);
7337 /* Finalize is called only once, dispose can be called multiple times.
7338 * We use mutexes and don't reset stuff to NULL here so let's register
7341 gst_xvimagesink_finalize (GObject * object)
7343 GstXvImageSink *xvimagesink;
7345 xvimagesink = GST_XVIMAGESINK (object);
7347 gst_xvimagesink_reset (xvimagesink);
7349 if (xvimagesink->display_name) {
7350 g_free (xvimagesink->display_name);
7351 xvimagesink->display_name = NULL;
7354 if (xvimagesink->par) {
7355 g_free (xvimagesink->par);
7356 xvimagesink->par = NULL;
7358 if (xvimagesink->x_lock) {
7359 g_mutex_free (xvimagesink->x_lock);
7360 xvimagesink->x_lock = NULL;
7362 if (xvimagesink->flow_lock) {
7363 g_mutex_free (xvimagesink->flow_lock);
7364 xvimagesink->flow_lock = NULL;
7366 if (xvimagesink->pool_lock) {
7367 g_mutex_free (xvimagesink->pool_lock);
7368 xvimagesink->pool_lock = NULL;
7370 #ifdef GST_EXT_XV_ENHANCEMENT
7371 if (xvimagesink->display_buffer_lock) {
7372 g_mutex_free (xvimagesink->display_buffer_lock);
7373 xvimagesink->display_buffer_lock = NULL;
7375 #endif /* GST_EXT_XV_ENHANCEMENT */
7377 g_free (xvimagesink->media_title);
7379 G_OBJECT_CLASS (parent_class)->finalize (object);
7383 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
7384 GstXvImageSinkClass * xvimagesinkclass)
7386 #ifdef GST_EXT_XV_ENHANCEMENT
7389 #endif /* GST_EXT_XV_ENHANCEMENT */
7391 xvimagesink->display_name = NULL;
7392 xvimagesink->adaptor_no = 0;
7393 xvimagesink->xcontext = NULL;
7394 xvimagesink->xwindow = NULL;
7395 xvimagesink->xvimage = NULL;
7396 xvimagesink->cur_image = NULL;
7398 xvimagesink->hue = xvimagesink->saturation = 0;
7399 xvimagesink->contrast = xvimagesink->brightness = 0;
7400 xvimagesink->cb_changed = FALSE;
7402 xvimagesink->fps_n = 0;
7403 xvimagesink->fps_d = 0;
7404 xvimagesink->video_width = 0;
7405 xvimagesink->video_height = 0;
7407 xvimagesink->x_lock = g_mutex_new ();
7408 xvimagesink->flow_lock = g_mutex_new ();
7410 xvimagesink->image_pool = NULL;
7411 xvimagesink->pool_lock = g_mutex_new ();
7413 xvimagesink->synchronous = FALSE;
7414 xvimagesink->double_buffer = TRUE;
7415 xvimagesink->running = FALSE;
7416 xvimagesink->keep_aspect = FALSE;
7417 xvimagesink->handle_events = TRUE;
7418 xvimagesink->par = NULL;
7419 xvimagesink->handle_expose = TRUE;
7420 xvimagesink->autopaint_colorkey = TRUE;
7422 /* on 16bit displays this becomes r,g,b = 1,2,3
7423 * on 24bit displays this becomes r,g,b = 8,8,16
7424 * as a port atom value
7426 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
7427 xvimagesink->draw_borders = TRUE;
7429 #ifdef GST_EXT_XV_ENHANCEMENT
7430 xvimagesink->xid_updated = FALSE;
7431 xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE;
7432 xvimagesink->csc_range = CSC_RANGE_NARROW;
7433 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
7434 xvimagesink->flip = DEF_DISPLAY_FLIP;
7435 xvimagesink->rotate_angle = DEGREE_270;
7436 xvimagesink->visible = TRUE;
7437 xvimagesink->zoom = 1.0;
7438 xvimagesink->zoom_pos_x = -1;
7439 xvimagesink->zoom_pos_y = -1;
7440 xvimagesink->rotation = -1;
7441 xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
7442 xvimagesink->orientation = DEGREE_0;
7443 xvimagesink->dst_roi.x = 0;
7444 xvimagesink->dst_roi.y = 0;
7445 xvimagesink->dst_roi.w = 0;
7446 xvimagesink->dst_roi.h = 0;
7447 xvimagesink->src_crop.x = 0;
7448 xvimagesink->src_crop.y = 0;
7449 xvimagesink->src_crop.w = 0;
7450 xvimagesink->src_crop.h = 0;
7451 xvimagesink->xim_transparenter = NULL;
7452 xvimagesink->scr_w = 0;
7453 xvimagesink->scr_h = 0;
7454 xvimagesink->aligned_width = 0;
7455 xvimagesink->aligned_height = 0;
7456 xvimagesink->stop_video = FALSE;
7457 xvimagesink->is_hided = FALSE;
7458 xvimagesink->is_quick_panel_on = FALSE;
7459 xvimagesink->is_multi_window = FALSE;
7460 xvimagesink->drm_fd = -1;
7461 xvimagesink->current_pixmap_idx = -1;
7462 xvimagesink->get_pixmap_cb = NULL;
7463 xvimagesink->get_pixmap_cb_user_data = NULL;
7465 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
7466 xvimagesink->displaying_buffers[i].buffer = NULL;
7467 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
7468 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
7469 xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
7470 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
7471 xvimagesink->displaying_buffers[i].ref_count = 0;
7475 xvimagesink->display_buffer_lock = g_mutex_new ();
7477 xvimagesink->displayed_buffer_count = 0;
7478 xvimagesink->displaying_buffer_count = 0;
7479 xvimagesink->is_zero_copy_format = FALSE;
7480 xvimagesink->secure_path = SECURE_PATH_INIT;
7481 xvimagesink->drm_level = DRM_LEVEL_0;
7482 xvimagesink->last_added_buffer_index = -1;
7483 xvimagesink->bufmgr = NULL;
7484 xvimagesink->flush_buffer = NULL;
7485 xvimagesink->enable_flush_buffer = TRUE;
7486 xvimagesink->pixmap_for_subpicture = 0;
7487 xvimagesink->is_subpicture_format = FALSE;
7488 xvimagesink->set_overlay_for_subpicture_just_once = FALSE;
7489 xvimagesink->subpicture = FALSE;
7490 xvimagesink->external_width = 0;
7491 xvimagesink->external_height = 0;
7492 xvimagesink->skip_frame_due_to_external_dev = FALSE;
7493 xvimagesink->is_hided_subpicture = FALSE;
7494 xvimagesink->is_quick_panel_on_subpicture = FALSE;
7495 xvimagesink->is_multi_window_subpicture = FALSE;
7496 xvimagesink->keep_external_fullscreen_post = FALSE;
7497 xvimagesink->keep_external_fullscreen_prev = FALSE;
7499 GST_WARNING("FAIL to call XInitThreads()");
7500 if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL))
7501 GST_WARNING("vconf set fail");
7502 #endif /* GST_EXT_XV_ENHANCEMENT */
7506 gst_xvimagesink_base_init (gpointer g_class)
7508 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
7510 gst_element_class_set_details_simple (element_class,
7511 "Video sink", "Sink/Video",
7512 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
7514 gst_element_class_add_static_pad_template (element_class,
7515 &gst_xvimagesink_sink_template_factory);
7519 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
7521 GObjectClass *gobject_class;
7522 GstElementClass *gstelement_class;
7523 GstBaseSinkClass *gstbasesink_class;
7524 GstVideoSinkClass *videosink_class;
7526 gobject_class = (GObjectClass *) klass;
7527 gstelement_class = (GstElementClass *) klass;
7528 gstbasesink_class = (GstBaseSinkClass *) klass;
7529 videosink_class = (GstVideoSinkClass *) klass;
7531 gobject_class->set_property = gst_xvimagesink_set_property;
7532 gobject_class->get_property = gst_xvimagesink_get_property;
7534 g_object_class_install_property (gobject_class, PROP_CONTRAST,
7535 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
7536 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7537 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
7538 g_param_spec_int ("brightness", "Brightness",
7539 "The brightness of the video", -1000, 1000, 0,
7540 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7541 g_object_class_install_property (gobject_class, PROP_HUE,
7542 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
7543 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7544 g_object_class_install_property (gobject_class, PROP_SATURATION,
7545 g_param_spec_int ("saturation", "Saturation",
7546 "The saturation of the video", -1000, 1000, 0,
7547 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7548 g_object_class_install_property (gobject_class, PROP_DISPLAY,
7549 g_param_spec_string ("display", "Display", "X Display name", NULL,
7550 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7551 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
7552 g_param_spec_boolean ("synchronous", "Synchronous",
7553 "When enabled, runs the X display in synchronous mode. "
7554 "(unrelated to A/V sync, used only for debugging)", FALSE,
7555 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7556 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
7557 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
7558 "The pixel aspect ratio of the device", "1/1",
7559 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7560 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
7561 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
7562 "When enabled, scaling will respect original aspect ratio", FALSE,
7563 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7564 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
7565 g_param_spec_boolean ("handle-events", "Handle XEvents",
7566 "When enabled, XEvents will be selected and handled", TRUE,
7567 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7568 g_object_class_install_property (gobject_class, PROP_DEVICE,
7569 g_param_spec_string ("device", "Adaptor number",
7570 "The number of the video adaptor", "0",
7571 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7572 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
7573 g_param_spec_string ("device-name", "Adaptor name",
7574 "The name of the video adaptor", NULL,
7575 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7576 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH,
7577 g_param_spec_int ("external-width", "external width",
7578 "width of external display", 0, G_MAXINT,
7579 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7580 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT,
7581 g_param_spec_int ("external-height", "external height",
7582 "height of external display", 0, G_MAXINT,
7583 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7585 * GstXvImageSink:handle-expose
7587 * When enabled, the current frame will always be drawn in response to X
7592 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
7593 g_param_spec_boolean ("handle-expose", "Handle expose",
7595 "the current frame will always be drawn in response to X Expose "
7596 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7599 * GstXvImageSink:double-buffer
7601 * Whether to double-buffer the output.
7605 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
7606 g_param_spec_boolean ("double-buffer", "Double-buffer",
7607 "Whether to double-buffer the output", TRUE,
7608 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7610 * GstXvImageSink:autopaint-colorkey
7612 * Whether to autofill overlay with colorkey
7616 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
7617 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
7618 "Whether to autofill overlay with colorkey", TRUE,
7619 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7621 * GstXvImageSink:colorkey
7623 * Color to use for the overlay mask.
7627 g_object_class_install_property (gobject_class, PROP_COLORKEY,
7628 g_param_spec_int ("colorkey", "Colorkey",
7629 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
7630 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7633 * GstXvImageSink:draw-borders
7635 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
7636 * unused parts of the video area.
7640 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
7641 g_param_spec_boolean ("draw-borders", "Colorkey",
7642 "Draw black borders to fill unused area in force-aspect-ratio mode",
7643 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7646 * GstXvImageSink:window-width
7648 * Actual width of the video window.
7652 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
7653 g_param_spec_uint64 ("window-width", "window-width",
7654 "Width of the window", 0, G_MAXUINT64, 0,
7655 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7658 * GstXvImageSink:window-height
7660 * Actual height of the video window.
7664 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
7665 g_param_spec_uint64 ("window-height", "window-height",
7666 "Height of the window", 0, G_MAXUINT64, 0,
7667 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7669 #ifdef GST_EXT_XV_ENHANCEMENT
7671 * GstXvImageSink:display-mode
7673 * select display mode
7675 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
7676 g_param_spec_enum("display-mode", "Display Mode",
7677 "Display device setting",
7678 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE,
7679 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7682 * GstXvImageSink:csc-range
7684 * select color space range
7686 g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
7687 g_param_spec_enum("csc-range", "Color Space Range",
7688 "Color space range setting",
7689 GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
7690 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7693 * GstXvImageSink:display-geometry-method
7695 * Display geometrical method setting
7697 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
7698 g_param_spec_enum("display-geometry-method", "Display geometry method",
7699 "Geometrical method for display",
7700 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
7701 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7704 * GstXvImageSink:display-flip
7706 * Display flip setting
7708 g_object_class_install_property(gobject_class, PROP_FLIP,
7709 g_param_spec_enum("flip", "Display flip",
7711 GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
7712 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7715 * GstXvImageSink:rotate
7717 * Draw rotation angle setting
7719 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
7720 g_param_spec_enum("rotate", "Rotate angle",
7721 "Rotate angle of display output",
7722 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
7723 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7726 * GstXvImageSink:visible
7728 * Whether reserve original src size or not
7730 g_object_class_install_property (gobject_class, PROP_VISIBLE,
7731 g_param_spec_boolean ("visible", "Visible",
7732 "Draws screen or blacks out, true means visible, false blacks out",
7733 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7736 * GstXvImageSink:zoom
7738 * Scale small area of screen to 1X~ 9X
7740 g_object_class_install_property (gobject_class, PROP_ZOOM,
7741 g_param_spec_float ("zoom", "Zoom",
7742 "Zooms screen as nX", 1.0, 9.0, 1.0,
7743 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7746 * GstXvImageSink:zoom-pos-x
7748 * Standard x-position of zoom
7750 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
7751 g_param_spec_int ("zoom-pos-x", "Zoom Position X",
7752 "Standard x-position of zoom", -1, 3840, -1,
7753 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7756 * GstXvImageSink:zoom-pos-y
7758 * Standard y-position of zoom
7760 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
7761 g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
7762 "Standard y-position of zoom", -1, 3840, -1,
7763 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7766 * GstXvImageSink:dst-roi-mode
7768 * Display geometrical method of ROI setting
7770 g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
7771 g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
7772 "Geometrical method of ROI for display",
7773 GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
7774 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7777 * GstXvImageSink:orientation
7779 * Orientation information which will be used for ROI/ZOOM
7781 g_object_class_install_property(gobject_class, PROP_ORIENTATION,
7782 g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
7783 "Orientation information for display",
7784 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
7785 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7788 * GstXvImageSink:dst-roi-x
7790 * X value of Destination ROI
7792 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
7793 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
7794 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7795 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7798 * GstXvImageSink:dst-roi-y
7800 * Y value of Destination ROI
7802 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
7803 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
7804 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7805 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7808 * GstXvImageSink:dst-roi-w
7810 * W value of Destination ROI
7812 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
7813 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
7814 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7815 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7818 * GstXvImageSink:dst-roi-h
7820 * H value of Destination ROI
7822 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
7823 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
7824 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7825 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7828 * GstXvImageSink:stop-video
7830 * Stop video for releasing video source buffer
7832 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
7833 g_param_spec_int ("stop-video", "Stop-Video",
7834 "Stop video for releasing video source buffer", 0, 1, 0,
7835 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7837 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
7838 g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
7839 "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
7841 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
7842 g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
7843 "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
7845 g_object_class_install_property (gobject_class, PROP_SUBPICTURE,
7846 g_param_spec_boolean ("subpicture", "Subpicture",
7847 "identifier of player for supporting subpicture", FALSE,
7848 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7851 * GstXvImageSink:src-crop-x
7853 * X value of video source crop
7855 g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
7856 g_param_spec_int ("src-crop-x", "Source Crop X",
7857 "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7858 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7861 * GstXvImageSink:src-crop-y
7863 * Y value of video source crop
7865 g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
7866 g_param_spec_int ("src-crop-y", "Source Crop X",
7867 "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7868 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7871 * GstXvImageSink:src-crop-w
7873 * Width value of video source crop
7875 g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
7876 g_param_spec_int ("src-crop-w", "Source Crop Width",
7877 "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7878 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7881 * GstXvImageSink:src-crop-h
7883 * Height value of video source crop
7885 g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
7886 g_param_spec_int ("src-crop-h", "Source Crop Height",
7887 "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7888 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7891 * GstXvImageSink:enable-flush-buffer
7893 * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
7895 g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
7896 g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
7897 "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
7898 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7901 * GstXvImageSink:is-pixmap
7903 * Check using pixmap id for blocking X api
7905 g_object_class_install_property (gobject_class, PROP_PIXMAP,
7906 g_param_spec_boolean("is-pixmap", "Check if use pixmap",
7907 "Check using pixmap id for blocking X api",
7908 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7911 * GstXvImageSink:hided-window
7913 * check window status for hiding subtitle
7915 g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW,
7916 g_param_spec_boolean("hided-window", "Hided window",
7917 "check window status for hiding subtitle",
7918 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7921 * GstXvImageSink:quick-panel-on
7923 * check quick-panel status for hiding subtitle
7925 g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON,
7926 g_param_spec_boolean("quick-panel-on", "Quick panel On",
7927 "check quick-panel status for hiding subtitle",
7928 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7931 * GstXvImageSink:multiwindow-activated
7933 * check multiwindow-activated status for hiding subtitle
7935 g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE,
7936 g_param_spec_boolean("multiwindow-active", "Multiwindow Activate",
7937 "check multiwindow status for hiding subtitle",
7938 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7941 * GstXvImageSink:keep-external-fullscreen-post
7943 * keep video-only mode for special case, it is set immediately.
7945 g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
7946 g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen",
7947 "set video-only mode forcedly for special case",
7948 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7951 * GstXvImageSink:keep-external-fullscreen-prev
7953 * keep video-only mode for special case, it is set in advance.
7955 g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
7956 g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen",
7957 "set video-only mode forcedly for special case",
7958 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7961 * GstXvImageSink::frame-render-error
7963 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
7964 "frame-render-error",
7965 G_TYPE_FROM_CLASS (klass),
7970 gst_xvimagesink_BOOLEAN__POINTER,
7975 * GstXvImageSink::display-status
7977 gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new (
7979 G_TYPE_FROM_CLASS (klass),
7980 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7984 g_cclosure_marshal_VOID__INT,
7990 * GstXvImageSink::external-resolution
7992 gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new (
7993 "external-resolution",
7994 G_TYPE_FROM_CLASS (klass),
7995 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7999 gst_marshal_VOID__INT_INT,
8006 * GstXvImageSink::hided-window
8008 gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new (
8010 G_TYPE_FROM_CLASS (klass),
8011 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8015 g_cclosure_marshal_VOID__BOOLEAN,
8021 * GstXvImageSink::quick-panel-on
8023 gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new (
8025 G_TYPE_FROM_CLASS (klass),
8026 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8030 g_cclosure_marshal_VOID__BOOLEAN,
8036 * GstXvImageSink::multiwindow-active
8038 gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new (
8039 "multiwindow-active",
8040 G_TYPE_FROM_CLASS (klass),
8041 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
8045 g_cclosure_marshal_VOID__BOOLEAN,
8050 #endif /* GST_EXT_XV_ENHANCEMENT */
8052 gobject_class->finalize = gst_xvimagesink_finalize;
8054 gstelement_class->change_state =
8055 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
8057 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
8058 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
8059 gstbasesink_class->buffer_alloc =
8060 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
8061 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
8062 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
8064 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
8067 /* ============================================================= */
8069 /* Public Methods */
8071 /* ============================================================= */
8073 /* =========================================== */
8075 /* Object typing & Creation */
8077 /* =========================================== */
8079 gst_xvimagesink_init_interfaces (GType type)
8081 static const GInterfaceInfo iface_info = {
8082 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
8086 static const GInterfaceInfo navigation_info = {
8087 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
8091 static const GInterfaceInfo overlay_info = {
8092 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
8096 static const GInterfaceInfo colorbalance_info = {
8097 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
8101 static const GInterfaceInfo propertyprobe_info = {
8102 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
8107 g_type_add_interface_static (type,
8108 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
8109 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
8110 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
8111 g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
8112 &colorbalance_info);
8113 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
8114 &propertyprobe_info);
8116 /* register type and create class in a more safe place instead of at
8117 * runtime since the type registration and class creation is not
8119 g_type_class_ref (gst_xvimage_buffer_get_type ());
8123 plugin_init (GstPlugin * plugin)
8125 if (!gst_element_register (plugin, "xvimagesink",
8126 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
8129 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
8130 "xvimagesink element");
8131 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
8136 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
8139 "XFree86 video output plugin using Xv extension",
8140 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)