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 performance checking */
153 BUF_SHARE_METHOD_PADDR = 0,
155 BUF_SHARE_METHOD_TIZEN_BUFFER
156 } buf_share_method_t;
158 #define _BUFFER_WAIT_TIMEOUT 2000000
159 #define _CHECK_DISPLAYED_BUFFER_COUNT 30
160 #define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */
162 /* max channel count *********************************************************/
163 #define SCMN_IMGB_MAX_PLANE (4)
165 /* image buffer definition ***************************************************
167 +------------------------------------------+ ---
170 | +---------------------------+ --- | |
172 | |<---------- w[] ---------->| | | |
180 | +---------------------------+ --- | |
182 +------------------------------------------+ ---
184 |<----------------- s[] ------------------>|
189 /* width of each image plane */
190 int w[SCMN_IMGB_MAX_PLANE];
191 /* height of each image plane */
192 int h[SCMN_IMGB_MAX_PLANE];
193 /* stride of each image plane */
194 int s[SCMN_IMGB_MAX_PLANE];
195 /* elevation of each image plane */
196 int e[SCMN_IMGB_MAX_PLANE];
197 /* user space address of each image plane */
198 void *a[SCMN_IMGB_MAX_PLANE];
199 /* physical address of each image plane, if needs */
200 void *p[SCMN_IMGB_MAX_PLANE];
201 /* color space type of image */
203 /* left postion, if needs */
205 /* top position, if needs */
207 /* to align memory */
212 int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
213 /* buffer share method */
214 int buf_share_method;
215 /* Y plane size in case of ST12 */
217 /* UV plane size in case of ST12 */
219 /* Tizen buffer object */
220 void *bo[SCMN_IMGB_MAX_PLANE];
225 /* TZ memory buffer */
228 #endif /* GST_EXT_XV_ENHANCEMENT */
230 /* Debugging category */
231 #include <gst/gstinfo.h>
233 #include "gst/glib-compat-private.h"
235 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
236 #define GST_CAT_DEFAULT gst_debug_xvimagesink
237 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
239 #ifdef GST_EXT_XV_ENHANCEMENT
240 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
241 #define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
244 gst_xvimagesink_display_mode_get_type(void)
246 static GType xvimagesink_display_mode_type = 0;
247 static const GEnumValue display_mode_type[] = {
248 { 0, "Default mode", "DEFAULT"},
249 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
250 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
254 if (!xvimagesink_display_mode_type) {
255 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
258 return xvimagesink_display_mode_type;
262 gst_xvimagesink_csc_range_get_type(void)
264 static GType xvimagesink_csc_range_type = 0;
265 static const GEnumValue csc_range_type[] = {
266 { 0, "Narrow range", "NARROW"},
267 { 1, "Wide range", "WIDE"},
271 if (!xvimagesink_csc_range_type) {
272 xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
275 return xvimagesink_csc_range_type;
286 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
289 gst_xvimagesink_rotate_angle_get_type(void)
291 static GType xvimagesink_rotate_angle_type = 0;
292 static const GEnumValue rotate_angle_type[] = {
293 { 0, "No rotate", "DEGREE_0"},
294 { 1, "Rotate 90 degree", "DEGREE_90"},
295 { 2, "Rotate 180 degree", "DEGREE_180"},
296 { 3, "Rotate 270 degree", "DEGREE_270"},
300 if (!xvimagesink_rotate_angle_type) {
301 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
304 return xvimagesink_rotate_angle_type;
308 DISP_GEO_METHOD_LETTER_BOX = 0,
309 DISP_GEO_METHOD_ORIGIN_SIZE,
310 DISP_GEO_METHOD_FULL_SCREEN,
311 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
312 DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
313 DISP_GEO_METHOD_CUSTOM_ROI,
316 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
325 #define DEF_DISPLAY_FLIP FLIP_NONE
327 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
328 #define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type())
331 gst_xvimagesink_display_geometry_method_get_type(void)
333 static GType xvimagesink_display_geometry_method_type = 0;
334 static const GEnumValue display_geometry_method_type[] = {
335 { 0, "Letter box", "LETTER_BOX"},
336 { 1, "Origin size", "ORIGIN_SIZE"},
337 { 2, "Full-screen", "FULL_SCREEN"},
338 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
339 { 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"},
340 { 5, "Explicitly described destination ROI", "CUSTOM_ROI"},
344 if (!xvimagesink_display_geometry_method_type) {
345 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
348 return xvimagesink_display_geometry_method_type;
352 gst_xvimagesink_flip_get_type(void)
354 static GType xvimagesink_flip_type = 0;
355 static const GEnumValue flip_type[] = {
356 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
357 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
358 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
359 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
360 { FLIP_NUM, NULL, NULL},
363 if (!xvimagesink_flip_type) {
364 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
367 return xvimagesink_flip_type;
370 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
372 gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure,
373 GValue *return_value G_GNUC_UNUSED,
374 guint n_param_values,
375 const GValue *param_values,
376 gpointer invocation_hint G_GNUC_UNUSED,
377 gpointer marshal_data)
379 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
382 register GMarshalFunc_BOOLEAN__POINTER callback;
383 register GCClosure *cc = (GCClosure*) closure;
384 register gpointer data1, data2;
388 g_return_if_fail (return_value != NULL);
389 g_return_if_fail (n_param_values == 2);
391 if (G_CCLOSURE_SWAP_DATA (closure)) {
392 data1 = closure->data;
393 data2 = g_value_peek_pointer (param_values + 0);
395 data1 = g_value_peek_pointer (param_values + 0);
396 data2 = closure->data;
398 callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
400 v_return = callback (data1,
401 g_marshal_value_peek_pointer (param_values + 1),
404 g_value_set_boolean (return_value, v_return);
409 SIGNAL_FRAME_RENDER_ERROR,
412 static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
414 #endif /* GST_EXT_XV_ENHANCEMENT */
419 unsigned long functions;
420 unsigned long decorations;
422 unsigned long status;
424 MotifWmHints, MwmHints;
426 #define MWM_HINTS_DECORATIONS (1L << 1)
428 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
430 static GstBufferClass *xvimage_buffer_parent_class = NULL;
431 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
433 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
435 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
437 static void gst_xvimagesink_expose (GstXOverlay * overlay);
439 #ifdef GST_EXT_XV_ENHANCEMENT
440 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
441 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
442 static gboolean set_csc_range(GstXContext *xcontext, int set_range);
443 static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
444 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
445 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
446 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
447 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
448 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
449 #endif /* GST_EXT_XV_ENHANCEMENT */
451 /* Default template - initiated with class struct to allow gst-register to work
453 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
454 GST_STATIC_PAD_TEMPLATE ("sink",
457 GST_STATIC_CAPS ("video/x-raw-rgb, "
458 "framerate = (fraction) [ 0, MAX ], "
459 "width = (int) [ 1, MAX ], "
460 "height = (int) [ 1, MAX ]; "
462 "framerate = (fraction) [ 0, MAX ], "
463 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
475 PROP_PIXEL_ASPECT_RATIO,
476 PROP_FORCE_ASPECT_RATIO,
482 PROP_AUTOPAINT_COLORKEY,
487 #ifdef GST_EXT_XV_ENHANCEMENT
492 PROP_DISPLAY_GEOMETRY_METHOD,
501 PROP_PIXMAP_CB_USER_DATA,
502 #endif /* GST_EXT_XV_ENHANCEMENT */
505 static void gst_xvimagesink_init_interfaces (GType type);
507 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
508 GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
511 /* ============================================================= */
513 /* Private Methods */
515 /* ============================================================= */
517 /* xvimage buffers */
519 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
521 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
522 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
523 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
525 /* This function destroys a GstXvImage handling XShm availability */
527 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
529 GstXvImageSink *xvimagesink;
531 GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
533 xvimagesink = xvimage->xvimagesink;
534 if (G_UNLIKELY (xvimagesink == NULL))
537 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
539 GST_OBJECT_LOCK (xvimagesink);
541 /* If the destroyed image is the current one we destroy our reference too */
542 if (xvimagesink->cur_image == xvimage)
543 xvimagesink->cur_image = NULL;
545 /* We might have some buffers destroyed after changing state to NULL */
546 if (xvimagesink->xcontext == NULL) {
547 GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
549 /* Need to free the shared memory segment even if the x context
550 * was already cleaned up */
551 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
552 shmdt (xvimage->SHMInfo.shmaddr);
558 g_mutex_lock (xvimagesink->x_lock);
561 if (xvimagesink->xcontext->use_xshm) {
562 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
563 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
564 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
565 XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
566 XSync (xvimagesink->xcontext->disp, FALSE);
568 shmdt (xvimage->SHMInfo.shmaddr);
570 if (xvimage->xvimage)
571 XFree (xvimage->xvimage);
573 #endif /* HAVE_XSHM */
575 if (xvimage->xvimage) {
576 if (xvimage->xvimage->data) {
577 g_free (xvimage->xvimage->data);
579 XFree (xvimage->xvimage);
583 XSync (xvimagesink->xcontext->disp, FALSE);
585 g_mutex_unlock (xvimagesink->x_lock);
588 GST_OBJECT_UNLOCK (xvimagesink);
589 xvimage->xvimagesink = NULL;
590 gst_object_unref (xvimagesink);
592 GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
599 GST_WARNING ("no sink found");
605 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
607 GstXvImageSink *xvimagesink;
610 xvimagesink = xvimage->xvimagesink;
611 if (G_UNLIKELY (xvimagesink == NULL))
614 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
616 GST_OBJECT_LOCK (xvimagesink);
617 running = xvimagesink->running;
618 GST_OBJECT_UNLOCK (xvimagesink);
620 /* If our geometry changed we can't reuse that image. */
621 if (running == FALSE) {
622 GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
623 gst_xvimage_buffer_destroy (xvimage);
624 } else if ((xvimage->width != xvimagesink->video_width) ||
625 (xvimage->height != xvimagesink->video_height)) {
626 GST_LOG_OBJECT (xvimage,
627 "destroy image as its size changed %dx%d vs current %dx%d",
628 xvimage->width, xvimage->height,
629 xvimagesink->video_width, xvimagesink->video_height);
630 gst_xvimage_buffer_destroy (xvimage);
632 /* In that case we can reuse the image and add it to our image pool. */
633 GST_LOG_OBJECT (xvimage, "recycling image in pool");
634 /* need to increment the refcount again to recycle */
635 gst_buffer_ref (GST_BUFFER_CAST (xvimage));
636 g_mutex_lock (xvimagesink->pool_lock);
637 xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
639 g_mutex_unlock (xvimagesink->pool_lock);
645 GST_WARNING ("no sink found");
651 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
653 /* make sure it is not recycled */
655 xvimage->height = -1;
656 gst_buffer_unref (GST_BUFFER (xvimage));
660 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
663 xvimage->SHMInfo.shmaddr = ((void *) -1);
664 xvimage->SHMInfo.shmid = -1;
669 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
671 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
673 xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
675 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
676 gst_xvimage_buffer_finalize;
680 gst_xvimage_buffer_get_type (void)
682 static GType _gst_xvimage_buffer_type;
684 if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
685 static const GTypeInfo xvimage_buffer_info = {
686 sizeof (GstBufferClass),
689 gst_xvimage_buffer_class_init,
692 sizeof (GstXvImageBuffer),
694 (GInstanceInitFunc) gst_xvimage_buffer_init,
697 _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
698 "GstXvImageBuffer", &xvimage_buffer_info, 0);
700 return _gst_xvimage_buffer_type;
705 static gboolean error_caught = FALSE;
708 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
710 char error_msg[1024];
712 #ifdef GST_EXT_XV_ENHANCEMENT
714 XGetErrorText (display, xevent->error_code, error_msg, 1024);
715 error_msg[1023] = '\0';
716 GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
718 GST_ERROR("CAUTION:xevent is NULL");
720 #else /* GST_EXT_XV_ENHANCEMENT */
721 XGetErrorText (display, xevent->error_code, error_msg, 1024);
722 GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
723 #endif /* GST_EXT_XV_ENHANCEMENT */
729 /* This function checks that it is actually really possible to create an image
732 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
735 XShmSegmentInfo SHMInfo;
737 int (*handler) (Display *, XErrorEvent *);
738 gboolean result = FALSE;
739 gboolean did_attach = FALSE;
741 g_return_val_if_fail (xcontext != NULL, FALSE);
743 /* Sync to ensure any older errors are already processed */
744 XSync (xcontext->disp, FALSE);
746 /* Set defaults so we don't free these later unnecessarily */
747 SHMInfo.shmaddr = ((void *) -1);
750 /* Setting an error handler to catch failure */
751 error_caught = FALSE;
752 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
754 /* Trying to create a 1x1 picture */
755 GST_DEBUG ("XvShmCreateImage of 1x1");
756 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
757 xcontext->im_format, NULL, 1, 1, &SHMInfo);
759 /* Might cause an error, sync to ensure it is noticed */
760 XSync (xcontext->disp, FALSE);
761 if (!xvimage || error_caught) {
762 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
765 size = xvimage->data_size;
767 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
768 if (SHMInfo.shmid == -1) {
769 GST_WARNING ("could not get shared memory of %d bytes", size);
773 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
774 if (SHMInfo.shmaddr == ((void *) -1)) {
775 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
776 /* Clean up the shared memory segment */
777 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
781 xvimage->data = SHMInfo.shmaddr;
782 SHMInfo.readOnly = FALSE;
784 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
785 GST_WARNING ("Failed to XShmAttach");
786 /* Clean up the shared memory segment */
787 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
791 /* Sync to ensure we see any errors we caused */
792 XSync (xcontext->disp, FALSE);
794 /* Delete the shared memory segment as soon as everyone is attached.
795 * This way, it will be deleted as soon as we detach later, and not
796 * leaked if we crash. */
797 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
800 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
804 /* store whether we succeeded in result */
807 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
808 "Not using shared memory.");
812 /* Sync to ensure we swallow any errors we caused and reset error_caught */
813 XSync (xcontext->disp, FALSE);
815 error_caught = FALSE;
816 XSetErrorHandler (handler);
819 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
820 SHMInfo.shmid, SHMInfo.shmseg);
821 XShmDetach (xcontext->disp, &SHMInfo);
822 XSync (xcontext->disp, FALSE);
824 if (SHMInfo.shmaddr != ((void *) -1))
825 shmdt (SHMInfo.shmaddr);
830 #endif /* HAVE_XSHM */
832 /* This function handles GstXvImage creation depending on XShm availability */
833 static GstXvImageBuffer *
834 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
836 GstXvImageBuffer *xvimage = NULL;
837 GstStructure *structure = NULL;
838 gboolean succeeded = FALSE;
839 int (*handler) (Display *, XErrorEvent *);
841 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
846 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
847 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
849 structure = gst_caps_get_structure (caps, 0);
851 if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
852 !gst_structure_get_int (structure, "height", &xvimage->height)) {
853 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
856 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
858 #ifdef GST_EXT_XV_ENHANCEMENT
859 GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
860 xvimagesink->aligned_width, xvimagesink->aligned_height);
861 if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
862 GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
863 xvimagesink->aligned_width = xvimage->width;
864 xvimagesink->aligned_height = xvimage->height;
866 #endif /* GST_EXT_XV_ENHANCEMENT */
868 xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
869 if (xvimage->im_format == -1) {
870 GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
871 GST_PTR_FORMAT, caps);
872 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
873 ("Failed to create output image buffer of %dx%d pixels",
874 xvimage->width, xvimage->height), ("Invalid input caps"));
877 xvimage->xvimagesink = gst_object_ref (xvimagesink);
879 g_mutex_lock (xvimagesink->x_lock);
881 #ifdef GST_EXT_XV_ENHANCEMENT
882 XSync (xvimagesink->xcontext->disp, FALSE);
883 #endif /* GST_EXT_XV_ENHANCEMENT */
884 /* Setting an error handler to catch failure */
885 error_caught = FALSE;
886 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
889 if (xvimagesink->xcontext->use_xshm) {
892 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
893 xvimagesink->xcontext->xv_port_id,
894 xvimage->im_format, NULL,
895 #ifdef GST_EXT_XV_ENHANCEMENT
896 xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
897 #else /* GST_EXT_XV_ENHANCEMENT */
898 xvimage->width, xvimage->height, &xvimage->SHMInfo);
899 #endif /* GST_EXT_XV_ENHANCEMENT */
900 if (!xvimage->xvimage || error_caught) {
901 g_mutex_unlock (xvimagesink->x_lock);
903 /* Reset error flag */
904 error_caught = FALSE;
907 GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
908 ("Failed to create output image buffer of %dx%d pixels",
909 xvimage->width, xvimage->height),
910 ("could not XvShmCreateImage a %dx%d image",
911 xvimage->width, xvimage->height));
913 #ifdef GST_EXT_XV_ENHANCEMENT
914 /* must not change "use_xshm",
915 because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
917 #else /* GST_EXT_XV_ENHANCEMENT */
918 /* Retry without XShm */
919 xvimagesink->xcontext->use_xshm = FALSE;
921 /* Hold X mutex again to try without XShm */
922 g_mutex_lock (xvimagesink->x_lock);
924 #endif /* GST_EXT_XV_ENHANCEMENT */
927 /* we have to use the returned data_size for our shm size */
928 xvimage->size = xvimage->xvimage->data_size;
929 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
932 /* calculate the expected size. This is only for sanity checking the
933 * number we get from X. */
934 switch (xvimage->im_format) {
935 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
936 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
943 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
944 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
945 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
947 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
948 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
951 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
953 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
954 GST_DEBUG_OBJECT (xvimagesink,
955 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
956 plane, pitches[plane], offsets[plane]);
960 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
961 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
962 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
965 #ifdef GST_EXT_XV_ENHANCEMENT
966 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
967 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
968 case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
969 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
970 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
971 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
972 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
973 expected_size = sizeof(SCMN_IMGB);
975 #endif /* GST_EXT_XV_ENHANCEMENT */
980 if (expected_size != 0 && xvimage->size != expected_size) {
981 GST_WARNING_OBJECT (xvimagesink,
982 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
983 xvimage->size, expected_size);
986 /* Be verbose about our XvImage stride */
990 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
991 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
992 "offset of %d", plane, xvimage->xvimage->pitches[plane],
993 xvimage->xvimage->offsets[plane]);
997 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
999 if (xvimage->SHMInfo.shmid == -1) {
1000 g_mutex_unlock (xvimagesink->x_lock);
1001 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1002 ("Failed to create output image buffer of %dx%d pixels",
1003 xvimage->width, xvimage->height),
1004 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1006 goto beach_unlocked;
1009 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1010 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1011 g_mutex_unlock (xvimagesink->x_lock);
1012 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1013 ("Failed to create output image buffer of %dx%d pixels",
1014 xvimage->width, xvimage->height),
1015 ("Failed to shmat: %s", g_strerror (errno)));
1016 /* Clean up the shared memory segment */
1017 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1018 goto beach_unlocked;
1021 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1022 xvimage->SHMInfo.readOnly = FALSE;
1024 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1025 /* Clean up the shared memory segment */
1026 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1028 g_mutex_unlock (xvimagesink->x_lock);
1029 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1030 ("Failed to create output image buffer of %dx%d pixels",
1031 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1032 goto beach_unlocked;
1035 XSync (xvimagesink->xcontext->disp, FALSE);
1037 /* Delete the shared memory segment as soon as we everyone is attached.
1038 * This way, it will be deleted as soon as we detach later, and not
1039 * leaked if we crash. */
1040 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1042 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1043 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1045 #ifndef GST_EXT_XV_ENHANCEMENT
1047 #endif /* GST_EXT_XV_ENHANCEMENT */
1048 #endif /* HAVE_XSHM */
1050 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1051 xvimagesink->xcontext->xv_port_id,
1052 #ifdef GST_EXT_XV_ENHANCEMENT
1053 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1054 #else /* GST_EXT_XV_ENHANCEMENT */
1055 xvimage->im_format, NULL, xvimage->width, xvimage->height);
1056 #endif /* GST_EXT_XV_ENHANCEMENT */
1057 if (!xvimage->xvimage || error_caught) {
1058 g_mutex_unlock (xvimagesink->x_lock);
1059 /* Reset error handler */
1060 error_caught = FALSE;
1061 XSetErrorHandler (handler);
1063 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1064 ("Failed to create outputimage buffer of %dx%d pixels",
1065 xvimage->width, xvimage->height),
1066 ("could not XvCreateImage a %dx%d image",
1067 xvimage->width, xvimage->height));
1068 goto beach_unlocked;
1071 /* we have to use the returned data_size for our image size */
1072 xvimage->size = xvimage->xvimage->data_size;
1073 xvimage->xvimage->data = g_malloc (xvimage->size);
1075 XSync (xvimagesink->xcontext->disp, FALSE);
1078 /* Reset error handler */
1079 error_caught = FALSE;
1080 XSetErrorHandler (handler);
1084 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1085 GST_BUFFER_SIZE (xvimage) = xvimage->size;
1087 g_mutex_unlock (xvimagesink->x_lock);
1091 gst_xvimage_buffer_free (xvimage);
1098 /* We are called with the x_lock taken */
1100 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
1101 GstXWindow * xwindow, GstVideoRectangle rect)
1105 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1106 g_return_if_fail (xwindow != NULL);
1108 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1109 xvimagesink->xcontext->black);
1112 if (rect.x > xvimagesink->render_rect.x) {
1113 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1114 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1115 rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
1119 t1 = rect.x + rect.w;
1120 t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
1122 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1123 t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
1127 if (rect.y > xvimagesink->render_rect.y) {
1128 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1129 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1130 xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
1134 t1 = rect.y + rect.h;
1135 t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
1137 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1138 xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
1142 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
1143 * if no window was available */
1145 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
1146 GstXvImageBuffer * xvimage)
1148 GstVideoRectangle result;
1149 gboolean draw_border = FALSE;
1151 #ifdef GST_EXT_XV_ENHANCEMENT
1152 static Atom atom_rotation = None;
1153 static Atom atom_hflip = None;
1154 static Atom atom_vflip = None;
1155 gboolean set_hflip = FALSE;
1156 gboolean set_vflip = FALSE;
1158 GstVideoRectangle src_origin = { 0, 0, 0, 0};
1159 GstVideoRectangle src_input = { 0, 0, 0, 0};
1160 GstVideoRectangle src = { 0, 0, 0, 0};
1161 GstVideoRectangle dst = { 0, 0, 0, 0};
1166 int (*handler) (Display *, XErrorEvent *) = NULL;
1167 gboolean res = FALSE;
1168 XV_DATA_PTR img_data = NULL;
1169 #endif /* GST_EXT_XV_ENHANCEMENT */
1171 /* We take the flow_lock. If expose is in there we don't want to run
1172 concurrently from the data flow thread */
1173 g_mutex_lock (xvimagesink->flow_lock);
1175 #ifdef GST_EXT_XV_ENHANCEMENT
1176 if (xvimagesink->xid_updated) {
1177 if (xvimage && xvimagesink->xvimage == NULL) {
1178 GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
1181 xvimagesink->xid_updated = FALSE;
1183 #endif /* GST_EXT_XV_ENHANCEMENT */
1185 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1186 #ifdef GST_EXT_XV_ENHANCEMENT
1187 if (xvimagesink->get_pixmap_cb) {
1188 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
1190 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
1191 g_mutex_unlock(xvimagesink->flow_lock);
1194 #else /* GST_EXT_XV_ENHANCEMENT */
1195 g_mutex_unlock (xvimagesink->flow_lock);
1197 #endif /* GST_EXT_XV_ENHANCEMENT */
1200 #ifdef GST_EXT_XV_ENHANCEMENT
1201 if (xvimagesink->visible == FALSE ||
1202 xvimagesink->is_hided) {
1203 GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
1204 xvimagesink->visible, xvimagesink->is_hided);
1205 g_mutex_unlock(xvimagesink->flow_lock);
1208 #endif /* GST_EXT_XV_ENHANCEMENT */
1210 /* Draw borders when displaying the first frame. After this
1211 draw borders only on expose event or after a size change. */
1212 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1216 /* Store a reference to the last image we put, lose the previous one */
1217 if (xvimage && xvimagesink->cur_image != xvimage) {
1218 if (xvimagesink->cur_image) {
1219 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1220 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1222 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1223 xvimagesink->cur_image =
1224 GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1227 /* Expose sends a NULL image, we take the latest frame */
1229 if (xvimagesink->cur_image) {
1231 xvimage = xvimagesink->cur_image;
1233 #ifdef GST_EXT_XV_ENHANCEMENT
1234 GST_INFO_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1235 /* no need to release gem handle */
1236 #endif /* GST_EXT_XV_ENHANCEMENT */
1237 g_mutex_unlock (xvimagesink->flow_lock);
1242 #ifdef GST_EXT_XV_ENHANCEMENT
1243 if (!xvimagesink->get_pixmap_cb) {
1244 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1246 /* for multi-pixmap usage for the video texture */
1247 gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
1248 idx = xvimagesink->current_pixmap_idx;
1250 g_mutex_unlock (xvimagesink->flow_lock);
1252 } else if (idx == -2) {
1253 GST_WARNING_OBJECT(xvimagesink, "Skip putImage().");
1254 g_mutex_unlock (xvimagesink->flow_lock);
1260 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1262 src_input.w = src_origin.w = xvimagesink->video_width;
1263 src_input.h = src_origin.h = xvimagesink->video_height;
1265 if (xvimagesink->rotate_angle == DEGREE_0 ||
1266 xvimagesink->rotate_angle == DEGREE_180) {
1267 src.w = src_origin.w;
1268 src.h = src_origin.h;
1270 src.w = src_origin.h;
1271 src.h = src_origin.w;
1274 dst.w = xvimagesink->render_rect.w;
1275 dst.h = xvimagesink->render_rect.h;
1277 switch (xvimagesink->display_geometry_method)
1279 case DISP_GEO_METHOD_LETTER_BOX:
1280 gst_video_sink_center_rect (src, dst, &result, TRUE);
1281 result.x += xvimagesink->render_rect.x;
1282 result.y += xvimagesink->render_rect.y;
1285 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
1286 GST_WARNING_OBJECT(xvimagesink, "not supported API, set ORIGIN_SIZE mode");
1287 case DISP_GEO_METHOD_ORIGIN_SIZE:
1288 gst_video_sink_center_rect (src, dst, &result, FALSE);
1289 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1291 if (xvimagesink->rotate_angle == DEGREE_90 ||
1292 xvimagesink->rotate_angle == DEGREE_270) {
1293 src_input.x = src_input.x ^ src_input.y;
1294 src_input.y = src_input.x ^ src_input.y;
1295 src_input.x = src_input.x ^ src_input.y;
1297 src_input.w = src_input.w ^ src_input.h;
1298 src_input.h = src_input.w ^ src_input.h;
1299 src_input.w = src_input.w ^ src_input.h;
1303 case DISP_GEO_METHOD_FULL_SCREEN:
1304 result.x = result.y = 0;
1305 if (!xvimagesink->get_pixmap_cb) {
1306 result.w = xvimagesink->xwindow->width;
1307 result.h = xvimagesink->xwindow->height;
1309 result.w = xvimagesink->xpixmap[idx]->width;
1310 result.h = xvimagesink->xpixmap[idx]->height;
1314 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1315 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1317 result.x = result.y = 0;
1321 if (xvimagesink->rotate_angle == DEGREE_90 ||
1322 xvimagesink->rotate_angle == DEGREE_270) {
1323 src_input.x = src_input.x ^ src_input.y;
1324 src_input.y = src_input.x ^ src_input.y;
1325 src_input.x = src_input.x ^ src_input.y;
1327 src_input.w = src_input.w ^ src_input.h;
1328 src_input.h = src_input.w ^ src_input.h;
1329 src_input.w = src_input.w ^ src_input.h;
1333 case DISP_GEO_METHOD_CUSTOM_ROI:
1334 #ifdef GST_EXT_XV_ENHANCEMENT_ROI_MODE
1335 switch (xvimagesink->rotate_angle) {
1337 result.w = xvimagesink->dst_roi.h;
1338 result.h = xvimagesink->dst_roi.w;
1340 result.x = xvimagesink->dst_roi.y;
1341 if (!xvimagesink->get_pixmap_cb) {
1342 result.y = xvimagesink->xwindow->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
1344 result.y = xvimagesink->xpixmap[idx]->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
1348 result.w = xvimagesink->dst_roi.w;
1349 result.h = xvimagesink->dst_roi.h;
1351 if (!xvimagesink->get_pixmap_cb) {
1352 result.x = xvimagesink->xwindow->width - result.w - xvimagesink->dst_roi.x;
1353 result.y = xvimagesink->xwindow->height - result.h - xvimagesink->dst_roi.y;
1355 result.x = xvimagesink->xpixmap[idx]->width - result.w - xvimagesink->dst_roi.x;
1356 result.y = xvimagesink->xpixmap[idx]->height - result.h - xvimagesink->dst_roi.y;
1360 result.w = xvimagesink->dst_roi.h;
1361 result.h = xvimagesink->dst_roi.w;
1363 if (!xvimagesink->get_pixmap_cb) {
1364 result.x = xvimagesink->xwindow->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
1366 result.x = xvimagesink->xpixmap[idx]->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
1368 result.y = xvimagesink->dst_roi.x;
1371 result.x = xvimagesink->dst_roi.x;
1372 result.y = xvimagesink->dst_roi.y;
1373 result.w = xvimagesink->dst_roi.w;
1374 result.h = xvimagesink->dst_roi.h;
1378 GST_LOG_OBJECT(xvimagesink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1379 xvimagesink->rotate_angle,
1380 xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1381 result.x, result.y, result.w, result.h);
1382 #else /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1383 result.x = xvimagesink->dst_roi.x;
1384 result.y = xvimagesink->dst_roi.y;
1385 result.w = xvimagesink->dst_roi.w;
1386 result.h = xvimagesink->dst_roi.h;
1388 if (xvimagesink->rotate_angle == DEGREE_90 ||
1389 xvimagesink->rotate_angle == DEGREE_270) {
1390 result.w = xvimagesink->dst_roi.h;
1391 result.h = xvimagesink->dst_roi.w;
1393 #endif /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1400 if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) {
1401 src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1;
1402 src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1;
1403 src_input.w /= xvimagesink->zoom;
1404 src_input.h /= xvimagesink->zoom;
1407 #else /* GST_EXT_XV_ENHANCEMENT */
1408 if (xvimagesink->keep_aspect) {
1409 GstVideoRectangle src, dst;
1411 /* We use the calculated geometry from _setcaps as a source to respect
1412 source and screen pixel aspect ratios. */
1413 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1414 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1415 dst.w = xvimagesink->render_rect.w;
1416 dst.h = xvimagesink->render_rect.h;
1418 gst_video_sink_center_rect (src, dst, &result, TRUE);
1419 result.x += xvimagesink->render_rect.x;
1420 result.y += xvimagesink->render_rect.y;
1422 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1424 #endif /* GST_EXT_XV_ENHANCEMENT */
1426 g_mutex_lock (xvimagesink->x_lock);
1428 #ifdef GST_EXT_XV_ENHANCEMENT
1429 if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
1431 if (draw_border && xvimagesink->draw_borders) {
1432 #endif /* GST_EXT_XV_ENHANCEMENT */
1433 gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1435 xvimagesink->redraw_border = FALSE;
1438 /* We scale to the window's geometry */
1440 if (xvimagesink->xcontext->use_xshm) {
1441 GST_LOG_OBJECT (xvimagesink,
1442 "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1444 xvimage->width, xvimage->height,
1445 xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1447 #ifdef GST_EXT_XV_ENHANCEMENT
1448 switch( xvimagesink->rotate_angle )
1450 /* There's slightly weired code (CCW? CW?) */
1463 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1464 xvimagesink->rotate_angle );
1468 /* Trim as proper size */
1469 if (src_input.w % 2 == 1) {
1472 if (src_input.h % 2 == 1) {
1476 if (!xvimagesink->get_pixmap_cb) {
1477 GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1478 xvimagesink->scr_w, xvimagesink->scr_h,
1479 xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1480 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1481 src_origin.w, src_origin.h,
1482 dst.x, dst.y, dst.w, dst.h,
1483 src_input.x, src_input.y, src_input.w, src_input.h,
1484 result.x, result.y, result.w, result.h );
1486 GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1487 xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
1488 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1489 src_origin.w, src_origin.h,
1490 dst.x, dst.y, dst.w, dst.h,
1491 src_input.x, src_input.y, src_input.w, src_input.h,
1492 result.x, result.y, result.w, result.h );
1495 /* set display rotation */
1496 if (atom_rotation == None) {
1497 atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1498 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1501 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate);
1502 if (ret != Success) {
1503 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1504 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1508 /* set display flip */
1509 if (atom_hflip == None) {
1510 atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
1511 "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1513 if (atom_vflip == None) {
1514 atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
1515 "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1518 switch (xvimagesink->flip) {
1519 case FLIP_HORIZONTAL:
1538 GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
1540 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1541 if (ret != Success) {
1542 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1543 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
1545 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1546 if (ret != Success) {
1547 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1548 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
1551 /* set error handler */
1552 error_caught = FALSE;
1553 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
1555 /* src input indicates the status when degree is 0 */
1556 /* dst input indicates the area that src will be shown regardless of rotate */
1557 if (xvimagesink->visible && !xvimagesink->is_hided) {
1558 if (xvimagesink->xim_transparenter) {
1559 GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1560 XPutImage(xvimagesink->xcontext->disp,
1561 xvimagesink->xwindow->win,
1562 xvimagesink->xwindow->gc,
1563 xvimagesink->xim_transparenter,
1565 result.x, result.y, result.w, result.h);
1569 if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) {
1570 img_data = (XV_DATA_PTR)xvimage->xvimage->data;
1571 if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
1572 _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
1573 xvimage->current_buffer = NULL;
1577 g_mutex_lock(xvimagesink->display_buffer_lock);
1578 if (xvimagesink->displaying_buffer_count > 3) {
1579 g_mutex_unlock(xvimagesink->display_buffer_lock);
1580 GST_WARNING("too many buffers are pushed. skip this... [displaying_buffer_count %d]",
1581 xvimagesink->displaying_buffer_count);
1583 } else if (xvimagesink->get_pixmap_cb) {
1584 gint idx = xvimagesink->current_pixmap_idx;
1586 g_mutex_unlock(xvimagesink->display_buffer_lock);
1588 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1589 xvimagesink->xcontext->xv_port_id,
1590 xvimagesink->xpixmap[idx]->pixmap,
1591 xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
1592 src_input.x, src_input.y, src_input.w, src_input.h,
1593 result.x, result.y, result.w, result.h, FALSE);
1594 GST_LOG_OBJECT(xvimagesink, "pixmap[%d]->pixmap = %d", idx, xvimagesink->xpixmap[idx]->pixmap);
1596 g_mutex_unlock(xvimagesink->display_buffer_lock);
1598 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1599 xvimagesink->xcontext->xv_port_id,
1600 xvimagesink->xwindow->win,
1601 xvimagesink->xwindow->gc, xvimage->xvimage,
1602 src_input.x, src_input.y, src_input.w, src_input.h,
1603 result.x, result.y, result.w, result.h, FALSE);
1605 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret );
1607 GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1609 #else /* GST_EXT_XV_ENHANCEMENT */
1610 XvShmPutImage (xvimagesink->xcontext->disp,
1611 xvimagesink->xcontext->xv_port_id,
1612 xvimagesink->xwindow->win,
1613 xvimagesink->xwindow->gc, xvimage->xvimage,
1614 xvimagesink->disp_x, xvimagesink->disp_y,
1615 xvimagesink->disp_width, xvimagesink->disp_height,
1616 result.x, result.y, result.w, result.h, FALSE);
1617 #endif /* GST_EXT_XV_ENHANCEMENT */
1619 #endif /* HAVE_XSHM */
1621 XvPutImage (xvimagesink->xcontext->disp,
1622 xvimagesink->xcontext->xv_port_id,
1623 xvimagesink->xwindow->win,
1624 xvimagesink->xwindow->gc, xvimage->xvimage,
1625 xvimagesink->disp_x, xvimagesink->disp_y,
1626 xvimagesink->disp_width, xvimagesink->disp_height,
1627 result.x, result.y, result.w, result.h);
1630 XSync (xvimagesink->xcontext->disp, FALSE);
1633 #ifdef GST_EXT_XV_ENHANCEMENT
1634 if (ret || error_caught || xvimagesink->get_pixmap_cb) {
1635 GST_DEBUG("error or pixmap_cb");
1637 if (ret || error_caught) {
1638 GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
1639 ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
1641 if (xvimagesink->get_pixmap_cb) {
1642 g_signal_emit (G_OBJECT (xvimagesink),
1643 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
1645 &xvimagesink->xpixmap[idx]->pixmap,
1650 /* release gem handle */
1651 if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
1652 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
1653 gem_name[0] = img_data->YBuf;
1654 gem_name[1] = img_data->CbBuf;
1655 gem_name[2] = img_data->CrBuf;
1656 _remove_displaying_buffer(xvimagesink, gem_name);
1660 /* Reset error handler */
1662 error_caught = FALSE;
1663 XSetErrorHandler (handler);
1665 #endif /* GST_EXT_XV_ENHANCEMENT */
1666 #endif /* HAVE_XSHM */
1668 g_mutex_unlock (xvimagesink->x_lock);
1670 g_mutex_unlock (xvimagesink->flow_lock);
1676 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
1677 GstXWindow * window)
1679 Atom hints_atom = None;
1680 MotifWmHints *hints;
1682 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
1683 g_return_val_if_fail (window != NULL, FALSE);
1685 g_mutex_lock (xvimagesink->x_lock);
1687 hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
1689 if (hints_atom == None) {
1690 g_mutex_unlock (xvimagesink->x_lock);
1694 hints = g_malloc0 (sizeof (MotifWmHints));
1696 hints->flags |= MWM_HINTS_DECORATIONS;
1697 hints->decorations = 1 << 0;
1699 XChangeProperty (xvimagesink->xcontext->disp, window->win,
1700 hints_atom, hints_atom, 32, PropModeReplace,
1701 (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
1703 XSync (xvimagesink->xcontext->disp, FALSE);
1705 g_mutex_unlock (xvimagesink->x_lock);
1713 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1714 GstXWindow * xwindow, const gchar * media_title)
1717 g_free (xvimagesink->media_title);
1718 xvimagesink->media_title = g_strdup (media_title);
1721 /* we have a window */
1722 if (xwindow->internal) {
1723 XTextProperty xproperty;
1724 const gchar *app_name;
1725 const gchar *title = NULL;
1726 gchar *title_mem = NULL;
1728 /* set application name as a title */
1729 app_name = g_get_application_name ();
1731 if (app_name && xvimagesink->media_title) {
1732 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1734 } else if (app_name) {
1736 } else if (xvimagesink->media_title) {
1737 title = xvimagesink->media_title;
1741 if ((XStringListToTextProperty (((char **) &title), 1,
1742 &xproperty)) != 0) {
1743 XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
1744 XFree (xproperty.value);
1753 #ifdef GST_EXT_XV_ENHANCEMENT
1754 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
1758 /* create a normal ximage */
1759 xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
1761 GST_INFO("ximage %p", xim);
1763 /* allocate data for it */
1765 xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
1767 memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
1770 GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
1776 GST_ERROR("failed to create Ximage");
1782 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
1785 static gboolean is_exist = FALSE;
1786 static XvPortID current_port_id = -1;
1787 Atom atom_output = None;
1789 if (xcontext == NULL) {
1790 GST_WARNING("xcontext is NULL");
1794 /* check once per one xv_port_id */
1795 if (current_port_id != xcontext->xv_port_id) {
1796 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
1799 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
1800 xcontext->xv_port_id, &count);
1802 current_port_id = xcontext->xv_port_id;
1803 for (i = 0 ; i < count ; i++) {
1804 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
1806 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
1812 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
1813 xcontext->disp, xcontext->xv_port_id);
1818 GST_WARNING("set display mode %d", set_mode);
1819 atom_output = XInternAtom(xcontext->disp,
1820 "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
1821 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
1822 atom_output, set_mode);
1823 if (ret == Success) {
1826 GST_WARNING("display mode[%d] set failed.", set_mode);
1829 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
1836 static gboolean set_csc_range(GstXContext *xcontext, int set_range)
1839 static gboolean is_exist = FALSE;
1840 static XvPortID current_port_id = -1;
1841 Atom atom_csc_range = None;
1843 if (xcontext == NULL) {
1844 GST_WARNING("xcontext is NULL");
1848 /* check once per one xv_port_id */
1849 if (current_port_id != xcontext->xv_port_id) {
1850 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
1853 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
1854 xcontext->xv_port_id, &count);
1856 current_port_id = xcontext->xv_port_id;
1857 for (i = 0 ; i < count ; i++) {
1858 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
1860 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
1866 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
1867 xcontext->disp, xcontext->xv_port_id);
1872 GST_WARNING("set csc range %d", set_range);
1873 atom_csc_range = XInternAtom(xcontext->disp,
1874 "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
1875 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
1876 atom_csc_range, set_range);
1877 if (ret == Success) {
1880 GST_WARNING("csc range[%d] set failed.", set_range);
1883 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
1890 static void drm_init(GstXvImageSink *xvimagesink)
1897 char *driverName = NULL;
1898 char *deviceName = NULL;
1899 struct drm_auth auth_arg = {0};
1901 xvimagesink->drm_fd = -1;
1903 dpy = XOpenDisplay(0);
1905 GST_ERROR("XOpenDisplay failed errno:%d", errno);
1912 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
1913 GST_ERROR("DRI2QueryExtension !!");
1914 goto DRM_INIT_ERROR;
1917 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
1918 GST_ERROR("DRI2QueryVersion !!");
1919 goto DRM_INIT_ERROR;
1922 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
1923 GST_ERROR("DRI2Connect !!");
1924 goto DRM_INIT_ERROR;
1927 if (!driverName || !deviceName) {
1928 GST_ERROR("driverName or deviceName is not valid");
1929 goto DRM_INIT_ERROR;
1932 GST_INFO("Open drm device : %s", deviceName);
1934 /* get the drm_fd though opening the deviceName */
1935 xvimagesink->drm_fd = open(deviceName, O_RDWR);
1936 if (xvimagesink->drm_fd < 0) {
1937 GST_ERROR("cannot open drm device (%s)", deviceName);
1938 goto DRM_INIT_ERROR;
1941 /* get magic from drm to authentication */
1942 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
1943 GST_ERROR("cannot get drm auth magic");
1944 goto DRM_INIT_ERROR;
1947 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
1948 GST_ERROR("cannot get drm authentication from X");
1949 goto DRM_INIT_ERROR;
1961 if (xvimagesink->drm_fd >= 0) {
1962 close(xvimagesink->drm_fd);
1963 xvimagesink->drm_fd = -1;
1978 static void drm_fini(GstXvImageSink *xvimagesink)
1982 if (xvimagesink->drm_fd >= 0) {
1985 gboolean is_timeout = FALSE;
1987 /* close remained gem handle */
1988 g_mutex_lock(xvimagesink->display_buffer_lock);
1989 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
1990 if (xvimagesink->displaying_buffers[i].buffer) {
1991 GTimeVal abstimeout;
1993 GST_WARNING("remained buffer %p, name %u %u %u, handle %u %u %u",
1994 xvimagesink->displaying_buffers[i].buffer,
1995 xvimagesink->displaying_buffers[i].gem_name[0],
1996 xvimagesink->displaying_buffers[i].gem_name[1],
1997 xvimagesink->displaying_buffers[i].gem_name[2],
1998 xvimagesink->displaying_buffers[i].gem_handle[0],
1999 xvimagesink->displaying_buffers[i].gem_handle[1],
2000 xvimagesink->displaying_buffers[i].gem_handle[2]);
2002 g_get_current_time(&abstimeout);
2003 g_time_val_add(&abstimeout, _BUFFER_WAIT_TIMEOUT);
2006 !g_cond_timed_wait(xvimagesink->display_buffer_cond,
2007 xvimagesink->display_buffer_lock,
2009 GST_ERROR("Buffer wait timeout[%d usec] or is_timeout[%d]. Force Unref buffer",
2010 _BUFFER_WAIT_TIMEOUT, is_timeout);
2012 /* set flag not to wait next time */
2015 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2016 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2017 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2019 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2020 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2021 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2024 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2025 xvimagesink->displaying_buffers[i].buffer = NULL;
2027 GST_WARNING("Signal received. check again...");
2030 /* init index and check again from first */
2034 g_mutex_unlock(xvimagesink->display_buffer_lock);
2036 GST_INFO("close drm_fd %d", xvimagesink->drm_fd);
2037 close(xvimagesink->drm_fd);
2038 xvimagesink->drm_fd = -1;
2040 GST_INFO("DRM device is NOT opened");
2046 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
2050 struct drm_prime_handle prime_arg = {0,};
2051 struct drm_gem_flink flink_arg = {0,};
2053 if (!xvimagesink || !gem_handle) {
2054 GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
2058 if (xvimagesink->drm_fd <= 0) {
2059 GST_ERROR("DRM is not opened");
2063 if (dmabuf_fd <= 0) {
2064 GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
2068 prime_arg.fd = dmabuf_fd;
2069 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
2071 GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u", ret, dmabuf_fd);
2075 *gem_handle = prime_arg.handle;
2076 flink_arg.handle = prime_arg.handle;
2077 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
2079 GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u", ret, *gem_handle, flink_arg.name);
2083 return flink_arg.name;
2086 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
2088 struct drm_gem_close close_arg = {0,};
2090 if (xvimagesink->drm_fd < 0 || !gem_handle) {
2091 GST_ERROR("DRM is not opened");
2095 if (*gem_handle <= 0) {
2096 GST_DEBUG("invalid gem handle %u", *gem_handle);
2100 GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
2102 close_arg.handle = *gem_handle;
2103 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
2104 GST_ERROR("cannot close drm gem handle %u", *gem_handle);
2114 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
2119 if (!xvimagesink || !img_data) {
2120 GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
2124 /* lock display buffer mutex */
2125 g_mutex_lock(xvimagesink->display_buffer_lock);
2127 /* increase displaying buffer count */
2128 xvimagesink->displaying_buffer_count++;
2130 /* check duplicated */
2131 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2132 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2133 if ((img_data->dmabuf_fd[0] > 0 &&
2134 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
2135 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
2136 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
2138 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
2139 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
2140 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
2141 /* increase ref count */
2142 xvimagesink->displaying_buffers[i].ref_count++;
2144 /* set buffer info */
2145 img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
2146 img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
2147 img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
2149 if (img_data->dmabuf_fd[0] > 0) {
2150 GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
2151 img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
2152 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2154 GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
2155 img_data->bo[0], img_data->bo[1], img_data->bo[2],
2156 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2159 /* unlock display buffer mutex */
2160 g_mutex_unlock(xvimagesink->display_buffer_lock);
2166 /* store buffer temporarily */
2167 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2168 if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
2170 /* increase ref count of buffer */
2171 gst_buffer_ref(buffer);
2172 xvimagesink->displaying_buffers[i].buffer = buffer;
2175 if (img_data->dmabuf_fd[0] > 0) {
2176 /* convert fd to name */
2177 img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
2178 img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
2179 img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
2182 if (img_data->bo[0]) {
2183 img_data->YBuf = tbm_bo_export(img_data->bo[0]);
2185 if (img_data->bo[1]) {
2186 img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
2188 if (img_data->bo[2]) {
2189 img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
2193 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2194 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
2195 xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
2196 xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
2199 /* set buffer info */
2200 xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
2201 xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
2202 xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
2205 xvimagesink->displaying_buffers[i].ref_count = 1;
2207 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2208 GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2209 xvimagesink->displayed_buffer_count,
2210 i, xvimagesink->displaying_buffers[i].buffer,
2211 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2212 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2213 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2214 xvimagesink->displaying_buffers[i].gem_handle[0],
2215 xvimagesink->displaying_buffers[i].gem_handle[1],
2216 xvimagesink->displaying_buffers[i].gem_handle[2],
2217 xvimagesink->displaying_buffers[i].gem_name[0],
2218 xvimagesink->displaying_buffers[i].gem_name[1],
2219 xvimagesink->displaying_buffers[i].gem_name[2]);
2221 GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2222 i, xvimagesink->displaying_buffers[i].buffer,
2223 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2224 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2225 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2226 xvimagesink->displaying_buffers[i].gem_handle[0],
2227 xvimagesink->displaying_buffers[i].gem_handle[1],
2228 xvimagesink->displaying_buffers[i].gem_handle[2],
2229 xvimagesink->displaying_buffers[i].gem_name[0],
2230 xvimagesink->displaying_buffers[i].gem_name[1],
2231 xvimagesink->displaying_buffers[i].gem_name[2]);
2234 /* unlock display buffer mutex */
2235 g_mutex_unlock(xvimagesink->display_buffer_lock);
2237 /* get current time */
2238 gettimeofday(&xvimagesink->request_time[i], NULL);
2243 /* decrease displaying buffer count */
2244 xvimagesink->displaying_buffer_count--;
2246 /* unlock display buffer mutex */
2247 g_mutex_unlock(xvimagesink->display_buffer_lock);
2249 GST_ERROR("should not be reached here. buffer slot is FULL...");
2255 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
2260 if (!xvimagesink || !gem_name) {
2261 GST_ERROR("handle is NULL %p, %p", xvimagesink, gem_name);
2265 /* lock display buffer mutex */
2266 g_mutex_lock(xvimagesink->display_buffer_lock);
2268 if (xvimagesink->displaying_buffer_count == 0) {
2269 GST_WARNING("there is no displaying buffer");
2270 /* unlock display buffer mutex */
2271 g_mutex_unlock(xvimagesink->display_buffer_lock);
2275 GST_DEBUG("gem name [%u %u %u], displaying buffer count %d",
2276 gem_name[0], gem_name[1], gem_name[2],
2277 xvimagesink->displaying_buffer_count);
2279 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2280 if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
2281 xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
2282 xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
2283 struct timeval current_time;
2285 /* get current time to calculate displaying time */
2286 gettimeofday(¤t_time, NULL);
2288 GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
2289 (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
2290 (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
2292 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2293 xvimagesink->displayed_buffer_count++;
2294 GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2295 xvimagesink->displayed_buffer_count,
2296 i, xvimagesink->displaying_buffers[i].buffer,
2297 xvimagesink->displaying_buffers[i].gem_handle[0],
2298 xvimagesink->displaying_buffers[i].gem_handle[1],
2299 xvimagesink->displaying_buffers[i].gem_handle[2],
2300 xvimagesink->displaying_buffers[i].gem_name[0],
2301 xvimagesink->displaying_buffers[i].gem_name[1],
2302 xvimagesink->displaying_buffers[i].gem_name[2]);
2304 GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2305 i, xvimagesink->displaying_buffers[i].buffer,
2306 xvimagesink->displaying_buffers[i].gem_handle[0],
2307 xvimagesink->displaying_buffers[i].gem_handle[1],
2308 xvimagesink->displaying_buffers[i].gem_handle[2],
2309 xvimagesink->displaying_buffers[i].gem_name[0],
2310 xvimagesink->displaying_buffers[i].gem_name[1],
2311 xvimagesink->displaying_buffers[i].gem_name[2]);
2314 /* decrease displaying buffer count */
2315 xvimagesink->displaying_buffer_count--;
2317 /* decrease ref count */
2318 xvimagesink->displaying_buffers[i].ref_count--;
2320 if (xvimagesink->displaying_buffers[i].ref_count > 0) {
2321 GST_WARNING("ref count not zero[%d], skip close gem handle",
2322 xvimagesink->displaying_buffers[i].ref_count);
2326 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2327 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2328 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2330 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2331 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2332 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2335 if (xvimagesink->displaying_buffers[i].buffer) {
2336 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2337 xvimagesink->displaying_buffers[i].buffer = NULL;
2339 GST_WARNING("no buffer to unref");
2345 /* send signal to wait display_buffer_cond */
2346 g_cond_signal(xvimagesink->display_buffer_cond);
2348 /* unlock display buffer mutex */
2349 g_mutex_unlock(xvimagesink->display_buffer_lock);
2355 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
2361 unsigned long num_ret = 0;
2362 unsigned long bytes = 0;
2363 unsigned char *prop_ret = NULL;
2364 unsigned int data = 0;
2365 Atom atom_output_external;
2367 atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
2368 "XV_OUTPUT_EXTERNAL", False);
2369 if (atom_output_external != None) {
2370 ret = XGetWindowProperty(xvimagesink->xcontext->disp,
2371 xvimagesink->xwindow->win,
2372 atom_output_external, 0, 0x7fffffff,
2373 False, XA_CARDINAL, &type_ret, &size_ret,
2374 &num_ret, &bytes, &prop_ret);
2375 if (ret != Success) {
2376 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
2384 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
2394 for (i = 0 ; i < num_ret ; i++) {
2395 (&data)[i] = prop_ret[i];
2399 for (i = 0 ; i < num_ret ; i++) {
2400 ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
2404 for (i = 0 ; i < num_ret ; i++) {
2405 ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
2412 GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
2416 GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
2420 GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
2425 #endif /* GST_EXT_XV_ENHANCEMENT */
2427 /* This function handles a GstXWindow creation
2428 * The width and height are the actual pixel size on the display */
2430 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
2431 gint width, gint height)
2433 GstXWindow *xwindow = NULL;
2435 #ifdef GST_EXT_XV_ENHANCEMENT
2436 XSetWindowAttributes win_attr;
2437 XWindowAttributes root_attr;
2438 #endif /* GST_EXT_XV_ENHANCEMENT */
2440 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2442 xwindow = g_new0 (GstXWindow, 1);
2444 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2445 #ifdef GST_EXT_XV_ENHANCEMENT
2447 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
2448 xvimagesink->render_rect.w = xwindow->width = width;
2449 xvimagesink->render_rect.h = xwindow->height = height;
2452 xvimagesink->render_rect.w = xwindow->width = height;
2453 xvimagesink->render_rect.h = xwindow->height = width;
2456 XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
2458 if (xwindow->width > root_attr.width) {
2459 GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
2460 xwindow->width, root_attr.width);
2461 xvimagesink->render_rect.w = xwindow->width = root_attr.width;
2463 if (xwindow->height > root_attr.height) {
2464 GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
2465 xwindow->height, root_attr.height);
2466 xvimagesink->render_rect.h = xwindow->height = root_attr.height;
2468 xwindow->internal = TRUE;
2470 g_mutex_lock (xvimagesink->x_lock);
2472 GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
2474 xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
2475 xvimagesink->xcontext->root,
2476 0, 0, xwindow->width, xwindow->height,
2479 xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
2480 xvimagesink->xcontext->root,
2481 xwindow->width, xwindow->height);
2483 /* Make window manager not to change window size as Full screen */
2484 win_attr.override_redirect = True;
2485 XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
2486 #else /* GST_EXT_XV_ENHANCEMENT */
2487 xvimagesink->render_rect.w = width;
2488 xvimagesink->render_rect.h = height;
2490 xwindow->width = width;
2491 xwindow->height = height;
2492 xwindow->internal = TRUE;
2494 g_mutex_lock (xvimagesink->x_lock);
2496 xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
2497 xvimagesink->xcontext->root,
2498 0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
2499 #endif /* GST_EXT_XV_ENHANCEMENT */
2501 /* We have to do that to prevent X from redrawing the background on
2502 * ConfigureNotify. This takes away flickering of video when resizing. */
2503 XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
2505 /* set application name as a title */
2506 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
2508 if (xvimagesink->handle_events) {
2511 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
2512 StructureNotifyMask | PointerMotionMask | KeyPressMask |
2513 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
2515 /* Tell the window manager we'd like delete client messages instead of
2517 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2518 "WM_DELETE_WINDOW", True);
2519 if (wm_delete != None) {
2520 (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
2525 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
2526 xwindow->win, 0, &values);
2528 XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
2530 XSync (xvimagesink->xcontext->disp, FALSE);
2532 g_mutex_unlock (xvimagesink->x_lock);
2534 gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
2536 gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
2541 /* This function destroys a GstXWindow */
2543 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
2544 GstXWindow * xwindow)
2546 g_return_if_fail (xwindow != NULL);
2547 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2549 g_mutex_lock (xvimagesink->x_lock);
2551 /* If we did not create that window we just free the GC and let it live */
2552 if (xwindow->internal) {
2553 XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
2554 if (xvimagesink->xim_transparenter) {
2555 XDestroyImage(xvimagesink->xim_transparenter);
2556 xvimagesink->xim_transparenter = NULL;
2559 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
2562 XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
2564 XSync (xvimagesink->xcontext->disp, FALSE);
2566 g_mutex_unlock (xvimagesink->x_lock);
2571 #ifdef GST_EXT_XV_ENHANCEMENT
2572 /* This function destroys a GstXWindow */
2574 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
2575 GstXPixmap * xpixmap)
2577 g_return_if_fail (xpixmap != NULL);
2578 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2580 g_mutex_lock (xvimagesink->x_lock);
2582 XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
2584 XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
2586 XSync (xvimagesink->xcontext->disp, FALSE);
2588 g_mutex_unlock (xvimagesink->x_lock);
2592 #endif /* GST_EXT_XV_ENHANCEMENT */
2595 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
2597 #ifdef GST_EXT_XV_ENHANCEMENT
2598 Window root_window, child_window;
2599 XWindowAttributes root_attr;
2603 unsigned int cur_win_width = 0;
2604 unsigned int cur_win_height = 0;
2605 unsigned int cur_win_border_width = 0;
2606 unsigned int cur_win_depth = 0;
2607 #else /* GST_EXT_XV_ENHANCEMENT */
2608 XWindowAttributes attr;
2609 #endif /* GST_EXT_XV_ENHANCEMENT */
2611 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2613 /* Update the window geometry */
2614 g_mutex_lock (xvimagesink->x_lock);
2615 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
2616 g_mutex_unlock (xvimagesink->x_lock);
2620 #ifdef GST_EXT_XV_ENHANCEMENT
2621 /* Get root window and size of current window */
2622 XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
2623 &cur_win_x, &cur_win_y, /* relative x, y */
2624 &cur_win_width, &cur_win_height,
2625 &cur_win_border_width, &cur_win_depth );
2627 xvimagesink->xwindow->width = cur_win_width;
2628 xvimagesink->xwindow->height = cur_win_height;
2630 /* Get absolute coordinates of current window */
2631 XTranslateCoordinates( xvimagesink->xcontext->disp,
2632 xvimagesink->xwindow->win,
2635 &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
2638 xvimagesink->xwindow->x = cur_win_x;
2639 xvimagesink->xwindow->y = cur_win_y;
2641 /* Get size of root window == size of screen */
2642 XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
2644 xvimagesink->scr_w = root_attr.width;
2645 xvimagesink->scr_h = root_attr.height;
2647 if (!xvimagesink->have_render_rect) {
2648 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2649 xvimagesink->render_rect.w = cur_win_width;
2650 xvimagesink->render_rect.h = cur_win_height;
2653 GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
2654 xvimagesink->scr_w, xvimagesink->scr_h,
2655 xvimagesink->xwindow->x, xvimagesink->xwindow->y,
2656 xvimagesink->xwindow->width, xvimagesink->xwindow->height,
2657 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
2658 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
2659 #else /* GST_EXT_XV_ENHANCEMENT */
2660 XGetWindowAttributes (xvimagesink->xcontext->disp,
2661 xvimagesink->xwindow->win, &attr);
2663 xvimagesink->xwindow->width = attr.width;
2664 xvimagesink->xwindow->height = attr.height;
2666 if (!xvimagesink->have_render_rect) {
2667 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2668 xvimagesink->render_rect.w = attr.width;
2669 xvimagesink->render_rect.h = attr.height;
2671 #endif /* GST_EXT_XV_ENHANCEMENT */
2673 g_mutex_unlock (xvimagesink->x_lock);
2677 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
2678 GstXWindow * xwindow)
2680 g_return_if_fail (xwindow != NULL);
2681 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2683 g_mutex_lock (xvimagesink->x_lock);
2684 #ifdef GST_EXT_XV_ENHANCEMENT
2685 GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
2686 #endif /* GST_EXT_XV_ENHANCEMENT */
2688 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
2690 #ifdef GST_EXT_XV_ENHANCEMENT
2692 /* NOTE : it should be enabled in pixmap buffer case,
2693 if we can check whether if it is a pixmap or a window by X API */
2694 /* Preview area is not updated before other UI is updated in the screen. */
2695 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
2696 xvimagesink->xcontext->black);
2698 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
2699 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
2700 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
2702 #endif /* GST_EXT_XV_ENHANCEMENT */
2704 XSync (xvimagesink->xcontext->disp, FALSE);
2706 g_mutex_unlock (xvimagesink->x_lock);
2709 /* This function commits our internal colorbalance settings to our grabbed Xv
2710 port. If the xcontext is not initialized yet it simply returns */
2712 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
2714 GList *channels = NULL;
2716 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2718 /* If we haven't initialized the X context we can't update anything */
2719 if (xvimagesink->xcontext == NULL)
2722 /* Don't set the attributes if they haven't been changed, to avoid
2723 * rounding errors changing the values */
2724 if (!xvimagesink->cb_changed)
2727 /* For each channel of the colorbalance we calculate the correct value
2728 doing range conversion and then set the Xv port attribute to match our
2730 channels = xvimagesink->xcontext->channels_list;
2733 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
2734 GstColorBalanceChannel *channel = NULL;
2737 gdouble convert_coef;
2739 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
2740 g_object_ref (channel);
2742 /* Our range conversion coef */
2743 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
2745 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2746 value = xvimagesink->hue;
2747 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2748 value = xvimagesink->saturation;
2749 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2750 value = xvimagesink->contrast;
2751 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2752 value = xvimagesink->brightness;
2754 g_warning ("got an unknown channel %s", channel->label);
2755 g_object_unref (channel);
2759 /* Committing to Xv port */
2760 g_mutex_lock (xvimagesink->x_lock);
2762 XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
2763 if (prop_atom != None) {
2766 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
2767 XvSetPortAttribute (xvimagesink->xcontext->disp,
2768 xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
2770 g_mutex_unlock (xvimagesink->x_lock);
2772 g_object_unref (channel);
2774 channels = g_list_next (channels);
2778 /* This function handles XEvents that might be in the queue. It generates
2779 GstEvent that will be sent upstream in the pipeline to handle interactivity
2780 and navigation. It will also listen for configure events on the window to
2781 trigger caps renegotiation so on the fly software scaling can work. */
2783 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
2786 guint pointer_x = 0, pointer_y = 0;
2787 gboolean pointer_moved = FALSE;
2788 gboolean exposed = FALSE, configured = FALSE;
2790 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2792 #ifdef GST_EXT_XV_ENHANCEMENT
2793 GST_LOG("check x event");
2794 #endif /* GST_EXT_XV_ENHANCEMENT */
2796 /* Handle Interaction, produces navigation events */
2798 /* We get all pointer motion events, only the last position is
2800 g_mutex_lock (xvimagesink->flow_lock);
2801 g_mutex_lock (xvimagesink->x_lock);
2802 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2803 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
2804 g_mutex_unlock (xvimagesink->x_lock);
2805 g_mutex_unlock (xvimagesink->flow_lock);
2809 pointer_x = e.xmotion.x;
2810 pointer_y = e.xmotion.y;
2811 pointer_moved = TRUE;
2816 g_mutex_lock (xvimagesink->flow_lock);
2817 g_mutex_lock (xvimagesink->x_lock);
2819 if (pointer_moved) {
2820 g_mutex_unlock (xvimagesink->x_lock);
2821 g_mutex_unlock (xvimagesink->flow_lock);
2823 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
2824 pointer_x, pointer_y);
2825 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2826 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
2828 g_mutex_lock (xvimagesink->flow_lock);
2829 g_mutex_lock (xvimagesink->x_lock);
2832 /* We get all events on our window to throw them upstream */
2833 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2834 xvimagesink->xwindow->win,
2835 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
2839 /* We lock only for the X function call */
2840 g_mutex_unlock (xvimagesink->x_lock);
2841 g_mutex_unlock (xvimagesink->flow_lock);
2845 /* Mouse button pressed over our window. We send upstream
2846 events for interactivity/navigation */
2847 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
2848 e.xbutton.button, e.xbutton.x, e.xbutton.y);
2849 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2850 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
2853 /* Mouse button released over our window. We send upstream
2854 events for interactivity/navigation */
2855 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
2856 e.xbutton.button, e.xbutton.x, e.xbutton.y);
2857 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
2858 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
2862 /* Key pressed/released over our window. We send upstream
2863 events for interactivity/navigation */
2864 GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
2865 e.xkey.keycode, e.xkey.x, e.xkey.y);
2866 g_mutex_lock (xvimagesink->x_lock);
2867 keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
2869 g_mutex_unlock (xvimagesink->x_lock);
2870 if (keysym != NoSymbol) {
2871 char *key_str = NULL;
2873 g_mutex_lock (xvimagesink->x_lock);
2874 key_str = XKeysymToString (keysym);
2875 g_mutex_unlock (xvimagesink->x_lock);
2876 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
2877 e.type == KeyPress ? "key-press" : "key-release", key_str);
2879 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
2880 e.type == KeyPress ? "key-press" : "key-release", "unknown");
2884 GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
2886 g_mutex_lock (xvimagesink->flow_lock);
2887 g_mutex_lock (xvimagesink->x_lock);
2891 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
2892 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
2897 case ConfigureNotify:
2898 g_mutex_unlock (xvimagesink->x_lock);
2899 #ifdef GST_EXT_XV_ENHANCEMENT
2900 GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
2901 #endif /* GST_EXT_XV_ENHANCEMENT */
2902 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
2903 #ifdef GST_EXT_XV_ENHANCEMENT
2904 GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
2905 #endif /* GST_EXT_XV_ENHANCEMENT */
2906 g_mutex_lock (xvimagesink->x_lock);
2914 if (xvimagesink->handle_expose && (exposed || configured)) {
2915 g_mutex_unlock (xvimagesink->x_lock);
2916 g_mutex_unlock (xvimagesink->flow_lock);
2918 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
2920 g_mutex_lock (xvimagesink->flow_lock);
2921 g_mutex_lock (xvimagesink->x_lock);
2924 /* Handle Display events */
2925 while (XPending (xvimagesink->xcontext->disp)) {
2926 XNextEvent (xvimagesink->xcontext->disp, &e);
2929 case ClientMessage:{
2930 #ifdef GST_EXT_XV_ENHANCEMENT
2931 XClientMessageEvent *cme = (XClientMessageEvent *)&e;
2932 Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
2933 #endif /* GST_EXT_XV_ENHANCEMENT */
2936 #ifdef GST_EXT_XV_ENHANCEMENT
2937 GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
2938 if (cme->message_type == buffer_atom) {
2939 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
2941 GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
2942 cme->data.l[0], cme->data.l[1]);
2944 gem_name[0] = cme->data.l[0];
2945 gem_name[1] = cme->data.l[1];
2947 _remove_displaying_buffer(xvimagesink, gem_name);
2950 #endif /* GST_EXT_XV_ENHANCEMENT */
2952 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
2953 "WM_DELETE_WINDOW", True);
2954 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
2955 /* Handle window deletion by posting an error on the bus */
2956 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
2957 ("Output window was closed"), (NULL));
2959 g_mutex_unlock (xvimagesink->x_lock);
2960 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
2961 xvimagesink->xwindow = NULL;
2962 g_mutex_lock (xvimagesink->x_lock);
2966 #ifdef GST_EXT_XV_ENHANCEMENT
2967 case VisibilityNotify:
2968 if (xvimagesink->xwindow &&
2969 (e.xvisibility.window == xvimagesink->xwindow->win)) {
2970 if (e.xvisibility.state == VisibilityFullyObscured) {
2973 GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
2975 if (!_is_connected_to_external_display(xvimagesink)) {
2977 atom_stream = XInternAtom(xvimagesink->xcontext->disp,
2978 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
2980 GST_WARNING_OBJECT(xvimagesink, "call STREAM_OFF");
2982 xvimagesink->is_hided = TRUE;
2983 atom_stream = XInternAtom(xvimagesink->xcontext->disp,
2984 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
2985 if (atom_stream != None) {
2986 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
2987 xvimagesink->xcontext->xv_port_id,
2988 atom_stream, 0) != Success) {
2989 GST_WARNING_OBJECT(xvimagesink, "STREAM OFF failed");
2993 GST_WARNING_OBJECT(xvimagesink, "atom_stream is NONE");
2996 xvimagesink->is_hided = TRUE;
2997 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
2998 XSync(xvimagesink->xcontext->disp, FALSE);
3000 GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip STREAM_OFF");
3003 GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
3005 if (xvimagesink->is_hided) {
3006 g_mutex_unlock(xvimagesink->x_lock);
3007 g_mutex_unlock(xvimagesink->flow_lock);
3009 xvimagesink->is_hided = FALSE;
3010 gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
3012 g_mutex_lock(xvimagesink->flow_lock);
3013 g_mutex_lock(xvimagesink->x_lock);
3015 GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
3020 #endif /* GST_EXT_XV_ENHANCEMENT */
3026 g_mutex_unlock (xvimagesink->x_lock);
3027 g_mutex_unlock (xvimagesink->flow_lock);
3031 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3032 XvAdaptorInfo * adaptors, int adaptor_no)
3037 /* Do we support XvImageMask ? */
3038 if (!(adaptors[adaptor_no].type & XvImageMask)) {
3039 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3040 adaptors[adaptor_no].name);
3044 /* We found such an adaptor, looking for an available port */
3045 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3046 /* We try to grab the port */
3047 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3048 if (Success == res) {
3049 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3050 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3051 adaptors[adaptor_no].num_ports);
3053 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3054 adaptors[adaptor_no].name, res);
3059 /* This function generates a caps with all supported format by the first
3060 Xv grabable port we find. We store each one of the supported formats in a
3061 format list and append the format to a newly created caps that we return
3062 If this function does not return NULL because of an error, it also grabs
3063 the port via XvGrabPort */
3065 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3066 GstXContext * xcontext)
3069 XvAdaptorInfo *adaptors;
3071 XvImageFormatValues *formats = NULL;
3073 XvEncodingInfo *encodings = NULL;
3074 gulong max_w = G_MAXINT, max_h = G_MAXINT;
3075 GstCaps *caps = NULL;
3076 GstCaps *rgb_caps = NULL;
3078 g_return_val_if_fail (xcontext != NULL, NULL);
3080 /* First let's check that XVideo extension is available */
3081 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3082 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3083 ("Could not initialise Xv output"),
3084 ("XVideo extension is not available"));
3088 /* Then we get adaptors list */
3089 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3090 &xcontext->nb_adaptors, &adaptors)) {
3091 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3092 ("Could not initialise Xv output"),
3093 ("Failed getting XV adaptors list"));
3097 xcontext->xv_port_id = 0;
3099 GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors);
3101 xcontext->adaptors =
3102 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3104 /* Now fill up our adaptor name array */
3105 for (i = 0; i < xcontext->nb_adaptors; i++) {
3106 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3109 if (xvimagesink->adaptor_no >= 0 &&
3110 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3111 /* Find xv port from user defined adaptor */
3112 gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
3113 xvimagesink->adaptor_no);
3116 if (!xcontext->xv_port_id) {
3117 /* Now search for an adaptor that supports XvImageMask */
3118 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3119 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3120 xvimagesink->adaptor_no = i;
3124 XvFreeAdaptorInfo (adaptors);
3126 if (!xcontext->xv_port_id) {
3127 xvimagesink->adaptor_no = -1;
3128 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3129 ("Could not initialise Xv output"), ("No port available"));
3133 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3135 int count, todo = 3;
3136 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3137 xcontext->xv_port_id, &count);
3138 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3139 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3140 static const char colorkey[] = "XV_COLORKEY";
3142 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3144 xvimagesink->have_autopaint_colorkey = FALSE;
3145 xvimagesink->have_double_buffer = FALSE;
3146 xvimagesink->have_colorkey = FALSE;
3148 for (i = 0; ((i < count) && todo); i++)
3149 if (!strcmp (attr[i].name, autopaint)) {
3150 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3152 /* turn on autopaint colorkey */
3153 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3154 (xvimagesink->autopaint_colorkey ? 1 : 0));
3156 xvimagesink->have_autopaint_colorkey = TRUE;
3157 } else if (!strcmp (attr[i].name, dbl_buffer)) {
3158 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3160 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3161 (xvimagesink->double_buffer ? 1 : 0));
3163 xvimagesink->have_double_buffer = TRUE;
3164 } else if (!strcmp (attr[i].name, colorkey)) {
3165 /* Set the colorkey, default is something that is dark but hopefully
3166 * won't randomly appear on the screen elsewhere (ie not black or greys)
3167 * can be overridden by setting "colorkey" property
3169 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3171 gboolean set_attr = TRUE;
3174 /* set a colorkey in the right format RGB565/RGB888
3175 * We only handle these 2 cases, because they're the only types of
3176 * devices we've encountered. If we don't recognise it, leave it alone
3178 cr = (xvimagesink->colorkey >> 16);
3179 cg = (xvimagesink->colorkey >> 8) & 0xFF;
3180 cb = (xvimagesink->colorkey) & 0xFF;
3181 switch (xcontext->depth) {
3182 case 16: /* RGB 565 */
3186 ckey = (cr << 11) | (cg << 5) | cb;
3189 case 32: /* RGB 888 / ARGB 8888 */
3190 ckey = (cr << 16) | (cg << 8) | cb;
3193 GST_DEBUG_OBJECT (xvimagesink,
3194 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3201 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3202 (guint32) attr[i].max_value);
3203 GST_LOG_OBJECT (xvimagesink,
3204 "Setting color key for display depth %d to 0x%x",
3205 xcontext->depth, ckey);
3207 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3211 xvimagesink->have_colorkey = TRUE;
3217 /* Get the list of encodings supported by the adapter and look for the
3218 * XV_IMAGE encoding so we can determine the maximum width and height
3220 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3223 for (i = 0; i < nb_encodings; i++) {
3224 GST_LOG_OBJECT (xvimagesink,
3225 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3226 i, encodings[i].name, encodings[i].width, encodings[i].height,
3227 encodings[i].rate.numerator, encodings[i].rate.denominator);
3228 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3229 max_w = encodings[i].width;
3230 max_h = encodings[i].height;
3231 #ifdef GST_EXT_XV_ENHANCEMENT
3232 xvimagesink->scr_w = max_w;
3233 xvimagesink->scr_h = max_h;
3234 #endif /* GST_EXT_XV_ENHANCEMENT */
3238 XvFreeEncodingInfo (encodings);
3240 /* We get all image formats supported by our port */
3241 formats = XvListImageFormats (xcontext->disp,
3242 xcontext->xv_port_id, &nb_formats);
3243 caps = gst_caps_new_empty ();
3244 for (i = 0; i < nb_formats; i++) {
3245 GstCaps *format_caps = NULL;
3246 gboolean is_rgb_format = FALSE;
3248 /* We set the image format of the xcontext to an existing one. This
3249 is just some valid image format for making our xshm calls check before
3250 caps negotiation really happens. */
3251 xcontext->im_format = formats[i].id;
3253 switch (formats[i].type) {
3256 XvImageFormatValues *fmt = &(formats[i]);
3257 gint endianness = G_BIG_ENDIAN;
3259 if (fmt->byte_order == LSBFirst) {
3260 /* our caps system handles 24/32bpp RGB as big-endian. */
3261 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
3262 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
3263 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
3264 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
3266 if (fmt->bits_per_pixel == 24) {
3267 fmt->red_mask >>= 8;
3268 fmt->green_mask >>= 8;
3269 fmt->blue_mask >>= 8;
3272 endianness = G_LITTLE_ENDIAN;
3275 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
3276 #ifdef GST_EXT_XV_ENHANCEMENT
3277 "format", GST_TYPE_FOURCC, formats[i].id,
3278 #endif /* GST_EXT_XV_ENHANCEMENT */
3279 "endianness", G_TYPE_INT, endianness,
3280 "depth", G_TYPE_INT, fmt->depth,
3281 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
3282 "red_mask", G_TYPE_INT, fmt->red_mask,
3283 "green_mask", G_TYPE_INT, fmt->green_mask,
3284 "blue_mask", G_TYPE_INT, fmt->blue_mask,
3285 "width", GST_TYPE_INT_RANGE, 1, max_w,
3286 "height", GST_TYPE_INT_RANGE, 1, max_h,
3287 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3289 is_rgb_format = TRUE;
3293 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
3294 "format", GST_TYPE_FOURCC, formats[i].id,
3295 "width", GST_TYPE_INT_RANGE, 1, max_w,
3296 "height", GST_TYPE_INT_RANGE, 1, max_h,
3297 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3300 g_assert_not_reached ();
3305 GstXvImageFormat *format = NULL;
3307 format = g_new0 (GstXvImageFormat, 1);
3309 format->format = formats[i].id;
3310 format->caps = gst_caps_copy (format_caps);
3311 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
3314 if (is_rgb_format) {
3315 if (rgb_caps == NULL)
3316 rgb_caps = format_caps;
3318 gst_caps_append (rgb_caps, format_caps);
3320 gst_caps_append (caps, format_caps);
3324 /* Collected all caps into either the caps or rgb_caps structures.
3325 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
3327 gst_caps_append (caps, rgb_caps);
3332 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
3334 if (gst_caps_is_empty (caps)) {
3335 gst_caps_unref (caps);
3336 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
3337 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
3338 ("No supported format found"));
3346 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
3348 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3350 GST_OBJECT_LOCK (xvimagesink);
3351 while (xvimagesink->running) {
3352 GST_OBJECT_UNLOCK (xvimagesink);
3354 if (xvimagesink->xwindow) {
3355 gst_xvimagesink_handle_xevents (xvimagesink);
3358 #ifdef GST_EXT_XV_ENHANCEMENT
3359 g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
3360 #else /* GST_EXT_XV_ENHANCEMENT */
3361 /* FIXME: do we want to align this with the framerate or anything else? */
3362 g_usleep (G_USEC_PER_SEC / 20);
3363 #endif /* GST_EXT_XV_ENHANCEMENT */
3365 GST_OBJECT_LOCK (xvimagesink);
3367 GST_OBJECT_UNLOCK (xvimagesink);
3373 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
3375 GThread *thread = NULL;
3377 /* don't start the thread too early */
3378 if (xvimagesink->xcontext == NULL) {
3382 GST_OBJECT_LOCK (xvimagesink);
3383 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
3384 if (!xvimagesink->event_thread) {
3385 /* Setup our event listening thread */
3386 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
3387 xvimagesink->handle_expose, xvimagesink->handle_events);
3388 xvimagesink->running = TRUE;
3389 #if !GLIB_CHECK_VERSION (2, 31, 0)
3390 xvimagesink->event_thread = g_thread_create (
3391 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
3393 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
3394 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
3398 if (xvimagesink->event_thread) {
3399 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
3400 xvimagesink->handle_expose, xvimagesink->handle_events);
3401 xvimagesink->running = FALSE;
3402 /* grab thread and mark it as NULL */
3403 thread = xvimagesink->event_thread;
3404 xvimagesink->event_thread = NULL;
3407 GST_OBJECT_UNLOCK (xvimagesink);
3409 /* Wait for our event thread to finish */
3411 g_thread_join (thread);
3416 #ifdef GST_EXT_XV_ENHANCEMENT
3418 * gst_xvimagesink_prepare_xid:
3419 * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
3421 * This will post a "prepare-xid" element message with video size and display size on the bus
3422 * to give applications an opportunity to call
3423 * gst_x_overlay_set_xwindow_id() before a plugin creates its own
3426 * This function should only be used by video overlay plugin developers.
3429 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
3434 g_return_if_fail (overlay != NULL);
3435 g_return_if_fail (GST_IS_X_OVERLAY (overlay));
3437 GstXvImageSink *xvimagesink;
3438 xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
3440 GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
3441 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
3443 GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
3444 s = gst_structure_new ("prepare-xid",
3445 "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
3446 "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
3447 "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
3448 "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
3450 msg = gst_message_new_element (GST_OBJECT (overlay), s);
3451 gst_element_post_message (GST_ELEMENT (overlay), msg);
3453 #endif /* GST_EXT_XV_ENHANCEMENT */
3456 /* This function calculates the pixel aspect ratio based on the properties
3457 * in the xcontext structure and stores it there. */
3459 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
3461 static const gint par[][2] = {
3462 {1, 1}, /* regular screen */
3463 {16, 15}, /* PAL TV */
3464 {11, 10}, /* 525 line Rec.601 video */
3465 {54, 59}, /* 625 line Rec.601 video */
3466 {64, 45}, /* 1280x1024 on 16:9 display */
3467 {5, 3}, /* 1280x1024 on 4:3 display */
3468 {4, 3} /* 800x600 on 16:9 display */
3475 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
3477 /* first calculate the "real" ratio based on the X values;
3478 * which is the "physical" w/h divided by the w/h in pixels of the display */
3479 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
3480 / (xcontext->heightmm * xcontext->width);
3482 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
3484 if (xcontext->width == 720 && xcontext->height == 576) {
3485 ratio = 4.0 * 576 / (3.0 * 720);
3487 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
3488 /* now find the one from par[][2] with the lowest delta to the real one */
3492 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
3493 gdouble this_delta = DELTA (i);
3495 if (this_delta < delta) {
3501 GST_DEBUG ("Decided on index %d (%d/%d)", index,
3502 par[index][0], par[index][1]);
3504 g_free (xcontext->par);
3505 xcontext->par = g_new0 (GValue, 1);
3506 g_value_init (xcontext->par, GST_TYPE_FRACTION);
3507 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
3508 GST_DEBUG ("set xcontext PAR to %d/%d",
3509 gst_value_get_fraction_numerator (xcontext->par),
3510 gst_value_get_fraction_denominator (xcontext->par));
3513 /* This function gets the X Display and global info about it. Everything is
3514 stored in our object and will be cleaned when the object is disposed. Note
3515 here that caps for supported format are generated without any window or
3517 static GstXContext *
3518 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
3520 GstXContext *xcontext = NULL;
3521 XPixmapFormatValues *px_formats = NULL;
3522 gint nb_formats = 0, i, j, N_attr;
3523 XvAttribute *xv_attr;
3525 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
3526 "XV_BRIGHTNESS", "XV_CONTRAST"
3529 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3531 xcontext = g_new0 (GstXContext, 1);
3532 xcontext->im_format = 0;
3534 g_mutex_lock (xvimagesink->x_lock);
3536 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
3538 if (!xcontext->disp) {
3539 g_mutex_unlock (xvimagesink->x_lock);
3541 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
3542 ("Could not initialise Xv output"), ("Could not open display"));
3546 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
3547 xcontext->screen_num = DefaultScreen (xcontext->disp);
3548 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
3549 xcontext->root = DefaultRootWindow (xcontext->disp);
3550 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
3551 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
3552 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
3554 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
3555 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
3556 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
3557 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
3559 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
3560 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
3562 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
3563 /* We get supported pixmap formats at supported depth */
3564 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
3567 XCloseDisplay (xcontext->disp);
3568 g_mutex_unlock (xvimagesink->x_lock);
3569 g_free (xcontext->par);
3571 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3572 ("Could not initialise Xv output"), ("Could not get pixel formats"));
3576 /* We get bpp value corresponding to our running depth */
3577 for (i = 0; i < nb_formats; i++) {
3578 if (px_formats[i].depth == xcontext->depth)
3579 xcontext->bpp = px_formats[i].bits_per_pixel;
3584 xcontext->endianness =
3585 (ImageByteOrder (xcontext->disp) ==
3586 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
3588 /* our caps system handles 24/32bpp RGB as big-endian. */
3589 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
3590 xcontext->endianness == G_LITTLE_ENDIAN) {
3591 xcontext->endianness = G_BIG_ENDIAN;
3592 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
3593 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
3594 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
3595 if (xcontext->bpp == 24) {
3596 xcontext->visual->red_mask >>= 8;
3597 xcontext->visual->green_mask >>= 8;
3598 xcontext->visual->blue_mask >>= 8;
3602 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
3604 if (!xcontext->caps) {
3605 XCloseDisplay (xcontext->disp);
3606 g_mutex_unlock (xvimagesink->x_lock);
3607 g_free (xcontext->par);
3609 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
3613 /* Search for XShm extension support */
3614 if (XShmQueryExtension (xcontext->disp) &&
3615 gst_xvimagesink_check_xshm_calls (xcontext)) {
3616 xcontext->use_xshm = TRUE;
3617 GST_DEBUG ("xvimagesink is using XShm extension");
3619 #endif /* HAVE_XSHM */
3621 xcontext->use_xshm = FALSE;
3622 GST_DEBUG ("xvimagesink is not using XShm extension");
3625 xv_attr = XvQueryPortAttributes (xcontext->disp,
3626 xcontext->xv_port_id, &N_attr);
3629 /* Generate the channels list */
3630 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
3631 XvAttribute *matching_attr = NULL;
3633 /* Retrieve the property atom if it exists. If it doesn't exist,
3634 * the attribute itself must not either, so we can skip */
3635 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
3636 if (prop_atom == None)
3639 if (xv_attr != NULL) {
3640 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
3641 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
3642 matching_attr = xv_attr + j;
3645 if (matching_attr) {
3646 GstColorBalanceChannel *channel;
3648 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
3649 channel->label = g_strdup (channels[i]);
3650 channel->min_value = matching_attr->min_value;
3651 channel->max_value = matching_attr->max_value;
3653 xcontext->channels_list = g_list_append (xcontext->channels_list,
3656 /* If the colorbalance settings have not been touched we get Xv values
3657 as defaults and update our internal variables */
3658 if (!xvimagesink->cb_changed) {
3661 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
3663 /* Normalize val to [-1000, 1000] */
3664 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
3665 (double) (channel->max_value - channel->min_value));
3667 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
3668 xvimagesink->hue = val;
3669 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
3670 xvimagesink->saturation = val;
3671 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
3672 xvimagesink->brightness = val;
3673 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
3674 xvimagesink->contrast = val;
3682 #ifdef GST_EXT_XV_ENHANCEMENT
3683 set_display_mode(xcontext, xvimagesink->display_mode);
3684 set_csc_range(xcontext, xvimagesink->csc_range);
3685 #endif /* GST_EXT_XV_ENHANCEMENT */
3687 g_mutex_unlock (xvimagesink->x_lock);
3692 /* This function cleans the X context. Closing the Display, releasing the XV
3693 port and unrefing the caps for supported formats. */
3695 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
3697 GList *formats_list, *channels_list;
3698 GstXContext *xcontext;
3701 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3703 GST_OBJECT_LOCK (xvimagesink);
3704 if (xvimagesink->xcontext == NULL) {
3705 GST_OBJECT_UNLOCK (xvimagesink);
3709 /* Take the XContext from the sink and clean it up */
3710 xcontext = xvimagesink->xcontext;
3711 xvimagesink->xcontext = NULL;
3713 GST_OBJECT_UNLOCK (xvimagesink);
3716 formats_list = xcontext->formats_list;
3718 while (formats_list) {
3719 GstXvImageFormat *format = formats_list->data;
3721 gst_caps_unref (format->caps);
3723 formats_list = g_list_next (formats_list);
3726 if (xcontext->formats_list)
3727 g_list_free (xcontext->formats_list);
3729 channels_list = xcontext->channels_list;
3731 while (channels_list) {
3732 GstColorBalanceChannel *channel = channels_list->data;
3734 g_object_unref (channel);
3735 channels_list = g_list_next (channels_list);
3738 if (xcontext->channels_list)
3739 g_list_free (xcontext->channels_list);
3741 gst_caps_unref (xcontext->caps);
3742 if (xcontext->last_caps)
3743 gst_caps_replace (&xcontext->last_caps, NULL);
3745 for (i = 0; i < xcontext->nb_adaptors; i++) {
3746 g_free (xcontext->adaptors[i]);
3749 g_free (xcontext->adaptors);
3751 g_free (xcontext->par);
3753 g_mutex_lock (xvimagesink->x_lock);
3755 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
3757 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
3759 XCloseDisplay (xcontext->disp);
3761 g_mutex_unlock (xvimagesink->x_lock);
3767 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
3769 g_mutex_lock (xvimagesink->pool_lock);
3771 while (xvimagesink->image_pool) {
3772 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
3774 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
3775 xvimagesink->image_pool);
3776 gst_xvimage_buffer_free (xvimage);
3779 g_mutex_unlock (xvimagesink->pool_lock);
3784 /* This function tries to get a format matching with a given caps in the
3785 supported list of formats we generated in gst_xvimagesink_get_xv_support */
3787 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
3792 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
3794 list = xvimagesink->xcontext->formats_list;
3797 GstXvImageFormat *format = list->data;
3800 if (gst_caps_can_intersect (caps, format->caps)) {
3801 return format->format;
3804 list = g_list_next (list);
3811 gst_xvimagesink_getcaps (GstBaseSink * bsink)
3813 GstXvImageSink *xvimagesink;
3815 xvimagesink = GST_XVIMAGESINK (bsink);
3817 if (xvimagesink->xcontext)
3818 return gst_caps_ref (xvimagesink->xcontext->caps);
3821 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
3826 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
3828 GstXvImageSink *xvimagesink;
3829 GstStructure *structure;
3830 guint32 im_format = 0;
3832 gint video_width, video_height;
3833 gint disp_x, disp_y;
3834 gint disp_width, disp_height;
3835 gint video_par_n, video_par_d; /* video's PAR */
3836 gint display_par_n, display_par_d; /* display's PAR */
3837 const GValue *caps_par;
3838 const GValue *caps_disp_reg;
3841 #ifdef GST_EXT_XV_ENHANCEMENT
3842 gboolean enable_last_buffer;
3843 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
3845 xvimagesink = GST_XVIMAGESINK (bsink);
3847 GST_DEBUG_OBJECT (xvimagesink,
3848 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
3849 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
3851 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
3852 goto incompatible_caps;
3854 structure = gst_caps_get_structure (caps, 0);
3855 ret = gst_structure_get_int (structure, "width", &video_width);
3856 ret &= gst_structure_get_int (structure, "height", &video_height);
3857 fps = gst_structure_get_value (structure, "framerate");
3858 ret &= (fps != NULL);
3861 goto incomplete_caps;
3863 #ifdef GST_EXT_XV_ENHANCEMENT
3864 xvimagesink->aligned_width = video_width;
3865 xvimagesink->aligned_height = video_height;
3867 /* get enable-last-buffer */
3868 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
3869 GST_INFO_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
3871 /* flush if enable-last-buffer is TRUE */
3872 if (enable_last_buffer) {
3873 GST_INFO_OBJECT(xvimagesink, "flush last-buffer");
3874 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
3875 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
3877 #endif /* GST_EXT_XV_ENHANCEMENT */
3879 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
3880 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
3882 xvimagesink->video_width = video_width;
3883 xvimagesink->video_height = video_height;
3885 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
3886 if (im_format == -1)
3887 goto invalid_format;
3889 /* get aspect ratio from caps if it's present, and
3890 * convert video width and height to a display width and height
3891 * using wd / hd = wv / hv * PARv / PARd */
3893 /* get video's PAR */
3894 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
3896 video_par_n = gst_value_get_fraction_numerator (caps_par);
3897 video_par_d = gst_value_get_fraction_denominator (caps_par);
3902 /* get display's PAR */
3903 if (xvimagesink->par) {
3904 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
3905 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
3911 /* get the display region */
3912 caps_disp_reg = gst_structure_get_value (structure, "display-region");
3913 if (caps_disp_reg) {
3914 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
3915 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
3916 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
3918 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
3920 disp_x = disp_y = 0;
3921 disp_width = video_width;
3922 disp_height = video_height;
3925 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
3926 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
3929 xvimagesink->disp_x = disp_x;
3930 xvimagesink->disp_y = disp_y;
3931 xvimagesink->disp_width = disp_width;
3932 xvimagesink->disp_height = disp_height;
3934 GST_DEBUG_OBJECT (xvimagesink,
3935 "video width/height: %dx%d, calculated display ratio: %d/%d",
3936 video_width, video_height, num, den);
3938 /* now find a width x height that respects this display ratio.
3939 * prefer those that have one of w/h the same as the incoming video
3940 * using wd / hd = num / den */
3942 /* start with same height, because of interlaced video */
3943 /* check hd / den is an integer scale factor, and scale wd with the PAR */
3944 if (video_height % den == 0) {
3945 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
3946 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
3947 gst_util_uint64_scale_int (video_height, num, den);
3948 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
3949 } else if (video_width % num == 0) {
3950 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
3951 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
3952 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
3953 gst_util_uint64_scale_int (video_width, den, num);
3955 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
3956 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
3957 gst_util_uint64_scale_int (video_height, num, den);
3958 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
3960 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
3961 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
3963 /* Notify application to set xwindow id now */
3964 g_mutex_lock (xvimagesink->flow_lock);
3965 #ifdef GST_EXT_XV_ENHANCEMENT
3966 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
3967 g_mutex_unlock (xvimagesink->flow_lock);
3968 gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
3970 if (!xvimagesink->xwindow) {
3971 g_mutex_unlock (xvimagesink->flow_lock);
3972 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
3975 g_mutex_unlock (xvimagesink->flow_lock);
3978 /* Creating our window and our image with the display size in pixels */
3979 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
3980 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
3981 goto no_display_size;
3983 g_mutex_lock (xvimagesink->flow_lock);
3984 #ifdef GST_EXT_XV_ENHANCEMENT
3985 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
3986 GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
3988 if (!xvimagesink->xwindow) {
3990 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
3991 GST_VIDEO_SINK_WIDTH (xvimagesink),
3992 GST_VIDEO_SINK_HEIGHT (xvimagesink));
3995 /* After a resize, we want to redraw the borders in case the new frame size
3996 * doesn't cover the same area */
3997 xvimagesink->redraw_border = TRUE;
3999 /* We renew our xvimage only if size or format changed;
4000 * the xvimage is the same size as the video pixel size */
4001 if ((xvimagesink->xvimage) &&
4002 ((im_format != xvimagesink->xvimage->im_format) ||
4003 (video_width != xvimagesink->xvimage->width) ||
4004 (video_height != xvimagesink->xvimage->height))) {
4005 GST_DEBUG_OBJECT (xvimagesink,
4006 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4007 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4008 GST_FOURCC_ARGS (im_format));
4009 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4010 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4011 xvimagesink->xvimage = NULL;
4014 g_mutex_unlock (xvimagesink->flow_lock);
4021 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4026 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4027 "height or framerate from intersected caps");
4032 GST_DEBUG_OBJECT (xvimagesink,
4033 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4038 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4039 ("Error calculating the output display ratio of the video."));
4044 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4045 ("Error calculating the output display ratio of the video."));
4050 static GstStateChangeReturn
4051 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4053 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4054 GstXvImageSink *xvimagesink;
4055 GstXContext *xcontext = NULL;
4056 #ifdef GST_EXT_XV_ENHANCEMENT
4057 Atom atom_preemption = None;
4058 #endif /* GST_EXT_XV_ENHANCEMENT */
4060 xvimagesink = GST_XVIMAGESINK (element);
4062 switch (transition) {
4063 case GST_STATE_CHANGE_NULL_TO_READY:
4064 #ifdef GST_EXT_XV_ENHANCEMENT
4065 GST_WARNING("NULL_TO_READY start");
4066 #endif /* GST_EXT_XV_ENHANCEMENT */
4067 /* Initializing the XContext */
4068 if (xvimagesink->xcontext == NULL) {
4069 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4070 if (xcontext == NULL)
4071 return GST_STATE_CHANGE_FAILURE;
4072 GST_OBJECT_LOCK (xvimagesink);
4074 xvimagesink->xcontext = xcontext;
4075 GST_OBJECT_UNLOCK (xvimagesink);
4078 /* update object's par with calculated one if not set yet */
4079 if (!xvimagesink->par) {
4080 xvimagesink->par = g_new0 (GValue, 1);
4081 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4082 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4084 /* call XSynchronize with the current value of synchronous */
4085 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4086 xvimagesink->synchronous ? "TRUE" : "FALSE");
4087 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4088 gst_xvimagesink_update_colorbalance (xvimagesink);
4089 gst_xvimagesink_manage_event_thread (xvimagesink);
4090 #ifdef GST_EXT_XV_ENHANCEMENT
4091 GST_WARNING("NULL_TO_READY done");
4092 #endif /* GST_EXT_XV_ENHANCEMENT */
4094 case GST_STATE_CHANGE_READY_TO_PAUSED:
4095 #ifdef GST_EXT_XV_ENHANCEMENT
4096 GST_WARNING("READY_TO_PAUSED start");
4097 #endif /* GST_EXT_XV_ENHANCEMENT */
4098 g_mutex_lock (xvimagesink->pool_lock);
4099 xvimagesink->pool_invalid = FALSE;
4100 g_mutex_unlock (xvimagesink->pool_lock);
4101 #ifdef GST_EXT_XV_ENHANCEMENT
4102 GST_WARNING("READY_TO_PAUSED done");
4103 #endif /* GST_EXT_XV_ENHANCEMENT */
4105 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4106 #ifdef GST_EXT_XV_ENHANCEMENT
4107 GST_WARNING("PAUSED_TO_PLAYING start");
4108 #if 0 /* This is removed in Xorg */
4109 g_mutex_lock (xvimagesink->x_lock);
4110 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4111 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4112 if (atom_preemption != None) {
4113 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4114 xvimagesink->xcontext->xv_port_id,
4115 atom_preemption, 1 ) != Success) {
4116 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4118 XSync (xvimagesink->xcontext->disp, FALSE);
4120 g_mutex_unlock (xvimagesink->x_lock);
4122 GST_WARNING("PAUSED_TO_PLAYING done");
4123 #endif /* GST_EXT_XV_ENHANCEMENT */
4125 case GST_STATE_CHANGE_PAUSED_TO_READY:
4126 #ifdef GST_EXT_XV_ENHANCEMENT
4127 GST_WARNING("PAUSED_TO_READY start");
4128 #endif /* GST_EXT_XV_ENHANCEMENT */
4129 g_mutex_lock (xvimagesink->pool_lock);
4130 xvimagesink->pool_invalid = TRUE;
4131 g_mutex_unlock (xvimagesink->pool_lock);
4137 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4139 switch (transition) {
4140 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4141 #ifdef GST_EXT_XV_ENHANCEMENT
4142 GST_WARNING("PLAYING_TO_PAUSED start");
4143 xvimagesink->rotate_changed = TRUE;
4144 #if 0 /* This is removed in Xorg */
4145 g_mutex_lock (xvimagesink->x_lock);
4146 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4147 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4148 if (atom_preemption != None) {
4149 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4150 xvimagesink->xcontext->xv_port_id,
4151 atom_preemption, 0 ) != Success) {
4152 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4154 XSync (xvimagesink->xcontext->disp, FALSE);
4156 g_mutex_unlock (xvimagesink->x_lock);
4158 /* init displayed buffer count */
4159 xvimagesink->displayed_buffer_count = 0;
4161 GST_WARNING("PLAYING_TO_PAUSED done");
4162 #endif /* GST_EXT_XV_ENHANCEMENT */
4164 case GST_STATE_CHANGE_PAUSED_TO_READY:
4165 xvimagesink->fps_n = 0;
4166 xvimagesink->fps_d = 1;
4167 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
4168 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
4169 #ifdef GST_EXT_XV_ENHANCEMENT
4171 drm_fini(xvimagesink);
4173 /* init displaying_buffer_count */
4174 xvimagesink->displaying_buffer_count = 0;
4176 GST_WARNING("PAUSED_TO_READY done");
4177 #endif /* GST_EXT_XV_ENHANCEMENT */
4179 case GST_STATE_CHANGE_READY_TO_NULL:
4180 #ifdef GST_EXT_XV_ENHANCEMENT
4181 GST_WARNING("READY_TO_NULL start");
4182 #endif /* GST_EXT_XV_ENHANCEMENT */
4183 gst_xvimagesink_reset (xvimagesink);
4184 #ifdef GST_EXT_XV_ENHANCEMENT
4185 GST_WARNING("READY_TO_NULL done");
4186 #endif /* GST_EXT_XV_ENHANCEMENT */
4196 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
4197 GstClockTime * start, GstClockTime * end)
4199 GstXvImageSink *xvimagesink;
4201 xvimagesink = GST_XVIMAGESINK (bsink);
4203 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
4204 *start = GST_BUFFER_TIMESTAMP (buf);
4205 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
4206 *end = *start + GST_BUFFER_DURATION (buf);
4208 if (xvimagesink->fps_n > 0) {
4210 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
4211 xvimagesink->fps_n);
4217 static GstFlowReturn
4218 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
4220 GstXvImageSink *xvimagesink;
4222 #ifdef GST_EXT_XV_ENHANCEMENT
4223 XV_DATA_PTR img_data = NULL;
4224 SCMN_IMGB *scmn_imgb = NULL;
4226 gboolean ret = FALSE;
4227 #endif /* GST_EXT_XV_ENHANCEMENT */
4229 xvimagesink = GST_XVIMAGESINK (vsink);
4231 #ifdef GST_EXT_XV_ENHANCEMENT
4232 if (xvimagesink->stop_video) {
4233 GST_INFO( "Stop video is TRUE. so skip show frame..." );
4236 #endif /* GST_EXT_XV_ENHANCEMENT */
4238 /* If this buffer has been allocated using our buffer management we simply
4239 put the ximage which is in the PRIVATE pointer */
4240 if (GST_IS_XVIMAGE_BUFFER (buf)) {
4241 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
4242 #ifdef GST_EXT_XV_ENHANCEMENT
4243 xvimagesink->xid_updated = FALSE;
4244 #endif /* GST_EXT_XV_ENHANCEMENT */
4245 if (!gst_xvimagesink_xvimage_put (xvimagesink,
4246 GST_XVIMAGE_BUFFER_CAST (buf)))
4249 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
4250 "slow copy into bufferpool buffer %p", buf);
4251 /* Else we have to copy the data into our private image, */
4252 /* if we have one... */
4253 #ifdef GST_EXT_XV_ENHANCEMENT
4254 g_mutex_lock (xvimagesink->flow_lock);
4255 #endif /* GST_EXT_XV_ENHANCEMENT */
4256 if (!xvimagesink->xvimage) {
4257 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
4259 #ifdef GST_EXT_XV_ENHANCEMENT
4260 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
4262 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
4263 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
4264 case GST_MAKE_FOURCC('S', 'N', '2', '1'):
4265 case GST_MAKE_FOURCC('S', '4', '2', '0'):
4266 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
4267 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
4268 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
4269 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
4270 case GST_MAKE_FOURCC('S', 'R', '3', '2'):
4271 case GST_MAKE_FOURCC('S', 'V', '1', '2'):
4272 xvimagesink->is_zero_copy_format = TRUE;
4273 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
4274 if(scmn_imgb == NULL) {
4275 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
4276 g_mutex_unlock (xvimagesink->flow_lock);
4280 /* skip buffer if aligned size is smaller than size of caps */
4281 if (scmn_imgb->s[0] < xvimagesink->video_width ||
4282 scmn_imgb->e[0] < xvimagesink->video_height) {
4283 GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
4284 xvimagesink->video_width, xvimagesink->video_height,
4285 scmn_imgb->s[0], scmn_imgb->e[0]);
4286 g_mutex_unlock (xvimagesink->flow_lock);
4290 xvimagesink->aligned_width = scmn_imgb->s[0];
4291 xvimagesink->aligned_height = scmn_imgb->e[0];
4292 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
4293 xvimagesink->aligned_width, xvimagesink->aligned_height);
4296 xvimagesink->is_zero_copy_format = FALSE;
4297 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
4301 GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
4302 #endif /* GST_EXT_XV_ENHANCEMENT */
4304 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
4305 GST_BUFFER_CAPS (buf));
4307 if (!xvimagesink->xvimage)
4308 /* The create method should have posted an informative error */
4311 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
4312 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4313 ("Failed to create output image buffer of %dx%d pixels",
4314 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
4315 ("XServer allocated buffer size did not match input buffer"));
4317 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
4318 xvimagesink->xvimage = NULL;
4323 #ifdef GST_EXT_XV_ENHANCEMENT
4324 if (xvimagesink->is_zero_copy_format) {
4325 /* Cases for specified formats of Samsung extension */
4326 GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
4327 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
4328 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
4329 xvimagesink->display_mode, xvimagesink->rotate_angle);
4331 if (xvimagesink->xvimage->xvimage->data) {
4332 img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
4333 memset(img_data, 0x0, sizeof(XV_DATA));
4334 XV_INIT_DATA(img_data);
4336 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
4337 if (scmn_imgb == NULL) {
4338 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
4339 g_mutex_unlock (xvimagesink->flow_lock);
4343 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
4344 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
4345 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
4346 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
4347 img_data->BufType = XV_BUF_TYPE_LEGACY;
4349 GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
4350 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
4351 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
4352 scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
4353 /* open drm to use gem */
4354 if (xvimagesink->drm_fd < 0) {
4355 drm_init(xvimagesink);
4358 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
4359 /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
4360 img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
4361 img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
4362 img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
4363 img_data->BufType = XV_BUF_TYPE_DMABUF;
4364 GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
4366 /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
4367 img_data->bo[0] = scmn_imgb->bo[0];
4368 img_data->bo[1] = scmn_imgb->bo[1];
4369 img_data->bo[2] = scmn_imgb->bo[2];
4370 GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
4373 /* check secure contents path */
4374 /* NOTE : does it need to set 0 during playing(recovery case)? */
4375 if (scmn_imgb->tz_enable) {
4376 if (!xvimagesink->is_secure_path) {
4377 Atom atom_secure = None;
4378 g_mutex_lock (xvimagesink->x_lock);
4379 atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
4380 if (atom_secure != None) {
4381 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, 1) != Success) {
4382 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.\n", atom_secure);
4384 GST_WARNING_OBJECT(xvimagesink, "secure contents path is enabled.\n");
4386 XSync (xvimagesink->xcontext->disp, FALSE);
4388 g_mutex_unlock (xvimagesink->x_lock);
4389 xvimagesink->is_secure_path = TRUE;
4393 /* set current buffer */
4394 xvimagesink->xvimage->current_buffer = buf;
4396 GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
4397 scmn_imgb->buf_share_method);
4398 g_mutex_unlock (xvimagesink->flow_lock);
4402 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
4403 g_mutex_unlock (xvimagesink->flow_lock);
4407 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
4408 memcpy (xvimagesink->xvimage->xvimage->data,
4409 GST_BUFFER_DATA (buf),
4410 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
4413 g_mutex_unlock (xvimagesink->flow_lock);
4414 ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
4418 #else /* GST_EXT_XV_ENHANCEMENT */
4419 memcpy (xvimagesink->xvimage->xvimage->data,
4420 GST_BUFFER_DATA (buf),
4421 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
4423 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
4425 #endif /* GST_EXT_XV_ENHANCEMENT */
4433 /* No image available. That's very bad ! */
4434 GST_WARNING_OBJECT (xvimagesink, "could not create image");
4435 #ifdef GST_EXT_XV_ENHANCEMENT
4436 g_mutex_unlock (xvimagesink->flow_lock);
4438 return GST_FLOW_ERROR;
4442 /* No Window available to put our image into */
4443 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
4444 return GST_FLOW_ERROR;
4449 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
4451 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
4453 switch (GST_EVENT_TYPE (event)) {
4454 case GST_EVENT_TAG:{
4456 gchar *title = NULL;
4458 gst_event_parse_tag (event, &l);
4459 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
4462 #ifdef GST_EXT_XV_ENHANCEMENT
4463 if (!xvimagesink->get_pixmap_cb) {
4465 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
4466 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
4470 #ifdef GST_EXT_XV_ENHANCEMENT
4479 if (GST_BASE_SINK_CLASS (parent_class)->event)
4480 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
4485 /* Buffer management */
4488 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
4491 GstCaps *intersection;
4495 gint par_n = 1, par_d = 1;
4499 new_caps = gst_caps_copy (caps);
4501 s = gst_caps_get_structure (new_caps, 0);
4503 gst_structure_get_int (s, "width", &width);
4504 gst_structure_get_int (s, "height", &height);
4505 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
4507 gst_structure_remove_field (s, "width");
4508 gst_structure_remove_field (s, "height");
4509 gst_structure_remove_field (s, "pixel-aspect-ratio");
4511 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4512 gst_caps_unref (new_caps);
4514 if (gst_caps_is_empty (intersection))
4515 return intersection;
4517 s = gst_caps_get_structure (intersection, 0);
4519 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
4521 /* xvimagesink supports all PARs */
4523 gst_structure_fixate_field_nearest_int (s, "width", width);
4524 gst_structure_fixate_field_nearest_int (s, "height", height);
4525 gst_structure_get_int (s, "width", &w);
4526 gst_structure_get_int (s, "height", &h);
4528 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
4529 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
4532 return intersection;
4535 static GstFlowReturn
4536 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
4537 GstCaps * caps, GstBuffer ** buf)
4539 GstFlowReturn ret = GST_FLOW_OK;
4540 GstXvImageSink *xvimagesink;
4541 GstXvImageBuffer *xvimage = NULL;
4542 GstCaps *intersection = NULL;
4543 GstStructure *structure = NULL;
4544 gint width, height, image_format;
4546 xvimagesink = GST_XVIMAGESINK (bsink);
4548 if (G_UNLIKELY (!caps))
4551 g_mutex_lock (xvimagesink->pool_lock);
4552 if (G_UNLIKELY (xvimagesink->pool_invalid))
4555 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
4556 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
4557 GST_LOG_OBJECT (xvimagesink,
4558 "buffer alloc for same last_caps, reusing caps");
4559 intersection = gst_caps_ref (caps);
4560 image_format = xvimagesink->xcontext->last_format;
4561 width = xvimagesink->xcontext->last_width;
4562 height = xvimagesink->xcontext->last_height;
4564 goto reuse_last_caps;
4567 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
4568 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
4569 caps, xvimagesink->xcontext->caps);
4571 /* Check the caps against our xcontext */
4572 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
4574 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
4575 GST_PTR_FORMAT, intersection);
4577 if (gst_caps_is_empty (intersection)) {
4580 gst_caps_unref (intersection);
4582 /* So we don't support this kind of buffer, let's define one we'd like */
4583 new_caps = gst_caps_copy (caps);
4585 structure = gst_caps_get_structure (new_caps, 0);
4586 if (!gst_structure_has_field (structure, "width") ||
4587 !gst_structure_has_field (structure, "height")) {
4588 gst_caps_unref (new_caps);
4592 /* Try different dimensions */
4594 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4596 if (gst_caps_is_empty (intersection)) {
4597 /* Try with different YUV formats first */
4598 gst_structure_set_name (structure, "video/x-raw-yuv");
4600 /* Remove format specific fields */
4601 gst_structure_remove_field (structure, "format");
4602 gst_structure_remove_field (structure, "endianness");
4603 gst_structure_remove_field (structure, "depth");
4604 gst_structure_remove_field (structure, "bpp");
4605 gst_structure_remove_field (structure, "red_mask");
4606 gst_structure_remove_field (structure, "green_mask");
4607 gst_structure_remove_field (structure, "blue_mask");
4608 gst_structure_remove_field (structure, "alpha_mask");
4610 /* Reuse intersection with Xcontext */
4611 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4614 if (gst_caps_is_empty (intersection)) {
4615 /* Try with different dimensions and YUV formats */
4617 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4620 if (gst_caps_is_empty (intersection)) {
4621 /* Now try with RGB */
4622 gst_structure_set_name (structure, "video/x-raw-rgb");
4623 /* And interset again */
4624 gst_caps_unref (intersection);
4625 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
4628 if (gst_caps_is_empty (intersection)) {
4629 /* Try with different dimensions and RGB formats */
4631 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
4634 /* Clean this copy */
4635 gst_caps_unref (new_caps);
4637 if (gst_caps_is_empty (intersection))
4641 /* Ensure the returned caps are fixed */
4642 gst_caps_truncate (intersection);
4644 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
4645 GST_PTR_FORMAT, intersection);
4646 if (gst_caps_is_equal (intersection, caps)) {
4647 /* Things work better if we return a buffer with the same caps ptr
4648 * as was asked for when we can */
4649 gst_caps_replace (&intersection, caps);
4652 /* Get image format from caps */
4653 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
4656 /* Get geometry from caps */
4657 structure = gst_caps_get_structure (intersection, 0);
4658 if (!gst_structure_get_int (structure, "width", &width) ||
4659 !gst_structure_get_int (structure, "height", &height) ||
4663 /* Store our caps and format as the last_caps to avoid expensive
4664 * caps intersection next time */
4665 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
4666 xvimagesink->xcontext->last_format = image_format;
4667 xvimagesink->xcontext->last_width = width;
4668 xvimagesink->xcontext->last_height = height;
4672 /* Walking through the pool cleaning unusable images and searching for a
4674 while (xvimagesink->image_pool) {
4675 xvimage = xvimagesink->image_pool->data;
4678 /* Removing from the pool */
4679 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4680 xvimagesink->image_pool);
4682 /* We check for geometry or image format changes */
4683 if ((xvimage->width != width) ||
4684 (xvimage->height != height) || (xvimage->im_format != image_format)) {
4685 /* This image is unusable. Destroying... */
4686 gst_xvimage_buffer_free (xvimage);
4689 /* We found a suitable image */
4690 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
4697 #ifdef GST_EXT_XV_ENHANCEMENT
4698 /* init aligned size */
4699 xvimagesink->aligned_width = 0;
4700 xvimagesink->aligned_height = 0;
4701 #endif /* GST_EXT_XV_ENHANCEMENT */
4703 /* We found no suitable image in the pool. Creating... */
4704 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
4705 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
4707 g_mutex_unlock (xvimagesink->pool_lock);
4710 /* Make sure the buffer is cleared of any previously used flags */
4711 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
4712 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
4715 *buf = GST_BUFFER_CAST (xvimage);
4719 gst_caps_unref (intersection);
4727 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
4728 ret = GST_FLOW_WRONG_STATE;
4729 g_mutex_unlock (xvimagesink->pool_lock);
4734 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
4735 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
4736 " are completely incompatible with those caps", caps,
4737 xvimagesink->xcontext->caps);
4738 ret = GST_FLOW_NOT_NEGOTIATED;
4739 g_mutex_unlock (xvimagesink->pool_lock);
4744 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
4745 GST_PTR_FORMAT, intersection);
4746 ret = GST_FLOW_NOT_NEGOTIATED;
4747 g_mutex_unlock (xvimagesink->pool_lock);
4752 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
4759 /* Interfaces stuff */
4762 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
4764 if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
4765 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
4772 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
4774 klass->supported = gst_xvimagesink_interface_supported;
4778 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
4779 GstStructure * structure)
4781 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
4784 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
4786 GstVideoRectangle src, dst, result;
4787 gdouble x, y, xscale = 1.0, yscale = 1.0;
4789 event = gst_event_new_navigation (structure);
4791 /* We take the flow_lock while we look at the window */
4792 g_mutex_lock (xvimagesink->flow_lock);
4794 if (!xvimagesink->xwindow) {
4795 g_mutex_unlock (xvimagesink->flow_lock);
4799 if (xvimagesink->keep_aspect) {
4800 /* We get the frame position using the calculated geometry from _setcaps
4801 that respect pixel aspect ratios */
4802 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
4803 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
4804 dst.w = xvimagesink->render_rect.w;
4805 dst.h = xvimagesink->render_rect.h;
4807 gst_video_sink_center_rect (src, dst, &result, TRUE);
4808 result.x += xvimagesink->render_rect.x;
4809 result.y += xvimagesink->render_rect.y;
4811 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
4814 g_mutex_unlock (xvimagesink->flow_lock);
4816 /* We calculate scaling using the original video frames geometry to include
4817 pixel aspect ratio scaling. */
4818 xscale = (gdouble) xvimagesink->video_width / result.w;
4819 yscale = (gdouble) xvimagesink->video_height / result.h;
4821 /* Converting pointer coordinates to the non scaled geometry */
4822 if (gst_structure_get_double (structure, "pointer_x", &x)) {
4823 x = MIN (x, result.x + result.w);
4824 x = MAX (x - result.x, 0);
4825 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
4826 (gdouble) x * xscale, NULL);
4828 if (gst_structure_get_double (structure, "pointer_y", &y)) {
4829 y = MIN (y, result.y + result.h);
4830 y = MAX (y - result.y, 0);
4831 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
4832 (gdouble) y * yscale, NULL);
4835 gst_pad_send_event (peer, event);
4836 gst_object_unref (peer);
4841 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
4843 iface->send_event = gst_xvimagesink_navigation_send_event;
4846 #ifdef GST_EXT_XV_ENHANCEMENT
4848 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
4852 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
4853 GstXPixmap *xpixmap = NULL;
4855 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4857 /* If the element has not initialized the X11 context try to do so */
4858 if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
4859 /* we have thrown a GST_ELEMENT_ERROR now */
4863 gst_xvimagesink_update_colorbalance (xvimagesink);
4865 GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
4867 /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
4868 if (pixmap_id == 0) {
4869 xvimagesink->current_pixmap_idx = -2;
4873 g_mutex_lock (xvimagesink->x_lock);
4875 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
4876 if (!xvimagesink->xpixmap[i]) {
4880 unsigned int cur_win_width = 0;
4881 unsigned int cur_win_height = 0;
4882 unsigned int cur_win_border_width = 0;
4883 unsigned int cur_win_depth = 0;
4885 GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
4887 xpixmap = g_new0 (GstXPixmap, 1);
4889 xpixmap->pixmap = pixmap_id;
4891 /* Get root window and size of current window */
4892 XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
4893 &cur_win_x, &cur_win_y, /* relative x, y */
4894 &cur_win_width, &cur_win_height,
4895 &cur_win_border_width, &cur_win_depth);
4896 if (!cur_win_width || !cur_win_height) {
4897 GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
4898 g_mutex_unlock (xvimagesink->x_lock);
4901 xpixmap->width = cur_win_width;
4902 xpixmap->height = cur_win_height;
4904 if (!xvimagesink->render_rect.w)
4905 xvimagesink->render_rect.w = cur_win_width;
4906 if (!xvimagesink->render_rect.h)
4907 xvimagesink->render_rect.h = cur_win_height;
4910 xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
4912 xvimagesink->xpixmap[i] = xpixmap;
4913 xvimagesink->current_pixmap_idx = i;
4915 GST_ERROR("failed to create xpixmap errno: %d", errno);
4918 g_mutex_unlock (xvimagesink->x_lock);
4921 } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
4922 GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
4923 xvimagesink->current_pixmap_idx = i;
4925 g_mutex_unlock (xvimagesink->x_lock);
4933 GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
4934 xvimagesink->current_pixmap_idx = -1;
4936 g_mutex_unlock (xvimagesink->x_lock);
4939 #endif /* GST_EXT_XV_ENHANCEMENT */
4942 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
4944 XID xwindow_id = id;
4945 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
4946 GstXWindow *xwindow = NULL;
4947 #ifdef GST_EXT_XV_ENHANCEMENT
4948 GstState current_state = GST_STATE_NULL;
4949 #endif /* GST_EXT_XV_ENHANCEMENT */
4951 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4953 g_mutex_lock (xvimagesink->flow_lock);
4955 #ifdef GST_EXT_XV_ENHANCEMENT
4956 gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
4957 GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
4958 xwindow_id, current_state);
4959 #endif /* GST_EXT_XV_ENHANCEMENT */
4961 /* If we already use that window return */
4962 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
4963 g_mutex_unlock (xvimagesink->flow_lock);
4967 /* If the element has not initialized the X11 context try to do so */
4968 if (!xvimagesink->xcontext &&
4969 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
4970 g_mutex_unlock (xvimagesink->flow_lock);
4971 /* we have thrown a GST_ELEMENT_ERROR now */
4975 gst_xvimagesink_update_colorbalance (xvimagesink);
4977 /* Clear image pool as the images are unusable anyway */
4978 gst_xvimagesink_imagepool_clear (xvimagesink);
4980 /* Clear the xvimage */
4981 if (xvimagesink->xvimage) {
4982 gst_xvimage_buffer_free (xvimagesink->xvimage);
4983 xvimagesink->xvimage = NULL;
4986 /* If a window is there already we destroy it */
4987 if (xvimagesink->xwindow) {
4988 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
4989 xvimagesink->xwindow = NULL;
4992 /* If the xid is 0 we go back to an internal window */
4993 if (xwindow_id == 0) {
4994 /* If no width/height caps nego did not happen window will be created
4995 during caps nego then */
4996 #ifdef GST_EXT_XV_ENHANCEMENT
4997 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
4998 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
4999 #endif /* GST_EXT_XV_ENHANCEMENT */
5000 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
5001 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
5003 gst_xvimagesink_xwindow_new (xvimagesink,
5004 GST_VIDEO_SINK_WIDTH (xvimagesink),
5005 GST_VIDEO_SINK_HEIGHT (xvimagesink));
5008 XWindowAttributes attr;
5010 xwindow = g_new0 (GstXWindow, 1);
5011 xwindow->win = xwindow_id;
5013 /* Set the event we want to receive and create a GC */
5014 g_mutex_lock (xvimagesink->x_lock);
5016 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
5018 xwindow->width = attr.width;
5019 xwindow->height = attr.height;
5020 xwindow->internal = FALSE;
5021 if (!xvimagesink->have_render_rect) {
5022 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
5023 xvimagesink->render_rect.w = attr.width;
5024 xvimagesink->render_rect.h = attr.height;
5026 if (xvimagesink->handle_events) {
5027 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
5028 StructureNotifyMask | PointerMotionMask | KeyPressMask |
5032 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
5033 xwindow->win, 0, NULL);
5034 g_mutex_unlock (xvimagesink->x_lock);
5038 xvimagesink->xwindow = xwindow;
5040 #ifdef GST_EXT_XV_ENHANCEMENT
5041 xvimagesink->xid_updated = TRUE;
5042 #endif /* GST_EXT_XV_ENHANCEMENT */
5044 g_mutex_unlock (xvimagesink->flow_lock);
5046 #ifdef GST_EXT_XV_ENHANCEMENT
5047 if (current_state == GST_STATE_PAUSED) {
5048 GstBuffer *last_buffer = NULL;
5049 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
5050 GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
5052 gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
5053 gst_buffer_unref(last_buffer);
5057 #endif /* GST_EXT_XV_ENHANCEMENT */
5061 gst_xvimagesink_expose (GstXOverlay * overlay)
5063 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5065 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
5066 #ifdef GST_EXT_XV_ENHANCEMENT
5067 GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it");
5068 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5069 #else /* GST_EXT_XV_ENHANCEMENT */
5070 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
5071 #endif /* GST_EXT_XV_ENHANCEMENT */
5075 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
5076 gboolean handle_events)
5078 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5080 xvimagesink->handle_events = handle_events;
5082 g_mutex_lock (xvimagesink->flow_lock);
5084 if (G_UNLIKELY (!xvimagesink->xwindow)) {
5085 g_mutex_unlock (xvimagesink->flow_lock);
5089 g_mutex_lock (xvimagesink->x_lock);
5091 if (handle_events) {
5092 if (xvimagesink->xwindow->internal) {
5093 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
5094 #ifdef GST_EXT_XV_ENHANCEMENT
5095 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
5096 #else /* GST_EXT_XV_ENHANCEMENT */
5097 ExposureMask | StructureNotifyMask | PointerMotionMask |
5098 #endif /* GST_EXT_XV_ENHANCEMENT */
5099 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
5101 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
5102 #ifdef GST_EXT_XV_ENHANCEMENT
5103 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
5104 #else /* GST_EXT_XV_ENHANCEMENT */
5105 ExposureMask | StructureNotifyMask | PointerMotionMask |
5106 #endif /* GST_EXT_XV_ENHANCEMENT */
5107 KeyPressMask | KeyReleaseMask);
5110 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
5113 g_mutex_unlock (xvimagesink->x_lock);
5115 g_mutex_unlock (xvimagesink->flow_lock);
5119 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
5120 gint width, gint height)
5122 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5124 /* FIXME: how about some locking? */
5125 if (width >= 0 && height >= 0) {
5126 xvimagesink->render_rect.x = x;
5127 xvimagesink->render_rect.y = y;
5128 xvimagesink->render_rect.w = width;
5129 xvimagesink->render_rect.h = height;
5130 xvimagesink->have_render_rect = TRUE;
5132 xvimagesink->render_rect.x = 0;
5133 xvimagesink->render_rect.y = 0;
5134 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
5135 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
5136 xvimagesink->have_render_rect = FALSE;
5141 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
5143 iface->set_window_handle = gst_xvimagesink_set_window_handle;
5144 iface->expose = gst_xvimagesink_expose;
5145 iface->handle_events = gst_xvimagesink_set_event_handling;
5146 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
5149 static const GList *
5150 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
5152 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5154 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
5156 if (xvimagesink->xcontext)
5157 return xvimagesink->xcontext->channels_list;
5163 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
5164 GstColorBalanceChannel * channel, gint value)
5166 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5168 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
5169 g_return_if_fail (channel->label != NULL);
5171 xvimagesink->cb_changed = TRUE;
5173 /* Normalize val to [-1000, 1000] */
5174 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
5175 (double) (channel->max_value - channel->min_value));
5177 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
5178 xvimagesink->hue = value;
5179 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
5180 xvimagesink->saturation = value;
5181 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
5182 xvimagesink->contrast = value;
5183 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
5184 xvimagesink->brightness = value;
5186 g_warning ("got an unknown channel %s", channel->label);
5190 gst_xvimagesink_update_colorbalance (xvimagesink);
5194 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
5195 GstColorBalanceChannel * channel)
5197 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
5200 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
5201 g_return_val_if_fail (channel->label != NULL, 0);
5203 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
5204 value = xvimagesink->hue;
5205 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
5206 value = xvimagesink->saturation;
5207 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
5208 value = xvimagesink->contrast;
5209 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
5210 value = xvimagesink->brightness;
5212 g_warning ("got an unknown channel %s", channel->label);
5215 /* Normalize val to [channel->min_value, channel->max_value] */
5216 value = channel->min_value + (channel->max_value - channel->min_value) *
5217 (value + 1000) / 2000;
5223 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
5225 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
5226 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
5227 iface->set_value = gst_xvimagesink_colorbalance_set_value;
5228 iface->get_value = gst_xvimagesink_colorbalance_get_value;
5231 static const GList *
5232 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
5234 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
5235 static GList *list = NULL;
5238 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
5240 g_list_append (list, g_object_class_find_property (klass,
5241 "autopaint-colorkey"));
5243 g_list_append (list, g_object_class_find_property (klass,
5246 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
5253 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
5254 guint prop_id, const GParamSpec * pspec)
5256 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5260 case PROP_AUTOPAINT_COLORKEY:
5261 case PROP_DOUBLE_BUFFER:
5263 GST_DEBUG_OBJECT (xvimagesink,
5264 "probing device list and get capabilities");
5265 if (!xvimagesink->xcontext) {
5266 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
5267 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
5271 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5277 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
5278 guint prop_id, const GParamSpec * pspec)
5280 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5281 gboolean ret = FALSE;
5285 case PROP_AUTOPAINT_COLORKEY:
5286 case PROP_DOUBLE_BUFFER:
5288 if (xvimagesink->xcontext != NULL) {
5295 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5302 static GValueArray *
5303 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
5304 guint prop_id, const GParamSpec * pspec)
5306 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
5307 GValueArray *array = NULL;
5309 if (G_UNLIKELY (!xvimagesink->xcontext)) {
5310 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
5319 GValue value = { 0 };
5321 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
5322 g_value_init (&value, G_TYPE_STRING);
5324 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
5325 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
5327 g_value_set_string (&value, adaptor_id_s);
5328 g_value_array_append (array, &value);
5329 g_free (adaptor_id_s);
5331 g_value_unset (&value);
5334 case PROP_AUTOPAINT_COLORKEY:
5335 if (xvimagesink->have_autopaint_colorkey) {
5336 GValue value = { 0 };
5338 array = g_value_array_new (2);
5339 g_value_init (&value, G_TYPE_BOOLEAN);
5340 g_value_set_boolean (&value, FALSE);
5341 g_value_array_append (array, &value);
5342 g_value_set_boolean (&value, TRUE);
5343 g_value_array_append (array, &value);
5344 g_value_unset (&value);
5347 case PROP_DOUBLE_BUFFER:
5348 if (xvimagesink->have_double_buffer) {
5349 GValue value = { 0 };
5351 array = g_value_array_new (2);
5352 g_value_init (&value, G_TYPE_BOOLEAN);
5353 g_value_set_boolean (&value, FALSE);
5354 g_value_array_append (array, &value);
5355 g_value_set_boolean (&value, TRUE);
5356 g_value_array_append (array, &value);
5357 g_value_unset (&value);
5361 if (xvimagesink->have_colorkey) {
5362 GValue value = { 0 };
5364 array = g_value_array_new (1);
5365 g_value_init (&value, GST_TYPE_INT_RANGE);
5366 gst_value_set_int_range (&value, 0, 0xffffff);
5367 g_value_array_append (array, &value);
5368 g_value_unset (&value);
5372 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
5381 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
5384 iface->get_properties = gst_xvimagesink_probe_get_properties;
5385 iface->probe_property = gst_xvimagesink_probe_probe_property;
5386 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
5387 iface->get_values = gst_xvimagesink_probe_get_values;
5390 /* =========================================== */
5392 /* Init & Class init */
5394 /* =========================================== */
5397 gst_xvimagesink_set_property (GObject * object, guint prop_id,
5398 const GValue * value, GParamSpec * pspec)
5400 GstXvImageSink *xvimagesink;
5402 g_return_if_fail (GST_IS_XVIMAGESINK (object));
5404 xvimagesink = GST_XVIMAGESINK (object);
5408 xvimagesink->hue = g_value_get_int (value);
5409 xvimagesink->cb_changed = TRUE;
5410 gst_xvimagesink_update_colorbalance (xvimagesink);
5413 xvimagesink->contrast = g_value_get_int (value);
5414 xvimagesink->cb_changed = TRUE;
5415 gst_xvimagesink_update_colorbalance (xvimagesink);
5417 case PROP_BRIGHTNESS:
5418 xvimagesink->brightness = g_value_get_int (value);
5419 xvimagesink->cb_changed = TRUE;
5420 gst_xvimagesink_update_colorbalance (xvimagesink);
5422 case PROP_SATURATION:
5423 xvimagesink->saturation = g_value_get_int (value);
5424 xvimagesink->cb_changed = TRUE;
5425 gst_xvimagesink_update_colorbalance (xvimagesink);
5428 xvimagesink->display_name = g_strdup (g_value_get_string (value));
5430 case PROP_SYNCHRONOUS:
5431 xvimagesink->synchronous = g_value_get_boolean (value);
5432 if (xvimagesink->xcontext) {
5433 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
5434 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
5435 xvimagesink->synchronous ? "TRUE" : "FALSE");
5438 case PROP_PIXEL_ASPECT_RATIO:
5439 g_free (xvimagesink->par);
5440 xvimagesink->par = g_new0 (GValue, 1);
5441 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
5442 if (!g_value_transform (value, xvimagesink->par)) {
5443 g_warning ("Could not transform string to aspect ratio");
5444 gst_value_set_fraction (xvimagesink->par, 1, 1);
5446 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
5447 gst_value_get_fraction_numerator (xvimagesink->par),
5448 gst_value_get_fraction_denominator (xvimagesink->par));
5450 case PROP_FORCE_ASPECT_RATIO:
5451 xvimagesink->keep_aspect = g_value_get_boolean (value);
5453 case PROP_HANDLE_EVENTS:
5454 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
5455 g_value_get_boolean (value));
5456 gst_xvimagesink_manage_event_thread (xvimagesink);
5459 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
5461 case PROP_HANDLE_EXPOSE:
5462 xvimagesink->handle_expose = g_value_get_boolean (value);
5463 gst_xvimagesink_manage_event_thread (xvimagesink);
5465 case PROP_DOUBLE_BUFFER:
5466 xvimagesink->double_buffer = g_value_get_boolean (value);
5468 case PROP_AUTOPAINT_COLORKEY:
5469 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
5472 xvimagesink->colorkey = g_value_get_int (value);
5474 case PROP_DRAW_BORDERS:
5475 xvimagesink->draw_borders = g_value_get_boolean (value);
5477 #ifdef GST_EXT_XV_ENHANCEMENT
5478 case PROP_DISPLAY_MODE:
5480 int set_mode = g_value_get_enum (value);
5482 g_mutex_lock(xvimagesink->flow_lock);
5483 g_mutex_lock(xvimagesink->x_lock);
5485 if (xvimagesink->display_mode != set_mode) {
5486 if (xvimagesink->xcontext) {
5487 /* set display mode */
5488 if (set_display_mode(xvimagesink->xcontext, set_mode)) {
5489 xvimagesink->display_mode = set_mode;
5491 GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
5494 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
5495 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
5496 xvimagesink->display_mode = set_mode;
5499 GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
5502 g_mutex_unlock(xvimagesink->x_lock);
5503 g_mutex_unlock(xvimagesink->flow_lock);
5506 case PROP_CSC_RANGE:
5508 int set_range = g_value_get_enum (value);
5510 g_mutex_lock(xvimagesink->flow_lock);
5511 g_mutex_lock(xvimagesink->x_lock);
5513 if (xvimagesink->csc_range != set_range) {
5514 if (xvimagesink->xcontext) {
5515 /* set color space range */
5516 if (set_csc_range(xvimagesink->xcontext, set_range)) {
5517 xvimagesink->csc_range = set_range;
5519 GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
5522 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
5523 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
5524 xvimagesink->csc_range = set_range;
5527 GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
5530 g_mutex_unlock(xvimagesink->x_lock);
5531 g_mutex_unlock(xvimagesink->flow_lock);
5534 case PROP_DISPLAY_GEOMETRY_METHOD:
5535 xvimagesink->display_geometry_method = g_value_get_enum (value);
5536 GST_LOG("Overlay geometry changed. update it");
5537 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5540 xvimagesink->flip = g_value_get_enum(value);
5542 case PROP_ROTATE_ANGLE:
5543 xvimagesink->rotate_angle = g_value_get_enum (value);
5544 xvimagesink->rotate_changed = TRUE;
5547 g_mutex_lock( xvimagesink->flow_lock );
5548 g_mutex_lock( xvimagesink->x_lock );
5550 GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
5552 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
5553 if (xvimagesink->xcontext) {
5555 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
5556 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
5557 if (atom_stream != None) {
5558 GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
5559 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5560 xvimagesink->xcontext->xv_port_id,
5561 atom_stream, 0 ) != Success) {
5562 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
5566 xvimagesink->visible = g_value_get_boolean (value);
5567 if ( xvimagesink->get_pixmap_cb ) {
5568 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5569 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5572 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
5574 XSync( xvimagesink->xcontext->disp, FALSE );
5576 GST_WARNING_OBJECT( xvimagesink, "xcontext is null, failed to set visible");
5577 g_mutex_unlock( xvimagesink->x_lock );
5578 g_mutex_unlock( xvimagesink->flow_lock );
5581 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
5582 g_mutex_unlock( xvimagesink->x_lock );
5583 g_mutex_unlock( xvimagesink->flow_lock );
5584 GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." );
5585 xvimagesink->visible = g_value_get_boolean (value);
5586 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
5587 g_mutex_lock( xvimagesink->flow_lock );
5588 g_mutex_lock( xvimagesink->x_lock );
5591 GST_INFO("set visible done");
5593 g_mutex_unlock( xvimagesink->x_lock );
5594 g_mutex_unlock( xvimagesink->flow_lock );
5597 xvimagesink->zoom = g_value_get_int (value);
5599 case PROP_DST_ROI_X:
5600 xvimagesink->dst_roi.x = g_value_get_int (value);
5602 case PROP_DST_ROI_Y:
5603 xvimagesink->dst_roi.y = g_value_get_int (value);
5605 case PROP_DST_ROI_W:
5606 xvimagesink->dst_roi.w = g_value_get_int (value);
5608 case PROP_DST_ROI_H:
5609 xvimagesink->dst_roi.h = g_value_get_int (value);
5611 case PROP_STOP_VIDEO:
5612 xvimagesink->stop_video = g_value_get_int (value);
5613 g_mutex_lock( xvimagesink->flow_lock );
5615 if( xvimagesink->stop_video )
5617 if ( xvimagesink->get_pixmap_cb ) {
5618 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5619 g_mutex_lock (xvimagesink->x_lock);
5620 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
5621 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5622 g_mutex_unlock (xvimagesink->x_lock);
5625 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
5626 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
5630 g_mutex_unlock( xvimagesink->flow_lock );
5632 case PROP_PIXMAP_CB:
5635 cb_func = g_value_get_pointer(value);
5637 xvimagesink->get_pixmap_cb = cb_func;
5638 GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
5642 case PROP_PIXMAP_CB_USER_DATA:
5645 user_data = g_value_get_pointer(value);
5647 xvimagesink->get_pixmap_cb_user_data = user_data;
5648 GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
5652 #endif /* GST_EXT_XV_ENHANCEMENT */
5654 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5660 gst_xvimagesink_get_property (GObject * object, guint prop_id,
5661 GValue * value, GParamSpec * pspec)
5663 GstXvImageSink *xvimagesink;
5665 g_return_if_fail (GST_IS_XVIMAGESINK (object));
5667 xvimagesink = GST_XVIMAGESINK (object);
5671 g_value_set_int (value, xvimagesink->hue);
5674 g_value_set_int (value, xvimagesink->contrast);
5676 case PROP_BRIGHTNESS:
5677 g_value_set_int (value, xvimagesink->brightness);
5679 case PROP_SATURATION:
5680 g_value_set_int (value, xvimagesink->saturation);
5683 g_value_set_string (value, xvimagesink->display_name);
5685 case PROP_SYNCHRONOUS:
5686 g_value_set_boolean (value, xvimagesink->synchronous);
5688 case PROP_PIXEL_ASPECT_RATIO:
5689 if (xvimagesink->par)
5690 g_value_transform (xvimagesink->par, value);
5692 case PROP_FORCE_ASPECT_RATIO:
5693 g_value_set_boolean (value, xvimagesink->keep_aspect);
5695 case PROP_HANDLE_EVENTS:
5696 g_value_set_boolean (value, xvimagesink->handle_events);
5700 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
5702 g_value_set_string (value, adaptor_no_s);
5703 g_free (adaptor_no_s);
5706 case PROP_DEVICE_NAME:
5707 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
5708 g_value_set_string (value,
5709 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
5711 g_value_set_string (value, NULL);
5714 case PROP_HANDLE_EXPOSE:
5715 g_value_set_boolean (value, xvimagesink->handle_expose);
5717 case PROP_DOUBLE_BUFFER:
5718 g_value_set_boolean (value, xvimagesink->double_buffer);
5720 case PROP_AUTOPAINT_COLORKEY:
5721 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
5724 g_value_set_int (value, xvimagesink->colorkey);
5726 case PROP_DRAW_BORDERS:
5727 g_value_set_boolean (value, xvimagesink->draw_borders);
5729 case PROP_WINDOW_WIDTH:
5730 if (xvimagesink->xwindow)
5731 g_value_set_uint64 (value, xvimagesink->xwindow->width);
5733 g_value_set_uint64 (value, 0);
5735 case PROP_WINDOW_HEIGHT:
5736 if (xvimagesink->xwindow)
5737 g_value_set_uint64 (value, xvimagesink->xwindow->height);
5739 g_value_set_uint64 (value, 0);
5741 #ifdef GST_EXT_XV_ENHANCEMENT
5742 case PROP_DISPLAY_MODE:
5743 g_value_set_enum (value, xvimagesink->display_mode);
5745 case PROP_CSC_RANGE:
5746 g_value_set_enum (value, xvimagesink->csc_range);
5748 case PROP_DISPLAY_GEOMETRY_METHOD:
5749 g_value_set_enum (value, xvimagesink->display_geometry_method);
5752 g_value_set_enum(value, xvimagesink->flip);
5754 case PROP_ROTATE_ANGLE:
5755 g_value_set_enum (value, xvimagesink->rotate_angle);
5758 g_value_set_boolean (value, xvimagesink->visible);
5761 g_value_set_int (value, xvimagesink->zoom);
5763 case PROP_DST_ROI_X:
5764 g_value_set_int (value, xvimagesink->dst_roi.x);
5766 case PROP_DST_ROI_Y:
5767 g_value_set_int (value, xvimagesink->dst_roi.y);
5769 case PROP_DST_ROI_W:
5770 g_value_set_int (value, xvimagesink->dst_roi.w);
5772 case PROP_DST_ROI_H:
5773 g_value_set_int (value, xvimagesink->dst_roi.h);
5775 case PROP_STOP_VIDEO:
5776 g_value_set_int (value, xvimagesink->stop_video);
5778 case PROP_PIXMAP_CB:
5779 g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
5781 case PROP_PIXMAP_CB_USER_DATA:
5782 g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
5784 #endif /* GST_EXT_XV_ENHANCEMENT */
5786 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5792 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
5796 GST_OBJECT_LOCK (xvimagesink);
5797 xvimagesink->running = FALSE;
5798 /* grab thread and mark it as NULL */
5799 thread = xvimagesink->event_thread;
5800 xvimagesink->event_thread = NULL;
5801 GST_OBJECT_UNLOCK (xvimagesink);
5803 /* invalidate the pool, current allocations continue, new buffer_alloc fails
5804 * with wrong_state */
5805 g_mutex_lock (xvimagesink->pool_lock);
5806 xvimagesink->pool_invalid = TRUE;
5807 g_mutex_unlock (xvimagesink->pool_lock);
5809 /* Wait for our event thread to finish before we clean up our stuff. */
5811 g_thread_join (thread);
5813 if (xvimagesink->cur_image) {
5814 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
5815 xvimagesink->cur_image = NULL;
5817 if (xvimagesink->xvimage) {
5818 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
5819 xvimagesink->xvimage = NULL;
5822 gst_xvimagesink_imagepool_clear (xvimagesink);
5824 if (xvimagesink->xwindow) {
5825 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
5826 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
5827 xvimagesink->xwindow = NULL;
5829 #ifdef GST_EXT_XV_ENHANCEMENT
5830 if (xvimagesink->get_pixmap_cb) {
5832 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
5833 g_mutex_lock (xvimagesink->x_lock);
5834 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
5835 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
5836 g_mutex_unlock (xvimagesink->x_lock);
5838 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
5839 if (xvimagesink->xpixmap[i]) {
5840 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
5841 xvimagesink->xpixmap[i] = NULL;
5844 xvimagesink->get_pixmap_cb = NULL;
5845 xvimagesink->get_pixmap_cb_user_data = NULL;
5847 #endif /* GST_EXT_XV_ENHANCEMENT */
5848 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
5849 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
5850 xvimagesink->have_render_rect = FALSE;
5852 gst_xvimagesink_xcontext_clear (xvimagesink);
5855 /* Finalize is called only once, dispose can be called multiple times.
5856 * We use mutexes and don't reset stuff to NULL here so let's register
5859 gst_xvimagesink_finalize (GObject * object)
5861 GstXvImageSink *xvimagesink;
5863 xvimagesink = GST_XVIMAGESINK (object);
5865 gst_xvimagesink_reset (xvimagesink);
5867 if (xvimagesink->display_name) {
5868 g_free (xvimagesink->display_name);
5869 xvimagesink->display_name = NULL;
5872 if (xvimagesink->par) {
5873 g_free (xvimagesink->par);
5874 xvimagesink->par = NULL;
5876 if (xvimagesink->x_lock) {
5877 g_mutex_free (xvimagesink->x_lock);
5878 xvimagesink->x_lock = NULL;
5880 if (xvimagesink->flow_lock) {
5881 g_mutex_free (xvimagesink->flow_lock);
5882 xvimagesink->flow_lock = NULL;
5884 if (xvimagesink->pool_lock) {
5885 g_mutex_free (xvimagesink->pool_lock);
5886 xvimagesink->pool_lock = NULL;
5888 #ifdef GST_EXT_XV_ENHANCEMENT
5889 if (xvimagesink->display_buffer_lock) {
5890 g_mutex_free (xvimagesink->display_buffer_lock);
5891 xvimagesink->display_buffer_lock = NULL;
5893 if (xvimagesink->display_buffer_cond) {
5894 g_cond_free (xvimagesink->display_buffer_cond);
5895 xvimagesink->display_buffer_cond = NULL;
5897 #endif /* GST_EXT_XV_ENHANCEMENT */
5899 g_free (xvimagesink->media_title);
5901 G_OBJECT_CLASS (parent_class)->finalize (object);
5905 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
5906 GstXvImageSinkClass * xvimagesinkclass)
5908 #ifdef GST_EXT_XV_ENHANCEMENT
5911 #endif /* GST_EXT_XV_ENHANCEMENT */
5913 xvimagesink->display_name = NULL;
5914 xvimagesink->adaptor_no = 0;
5915 xvimagesink->xcontext = NULL;
5916 xvimagesink->xwindow = NULL;
5917 xvimagesink->xvimage = NULL;
5918 xvimagesink->cur_image = NULL;
5920 xvimagesink->hue = xvimagesink->saturation = 0;
5921 xvimagesink->contrast = xvimagesink->brightness = 0;
5922 xvimagesink->cb_changed = FALSE;
5924 xvimagesink->fps_n = 0;
5925 xvimagesink->fps_d = 0;
5926 xvimagesink->video_width = 0;
5927 xvimagesink->video_height = 0;
5929 xvimagesink->x_lock = g_mutex_new ();
5930 xvimagesink->flow_lock = g_mutex_new ();
5932 xvimagesink->image_pool = NULL;
5933 xvimagesink->pool_lock = g_mutex_new ();
5935 xvimagesink->synchronous = FALSE;
5936 xvimagesink->double_buffer = TRUE;
5937 xvimagesink->running = FALSE;
5938 xvimagesink->keep_aspect = FALSE;
5939 xvimagesink->handle_events = TRUE;
5940 xvimagesink->par = NULL;
5941 xvimagesink->handle_expose = TRUE;
5942 xvimagesink->autopaint_colorkey = TRUE;
5944 /* on 16bit displays this becomes r,g,b = 1,2,3
5945 * on 24bit displays this becomes r,g,b = 8,8,16
5946 * as a port atom value
5948 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
5949 xvimagesink->draw_borders = TRUE;
5951 #ifdef GST_EXT_XV_ENHANCEMENT
5952 xvimagesink->xid_updated = FALSE;
5953 xvimagesink->display_mode = DISPLAY_MODE_DEFAULT;
5954 xvimagesink->csc_range = CSC_RANGE_NARROW;
5955 xvimagesink->rotate_changed = TRUE;
5956 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
5957 xvimagesink->flip = DEF_DISPLAY_FLIP;
5958 xvimagesink->rotate_angle = DEGREE_270;
5959 xvimagesink->visible = TRUE;
5960 xvimagesink->zoom = 1;
5961 xvimagesink->rotation = -1;
5962 xvimagesink->dst_roi.x = 0;
5963 xvimagesink->dst_roi.y = 0;
5964 xvimagesink->dst_roi.w = 0;
5965 xvimagesink->dst_roi.h = 0;
5966 xvimagesink->xim_transparenter = NULL;
5967 xvimagesink->scr_w = 0;
5968 xvimagesink->scr_h = 0;
5969 xvimagesink->aligned_width = 0;
5970 xvimagesink->aligned_height = 0;
5971 xvimagesink->stop_video = FALSE;
5972 xvimagesink->is_hided = FALSE;
5973 xvimagesink->drm_fd = -1;
5974 xvimagesink->current_pixmap_idx = -1;
5975 xvimagesink->get_pixmap_cb = NULL;
5976 xvimagesink->get_pixmap_cb_user_data = NULL;
5978 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
5979 xvimagesink->displaying_buffers[i].buffer = NULL;
5980 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
5981 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
5982 xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
5983 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
5984 xvimagesink->displaying_buffers[i].ref_count = 0;
5988 xvimagesink->display_buffer_lock = g_mutex_new ();
5989 xvimagesink->display_buffer_cond = g_cond_new ();
5991 xvimagesink->displayed_buffer_count = 0;
5992 xvimagesink->displaying_buffer_count = 0;
5993 xvimagesink->is_zero_copy_format = FALSE;
5994 xvimagesink->is_secure_path = FALSE;
5995 #endif /* GST_EXT_XV_ENHANCEMENT */
5999 gst_xvimagesink_base_init (gpointer g_class)
6001 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
6003 gst_element_class_set_details_simple (element_class,
6004 "Video sink", "Sink/Video",
6005 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
6007 gst_element_class_add_static_pad_template (element_class,
6008 &gst_xvimagesink_sink_template_factory);
6012 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
6014 GObjectClass *gobject_class;
6015 GstElementClass *gstelement_class;
6016 GstBaseSinkClass *gstbasesink_class;
6017 GstVideoSinkClass *videosink_class;
6019 gobject_class = (GObjectClass *) klass;
6020 gstelement_class = (GstElementClass *) klass;
6021 gstbasesink_class = (GstBaseSinkClass *) klass;
6022 videosink_class = (GstVideoSinkClass *) klass;
6024 gobject_class->set_property = gst_xvimagesink_set_property;
6025 gobject_class->get_property = gst_xvimagesink_get_property;
6027 g_object_class_install_property (gobject_class, PROP_CONTRAST,
6028 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
6029 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6030 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
6031 g_param_spec_int ("brightness", "Brightness",
6032 "The brightness of the video", -1000, 1000, 0,
6033 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6034 g_object_class_install_property (gobject_class, PROP_HUE,
6035 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
6036 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6037 g_object_class_install_property (gobject_class, PROP_SATURATION,
6038 g_param_spec_int ("saturation", "Saturation",
6039 "The saturation of the video", -1000, 1000, 0,
6040 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6041 g_object_class_install_property (gobject_class, PROP_DISPLAY,
6042 g_param_spec_string ("display", "Display", "X Display name", NULL,
6043 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6044 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
6045 g_param_spec_boolean ("synchronous", "Synchronous",
6046 "When enabled, runs the X display in synchronous mode. "
6047 "(unrelated to A/V sync, used only for debugging)", FALSE,
6048 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6049 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
6050 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
6051 "The pixel aspect ratio of the device", "1/1",
6052 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6053 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
6054 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
6055 "When enabled, scaling will respect original aspect ratio", FALSE,
6056 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6057 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
6058 g_param_spec_boolean ("handle-events", "Handle XEvents",
6059 "When enabled, XEvents will be selected and handled", TRUE,
6060 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6061 g_object_class_install_property (gobject_class, PROP_DEVICE,
6062 g_param_spec_string ("device", "Adaptor number",
6063 "The number of the video adaptor", "0",
6064 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6065 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
6066 g_param_spec_string ("device-name", "Adaptor name",
6067 "The name of the video adaptor", NULL,
6068 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6070 * GstXvImageSink:handle-expose
6072 * When enabled, the current frame will always be drawn in response to X
6077 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
6078 g_param_spec_boolean ("handle-expose", "Handle expose",
6080 "the current frame will always be drawn in response to X Expose "
6081 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6084 * GstXvImageSink:double-buffer
6086 * Whether to double-buffer the output.
6090 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
6091 g_param_spec_boolean ("double-buffer", "Double-buffer",
6092 "Whether to double-buffer the output", TRUE,
6093 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6095 * GstXvImageSink:autopaint-colorkey
6097 * Whether to autofill overlay with colorkey
6101 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
6102 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
6103 "Whether to autofill overlay with colorkey", TRUE,
6104 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6106 * GstXvImageSink:colorkey
6108 * Color to use for the overlay mask.
6112 g_object_class_install_property (gobject_class, PROP_COLORKEY,
6113 g_param_spec_int ("colorkey", "Colorkey",
6114 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
6115 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6118 * GstXvImageSink:draw-borders
6120 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
6121 * unused parts of the video area.
6125 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
6126 g_param_spec_boolean ("draw-borders", "Colorkey",
6127 "Draw black borders to fill unused area in force-aspect-ratio mode",
6128 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6131 * GstXvImageSink:window-width
6133 * Actual width of the video window.
6137 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
6138 g_param_spec_uint64 ("window-width", "window-width",
6139 "Width of the window", 0, G_MAXUINT64, 0,
6140 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6143 * GstXvImageSink:window-height
6145 * Actual height of the video window.
6149 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
6150 g_param_spec_uint64 ("window-height", "window-height",
6151 "Height of the window", 0, G_MAXUINT64, 0,
6152 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6154 #ifdef GST_EXT_XV_ENHANCEMENT
6156 * GstXvImageSink:display-mode
6158 * select display mode
6160 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
6161 g_param_spec_enum("display-mode", "Display Mode",
6162 "Display device setting",
6163 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
6164 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6167 * GstXvImageSink:csc-range
6169 * select color space range
6171 g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
6172 g_param_spec_enum("csc-range", "Color Space Range",
6173 "Color space range setting",
6174 GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
6175 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6178 * GstXvImageSink:display-geometry-method
6180 * Display geometrical method setting
6182 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
6183 g_param_spec_enum("display-geometry-method", "Display geometry method",
6184 "Geometrical method for display",
6185 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
6186 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6189 * GstXvImageSink:display-flip
6191 * Display flip setting
6193 g_object_class_install_property(gobject_class, PROP_FLIP,
6194 g_param_spec_enum("flip", "Display flip",
6196 GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
6197 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6200 * GstXvImageSink:rotate
6202 * Draw rotation angle setting
6204 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
6205 g_param_spec_enum("rotate", "Rotate angle",
6206 "Rotate angle of display output",
6207 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
6208 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6211 * GstXvImageSink:visible
6213 * Whether reserve original src size or not
6215 g_object_class_install_property (gobject_class, PROP_VISIBLE,
6216 g_param_spec_boolean ("visible", "Visible",
6217 "Draws screen or blacks out, true means visible, false blacks out",
6218 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6221 * GstXvImageSink:zoom
6223 * Scale small area of screen to 2X, 3X, ... , 9X
6225 g_object_class_install_property (gobject_class, PROP_ZOOM,
6226 g_param_spec_int ("zoom", "Zoom",
6227 "Zooms screen as nX", 1, 9, 1,
6228 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6231 * GstXvImageSink:dst-roi-x
6233 * X value of Destination ROI
6235 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
6236 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
6237 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
6238 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6241 * GstXvImageSink:dst-roi-y
6243 * Y value of Destination ROI
6245 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
6246 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
6247 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
6248 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6251 * GstXvImageSink:dst-roi-w
6253 * W value of Destination ROI
6255 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
6256 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
6257 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
6258 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6261 * GstXvImageSink:dst-roi-h
6263 * H value of Destination ROI
6265 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
6266 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
6267 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
6268 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6271 * GstXvImageSink:stop-video
6273 * Stop video for releasing video source buffer
6275 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
6276 g_param_spec_int ("stop-video", "Stop-Video",
6277 "Stop video for releasing video source buffer", 0, 1, 0,
6278 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6280 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
6281 g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
6282 "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
6284 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
6285 g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
6286 "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
6289 * GstXvImageSink::frame-render-error
6291 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
6292 "frame-render-error",
6293 G_TYPE_FROM_CLASS (klass),
6298 gst_xvimagesink_BOOLEAN__POINTER,
6303 #endif /* GST_EXT_XV_ENHANCEMENT */
6305 gobject_class->finalize = gst_xvimagesink_finalize;
6307 gstelement_class->change_state =
6308 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
6310 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
6311 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
6312 gstbasesink_class->buffer_alloc =
6313 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
6314 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
6315 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
6317 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
6320 /* ============================================================= */
6322 /* Public Methods */
6324 /* ============================================================= */
6326 /* =========================================== */
6328 /* Object typing & Creation */
6330 /* =========================================== */
6332 gst_xvimagesink_init_interfaces (GType type)
6334 static const GInterfaceInfo iface_info = {
6335 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
6339 static const GInterfaceInfo navigation_info = {
6340 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
6344 static const GInterfaceInfo overlay_info = {
6345 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
6349 static const GInterfaceInfo colorbalance_info = {
6350 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
6354 static const GInterfaceInfo propertyprobe_info = {
6355 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
6360 g_type_add_interface_static (type,
6361 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
6362 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
6363 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
6364 g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
6365 &colorbalance_info);
6366 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
6367 &propertyprobe_info);
6369 /* register type and create class in a more safe place instead of at
6370 * runtime since the type registration and class creation is not
6372 g_type_class_ref (gst_xvimage_buffer_get_type ());
6376 plugin_init (GstPlugin * plugin)
6378 if (!gst_element_register (plugin, "xvimagesink",
6379 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
6382 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
6383 "xvimagesink element");
6384 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
6389 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
6392 "XFree86 video output plugin using Xv extension",
6393 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)