2 * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3 * <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:element-xvimagesink
24 * XvImageSink renders video frames to a drawable (XWindow) on a local display
25 * using the XVideo extension. Rendering to a remote display is theoretically
26 * possible but i doubt that the XVideo extension is actually available when
27 * connecting to a remote display. This element can receive a Window ID from the
28 * application through the XOverlay interface and will then render video frames
29 * in this drawable. If no Window ID was provided by the application, the
30 * element will create its own internal window and render into it.
33 * <title>Scaling</title>
35 * The XVideo extension, when it's available, handles hardware accelerated
36 * scaling of video frames. This means that the element will just accept
37 * incoming video frames no matter their geometry and will then put them to the
38 * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
39 * property it is possible to enforce scaling with a constant aspect ratio,
40 * which means drawing black borders around the video frame.
44 * <title>Events</title>
46 * XvImageSink creates a thread to handle events coming from the drawable. There
47 * are several kind of events that can be grouped in 2 big categories: input
48 * events and window state related events. Input events will be translated to
49 * navigation events and pushed upstream for other elements to react on them.
50 * This includes events such as pointer moves, key press/release, clicks etc...
51 * Other events are used to handle the drawable appearance even when the data
52 * is not flowing (GST_STATE_PAUSED). That means that even when the element is
53 * paused, it will receive expose events from the drawable and draw the latest
54 * frame with correct borders/aspect-ratio.
58 * <title>Pixel aspect ratio</title>
60 * When changing state to GST_STATE_READY, XvImageSink will open a connection to
61 * the display specified in the #GstXvImageSink:display property or the
62 * default display if nothing specified. Once this connection is open it will
63 * inspect the display configuration including the physical display geometry and
64 * then calculate the pixel aspect ratio. When receiving video frames with a
65 * different pixel aspect ratio, XvImageSink will use hardware scaling to
66 * display the video frames correctly on display's pixel aspect ratio.
67 * Sometimes the calculated pixel aspect ratio can be wrong, it is
68 * then possible to enforce a specific pixel aspect ratio using the
69 * #GstXvImageSink:pixel-aspect-ratio property.
73 * <title>Examples</title>
75 * gst-launch -v videotestsrc ! xvimagesink
76 * ]| A pipeline to test hardware scaling.
77 * When the test video signal appears you can resize the window and see that
78 * video frames are scaled through hardware (no extra CPU cost).
80 * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
81 * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
82 * You can observe the borders drawn around the scaled image respecting aspect
85 * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
86 * ]| A pipeline to test navigation events.
87 * While moving the mouse pointer over the test signal you will see a black box
88 * following the mouse pointer. If you press the mouse button somewhere on the
89 * video and release it somewhere else a green box will appear where you pressed
90 * the button and a red one where you released it. (The navigationtest element
91 * is part of gst-plugins-good.) You can observe here that even if the images
92 * are scaled through hardware the pointer coordinates are converted back to the
93 * original video frame geometry so that the box can be drawn to the correct
94 * position. This also handles borders correctly, limiting coordinates to the
97 * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
98 * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
99 * videotestsrc, in most cases the pixel aspect ratio of the display will be
100 * 1/1. This means that XvImageSink will have to do the scaling to convert
101 * incoming frames to a size that will match the display pixel aspect ratio
102 * (from 320x240 to 320x180 in this case). Note that you might have to escape
103 * some characters for your shell like '\(fraction\)'.
105 * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
106 * ]| Demonstrates how to use the colorbalance interface.
110 /* for developers: there are two useful tools : xvinfo and xvattr */
117 #include <gst/interfaces/navigation.h>
118 #include <gst/interfaces/xoverlay.h>
119 #include <gst/interfaces/colorbalance.h>
120 #include <gst/interfaces/propertyprobe.h>
121 /* Helper functions */
122 #include <gst/video/video.h>
125 #include "xvimagesink.h"
127 #ifdef GST_EXT_XV_ENHANCEMENT
128 /* Samsung extension headers */
129 /* For xv extension header for buffer transfer (output) */
130 #include "xv_types.h"
132 /* max channel count *********************************************************/
133 #define SCMN_IMGB_MAX_PLANE (4)
135 /* image buffer definition ***************************************************
137 +------------------------------------------+ ---
140 | +---------------------------+ --- | |
142 | |<---------- w[] ---------->| | | |
150 | +---------------------------+ --- | |
152 +------------------------------------------+ ---
154 |<----------------- s[] ------------------>|
159 /* width of each image plane */
160 int w[SCMN_IMGB_MAX_PLANE];
161 /* height of each image plane */
162 int h[SCMN_IMGB_MAX_PLANE];
163 /* stride of each image plane */
164 int s[SCMN_IMGB_MAX_PLANE];
165 /* elevation of each image plane */
166 int e[SCMN_IMGB_MAX_PLANE];
167 /* user space address of each image plane */
168 void * a[SCMN_IMGB_MAX_PLANE];
169 /* physical address of each image plane, if needs */
170 void * p[SCMN_IMGB_MAX_PLANE];
171 /* color space type of image */
173 /* left postion, if needs */
175 /* top position, if needs */
177 /* to align memory */
182 #endif /* GST_EXT_XV_ENHANCEMENT */
184 /* Debugging category */
185 #include <gst/gstinfo.h>
187 #include "gst/glib-compat-private.h"
189 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
190 #define GST_CAT_DEFAULT gst_debug_xvimagesink
191 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
193 #ifdef GST_EXT_XV_ENHANCEMENT
194 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
197 gst_xvimagesink_display_mode_get_type(void)
199 static GType xvimagesink_display_mode_type = 0;
200 static const GEnumValue display_mode_type[] = {
201 { 0, "Default mode", "DEFAULT"},
202 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
203 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
207 if (!xvimagesink_display_mode_type) {
208 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
211 return xvimagesink_display_mode_type;
222 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
225 gst_xvimagesink_rotate_angle_get_type(void)
227 static GType xvimagesink_rotate_angle_type = 0;
228 static const GEnumValue rotate_angle_type[] = {
229 { 0, "No rotate", "DEGREE_0"},
230 { 1, "Rotate 90 degree", "DEGREE_90"},
231 { 2, "Rotate 180 degree", "DEGREE_180"},
232 { 3, "Rotate 270 degree", "DEGREE_270"},
236 if (!xvimagesink_rotate_angle_type) {
237 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
240 return xvimagesink_rotate_angle_type;
244 DISP_GEO_METHOD_LETTER_BOX = 0,
245 DISP_GEO_METHOD_ORIGIN_SIZE,
246 DISP_GEO_METHOD_FULL_SCREEN,
247 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
248 DISP_GEO_METHOD_CUSTOM_ROI,
252 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
254 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
257 gst_xvimagesink_display_geometry_method_get_type(void)
259 static GType xvimagesink_display_geometry_method_type = 0;
260 static const GEnumValue display_geometry_method_type[] = {
261 { 0, "Letter box", "LETTER_BOX"},
262 { 1, "Origin size", "ORIGIN_SIZE"},
263 { 2, "Full-screen", "FULL_SCREEN"},
264 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
265 { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
269 if (!xvimagesink_display_geometry_method_type) {
270 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
273 return xvimagesink_display_geometry_method_type;
275 #endif /* GST_EXT_XV_ENHANCEMENT */
280 unsigned long functions;
281 unsigned long decorations;
283 unsigned long status;
285 MotifWmHints, MwmHints;
287 #define MWM_HINTS_DECORATIONS (1L << 1)
289 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
291 static GstBufferClass *xvimage_buffer_parent_class = NULL;
292 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
294 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
296 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
298 static void gst_xvimagesink_expose (GstXOverlay * overlay);
300 #ifdef GST_EXT_XV_ENHANCEMENT
301 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
302 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
303 #endif /* GST_EXT_XV_ENHANCEMENT */
305 /* Default template - initiated with class struct to allow gst-register to work
307 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
308 GST_STATIC_PAD_TEMPLATE ("sink",
311 GST_STATIC_CAPS ("video/x-raw-rgb, "
312 "framerate = (fraction) [ 0, MAX ], "
313 "width = (int) [ 1, MAX ], "
314 "height = (int) [ 1, MAX ]; "
316 "framerate = (fraction) [ 0, MAX ], "
317 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
329 PROP_PIXEL_ASPECT_RATIO,
330 PROP_FORCE_ASPECT_RATIO,
336 PROP_AUTOPAINT_COLORKEY,
341 #ifdef GST_EXT_XV_ENHANCEMENT
344 PROP_DISPLAY_GEOMETRY_METHOD,
352 #endif /* GST_EXT_XV_ENHANCEMENT */
355 static void gst_xvimagesink_init_interfaces (GType type);
357 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
358 GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
361 /* ============================================================= */
363 /* Private Methods */
365 /* ============================================================= */
367 /* xvimage buffers */
369 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
371 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
372 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
373 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
375 /* This function destroys a GstXvImage handling XShm availability */
377 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
379 GstXvImageSink *xvimagesink;
381 GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
383 xvimagesink = xvimage->xvimagesink;
384 if (G_UNLIKELY (xvimagesink == NULL))
387 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
389 GST_OBJECT_LOCK (xvimagesink);
391 /* If the destroyed image is the current one we destroy our reference too */
392 if (xvimagesink->cur_image == xvimage)
393 xvimagesink->cur_image = NULL;
395 /* We might have some buffers destroyed after changing state to NULL */
396 if (xvimagesink->xcontext == NULL) {
397 GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
399 /* Need to free the shared memory segment even if the x context
400 * was already cleaned up */
401 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
402 shmdt (xvimage->SHMInfo.shmaddr);
408 g_mutex_lock (xvimagesink->x_lock);
411 if (xvimagesink->xcontext->use_xshm) {
412 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
413 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
414 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
415 XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
416 XSync (xvimagesink->xcontext->disp, FALSE);
418 shmdt (xvimage->SHMInfo.shmaddr);
420 if (xvimage->xvimage)
421 XFree (xvimage->xvimage);
423 #endif /* HAVE_XSHM */
425 if (xvimage->xvimage) {
426 if (xvimage->xvimage->data) {
427 g_free (xvimage->xvimage->data);
429 XFree (xvimage->xvimage);
433 XSync (xvimagesink->xcontext->disp, FALSE);
435 g_mutex_unlock (xvimagesink->x_lock);
438 GST_OBJECT_UNLOCK (xvimagesink);
439 xvimage->xvimagesink = NULL;
440 gst_object_unref (xvimagesink);
442 GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
449 GST_WARNING ("no sink found");
455 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
457 GstXvImageSink *xvimagesink;
460 xvimagesink = xvimage->xvimagesink;
461 if (G_UNLIKELY (xvimagesink == NULL))
464 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
466 GST_OBJECT_LOCK (xvimagesink);
467 running = xvimagesink->running;
468 GST_OBJECT_UNLOCK (xvimagesink);
470 /* If our geometry changed we can't reuse that image. */
471 if (running == FALSE) {
472 GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
473 gst_xvimage_buffer_destroy (xvimage);
474 } else if ((xvimage->width != xvimagesink->video_width) ||
475 (xvimage->height != xvimagesink->video_height)) {
476 GST_LOG_OBJECT (xvimage,
477 "destroy image as its size changed %dx%d vs current %dx%d",
478 xvimage->width, xvimage->height,
479 xvimagesink->video_width, xvimagesink->video_height);
480 gst_xvimage_buffer_destroy (xvimage);
482 /* In that case we can reuse the image and add it to our image pool. */
483 GST_LOG_OBJECT (xvimage, "recycling image in pool");
484 /* need to increment the refcount again to recycle */
485 gst_buffer_ref (GST_BUFFER_CAST (xvimage));
486 g_mutex_lock (xvimagesink->pool_lock);
487 xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
489 g_mutex_unlock (xvimagesink->pool_lock);
495 GST_WARNING ("no sink found");
501 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
503 /* make sure it is not recycled */
505 xvimage->height = -1;
506 gst_buffer_unref (GST_BUFFER (xvimage));
510 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
513 xvimage->SHMInfo.shmaddr = ((void *) -1);
514 xvimage->SHMInfo.shmid = -1;
519 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
521 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
523 xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
525 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
526 gst_xvimage_buffer_finalize;
530 gst_xvimage_buffer_get_type (void)
532 static GType _gst_xvimage_buffer_type;
534 if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
535 static const GTypeInfo xvimage_buffer_info = {
536 sizeof (GstBufferClass),
539 gst_xvimage_buffer_class_init,
542 sizeof (GstXvImageBuffer),
544 (GInstanceInitFunc) gst_xvimage_buffer_init,
547 _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
548 "GstXvImageBuffer", &xvimage_buffer_info, 0);
550 return _gst_xvimage_buffer_type;
555 static gboolean error_caught = FALSE;
558 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
560 char error_msg[1024];
562 XGetErrorText (display, xevent->error_code, error_msg, 1024);
563 GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
569 /* This function checks that it is actually really possible to create an image
572 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
575 XShmSegmentInfo SHMInfo;
577 int (*handler) (Display *, XErrorEvent *);
578 gboolean result = FALSE;
579 gboolean did_attach = FALSE;
581 g_return_val_if_fail (xcontext != NULL, FALSE);
583 /* Sync to ensure any older errors are already processed */
584 XSync (xcontext->disp, FALSE);
586 /* Set defaults so we don't free these later unnecessarily */
587 SHMInfo.shmaddr = ((void *) -1);
590 /* Setting an error handler to catch failure */
591 error_caught = FALSE;
592 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
594 /* Trying to create a 1x1 picture */
595 GST_DEBUG ("XvShmCreateImage of 1x1");
596 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
597 xcontext->im_format, NULL, 1, 1, &SHMInfo);
599 /* Might cause an error, sync to ensure it is noticed */
600 XSync (xcontext->disp, FALSE);
601 if (!xvimage || error_caught) {
602 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
605 size = xvimage->data_size;
607 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
608 if (SHMInfo.shmid == -1) {
609 GST_WARNING ("could not get shared memory of %d bytes", size);
613 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
614 if (SHMInfo.shmaddr == ((void *) -1)) {
615 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
616 /* Clean up the shared memory segment */
617 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
621 xvimage->data = SHMInfo.shmaddr;
622 SHMInfo.readOnly = FALSE;
624 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
625 GST_WARNING ("Failed to XShmAttach");
626 /* Clean up the shared memory segment */
627 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
631 /* Sync to ensure we see any errors we caused */
632 XSync (xcontext->disp, FALSE);
634 /* Delete the shared memory segment as soon as everyone is attached.
635 * This way, it will be deleted as soon as we detach later, and not
636 * leaked if we crash. */
637 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
640 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
644 /* store whether we succeeded in result */
647 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
648 "Not using shared memory.");
652 /* Sync to ensure we swallow any errors we caused and reset error_caught */
653 XSync (xcontext->disp, FALSE);
655 error_caught = FALSE;
656 XSetErrorHandler (handler);
659 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
660 SHMInfo.shmid, SHMInfo.shmseg);
661 XShmDetach (xcontext->disp, &SHMInfo);
662 XSync (xcontext->disp, FALSE);
664 if (SHMInfo.shmaddr != ((void *) -1))
665 shmdt (SHMInfo.shmaddr);
670 #endif /* HAVE_XSHM */
672 /* This function handles GstXvImage creation depending on XShm availability */
673 static GstXvImageBuffer *
674 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
676 GstXvImageBuffer *xvimage = NULL;
677 GstStructure *structure = NULL;
678 gboolean succeeded = FALSE;
679 int (*handler) (Display *, XErrorEvent *);
681 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
686 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
687 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
689 structure = gst_caps_get_structure (caps, 0);
691 if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
692 !gst_structure_get_int (structure, "height", &xvimage->height)) {
693 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
696 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
698 #ifdef GST_EXT_XV_ENHANCEMENT
699 GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
700 xvimagesink->aligned_width, xvimagesink->aligned_height);
701 if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
702 GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
703 xvimagesink->aligned_width = xvimage->width;
704 xvimagesink->aligned_height = xvimage->height;
706 #endif /* GST_EXT_XV_ENHANCEMENT */
708 xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
709 if (xvimage->im_format == -1) {
710 GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
711 GST_PTR_FORMAT, caps);
712 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
713 ("Failed to create output image buffer of %dx%d pixels",
714 xvimage->width, xvimage->height), ("Invalid input caps"));
717 xvimage->xvimagesink = gst_object_ref (xvimagesink);
719 g_mutex_lock (xvimagesink->x_lock);
721 /* Setting an error handler to catch failure */
722 error_caught = FALSE;
723 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
726 if (xvimagesink->xcontext->use_xshm) {
729 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
730 xvimagesink->xcontext->xv_port_id,
731 xvimage->im_format, NULL,
732 #ifdef GST_EXT_XV_ENHANCEMENT
733 xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
734 #else /* GST_EXT_XV_ENHANCEMENT */
735 xvimage->width, xvimage->height, &xvimage->SHMInfo);
736 #endif /* GST_EXT_XV_ENHANCEMENT */
737 if (!xvimage->xvimage || error_caught) {
738 g_mutex_unlock (xvimagesink->x_lock);
740 /* Reset error flag */
741 error_caught = FALSE;
744 GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
745 ("Failed to create output image buffer of %dx%d pixels",
746 xvimage->width, xvimage->height),
747 ("could not XvShmCreateImage a %dx%d image",
748 xvimage->width, xvimage->height));
750 /* Retry without XShm */
751 xvimagesink->xcontext->use_xshm = FALSE;
753 /* Hold X mutex again to try without XShm */
754 g_mutex_lock (xvimagesink->x_lock);
758 /* we have to use the returned data_size for our shm size */
759 xvimage->size = xvimage->xvimage->data_size;
760 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
763 /* calculate the expected size. This is only for sanity checking the
764 * number we get from X. */
765 switch (xvimage->im_format) {
766 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
767 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
774 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
775 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
776 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
778 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
779 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
782 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
784 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
785 GST_DEBUG_OBJECT (xvimagesink,
786 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
787 plane, pitches[plane], offsets[plane]);
791 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
792 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
793 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
796 #ifdef GST_EXT_XV_ENHANCEMENT
797 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
798 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
799 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
800 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
801 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
802 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
803 expected_size = sizeof(SCMN_IMGB);
805 #endif /* GST_EXT_XV_ENHANCEMENT */
810 if (expected_size != 0 && xvimage->size != expected_size) {
811 GST_WARNING_OBJECT (xvimagesink,
812 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
813 xvimage->size, expected_size);
816 /* Be verbose about our XvImage stride */
820 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
821 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
822 "offset of %d", plane, xvimage->xvimage->pitches[plane],
823 xvimage->xvimage->offsets[plane]);
827 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
829 if (xvimage->SHMInfo.shmid == -1) {
830 g_mutex_unlock (xvimagesink->x_lock);
831 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
832 ("Failed to create output image buffer of %dx%d pixels",
833 xvimage->width, xvimage->height),
834 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
839 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
840 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
841 g_mutex_unlock (xvimagesink->x_lock);
842 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
843 ("Failed to create output image buffer of %dx%d pixels",
844 xvimage->width, xvimage->height),
845 ("Failed to shmat: %s", g_strerror (errno)));
846 /* Clean up the shared memory segment */
847 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
851 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
852 xvimage->SHMInfo.readOnly = FALSE;
854 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
855 /* Clean up the shared memory segment */
856 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
858 g_mutex_unlock (xvimagesink->x_lock);
859 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
860 ("Failed to create output image buffer of %dx%d pixels",
861 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
865 XSync (xvimagesink->xcontext->disp, FALSE);
867 /* Delete the shared memory segment as soon as we everyone is attached.
868 * This way, it will be deleted as soon as we detach later, and not
869 * leaked if we crash. */
870 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
872 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
873 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
876 #endif /* HAVE_XSHM */
878 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
879 xvimagesink->xcontext->xv_port_id,
880 #ifdef GST_EXT_XV_ENHANCEMENT
881 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
882 #else /* GST_EXT_XV_ENHANCEMENT */
883 xvimage->im_format, NULL, xvimage->width, xvimage->height);
884 #endif /* GST_EXT_XV_ENHANCEMENT */
885 if (!xvimage->xvimage || error_caught) {
886 g_mutex_unlock (xvimagesink->x_lock);
887 /* Reset error handler */
888 error_caught = FALSE;
889 XSetErrorHandler (handler);
891 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
892 ("Failed to create outputimage buffer of %dx%d pixels",
893 xvimage->width, xvimage->height),
894 ("could not XvCreateImage a %dx%d image",
895 xvimage->width, xvimage->height));
899 /* we have to use the returned data_size for our image size */
900 xvimage->size = xvimage->xvimage->data_size;
901 xvimage->xvimage->data = g_malloc (xvimage->size);
903 XSync (xvimagesink->xcontext->disp, FALSE);
906 /* Reset error handler */
907 error_caught = FALSE;
908 XSetErrorHandler (handler);
912 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
913 GST_BUFFER_SIZE (xvimage) = xvimage->size;
915 g_mutex_unlock (xvimagesink->x_lock);
919 gst_xvimage_buffer_free (xvimage);
926 /* We are called with the x_lock taken */
928 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
929 GstXWindow * xwindow, GstVideoRectangle rect)
933 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
934 g_return_if_fail (xwindow != NULL);
936 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
937 xvimagesink->xcontext->black);
940 if (rect.x > xvimagesink->render_rect.x) {
941 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
942 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
943 rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
947 t1 = rect.x + rect.w;
948 t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
950 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
951 t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
955 if (rect.y > xvimagesink->render_rect.y) {
956 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
957 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
958 xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
962 t1 = rect.y + rect.h;
963 t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
965 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
966 xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
970 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
971 * if no window was available */
973 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
974 GstXvImageBuffer * xvimage)
976 GstVideoRectangle result;
977 gboolean draw_border = FALSE;
979 #ifdef GST_EXT_XV_ENHANCEMENT
980 static Atom atom_rotation = None;
982 GstVideoRectangle src_origin = { 0, 0, 0, 0};
983 GstVideoRectangle src_input = { 0, 0, 0, 0};
984 GstVideoRectangle src = { 0, 0, 0, 0};
985 GstVideoRectangle dst = { 0, 0, 0, 0};
989 #endif /* GST_EXT_XV_ENHANCEMENT */
991 /* We take the flow_lock. If expose is in there we don't want to run
992 concurrently from the data flow thread */
993 g_mutex_lock (xvimagesink->flow_lock);
995 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
996 #ifdef GST_EXT_XV_ENHANCEMENT
997 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
998 #endif /* GST_EXT_XV_ENHANCEMENT */
999 g_mutex_unlock (xvimagesink->flow_lock);
1003 #ifdef GST_EXT_XV_ENHANCEMENT
1004 if (xvimagesink->visible == FALSE) {
1005 GST_INFO_OBJECT(xvimagesink, "visible is FALSE. Skip xvimage_put.");
1006 g_mutex_unlock(xvimagesink->flow_lock);
1009 #endif /* GST_EXT_XV_ENHANCEMENT */
1011 /* Draw borders when displaying the first frame. After this
1012 draw borders only on expose event or after a size change. */
1013 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1017 /* Store a reference to the last image we put, lose the previous one */
1018 if (xvimage && xvimagesink->cur_image != xvimage) {
1019 if (xvimagesink->cur_image) {
1020 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1021 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1023 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1024 xvimagesink->cur_image =
1025 GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1028 /* Expose sends a NULL image, we take the latest frame */
1030 if (xvimagesink->cur_image) {
1032 xvimage = xvimagesink->cur_image;
1034 #ifdef GST_EXT_XV_ENHANCEMENT
1035 GST_INFO_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1036 #endif /* GST_EXT_XV_ENHANCEMENT */
1037 g_mutex_unlock (xvimagesink->flow_lock);
1042 #ifdef GST_EXT_XV_ENHANCEMENT
1043 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1046 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1048 src_input.w = src_origin.w = xvimagesink->video_width;
1049 src_input.h = src_origin.h = xvimagesink->video_height;
1051 if (xvimagesink->rotate_angle == DEGREE_0 ||
1052 xvimagesink->rotate_angle == DEGREE_180) {
1053 src.w = src_origin.w;
1054 src.h = src_origin.h;
1056 src.w = src_origin.h;
1057 src.h = src_origin.w;
1060 dst.w = xvimagesink->render_rect.w;
1061 dst.h = xvimagesink->render_rect.h;
1063 switch (xvimagesink->display_geometry_method)
1065 case DISP_GEO_METHOD_LETTER_BOX:
1066 gst_video_sink_center_rect (src, dst, &result, TRUE);
1067 result.x += xvimagesink->render_rect.x;
1068 result.y += xvimagesink->render_rect.y;
1071 case DISP_GEO_METHOD_ORIGIN_SIZE:
1072 gst_video_sink_center_rect (src, dst, &result, FALSE);
1073 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1075 if (xvimagesink->rotate_angle == DEGREE_90 ||
1076 xvimagesink->rotate_angle == DEGREE_270) {
1077 src_input.x = src_input.x ^ src_input.y;
1078 src_input.y = src_input.x ^ src_input.y;
1079 src_input.x = src_input.x ^ src_input.y;
1081 src_input.w = src_input.w ^ src_input.h;
1082 src_input.h = src_input.w ^ src_input.h;
1083 src_input.w = src_input.w ^ src_input.h;
1087 case DISP_GEO_METHOD_FULL_SCREEN:
1088 result.x = result.y = 0;
1089 result.w = xvimagesink->xwindow->width;
1090 result.h = xvimagesink->xwindow->height;
1093 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1094 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1096 result.x = result.y = 0;
1100 if (xvimagesink->rotate_angle == DEGREE_90 ||
1101 xvimagesink->rotate_angle == DEGREE_270) {
1102 src_input.x = src_input.x ^ src_input.y;
1103 src_input.y = src_input.x ^ src_input.y;
1104 src_input.x = src_input.x ^ src_input.y;
1106 src_input.w = src_input.w ^ src_input.h;
1107 src_input.h = src_input.w ^ src_input.h;
1108 src_input.w = src_input.w ^ src_input.h;
1112 case DISP_GEO_METHOD_CUSTOM_ROI:
1113 #ifdef GST_EXT_XV_ENHANCEMENT_ROI_MODE
1114 switch (xvimagesink->rotate_angle) {
1116 result.w = xvimagesink->dst_roi.h;
1117 result.h = xvimagesink->dst_roi.w;
1119 result.x = xvimagesink->dst_roi.y;
1120 result.y = xvimagesink->xwindow->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
1123 result.w = xvimagesink->dst_roi.w;
1124 result.h = xvimagesink->dst_roi.h;
1126 result.x = xvimagesink->xwindow->width - result.w - xvimagesink->dst_roi.x;
1127 result.y = xvimagesink->xwindow->height - result.h - xvimagesink->dst_roi.y;
1130 result.w = xvimagesink->dst_roi.h;
1131 result.h = xvimagesink->dst_roi.w;
1133 result.x = xvimagesink->xwindow->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
1134 result.y = xvimagesink->dst_roi.x;
1137 result.x = xvimagesink->dst_roi.x;
1138 result.y = xvimagesink->dst_roi.y;
1139 result.w = xvimagesink->dst_roi.w;
1140 result.h = xvimagesink->dst_roi.h;
1144 GST_LOG_OBJECT(xvimagesink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1145 xvimagesink->rotate_angle,
1146 xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1147 result.x, result.y, result.w, result.h);
1148 #else /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1149 result.x = xvimagesink->dst_roi.x;
1150 result.y = xvimagesink->dst_roi.y;
1151 result.w = xvimagesink->dst_roi.w;
1152 result.h = xvimagesink->dst_roi.h;
1154 if (xvimagesink->rotate_angle == DEGREE_90 ||
1155 xvimagesink->rotate_angle == DEGREE_270) {
1156 result.w = xvimagesink->dst_roi.h;
1157 result.h = xvimagesink->dst_roi.w;
1159 #endif /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
1166 if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) {
1167 src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1;
1168 src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1;
1169 src_input.w /= xvimagesink->zoom;
1170 src_input.h /= xvimagesink->zoom;
1172 #else /* GST_EXT_XV_ENHANCEMENT */
1173 if (xvimagesink->keep_aspect) {
1174 GstVideoRectangle src, dst;
1176 /* We use the calculated geometry from _setcaps as a source to respect
1177 source and screen pixel aspect ratios. */
1178 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1179 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1180 dst.w = xvimagesink->render_rect.w;
1181 dst.h = xvimagesink->render_rect.h;
1183 gst_video_sink_center_rect (src, dst, &result, TRUE);
1184 result.x += xvimagesink->render_rect.x;
1185 result.y += xvimagesink->render_rect.y;
1187 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1189 #endif /* GST_EXT_XV_ENHANCEMENT */
1191 g_mutex_lock (xvimagesink->x_lock);
1193 if (draw_border && xvimagesink->draw_borders) {
1194 gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1196 xvimagesink->redraw_border = FALSE;
1199 /* We scale to the window's geometry */
1201 if (xvimagesink->xcontext->use_xshm) {
1202 GST_LOG_OBJECT (xvimagesink,
1203 "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1205 xvimage->width, xvimage->height,
1206 xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1208 #ifdef GST_EXT_XV_ENHANCEMENT
1209 switch( xvimagesink->rotate_angle )
1211 /* There's slightly weired code (CCW? CW?) */
1224 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1225 xvimagesink->rotate_angle );
1229 /* Trim as proper size */
1230 if (src_input.w % 2 == 1) {
1233 if (src_input.h % 2 == 1) {
1237 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]",
1238 xvimagesink->scr_w, xvimagesink->scr_h,
1239 xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1240 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1241 src_origin.w, src_origin.h,
1242 dst.x, dst.y, dst.w, dst.h,
1243 src_input.x, src_input.y, src_input.w, src_input.h,
1244 result.x, result.y, result.w, result.h );
1246 if (atom_rotation == None) {
1247 atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1248 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1251 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate);
1252 if (ret != Success) {
1253 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1254 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1258 /* src input indicates the status when degree is 0 */
1259 /* dst input indicates the area that src will be shown regardless of rotate */
1261 if (xvimagesink->visible && !xvimagesink->is_hided) {
1262 if (xvimagesink->xim_transparenter) {
1263 GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1264 XPutImage(xvimagesink->xcontext->disp,
1265 xvimagesink->xwindow->win,
1266 xvimagesink->xwindow->gc,
1267 xvimagesink->xim_transparenter,
1269 result.x, result.y, result.w, result.h);
1272 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1273 xvimagesink->xcontext->xv_port_id,
1274 xvimagesink->xwindow->win,
1275 xvimagesink->xwindow->gc, xvimage->xvimage,
1276 src_input.x, src_input.y, src_input.w, src_input.h,
1277 result.x, result.y, result.w, result.h, FALSE);
1278 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret );
1280 GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1282 #else /* GST_EXT_XV_ENHANCEMENT */
1283 XvShmPutImage (xvimagesink->xcontext->disp,
1284 xvimagesink->xcontext->xv_port_id,
1285 xvimagesink->xwindow->win,
1286 xvimagesink->xwindow->gc, xvimage->xvimage,
1287 xvimagesink->disp_x, xvimagesink->disp_y,
1288 xvimagesink->disp_width, xvimagesink->disp_height,
1289 result.x, result.y, result.w, result.h, FALSE);
1290 #endif /* GST_EXT_XV_ENHANCEMENT */
1292 #endif /* HAVE_XSHM */
1294 XvPutImage (xvimagesink->xcontext->disp,
1295 xvimagesink->xcontext->xv_port_id,
1296 xvimagesink->xwindow->win,
1297 xvimagesink->xwindow->gc, xvimage->xvimage,
1298 xvimagesink->disp_x, xvimagesink->disp_y,
1299 xvimagesink->disp_width, xvimagesink->disp_height,
1300 result.x, result.y, result.w, result.h);
1303 XSync (xvimagesink->xcontext->disp, FALSE);
1305 g_mutex_unlock (xvimagesink->x_lock);
1307 g_mutex_unlock (xvimagesink->flow_lock);
1313 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
1314 GstXWindow * window)
1316 Atom hints_atom = None;
1317 MotifWmHints *hints;
1319 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
1320 g_return_val_if_fail (window != NULL, FALSE);
1322 g_mutex_lock (xvimagesink->x_lock);
1324 hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
1326 if (hints_atom == None) {
1327 g_mutex_unlock (xvimagesink->x_lock);
1331 hints = g_malloc0 (sizeof (MotifWmHints));
1333 hints->flags |= MWM_HINTS_DECORATIONS;
1334 hints->decorations = 1 << 0;
1336 XChangeProperty (xvimagesink->xcontext->disp, window->win,
1337 hints_atom, hints_atom, 32, PropModeReplace,
1338 (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
1340 XSync (xvimagesink->xcontext->disp, FALSE);
1342 g_mutex_unlock (xvimagesink->x_lock);
1350 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1351 GstXWindow * xwindow, const gchar * media_title)
1354 g_free (xvimagesink->media_title);
1355 xvimagesink->media_title = g_strdup (media_title);
1358 /* we have a window */
1359 if (xwindow->internal) {
1360 XTextProperty xproperty;
1361 const gchar *app_name;
1362 const gchar *title = NULL;
1363 gchar *title_mem = NULL;
1365 /* set application name as a title */
1366 app_name = g_get_application_name ();
1368 if (app_name && xvimagesink->media_title) {
1369 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1371 } else if (app_name) {
1373 } else if (xvimagesink->media_title) {
1374 title = xvimagesink->media_title;
1378 if ((XStringListToTextProperty (((char **) &title), 1,
1379 &xproperty)) != 0) {
1380 XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
1381 XFree (xproperty.value);
1390 #ifdef GST_EXT_XV_ENHANCEMENT
1391 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
1395 /* create a normal ximage */
1396 xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
1398 /* allocate data for it */
1400 xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
1403 memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
1404 if (!xim || !xim->data) {
1405 /* failed to create XImage or allocate data memory */
1417 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
1420 static gboolean is_exist = FALSE;
1421 static XvPortID current_port_id = -1;
1422 Atom atom_output = None;
1424 if (xcontext == NULL) {
1425 GST_WARNING("xcontext is NULL");
1429 /* check once per one xv_port_id */
1430 if (current_port_id != xcontext->xv_port_id) {
1431 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
1434 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
1435 xcontext->xv_port_id, &count);
1437 current_port_id = xcontext->xv_port_id;
1438 for (i = 0 ; i < count ; i++) {
1439 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
1441 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
1448 GST_INFO("set display mode %d", set_mode);
1449 atom_output = XInternAtom(xcontext->disp,
1450 "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
1451 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
1452 atom_output, set_mode);
1453 if (ret == Success) {
1456 GST_WARNING("display mode[%d] set failed.", set_mode);
1459 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
1464 #endif /* GST_EXT_XV_ENHANCEMENT */
1466 /* This function handles a GstXWindow creation
1467 * The width and height are the actual pixel size on the display */
1469 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
1470 gint width, gint height)
1472 GstXWindow *xwindow = NULL;
1474 #ifdef GST_EXT_XV_ENHANCEMENT
1475 XSetWindowAttributes win_attr;
1476 XWindowAttributes root_attr;
1477 #endif /* GST_EXT_XV_ENHANCEMENT */
1479 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1481 xwindow = g_new0 (GstXWindow, 1);
1483 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1484 #ifdef GST_EXT_XV_ENHANCEMENT
1486 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
1487 xvimagesink->render_rect.w = xwindow->width = width;
1488 xvimagesink->render_rect.h = xwindow->height = height;
1491 xvimagesink->render_rect.w = xwindow->width = height;
1492 xvimagesink->render_rect.h = xwindow->height = width;
1495 XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
1497 if (xwindow->width > root_attr.width) {
1498 GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
1499 xwindow->width, root_attr.width);
1500 xvimagesink->render_rect.w = xwindow->width = root_attr.width;
1502 if (xwindow->height > root_attr.height) {
1503 GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
1504 xwindow->height, root_attr.height);
1505 xvimagesink->render_rect.h = xwindow->height = root_attr.height;
1507 xwindow->internal = TRUE;
1509 g_mutex_lock (xvimagesink->x_lock);
1511 GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
1513 xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
1514 xvimagesink->xcontext->root,
1515 0, 0, xwindow->width, xwindow->height,
1518 xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
1519 xvimagesink->xcontext->root,
1520 xwindow->width, xwindow->height);
1522 /* Make window manager not to change window size as Full screen */
1523 win_attr.override_redirect = True;
1524 XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
1525 #else /* GST_EXT_XV_ENHANCEMENT */
1526 xvimagesink->render_rect.w = width;
1527 xvimagesink->render_rect.h = height;
1529 xwindow->width = width;
1530 xwindow->height = height;
1531 xwindow->internal = TRUE;
1533 g_mutex_lock (xvimagesink->x_lock);
1535 xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
1536 xvimagesink->xcontext->root,
1537 0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
1538 #endif /* GST_EXT_XV_ENHANCEMENT */
1540 /* We have to do that to prevent X from redrawing the background on
1541 * ConfigureNotify. This takes away flickering of video when resizing. */
1542 XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
1544 /* set application name as a title */
1545 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
1547 if (xvimagesink->handle_events) {
1550 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
1551 StructureNotifyMask | PointerMotionMask | KeyPressMask |
1552 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
1554 /* Tell the window manager we'd like delete client messages instead of
1556 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
1557 "WM_DELETE_WINDOW", True);
1558 if (wm_delete != None) {
1559 (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
1564 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
1565 xwindow->win, 0, &values);
1567 XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
1569 XSync (xvimagesink->xcontext->disp, FALSE);
1571 g_mutex_unlock (xvimagesink->x_lock);
1573 gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
1575 gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
1580 /* This function destroys a GstXWindow */
1582 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
1583 GstXWindow * xwindow)
1585 g_return_if_fail (xwindow != NULL);
1586 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1588 g_mutex_lock (xvimagesink->x_lock);
1590 /* If we did not create that window we just free the GC and let it live */
1591 if (xwindow->internal) {
1592 XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
1593 if (xvimagesink->xim_transparenter) {
1594 XDestroyImage(xvimagesink->xim_transparenter);
1595 xvimagesink->xim_transparenter = NULL;
1598 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
1601 XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
1603 XSync (xvimagesink->xcontext->disp, FALSE);
1605 g_mutex_unlock (xvimagesink->x_lock);
1611 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
1613 #ifdef GST_EXT_XV_ENHANCEMENT
1614 Window root_window, child_window;
1615 XWindowAttributes root_attr;
1619 unsigned int cur_win_width = 0;
1620 unsigned int cur_win_height = 0;
1621 unsigned int cur_win_border_width = 0;
1622 unsigned int cur_win_depth = 0;
1623 #else /* GST_EXT_XV_ENHANCEMENT */
1624 XWindowAttributes attr;
1625 #endif /* GST_EXT_XV_ENHANCEMENT */
1627 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1629 /* Update the window geometry */
1630 g_mutex_lock (xvimagesink->x_lock);
1631 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1632 g_mutex_unlock (xvimagesink->x_lock);
1636 #ifdef GST_EXT_XV_ENHANCEMENT
1637 /* Get root window and size of current window */
1638 XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
1639 &cur_win_x, &cur_win_y, /* relative x, y */
1640 &cur_win_width, &cur_win_height,
1641 &cur_win_border_width, &cur_win_depth );
1643 xvimagesink->xwindow->width = cur_win_width;
1644 xvimagesink->xwindow->height = cur_win_height;
1646 /* Get absolute coordinates of current window */
1647 XTranslateCoordinates( xvimagesink->xcontext->disp,
1648 xvimagesink->xwindow->win,
1651 &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
1654 xvimagesink->xwindow->x = cur_win_x;
1655 xvimagesink->xwindow->y = cur_win_y;
1657 /* Get size of root window == size of screen */
1658 XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
1660 xvimagesink->scr_w = root_attr.width;
1661 xvimagesink->scr_h = root_attr.height;
1663 if (!xvimagesink->have_render_rect) {
1664 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1665 xvimagesink->render_rect.w = cur_win_width;
1666 xvimagesink->render_rect.h = cur_win_height;
1669 GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
1670 xvimagesink->scr_w, xvimagesink->scr_h,
1671 xvimagesink->xwindow->x, xvimagesink->xwindow->y,
1672 xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1673 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1674 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
1675 #else /* GST_EXT_XV_ENHANCEMENT */
1676 XGetWindowAttributes (xvimagesink->xcontext->disp,
1677 xvimagesink->xwindow->win, &attr);
1679 xvimagesink->xwindow->width = attr.width;
1680 xvimagesink->xwindow->height = attr.height;
1682 if (!xvimagesink->have_render_rect) {
1683 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1684 xvimagesink->render_rect.w = attr.width;
1685 xvimagesink->render_rect.h = attr.height;
1687 #endif /* GST_EXT_XV_ENHANCEMENT */
1689 g_mutex_unlock (xvimagesink->x_lock);
1693 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
1694 GstXWindow * xwindow)
1696 g_return_if_fail (xwindow != NULL);
1697 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1699 g_mutex_lock (xvimagesink->x_lock);
1701 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1703 #ifndef GST_EXT_XV_ENHANCEMENT
1704 /* Preview area is not updated before other UI is updated in the screen. */
1705 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1706 xvimagesink->xcontext->black);
1708 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1709 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1710 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
1711 #endif /* GST_EXT_XV_ENHANCEMENT */
1713 XSync (xvimagesink->xcontext->disp, FALSE);
1715 g_mutex_unlock (xvimagesink->x_lock);
1718 /* This function commits our internal colorbalance settings to our grabbed Xv
1719 port. If the xcontext is not initialized yet it simply returns */
1721 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
1723 GList *channels = NULL;
1725 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1727 /* If we haven't initialized the X context we can't update anything */
1728 if (xvimagesink->xcontext == NULL)
1731 /* Don't set the attributes if they haven't been changed, to avoid
1732 * rounding errors changing the values */
1733 if (!xvimagesink->cb_changed)
1736 /* For each channel of the colorbalance we calculate the correct value
1737 doing range conversion and then set the Xv port attribute to match our
1739 channels = xvimagesink->xcontext->channels_list;
1742 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
1743 GstColorBalanceChannel *channel = NULL;
1746 gdouble convert_coef;
1748 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
1749 g_object_ref (channel);
1751 /* Our range conversion coef */
1752 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
1754 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
1755 value = xvimagesink->hue;
1756 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
1757 value = xvimagesink->saturation;
1758 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
1759 value = xvimagesink->contrast;
1760 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
1761 value = xvimagesink->brightness;
1763 g_warning ("got an unknown channel %s", channel->label);
1764 g_object_unref (channel);
1768 /* Committing to Xv port */
1769 g_mutex_lock (xvimagesink->x_lock);
1771 XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
1772 if (prop_atom != None) {
1775 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
1776 XvSetPortAttribute (xvimagesink->xcontext->disp,
1777 xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
1779 g_mutex_unlock (xvimagesink->x_lock);
1781 g_object_unref (channel);
1783 channels = g_list_next (channels);
1787 /* This function handles XEvents that might be in the queue. It generates
1788 GstEvent that will be sent upstream in the pipeline to handle interactivity
1789 and navigation. It will also listen for configure events on the window to
1790 trigger caps renegotiation so on the fly software scaling can work. */
1792 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
1795 guint pointer_x = 0, pointer_y = 0;
1796 gboolean pointer_moved = FALSE;
1797 gboolean exposed = FALSE, configured = FALSE;
1799 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1801 /* Handle Interaction, produces navigation events */
1803 /* We get all pointer motion events, only the last position is
1805 g_mutex_lock (xvimagesink->flow_lock);
1806 g_mutex_lock (xvimagesink->x_lock);
1807 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1808 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
1809 g_mutex_unlock (xvimagesink->x_lock);
1810 g_mutex_unlock (xvimagesink->flow_lock);
1814 pointer_x = e.xmotion.x;
1815 pointer_y = e.xmotion.y;
1816 pointer_moved = TRUE;
1821 g_mutex_lock (xvimagesink->flow_lock);
1822 g_mutex_lock (xvimagesink->x_lock);
1824 if (pointer_moved) {
1825 g_mutex_unlock (xvimagesink->x_lock);
1826 g_mutex_unlock (xvimagesink->flow_lock);
1828 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
1829 pointer_x, pointer_y);
1830 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1831 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
1833 g_mutex_lock (xvimagesink->flow_lock);
1834 g_mutex_lock (xvimagesink->x_lock);
1837 /* We get all events on our window to throw them upstream */
1838 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1839 xvimagesink->xwindow->win,
1840 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
1844 /* We lock only for the X function call */
1845 g_mutex_unlock (xvimagesink->x_lock);
1846 g_mutex_unlock (xvimagesink->flow_lock);
1850 /* Mouse button pressed over our window. We send upstream
1851 events for interactivity/navigation */
1852 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
1853 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1854 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1855 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1858 /* Mouse button released over our window. We send upstream
1859 events for interactivity/navigation */
1860 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
1861 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1862 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1863 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1867 /* Key pressed/released over our window. We send upstream
1868 events for interactivity/navigation */
1869 GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
1870 e.xkey.keycode, e.xkey.x, e.xkey.y);
1871 g_mutex_lock (xvimagesink->x_lock);
1872 keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
1874 g_mutex_unlock (xvimagesink->x_lock);
1875 if (keysym != NoSymbol) {
1876 char *key_str = NULL;
1878 g_mutex_lock (xvimagesink->x_lock);
1879 key_str = XKeysymToString (keysym);
1880 g_mutex_unlock (xvimagesink->x_lock);
1881 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1882 e.type == KeyPress ? "key-press" : "key-release", key_str);
1884 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1885 e.type == KeyPress ? "key-press" : "key-release", "unknown");
1889 GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
1891 g_mutex_lock (xvimagesink->flow_lock);
1892 g_mutex_lock (xvimagesink->x_lock);
1896 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1897 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
1902 case ConfigureNotify:
1903 g_mutex_unlock (xvimagesink->x_lock);
1904 #ifdef GST_EXT_XV_ENHANCEMENT
1905 GST_INFO_OBJECT (xvimagesink, "Call gst_xvimagesink_xwindow_update_geometry!");
1906 #endif /* GST_EXT_XV_ENHANCEMENT */
1907 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
1908 g_mutex_lock (xvimagesink->x_lock);
1916 if (xvimagesink->handle_expose && (exposed || configured)) {
1917 g_mutex_unlock (xvimagesink->x_lock);
1918 g_mutex_unlock (xvimagesink->flow_lock);
1920 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
1922 g_mutex_lock (xvimagesink->flow_lock);
1923 g_mutex_lock (xvimagesink->x_lock);
1926 /* Handle Display events */
1927 while (XPending (xvimagesink->xcontext->disp)) {
1928 XNextEvent (xvimagesink->xcontext->disp, &e);
1931 case ClientMessage:{
1932 #ifdef GST_EXT_XV_ENHANCEMENT
1933 int active_pid, deactive_pid;
1934 Atom active_win_atom;
1935 Atom deactive_win_atom;
1937 #endif /* GST_EXT_XV_ENHANCEMENT */
1940 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
1941 "WM_DELETE_WINDOW", True);
1942 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
1943 /* Handle window deletion by posting an error on the bus */
1944 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
1945 ("Output window was closed"), (NULL));
1947 g_mutex_unlock (xvimagesink->x_lock);
1948 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
1949 xvimagesink->xwindow = NULL;
1950 g_mutex_lock (xvimagesink->x_lock);
1952 #ifdef GST_EXT_XV_ENHANCEMENT
1953 GST_INFO_OBJECT( xvimagesink, "message type : %d", e.xclient.message_type );
1955 active_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_ACTIVATE_WINDOW", False);
1956 deactive_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_DEACTIVATE_WINDOW", False);
1958 if (!active_win_atom || !deactive_win_atom) {
1959 GST_WARNING_OBJECT( xvimagesink, "Can NOT get active[%d] or deactive[%d] win atom",
1960 active_win_atom, deactive_win_atom );
1962 if (e.xclient.message_type == deactive_win_atom) {
1963 /* Window is DEACTIVATED */
1964 /* Get pid of activated/deactivated window */
1965 active_pid = e.xclient.data.l[1];
1966 deactive_pid = e.xclient.data.l[3];
1968 if (active_pid != deactive_pid) {
1969 GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window DEACTIVATED" );
1971 xvimagesink->is_hided = TRUE;
1972 atom_stream = XInternAtom( xvimagesink->xcontext->disp,
1973 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
1974 if (atom_stream != None) {
1975 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
1976 xvimagesink->xcontext->xv_port_id,
1977 atom_stream, 0 ) != Success) {
1978 GST_WARNING_OBJECT( xvimagesink, "STREAM OFF failed" );
1980 XSync( xvimagesink->xcontext->disp, FALSE );
1983 GST_INFO_OBJECT( xvimagesink, "Window is DEACTIVATED, but same process. so Do not clear screen." );
1985 } else if (e.xclient.message_type == active_win_atom) {
1986 /* Window is ACTIVATED */
1987 /* Get pid of activated/deactivated window */
1988 active_pid = e.xclient.data.l[1];
1989 deactive_pid = e.xclient.data.l[3];
1991 if (active_pid != deactive_pid) {
1992 GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window ACTIVATED" );
1994 g_mutex_unlock (xvimagesink->x_lock);
1995 g_mutex_unlock (xvimagesink->flow_lock);
1997 xvimagesink->is_hided = FALSE;
1998 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
2000 g_mutex_lock (xvimagesink->flow_lock);
2001 g_mutex_lock (xvimagesink->x_lock);
2003 GST_INFO_OBJECT( xvimagesink, "Window is ACTIVATED, but same process. so Do not redraw screen." );
2007 #endif /* GST_EXT_XV_ENHANCEMENT */
2015 g_mutex_unlock (xvimagesink->x_lock);
2016 g_mutex_unlock (xvimagesink->flow_lock);
2020 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
2021 XvAdaptorInfo * adaptors, int adaptor_no)
2026 /* Do we support XvImageMask ? */
2027 if (!(adaptors[adaptor_no].type & XvImageMask)) {
2028 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
2029 adaptors[adaptor_no].name);
2033 /* We found such an adaptor, looking for an available port */
2034 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
2035 /* We try to grab the port */
2036 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
2037 if (Success == res) {
2038 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
2039 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
2040 adaptors[adaptor_no].num_ports);
2042 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
2043 adaptors[adaptor_no].name, res);
2048 /* This function generates a caps with all supported format by the first
2049 Xv grabable port we find. We store each one of the supported formats in a
2050 format list and append the format to a newly created caps that we return
2051 If this function does not return NULL because of an error, it also grabs
2052 the port via XvGrabPort */
2054 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
2055 GstXContext * xcontext)
2058 XvAdaptorInfo *adaptors;
2060 XvImageFormatValues *formats = NULL;
2062 XvEncodingInfo *encodings = NULL;
2063 gulong max_w = G_MAXINT, max_h = G_MAXINT;
2064 GstCaps *caps = NULL;
2065 GstCaps *rgb_caps = NULL;
2067 g_return_val_if_fail (xcontext != NULL, NULL);
2069 /* First let's check that XVideo extension is available */
2070 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
2071 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
2072 ("Could not initialise Xv output"),
2073 ("XVideo extension is not available"));
2077 /* Then we get adaptors list */
2078 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
2079 &xcontext->nb_adaptors, &adaptors)) {
2080 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
2081 ("Could not initialise Xv output"),
2082 ("Failed getting XV adaptors list"));
2086 xcontext->xv_port_id = 0;
2088 GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors);
2090 xcontext->adaptors =
2091 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
2093 /* Now fill up our adaptor name array */
2094 for (i = 0; i < xcontext->nb_adaptors; i++) {
2095 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
2098 if (xvimagesink->adaptor_no >= 0 &&
2099 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
2100 /* Find xv port from user defined adaptor */
2101 gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
2102 xvimagesink->adaptor_no);
2105 if (!xcontext->xv_port_id) {
2106 /* Now search for an adaptor that supports XvImageMask */
2107 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
2108 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
2109 xvimagesink->adaptor_no = i;
2113 XvFreeAdaptorInfo (adaptors);
2115 if (!xcontext->xv_port_id) {
2116 xvimagesink->adaptor_no = -1;
2117 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
2118 ("Could not initialise Xv output"), ("No port available"));
2122 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
2124 int count, todo = 3;
2125 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
2126 xcontext->xv_port_id, &count);
2127 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
2128 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
2129 static const char colorkey[] = "XV_COLORKEY";
2131 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
2133 xvimagesink->have_autopaint_colorkey = FALSE;
2134 xvimagesink->have_double_buffer = FALSE;
2135 xvimagesink->have_colorkey = FALSE;
2137 for (i = 0; ((i < count) && todo); i++)
2138 if (!strcmp (attr[i].name, autopaint)) {
2139 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
2141 /* turn on autopaint colorkey */
2142 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2143 (xvimagesink->autopaint_colorkey ? 1 : 0));
2145 xvimagesink->have_autopaint_colorkey = TRUE;
2146 } else if (!strcmp (attr[i].name, dbl_buffer)) {
2147 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
2149 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2150 (xvimagesink->double_buffer ? 1 : 0));
2152 xvimagesink->have_double_buffer = TRUE;
2153 } else if (!strcmp (attr[i].name, colorkey)) {
2154 /* Set the colorkey, default is something that is dark but hopefully
2155 * won't randomly appear on the screen elsewhere (ie not black or greys)
2156 * can be overridden by setting "colorkey" property
2158 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
2160 gboolean set_attr = TRUE;
2163 /* set a colorkey in the right format RGB565/RGB888
2164 * We only handle these 2 cases, because they're the only types of
2165 * devices we've encountered. If we don't recognise it, leave it alone
2167 cr = (xvimagesink->colorkey >> 16);
2168 cg = (xvimagesink->colorkey >> 8) & 0xFF;
2169 cb = (xvimagesink->colorkey) & 0xFF;
2170 switch (xcontext->depth) {
2171 case 16: /* RGB 565 */
2175 ckey = (cr << 11) | (cg << 5) | cb;
2178 case 32: /* RGB 888 / ARGB 8888 */
2179 ckey = (cr << 16) | (cg << 8) | cb;
2182 GST_DEBUG_OBJECT (xvimagesink,
2183 "Unknown bit depth %d for Xv Colorkey - not adjusting",
2190 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
2191 (guint32) attr[i].max_value);
2192 GST_LOG_OBJECT (xvimagesink,
2193 "Setting color key for display depth %d to 0x%x",
2194 xcontext->depth, ckey);
2196 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2200 xvimagesink->have_colorkey = TRUE;
2206 /* Get the list of encodings supported by the adapter and look for the
2207 * XV_IMAGE encoding so we can determine the maximum width and height
2209 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
2212 for (i = 0; i < nb_encodings; i++) {
2213 GST_LOG_OBJECT (xvimagesink,
2214 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
2215 i, encodings[i].name, encodings[i].width, encodings[i].height,
2216 encodings[i].rate.numerator, encodings[i].rate.denominator);
2217 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
2218 max_w = encodings[i].width;
2219 max_h = encodings[i].height;
2220 #ifdef GST_EXT_XV_ENHANCEMENT
2221 xvimagesink->scr_w = max_w;
2222 xvimagesink->scr_h = max_h;
2223 #endif /* GST_EXT_XV_ENHANCEMENT */
2227 XvFreeEncodingInfo (encodings);
2229 /* We get all image formats supported by our port */
2230 formats = XvListImageFormats (xcontext->disp,
2231 xcontext->xv_port_id, &nb_formats);
2232 caps = gst_caps_new_empty ();
2233 for (i = 0; i < nb_formats; i++) {
2234 GstCaps *format_caps = NULL;
2235 gboolean is_rgb_format = FALSE;
2237 /* We set the image format of the xcontext to an existing one. This
2238 is just some valid image format for making our xshm calls check before
2239 caps negotiation really happens. */
2240 xcontext->im_format = formats[i].id;
2242 switch (formats[i].type) {
2245 XvImageFormatValues *fmt = &(formats[i]);
2246 gint endianness = G_BIG_ENDIAN;
2248 if (fmt->byte_order == LSBFirst) {
2249 /* our caps system handles 24/32bpp RGB as big-endian. */
2250 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
2251 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
2252 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
2253 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
2255 if (fmt->bits_per_pixel == 24) {
2256 fmt->red_mask >>= 8;
2257 fmt->green_mask >>= 8;
2258 fmt->blue_mask >>= 8;
2261 endianness = G_LITTLE_ENDIAN;
2264 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
2265 "endianness", G_TYPE_INT, endianness,
2266 "depth", G_TYPE_INT, fmt->depth,
2267 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
2268 "red_mask", G_TYPE_INT, fmt->red_mask,
2269 "green_mask", G_TYPE_INT, fmt->green_mask,
2270 "blue_mask", G_TYPE_INT, fmt->blue_mask,
2271 "width", GST_TYPE_INT_RANGE, 1, max_w,
2272 "height", GST_TYPE_INT_RANGE, 1, max_h,
2273 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2275 is_rgb_format = TRUE;
2279 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
2280 "format", GST_TYPE_FOURCC, formats[i].id,
2281 "width", GST_TYPE_INT_RANGE, 1, max_w,
2282 "height", GST_TYPE_INT_RANGE, 1, max_h,
2283 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2286 g_assert_not_reached ();
2291 GstXvImageFormat *format = NULL;
2293 format = g_new0 (GstXvImageFormat, 1);
2295 format->format = formats[i].id;
2296 format->caps = gst_caps_copy (format_caps);
2297 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
2300 if (is_rgb_format) {
2301 if (rgb_caps == NULL)
2302 rgb_caps = format_caps;
2304 gst_caps_append (rgb_caps, format_caps);
2306 gst_caps_append (caps, format_caps);
2310 /* Collected all caps into either the caps or rgb_caps structures.
2311 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
2313 gst_caps_append (caps, rgb_caps);
2318 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
2320 if (gst_caps_is_empty (caps)) {
2321 gst_caps_unref (caps);
2322 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2323 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
2324 ("No supported format found"));
2332 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
2334 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2336 GST_OBJECT_LOCK (xvimagesink);
2337 while (xvimagesink->running) {
2338 GST_OBJECT_UNLOCK (xvimagesink);
2340 if (xvimagesink->xwindow) {
2341 gst_xvimagesink_handle_xevents (xvimagesink);
2343 /* FIXME: do we want to align this with the framerate or anything else? */
2344 g_usleep (G_USEC_PER_SEC / 20);
2346 GST_OBJECT_LOCK (xvimagesink);
2348 GST_OBJECT_UNLOCK (xvimagesink);
2354 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
2356 GThread *thread = NULL;
2358 /* don't start the thread too early */
2359 if (xvimagesink->xcontext == NULL) {
2363 GST_OBJECT_LOCK (xvimagesink);
2364 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
2365 if (!xvimagesink->event_thread) {
2366 /* Setup our event listening thread */
2367 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
2368 xvimagesink->handle_expose, xvimagesink->handle_events);
2369 xvimagesink->running = TRUE;
2370 #if !GLIB_CHECK_VERSION (2, 31, 0)
2371 xvimagesink->event_thread = g_thread_create (
2372 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
2374 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
2375 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
2379 if (xvimagesink->event_thread) {
2380 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
2381 xvimagesink->handle_expose, xvimagesink->handle_events);
2382 xvimagesink->running = FALSE;
2383 /* grab thread and mark it as NULL */
2384 thread = xvimagesink->event_thread;
2385 xvimagesink->event_thread = NULL;
2388 GST_OBJECT_UNLOCK (xvimagesink);
2390 /* Wait for our event thread to finish */
2392 g_thread_join (thread);
2397 /* This function calculates the pixel aspect ratio based on the properties
2398 * in the xcontext structure and stores it there. */
2400 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
2402 static const gint par[][2] = {
2403 {1, 1}, /* regular screen */
2404 {16, 15}, /* PAL TV */
2405 {11, 10}, /* 525 line Rec.601 video */
2406 {54, 59}, /* 625 line Rec.601 video */
2407 {64, 45}, /* 1280x1024 on 16:9 display */
2408 {5, 3}, /* 1280x1024 on 4:3 display */
2409 {4, 3} /* 800x600 on 16:9 display */
2416 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
2418 /* first calculate the "real" ratio based on the X values;
2419 * which is the "physical" w/h divided by the w/h in pixels of the display */
2420 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
2421 / (xcontext->heightmm * xcontext->width);
2423 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
2425 if (xcontext->width == 720 && xcontext->height == 576) {
2426 ratio = 4.0 * 576 / (3.0 * 720);
2428 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
2429 /* now find the one from par[][2] with the lowest delta to the real one */
2433 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
2434 gdouble this_delta = DELTA (i);
2436 if (this_delta < delta) {
2442 GST_DEBUG ("Decided on index %d (%d/%d)", index,
2443 par[index][0], par[index][1]);
2445 g_free (xcontext->par);
2446 xcontext->par = g_new0 (GValue, 1);
2447 g_value_init (xcontext->par, GST_TYPE_FRACTION);
2448 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
2449 GST_DEBUG ("set xcontext PAR to %d/%d",
2450 gst_value_get_fraction_numerator (xcontext->par),
2451 gst_value_get_fraction_denominator (xcontext->par));
2454 /* This function gets the X Display and global info about it. Everything is
2455 stored in our object and will be cleaned when the object is disposed. Note
2456 here that caps for supported format are generated without any window or
2458 static GstXContext *
2459 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
2461 GstXContext *xcontext = NULL;
2462 XPixmapFormatValues *px_formats = NULL;
2463 gint nb_formats = 0, i, j, N_attr;
2464 XvAttribute *xv_attr;
2466 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
2467 "XV_BRIGHTNESS", "XV_CONTRAST"
2470 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2472 xcontext = g_new0 (GstXContext, 1);
2473 xcontext->im_format = 0;
2475 g_mutex_lock (xvimagesink->x_lock);
2477 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
2479 if (!xcontext->disp) {
2480 g_mutex_unlock (xvimagesink->x_lock);
2482 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
2483 ("Could not initialise Xv output"), ("Could not open display"));
2487 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
2488 xcontext->screen_num = DefaultScreen (xcontext->disp);
2489 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
2490 xcontext->root = DefaultRootWindow (xcontext->disp);
2491 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
2492 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
2493 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
2495 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
2496 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
2497 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
2498 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
2500 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
2501 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
2503 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
2504 /* We get supported pixmap formats at supported depth */
2505 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
2508 XCloseDisplay (xcontext->disp);
2509 g_mutex_unlock (xvimagesink->x_lock);
2510 g_free (xcontext->par);
2512 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
2513 ("Could not initialise Xv output"), ("Could not get pixel formats"));
2517 /* We get bpp value corresponding to our running depth */
2518 for (i = 0; i < nb_formats; i++) {
2519 if (px_formats[i].depth == xcontext->depth)
2520 xcontext->bpp = px_formats[i].bits_per_pixel;
2525 xcontext->endianness =
2526 (ImageByteOrder (xcontext->disp) ==
2527 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
2529 /* our caps system handles 24/32bpp RGB as big-endian. */
2530 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
2531 xcontext->endianness == G_LITTLE_ENDIAN) {
2532 xcontext->endianness = G_BIG_ENDIAN;
2533 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
2534 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
2535 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
2536 if (xcontext->bpp == 24) {
2537 xcontext->visual->red_mask >>= 8;
2538 xcontext->visual->green_mask >>= 8;
2539 xcontext->visual->blue_mask >>= 8;
2543 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
2545 if (!xcontext->caps) {
2546 XCloseDisplay (xcontext->disp);
2547 g_mutex_unlock (xvimagesink->x_lock);
2548 g_free (xcontext->par);
2550 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
2554 /* Search for XShm extension support */
2555 if (XShmQueryExtension (xcontext->disp) &&
2556 gst_xvimagesink_check_xshm_calls (xcontext)) {
2557 xcontext->use_xshm = TRUE;
2558 GST_DEBUG ("xvimagesink is using XShm extension");
2560 #endif /* HAVE_XSHM */
2562 xcontext->use_xshm = FALSE;
2563 GST_DEBUG ("xvimagesink is not using XShm extension");
2566 xv_attr = XvQueryPortAttributes (xcontext->disp,
2567 xcontext->xv_port_id, &N_attr);
2570 /* Generate the channels list */
2571 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
2572 XvAttribute *matching_attr = NULL;
2574 /* Retrieve the property atom if it exists. If it doesn't exist,
2575 * the attribute itself must not either, so we can skip */
2576 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
2577 if (prop_atom == None)
2580 if (xv_attr != NULL) {
2581 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
2582 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
2583 matching_attr = xv_attr + j;
2586 if (matching_attr) {
2587 GstColorBalanceChannel *channel;
2589 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
2590 channel->label = g_strdup (channels[i]);
2591 channel->min_value = matching_attr->min_value;
2592 channel->max_value = matching_attr->max_value;
2594 xcontext->channels_list = g_list_append (xcontext->channels_list,
2597 /* If the colorbalance settings have not been touched we get Xv values
2598 as defaults and update our internal variables */
2599 if (!xvimagesink->cb_changed) {
2602 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
2604 /* Normalize val to [-1000, 1000] */
2605 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
2606 (double) (channel->max_value - channel->min_value));
2608 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
2609 xvimagesink->hue = val;
2610 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
2611 xvimagesink->saturation = val;
2612 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
2613 xvimagesink->brightness = val;
2614 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
2615 xvimagesink->contrast = val;
2623 #ifdef GST_EXT_XV_ENHANCEMENT
2624 set_display_mode(xcontext, xvimagesink->display_mode);
2625 #endif /* GST_EXT_XV_ENHANCEMENT */
2627 g_mutex_unlock (xvimagesink->x_lock);
2632 /* This function cleans the X context. Closing the Display, releasing the XV
2633 port and unrefing the caps for supported formats. */
2635 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
2637 GList *formats_list, *channels_list;
2638 GstXContext *xcontext;
2641 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2643 GST_OBJECT_LOCK (xvimagesink);
2644 if (xvimagesink->xcontext == NULL) {
2645 GST_OBJECT_UNLOCK (xvimagesink);
2649 /* Take the XContext from the sink and clean it up */
2650 xcontext = xvimagesink->xcontext;
2651 xvimagesink->xcontext = NULL;
2653 GST_OBJECT_UNLOCK (xvimagesink);
2656 formats_list = xcontext->formats_list;
2658 while (formats_list) {
2659 GstXvImageFormat *format = formats_list->data;
2661 gst_caps_unref (format->caps);
2663 formats_list = g_list_next (formats_list);
2666 if (xcontext->formats_list)
2667 g_list_free (xcontext->formats_list);
2669 channels_list = xcontext->channels_list;
2671 while (channels_list) {
2672 GstColorBalanceChannel *channel = channels_list->data;
2674 g_object_unref (channel);
2675 channels_list = g_list_next (channels_list);
2678 if (xcontext->channels_list)
2679 g_list_free (xcontext->channels_list);
2681 gst_caps_unref (xcontext->caps);
2682 if (xcontext->last_caps)
2683 gst_caps_replace (&xcontext->last_caps, NULL);
2685 for (i = 0; i < xcontext->nb_adaptors; i++) {
2686 g_free (xcontext->adaptors[i]);
2689 g_free (xcontext->adaptors);
2691 g_free (xcontext->par);
2693 g_mutex_lock (xvimagesink->x_lock);
2695 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
2697 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2699 XCloseDisplay (xcontext->disp);
2701 g_mutex_unlock (xvimagesink->x_lock);
2707 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
2709 g_mutex_lock (xvimagesink->pool_lock);
2711 while (xvimagesink->image_pool) {
2712 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
2714 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
2715 xvimagesink->image_pool);
2716 gst_xvimage_buffer_free (xvimage);
2719 g_mutex_unlock (xvimagesink->pool_lock);
2724 /* This function tries to get a format matching with a given caps in the
2725 supported list of formats we generated in gst_xvimagesink_get_xv_support */
2727 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
2732 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
2734 list = xvimagesink->xcontext->formats_list;
2737 GstXvImageFormat *format = list->data;
2740 if (gst_caps_can_intersect (caps, format->caps)) {
2741 return format->format;
2744 list = g_list_next (list);
2751 gst_xvimagesink_getcaps (GstBaseSink * bsink)
2753 GstXvImageSink *xvimagesink;
2755 xvimagesink = GST_XVIMAGESINK (bsink);
2757 if (xvimagesink->xcontext)
2758 return gst_caps_ref (xvimagesink->xcontext->caps);
2761 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
2766 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
2768 GstXvImageSink *xvimagesink;
2769 GstStructure *structure;
2770 guint32 im_format = 0;
2772 gint video_width, video_height;
2773 gint disp_x, disp_y;
2774 gint disp_width, disp_height;
2775 gint video_par_n, video_par_d; /* video's PAR */
2776 gint display_par_n, display_par_d; /* display's PAR */
2777 const GValue *caps_par;
2778 const GValue *caps_disp_reg;
2781 #ifdef GST_EXT_XV_ENHANCEMENT
2782 gboolean enable_last_buffer;
2783 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
2785 xvimagesink = GST_XVIMAGESINK (bsink);
2787 GST_DEBUG_OBJECT (xvimagesink,
2788 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
2789 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
2791 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
2792 goto incompatible_caps;
2794 structure = gst_caps_get_structure (caps, 0);
2795 ret = gst_structure_get_int (structure, "width", &video_width);
2796 ret &= gst_structure_get_int (structure, "height", &video_height);
2797 fps = gst_structure_get_value (structure, "framerate");
2798 ret &= (fps != NULL);
2801 goto incomplete_caps;
2803 #ifdef GST_EXT_XV_ENHANCEMENT
2804 xvimagesink->aligned_width = video_width;
2805 xvimagesink->aligned_height = video_height;
2807 /* get enable-last-buffer */
2808 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
2809 GST_INFO_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
2811 /* flush if enable-last-buffer is TRUE */
2812 if (enable_last_buffer) {
2813 GST_INFO_OBJECT(xvimagesink, "flush last-buffer");
2814 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
2815 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
2817 #endif /* GST_EXT_XV_ENHANCEMENT */
2819 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
2820 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
2822 xvimagesink->video_width = video_width;
2823 xvimagesink->video_height = video_height;
2825 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
2826 if (im_format == -1)
2827 goto invalid_format;
2829 /* get aspect ratio from caps if it's present, and
2830 * convert video width and height to a display width and height
2831 * using wd / hd = wv / hv * PARv / PARd */
2833 /* get video's PAR */
2834 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
2836 video_par_n = gst_value_get_fraction_numerator (caps_par);
2837 video_par_d = gst_value_get_fraction_denominator (caps_par);
2842 /* get display's PAR */
2843 if (xvimagesink->par) {
2844 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
2845 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
2851 /* get the display region */
2852 caps_disp_reg = gst_structure_get_value (structure, "display-region");
2853 if (caps_disp_reg) {
2854 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
2855 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
2856 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
2858 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
2860 disp_x = disp_y = 0;
2861 disp_width = video_width;
2862 disp_height = video_height;
2865 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
2866 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
2869 xvimagesink->disp_x = disp_x;
2870 xvimagesink->disp_y = disp_y;
2871 xvimagesink->disp_width = disp_width;
2872 xvimagesink->disp_height = disp_height;
2874 GST_DEBUG_OBJECT (xvimagesink,
2875 "video width/height: %dx%d, calculated display ratio: %d/%d",
2876 video_width, video_height, num, den);
2878 /* now find a width x height that respects this display ratio.
2879 * prefer those that have one of w/h the same as the incoming video
2880 * using wd / hd = num / den */
2882 /* start with same height, because of interlaced video */
2883 /* check hd / den is an integer scale factor, and scale wd with the PAR */
2884 if (video_height % den == 0) {
2885 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
2886 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
2887 gst_util_uint64_scale_int (video_height, num, den);
2888 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
2889 } else if (video_width % num == 0) {
2890 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
2891 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
2892 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
2893 gst_util_uint64_scale_int (video_width, den, num);
2895 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
2896 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
2897 gst_util_uint64_scale_int (video_height, num, den);
2898 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
2900 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
2901 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
2903 /* Notify application to set xwindow id now */
2904 g_mutex_lock (xvimagesink->flow_lock);
2905 if (!xvimagesink->xwindow) {
2906 g_mutex_unlock (xvimagesink->flow_lock);
2907 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
2909 g_mutex_unlock (xvimagesink->flow_lock);
2912 /* Creating our window and our image with the display size in pixels */
2913 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
2914 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
2915 goto no_display_size;
2917 g_mutex_lock (xvimagesink->flow_lock);
2918 if (!xvimagesink->xwindow) {
2919 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
2920 GST_VIDEO_SINK_WIDTH (xvimagesink),
2921 GST_VIDEO_SINK_HEIGHT (xvimagesink));
2924 /* After a resize, we want to redraw the borders in case the new frame size
2925 * doesn't cover the same area */
2926 xvimagesink->redraw_border = TRUE;
2928 /* We renew our xvimage only if size or format changed;
2929 * the xvimage is the same size as the video pixel size */
2930 if ((xvimagesink->xvimage) &&
2931 ((im_format != xvimagesink->xvimage->im_format) ||
2932 (video_width != xvimagesink->xvimage->width) ||
2933 (video_height != xvimagesink->xvimage->height))) {
2934 GST_DEBUG_OBJECT (xvimagesink,
2935 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
2936 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
2937 GST_FOURCC_ARGS (im_format));
2938 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
2939 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
2940 xvimagesink->xvimage = NULL;
2943 g_mutex_unlock (xvimagesink->flow_lock);
2950 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
2955 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
2956 "height or framerate from intersected caps");
2961 GST_DEBUG_OBJECT (xvimagesink,
2962 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
2967 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
2968 ("Error calculating the output display ratio of the video."));
2973 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
2974 ("Error calculating the output display ratio of the video."));
2979 static GstStateChangeReturn
2980 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
2982 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2983 GstXvImageSink *xvimagesink;
2984 GstXContext *xcontext = NULL;
2985 #ifdef GST_EXT_XV_ENHANCEMENT
2986 Atom atom_preemption = None;
2987 #endif /* GST_EXT_XV_ENHANCEMENT */
2989 xvimagesink = GST_XVIMAGESINK (element);
2991 switch (transition) {
2992 case GST_STATE_CHANGE_NULL_TO_READY:
2993 /* Initializing the XContext */
2994 if (xvimagesink->xcontext == NULL) {
2995 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
2996 if (xcontext == NULL)
2997 return GST_STATE_CHANGE_FAILURE;
2998 GST_OBJECT_LOCK (xvimagesink);
3000 xvimagesink->xcontext = xcontext;
3001 GST_OBJECT_UNLOCK (xvimagesink);
3004 /* update object's par with calculated one if not set yet */
3005 if (!xvimagesink->par) {
3006 xvimagesink->par = g_new0 (GValue, 1);
3007 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
3008 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
3010 /* call XSynchronize with the current value of synchronous */
3011 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
3012 xvimagesink->synchronous ? "TRUE" : "FALSE");
3013 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
3014 gst_xvimagesink_update_colorbalance (xvimagesink);
3015 gst_xvimagesink_manage_event_thread (xvimagesink);
3017 case GST_STATE_CHANGE_READY_TO_PAUSED:
3018 g_mutex_lock (xvimagesink->pool_lock);
3019 xvimagesink->pool_invalid = FALSE;
3020 g_mutex_unlock (xvimagesink->pool_lock);
3022 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3023 #ifdef GST_EXT_XV_ENHANCEMENT
3024 g_mutex_lock (xvimagesink->x_lock);
3025 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
3026 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
3027 if (atom_preemption != None) {
3028 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
3029 xvimagesink->xcontext->xv_port_id,
3030 atom_preemption, 1 ) != Success) {
3031 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
3033 XSync (xvimagesink->xcontext->disp, FALSE);
3035 g_mutex_unlock (xvimagesink->x_lock);
3036 #endif /* GST_EXT_XV_ENHANCEMENT */
3038 case GST_STATE_CHANGE_PAUSED_TO_READY:
3039 g_mutex_lock (xvimagesink->pool_lock);
3040 xvimagesink->pool_invalid = TRUE;
3041 g_mutex_unlock (xvimagesink->pool_lock);
3047 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3049 switch (transition) {
3050 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3051 #ifdef GST_EXT_XV_ENHANCEMENT
3052 xvimagesink->rotate_changed = TRUE;
3053 g_mutex_lock (xvimagesink->x_lock);
3054 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
3055 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
3056 if (atom_preemption != None) {
3057 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
3058 xvimagesink->xcontext->xv_port_id,
3059 atom_preemption, 0 ) != Success) {
3060 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
3062 XSync (xvimagesink->xcontext->disp, FALSE);
3064 g_mutex_unlock (xvimagesink->x_lock);
3065 #endif /* GST_EXT_XV_ENHANCEMENT */
3067 case GST_STATE_CHANGE_PAUSED_TO_READY:
3068 xvimagesink->fps_n = 0;
3069 xvimagesink->fps_d = 1;
3070 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
3071 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
3073 case GST_STATE_CHANGE_READY_TO_NULL:
3074 gst_xvimagesink_reset (xvimagesink);
3084 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
3085 GstClockTime * start, GstClockTime * end)
3087 GstXvImageSink *xvimagesink;
3089 xvimagesink = GST_XVIMAGESINK (bsink);
3091 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
3092 *start = GST_BUFFER_TIMESTAMP (buf);
3093 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
3094 *end = *start + GST_BUFFER_DURATION (buf);
3096 if (xvimagesink->fps_n > 0) {
3098 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
3099 xvimagesink->fps_n);
3105 static GstFlowReturn
3106 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
3108 GstXvImageSink *xvimagesink;
3110 #ifdef GST_EXT_XV_ENHANCEMENT
3111 XV_PUTIMAGE_DATA_PTR img_data = NULL;
3112 SCMN_IMGB *scmn_imgb = NULL;
3114 #endif /* GST_EXT_XV_ENHANCEMENT */
3116 xvimagesink = GST_XVIMAGESINK (vsink);
3118 #ifdef GST_EXT_XV_ENHANCEMENT
3119 if (xvimagesink->stop_video) {
3120 GST_INFO( "Stop video is TRUE. so skip show frame..." );
3123 #endif /* GST_EXT_XV_ENHANCEMENT */
3125 /* If this buffer has been allocated using our buffer management we simply
3126 put the ximage which is in the PRIVATE pointer */
3127 if (GST_IS_XVIMAGE_BUFFER (buf)) {
3128 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
3129 if (!gst_xvimagesink_xvimage_put (xvimagesink,
3130 GST_XVIMAGE_BUFFER_CAST (buf)))
3133 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
3134 "slow copy into bufferpool buffer %p", buf);
3135 /* Else we have to copy the data into our private image, */
3136 /* if we have one... */
3137 if (!xvimagesink->xvimage) {
3138 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
3140 #ifdef GST_EXT_XV_ENHANCEMENT
3141 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
3143 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
3144 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
3145 case GST_MAKE_FOURCC('S', '4', '2', '0'):
3146 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
3147 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
3148 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
3149 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
3150 if(scmn_imgb == NULL) {
3151 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
3155 /* skip buffer if aligned size is smaller than size of caps */
3156 if (scmn_imgb->s[0] < xvimagesink->video_width ||
3157 scmn_imgb->e[0] < xvimagesink->video_height) {
3158 GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
3159 xvimagesink->video_width, xvimagesink->video_height,
3160 scmn_imgb->s[0], scmn_imgb->e[0]);
3164 xvimagesink->aligned_width = scmn_imgb->s[0];
3165 xvimagesink->aligned_height = scmn_imgb->e[0];
3166 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
3167 xvimagesink->aligned_width, xvimagesink->aligned_height);
3170 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
3173 #endif /* GST_EXT_XV_ENHANCEMENT */
3175 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
3176 GST_BUFFER_CAPS (buf));
3178 if (!xvimagesink->xvimage)
3179 /* The create method should have posted an informative error */
3182 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
3183 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
3184 ("Failed to create output image buffer of %dx%d pixels",
3185 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
3186 ("XServer allocated buffer size did not match input buffer"));
3188 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
3189 xvimagesink->xvimage = NULL;
3194 #ifdef GST_EXT_XV_ENHANCEMENT
3195 switch (xvimagesink->xvimage->im_format) {
3196 /* Cases for specified formats of Samsung extension */
3197 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
3198 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
3199 case GST_MAKE_FOURCC('S', '4', '2', '0'):
3200 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
3201 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
3202 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
3203 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
3205 GST_DEBUG("Samsung extension display format activated. fourcc:%d,display mode:%d,Rotate angle:%d",
3206 xvimagesink->xvimage->im_format, xvimagesink->display_mode, xvimagesink->rotate_angle);
3208 if (xvimagesink->xvimage->xvimage->data) {
3209 img_data = (XV_PUTIMAGE_DATA_PTR) xvimagesink->xvimage->xvimage->data;
3210 XV_PUTIMAGE_INIT_DATA(img_data);
3212 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
3213 if (scmn_imgb == NULL) {
3214 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
3218 img_data->YPhyAddr = (unsigned int)scmn_imgb->p[0];
3219 img_data->CbPhyAddr = (unsigned int)scmn_imgb->p[1];
3220 img_data->CrPhyAddr = (unsigned int)scmn_imgb->p[2];
3222 GST_LOG_OBJECT(xvimagesink, "Ypaddr[%p],CbPaddr[%p],CrPaddr[%p]",
3223 img_data->YPhyAddr, img_data->CbPhyAddr, img_data->CrPhyAddr );
3225 img_data->RotAngle = xvimagesink->rotate_angle;
3226 img_data->VideoMode = xvimagesink->display_mode;
3228 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
3235 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
3236 memcpy (xvimagesink->xvimage->xvimage->data,
3237 GST_BUFFER_DATA (buf),
3238 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
3242 #else /* GST_EXT_XV_ENHANCEMENT */
3243 memcpy (xvimagesink->xvimage->xvimage->data,
3244 GST_BUFFER_DATA (buf),
3245 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
3246 #endif /* GST_EXT_XV_ENHANCEMENT */
3248 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
3257 /* No image available. That's very bad ! */
3258 GST_WARNING_OBJECT (xvimagesink, "could not create image");
3259 return GST_FLOW_ERROR;
3263 /* No Window available to put our image into */
3264 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
3265 return GST_FLOW_ERROR;
3270 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
3272 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
3274 switch (GST_EVENT_TYPE (event)) {
3275 case GST_EVENT_TAG:{
3277 gchar *title = NULL;
3279 gst_event_parse_tag (event, &l);
3280 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
3283 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
3284 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
3294 if (GST_BASE_SINK_CLASS (parent_class)->event)
3295 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
3300 /* Buffer management */
3303 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
3306 GstCaps *intersection;
3310 gint par_n = 1, par_d = 1;
3314 new_caps = gst_caps_copy (caps);
3316 s = gst_caps_get_structure (new_caps, 0);
3318 gst_structure_get_int (s, "width", &width);
3319 gst_structure_get_int (s, "height", &height);
3320 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
3322 gst_structure_remove_field (s, "width");
3323 gst_structure_remove_field (s, "height");
3324 gst_structure_remove_field (s, "pixel-aspect-ratio");
3326 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3327 gst_caps_unref (new_caps);
3329 if (gst_caps_is_empty (intersection))
3330 return intersection;
3332 s = gst_caps_get_structure (intersection, 0);
3334 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
3336 /* xvimagesink supports all PARs */
3338 gst_structure_fixate_field_nearest_int (s, "width", width);
3339 gst_structure_fixate_field_nearest_int (s, "height", height);
3340 gst_structure_get_int (s, "width", &w);
3341 gst_structure_get_int (s, "height", &h);
3343 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
3344 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
3347 return intersection;
3350 static GstFlowReturn
3351 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
3352 GstCaps * caps, GstBuffer ** buf)
3354 GstFlowReturn ret = GST_FLOW_OK;
3355 GstXvImageSink *xvimagesink;
3356 GstXvImageBuffer *xvimage = NULL;
3357 GstCaps *intersection = NULL;
3358 GstStructure *structure = NULL;
3359 gint width, height, image_format;
3361 xvimagesink = GST_XVIMAGESINK (bsink);
3363 if (G_UNLIKELY (!caps))
3366 g_mutex_lock (xvimagesink->pool_lock);
3367 if (G_UNLIKELY (xvimagesink->pool_invalid))
3370 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
3371 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
3372 GST_LOG_OBJECT (xvimagesink,
3373 "buffer alloc for same last_caps, reusing caps");
3374 intersection = gst_caps_ref (caps);
3375 image_format = xvimagesink->xcontext->last_format;
3376 width = xvimagesink->xcontext->last_width;
3377 height = xvimagesink->xcontext->last_height;
3379 goto reuse_last_caps;
3382 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
3383 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
3384 caps, xvimagesink->xcontext->caps);
3386 /* Check the caps against our xcontext */
3387 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
3389 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
3390 GST_PTR_FORMAT, intersection);
3392 if (gst_caps_is_empty (intersection)) {
3395 gst_caps_unref (intersection);
3397 /* So we don't support this kind of buffer, let's define one we'd like */
3398 new_caps = gst_caps_copy (caps);
3400 structure = gst_caps_get_structure (new_caps, 0);
3401 if (!gst_structure_has_field (structure, "width") ||
3402 !gst_structure_has_field (structure, "height")) {
3403 gst_caps_unref (new_caps);
3407 /* Try different dimensions */
3409 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3411 if (gst_caps_is_empty (intersection)) {
3412 /* Try with different YUV formats first */
3413 gst_structure_set_name (structure, "video/x-raw-yuv");
3415 /* Remove format specific fields */
3416 gst_structure_remove_field (structure, "format");
3417 gst_structure_remove_field (structure, "endianness");
3418 gst_structure_remove_field (structure, "depth");
3419 gst_structure_remove_field (structure, "bpp");
3420 gst_structure_remove_field (structure, "red_mask");
3421 gst_structure_remove_field (structure, "green_mask");
3422 gst_structure_remove_field (structure, "blue_mask");
3423 gst_structure_remove_field (structure, "alpha_mask");
3425 /* Reuse intersection with Xcontext */
3426 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3429 if (gst_caps_is_empty (intersection)) {
3430 /* Try with different dimensions and YUV formats */
3432 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3435 if (gst_caps_is_empty (intersection)) {
3436 /* Now try with RGB */
3437 gst_structure_set_name (structure, "video/x-raw-rgb");
3438 /* And interset again */
3439 gst_caps_unref (intersection);
3440 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3443 if (gst_caps_is_empty (intersection)) {
3444 /* Try with different dimensions and RGB formats */
3446 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3449 /* Clean this copy */
3450 gst_caps_unref (new_caps);
3452 if (gst_caps_is_empty (intersection))
3456 /* Ensure the returned caps are fixed */
3457 gst_caps_truncate (intersection);
3459 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
3460 GST_PTR_FORMAT, intersection);
3461 if (gst_caps_is_equal (intersection, caps)) {
3462 /* Things work better if we return a buffer with the same caps ptr
3463 * as was asked for when we can */
3464 gst_caps_replace (&intersection, caps);
3467 /* Get image format from caps */
3468 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
3471 /* Get geometry from caps */
3472 structure = gst_caps_get_structure (intersection, 0);
3473 if (!gst_structure_get_int (structure, "width", &width) ||
3474 !gst_structure_get_int (structure, "height", &height) ||
3478 /* Store our caps and format as the last_caps to avoid expensive
3479 * caps intersection next time */
3480 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
3481 xvimagesink->xcontext->last_format = image_format;
3482 xvimagesink->xcontext->last_width = width;
3483 xvimagesink->xcontext->last_height = height;
3487 /* Walking through the pool cleaning unusable images and searching for a
3489 while (xvimagesink->image_pool) {
3490 xvimage = xvimagesink->image_pool->data;
3493 /* Removing from the pool */
3494 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
3495 xvimagesink->image_pool);
3497 /* We check for geometry or image format changes */
3498 if ((xvimage->width != width) ||
3499 (xvimage->height != height) || (xvimage->im_format != image_format)) {
3500 /* This image is unusable. Destroying... */
3501 gst_xvimage_buffer_free (xvimage);
3504 /* We found a suitable image */
3505 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
3512 /* We found no suitable image in the pool. Creating... */
3513 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
3514 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
3516 g_mutex_unlock (xvimagesink->pool_lock);
3519 /* Make sure the buffer is cleared of any previously used flags */
3520 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
3521 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
3524 *buf = GST_BUFFER_CAST (xvimage);
3528 gst_caps_unref (intersection);
3536 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
3537 ret = GST_FLOW_WRONG_STATE;
3538 g_mutex_unlock (xvimagesink->pool_lock);
3543 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
3544 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
3545 " are completely incompatible with those caps", caps,
3546 xvimagesink->xcontext->caps);
3547 ret = GST_FLOW_NOT_NEGOTIATED;
3548 g_mutex_unlock (xvimagesink->pool_lock);
3553 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
3554 GST_PTR_FORMAT, intersection);
3555 ret = GST_FLOW_NOT_NEGOTIATED;
3556 g_mutex_unlock (xvimagesink->pool_lock);
3561 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
3568 /* Interfaces stuff */
3571 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
3573 if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
3574 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
3581 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
3583 klass->supported = gst_xvimagesink_interface_supported;
3587 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
3588 GstStructure * structure)
3590 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
3593 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
3595 GstVideoRectangle src, dst, result;
3596 gdouble x, y, xscale = 1.0, yscale = 1.0;
3598 event = gst_event_new_navigation (structure);
3600 /* We take the flow_lock while we look at the window */
3601 g_mutex_lock (xvimagesink->flow_lock);
3603 if (!xvimagesink->xwindow) {
3604 g_mutex_unlock (xvimagesink->flow_lock);
3608 if (xvimagesink->keep_aspect) {
3609 /* We get the frame position using the calculated geometry from _setcaps
3610 that respect pixel aspect ratios */
3611 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
3612 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
3613 dst.w = xvimagesink->render_rect.w;
3614 dst.h = xvimagesink->render_rect.h;
3616 gst_video_sink_center_rect (src, dst, &result, TRUE);
3617 result.x += xvimagesink->render_rect.x;
3618 result.y += xvimagesink->render_rect.y;
3620 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
3623 g_mutex_unlock (xvimagesink->flow_lock);
3625 /* We calculate scaling using the original video frames geometry to include
3626 pixel aspect ratio scaling. */
3627 xscale = (gdouble) xvimagesink->video_width / result.w;
3628 yscale = (gdouble) xvimagesink->video_height / result.h;
3630 /* Converting pointer coordinates to the non scaled geometry */
3631 if (gst_structure_get_double (structure, "pointer_x", &x)) {
3632 x = MIN (x, result.x + result.w);
3633 x = MAX (x - result.x, 0);
3634 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
3635 (gdouble) x * xscale, NULL);
3637 if (gst_structure_get_double (structure, "pointer_y", &y)) {
3638 y = MIN (y, result.y + result.h);
3639 y = MAX (y - result.y, 0);
3640 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
3641 (gdouble) y * yscale, NULL);
3644 gst_pad_send_event (peer, event);
3645 gst_object_unref (peer);
3650 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
3652 iface->send_event = gst_xvimagesink_navigation_send_event;
3656 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
3658 XID xwindow_id = id;
3659 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3660 GstXWindow *xwindow = NULL;
3662 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3664 g_mutex_lock (xvimagesink->flow_lock);
3666 #ifdef GST_EXT_XV_ENHANCEMENT
3667 GST_INFO_OBJECT( xvimagesink, "ENTER, id : %d", xwindow_id );
3668 #endif /* GST_EXT_XV_ENHANCEMENT */
3670 /* If we already use that window return */
3671 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
3672 g_mutex_unlock (xvimagesink->flow_lock);
3676 /* If the element has not initialized the X11 context try to do so */
3677 if (!xvimagesink->xcontext &&
3678 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
3679 g_mutex_unlock (xvimagesink->flow_lock);
3680 /* we have thrown a GST_ELEMENT_ERROR now */
3684 gst_xvimagesink_update_colorbalance (xvimagesink);
3686 /* Clear image pool as the images are unusable anyway */
3687 gst_xvimagesink_imagepool_clear (xvimagesink);
3689 /* Clear the xvimage */
3690 if (xvimagesink->xvimage) {
3691 gst_xvimage_buffer_free (xvimagesink->xvimage);
3692 xvimagesink->xvimage = NULL;
3695 /* If a window is there already we destroy it */
3696 if (xvimagesink->xwindow) {
3697 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
3698 xvimagesink->xwindow = NULL;
3701 /* If the xid is 0 we go back to an internal window */
3702 if (xwindow_id == 0) {
3703 /* If no width/height caps nego did not happen window will be created
3704 during caps nego then */
3705 #ifdef GST_EXT_XV_ENHANCEMENT
3706 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
3707 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
3708 #endif /* GST_EXT_XV_ENHANCEMENT */
3709 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
3710 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
3712 gst_xvimagesink_xwindow_new (xvimagesink,
3713 GST_VIDEO_SINK_WIDTH (xvimagesink),
3714 GST_VIDEO_SINK_HEIGHT (xvimagesink));
3717 XWindowAttributes attr;
3719 xwindow = g_new0 (GstXWindow, 1);
3720 xwindow->win = xwindow_id;
3722 /* Set the event we want to receive and create a GC */
3723 g_mutex_lock (xvimagesink->x_lock);
3725 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
3727 xwindow->width = attr.width;
3728 xwindow->height = attr.height;
3729 xwindow->internal = FALSE;
3730 if (!xvimagesink->have_render_rect) {
3731 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3732 xvimagesink->render_rect.w = attr.width;
3733 xvimagesink->render_rect.h = attr.height;
3735 if (xvimagesink->handle_events) {
3736 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
3737 StructureNotifyMask | PointerMotionMask | KeyPressMask |
3741 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
3742 xwindow->win, 0, NULL);
3743 g_mutex_unlock (xvimagesink->x_lock);
3747 xvimagesink->xwindow = xwindow;
3749 g_mutex_unlock (xvimagesink->flow_lock);
3753 gst_xvimagesink_expose (GstXOverlay * overlay)
3755 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3757 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
3758 #ifdef GST_EXT_XV_ENHANCEMENT
3759 GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it");
3760 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
3761 #else /* GST_EXT_XV_ENHANCEMENT */
3762 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
3763 #endif /* GST_EXT_XV_ENHANCEMENT */
3767 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
3768 gboolean handle_events)
3770 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3772 xvimagesink->handle_events = handle_events;
3774 g_mutex_lock (xvimagesink->flow_lock);
3776 if (G_UNLIKELY (!xvimagesink->xwindow)) {
3777 g_mutex_unlock (xvimagesink->flow_lock);
3781 g_mutex_lock (xvimagesink->x_lock);
3783 if (handle_events) {
3784 if (xvimagesink->xwindow->internal) {
3785 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
3786 ExposureMask | StructureNotifyMask | PointerMotionMask |
3787 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
3789 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
3790 ExposureMask | StructureNotifyMask | PointerMotionMask |
3791 KeyPressMask | KeyReleaseMask);
3794 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
3797 g_mutex_unlock (xvimagesink->x_lock);
3799 g_mutex_unlock (xvimagesink->flow_lock);
3803 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
3804 gint width, gint height)
3806 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3808 /* FIXME: how about some locking? */
3809 if (width >= 0 && height >= 0) {
3810 xvimagesink->render_rect.x = x;
3811 xvimagesink->render_rect.y = y;
3812 xvimagesink->render_rect.w = width;
3813 xvimagesink->render_rect.h = height;
3814 xvimagesink->have_render_rect = TRUE;
3816 xvimagesink->render_rect.x = 0;
3817 xvimagesink->render_rect.y = 0;
3818 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
3819 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
3820 xvimagesink->have_render_rect = FALSE;
3825 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
3827 iface->set_window_handle = gst_xvimagesink_set_window_handle;
3828 iface->expose = gst_xvimagesink_expose;
3829 iface->handle_events = gst_xvimagesink_set_event_handling;
3830 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
3833 static const GList *
3834 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
3836 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3838 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3840 if (xvimagesink->xcontext)
3841 return xvimagesink->xcontext->channels_list;
3847 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
3848 GstColorBalanceChannel * channel, gint value)
3850 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3852 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3853 g_return_if_fail (channel->label != NULL);
3855 xvimagesink->cb_changed = TRUE;
3857 /* Normalize val to [-1000, 1000] */
3858 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
3859 (double) (channel->max_value - channel->min_value));
3861 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3862 xvimagesink->hue = value;
3863 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3864 xvimagesink->saturation = value;
3865 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3866 xvimagesink->contrast = value;
3867 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3868 xvimagesink->brightness = value;
3870 g_warning ("got an unknown channel %s", channel->label);
3874 gst_xvimagesink_update_colorbalance (xvimagesink);
3878 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
3879 GstColorBalanceChannel * channel)
3881 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3884 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
3885 g_return_val_if_fail (channel->label != NULL, 0);
3887 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3888 value = xvimagesink->hue;
3889 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3890 value = xvimagesink->saturation;
3891 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3892 value = xvimagesink->contrast;
3893 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3894 value = xvimagesink->brightness;
3896 g_warning ("got an unknown channel %s", channel->label);
3899 /* Normalize val to [channel->min_value, channel->max_value] */
3900 value = channel->min_value + (channel->max_value - channel->min_value) *
3901 (value + 1000) / 2000;
3907 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
3909 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
3910 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
3911 iface->set_value = gst_xvimagesink_colorbalance_set_value;
3912 iface->get_value = gst_xvimagesink_colorbalance_get_value;
3915 static const GList *
3916 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
3918 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
3919 static GList *list = NULL;
3922 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
3924 g_list_append (list, g_object_class_find_property (klass,
3925 "autopaint-colorkey"));
3927 g_list_append (list, g_object_class_find_property (klass,
3930 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
3937 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
3938 guint prop_id, const GParamSpec * pspec)
3940 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3944 case PROP_AUTOPAINT_COLORKEY:
3945 case PROP_DOUBLE_BUFFER:
3947 GST_DEBUG_OBJECT (xvimagesink,
3948 "probing device list and get capabilities");
3949 if (!xvimagesink->xcontext) {
3950 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
3951 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
3955 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3961 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
3962 guint prop_id, const GParamSpec * pspec)
3964 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3965 gboolean ret = FALSE;
3969 case PROP_AUTOPAINT_COLORKEY:
3970 case PROP_DOUBLE_BUFFER:
3972 if (xvimagesink->xcontext != NULL) {
3979 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3986 static GValueArray *
3987 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
3988 guint prop_id, const GParamSpec * pspec)
3990 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3991 GValueArray *array = NULL;
3993 if (G_UNLIKELY (!xvimagesink->xcontext)) {
3994 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
4003 GValue value = { 0 };
4005 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
4006 g_value_init (&value, G_TYPE_STRING);
4008 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
4009 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
4011 g_value_set_string (&value, adaptor_id_s);
4012 g_value_array_append (array, &value);
4013 g_free (adaptor_id_s);
4015 g_value_unset (&value);
4018 case PROP_AUTOPAINT_COLORKEY:
4019 if (xvimagesink->have_autopaint_colorkey) {
4020 GValue value = { 0 };
4022 array = g_value_array_new (2);
4023 g_value_init (&value, G_TYPE_BOOLEAN);
4024 g_value_set_boolean (&value, FALSE);
4025 g_value_array_append (array, &value);
4026 g_value_set_boolean (&value, TRUE);
4027 g_value_array_append (array, &value);
4028 g_value_unset (&value);
4031 case PROP_DOUBLE_BUFFER:
4032 if (xvimagesink->have_double_buffer) {
4033 GValue value = { 0 };
4035 array = g_value_array_new (2);
4036 g_value_init (&value, G_TYPE_BOOLEAN);
4037 g_value_set_boolean (&value, FALSE);
4038 g_value_array_append (array, &value);
4039 g_value_set_boolean (&value, TRUE);
4040 g_value_array_append (array, &value);
4041 g_value_unset (&value);
4045 if (xvimagesink->have_colorkey) {
4046 GValue value = { 0 };
4048 array = g_value_array_new (1);
4049 g_value_init (&value, GST_TYPE_INT_RANGE);
4050 gst_value_set_int_range (&value, 0, 0xffffff);
4051 g_value_array_append (array, &value);
4052 g_value_unset (&value);
4056 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
4065 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
4068 iface->get_properties = gst_xvimagesink_probe_get_properties;
4069 iface->probe_property = gst_xvimagesink_probe_probe_property;
4070 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
4071 iface->get_values = gst_xvimagesink_probe_get_values;
4074 /* =========================================== */
4076 /* Init & Class init */
4078 /* =========================================== */
4081 gst_xvimagesink_set_property (GObject * object, guint prop_id,
4082 const GValue * value, GParamSpec * pspec)
4084 GstXvImageSink *xvimagesink;
4086 g_return_if_fail (GST_IS_XVIMAGESINK (object));
4088 xvimagesink = GST_XVIMAGESINK (object);
4092 xvimagesink->hue = g_value_get_int (value);
4093 xvimagesink->cb_changed = TRUE;
4094 gst_xvimagesink_update_colorbalance (xvimagesink);
4097 xvimagesink->contrast = g_value_get_int (value);
4098 xvimagesink->cb_changed = TRUE;
4099 gst_xvimagesink_update_colorbalance (xvimagesink);
4101 case PROP_BRIGHTNESS:
4102 xvimagesink->brightness = g_value_get_int (value);
4103 xvimagesink->cb_changed = TRUE;
4104 gst_xvimagesink_update_colorbalance (xvimagesink);
4106 case PROP_SATURATION:
4107 xvimagesink->saturation = g_value_get_int (value);
4108 xvimagesink->cb_changed = TRUE;
4109 gst_xvimagesink_update_colorbalance (xvimagesink);
4112 xvimagesink->display_name = g_strdup (g_value_get_string (value));
4114 case PROP_SYNCHRONOUS:
4115 xvimagesink->synchronous = g_value_get_boolean (value);
4116 if (xvimagesink->xcontext) {
4117 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4118 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4119 xvimagesink->synchronous ? "TRUE" : "FALSE");
4122 case PROP_PIXEL_ASPECT_RATIO:
4123 g_free (xvimagesink->par);
4124 xvimagesink->par = g_new0 (GValue, 1);
4125 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
4126 if (!g_value_transform (value, xvimagesink->par)) {
4127 g_warning ("Could not transform string to aspect ratio");
4128 gst_value_set_fraction (xvimagesink->par, 1, 1);
4130 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
4131 gst_value_get_fraction_numerator (xvimagesink->par),
4132 gst_value_get_fraction_denominator (xvimagesink->par));
4134 case PROP_FORCE_ASPECT_RATIO:
4135 xvimagesink->keep_aspect = g_value_get_boolean (value);
4137 case PROP_HANDLE_EVENTS:
4138 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
4139 g_value_get_boolean (value));
4140 gst_xvimagesink_manage_event_thread (xvimagesink);
4143 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
4145 case PROP_HANDLE_EXPOSE:
4146 xvimagesink->handle_expose = g_value_get_boolean (value);
4147 gst_xvimagesink_manage_event_thread (xvimagesink);
4149 case PROP_DOUBLE_BUFFER:
4150 xvimagesink->double_buffer = g_value_get_boolean (value);
4152 case PROP_AUTOPAINT_COLORKEY:
4153 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
4156 xvimagesink->colorkey = g_value_get_int (value);
4158 case PROP_DRAW_BORDERS:
4159 xvimagesink->draw_borders = g_value_get_boolean (value);
4161 #ifdef GST_EXT_XV_ENHANCEMENT
4162 case PROP_DISPLAY_MODE:
4164 int set_mode = g_value_get_enum (value);
4166 g_mutex_lock(xvimagesink->flow_lock);
4167 g_mutex_lock(xvimagesink->x_lock);
4169 if (xvimagesink->display_mode != set_mode) {
4170 if (xvimagesink->xcontext) {
4171 /* set display mode */
4172 if (set_display_mode(xvimagesink->xcontext, set_mode)) {
4173 xvimagesink->display_mode = set_mode;
4175 GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
4178 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
4179 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
4180 xvimagesink->display_mode = set_mode;
4183 GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
4186 g_mutex_unlock(xvimagesink->x_lock);
4187 g_mutex_unlock(xvimagesink->flow_lock);
4190 case PROP_DISPLAY_GEOMETRY_METHOD:
4191 xvimagesink->display_geometry_method = g_value_get_enum (value);
4192 GST_LOG("Overlay geometry changed. update it");
4193 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
4195 case PROP_ROTATE_ANGLE:
4196 xvimagesink->rotate_angle = g_value_get_enum (value);
4197 xvimagesink->rotate_changed = TRUE;
4200 g_mutex_lock( xvimagesink->flow_lock );
4201 g_mutex_lock( xvimagesink->x_lock );
4203 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
4204 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
4205 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
4206 if (atom_stream != None) {
4207 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4208 xvimagesink->xcontext->xv_port_id,
4209 atom_stream, 0 ) != Success) {
4210 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
4213 XSync( xvimagesink->xcontext->disp, FALSE );
4215 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
4216 g_mutex_unlock( xvimagesink->x_lock );
4217 g_mutex_unlock( xvimagesink->flow_lock );
4218 GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." );
4219 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
4220 g_mutex_lock( xvimagesink->flow_lock );
4221 g_mutex_lock( xvimagesink->x_lock );
4224 xvimagesink->visible = g_value_get_boolean (value);
4226 g_mutex_unlock( xvimagesink->x_lock );
4227 g_mutex_unlock( xvimagesink->flow_lock );
4230 xvimagesink->zoom = g_value_get_int (value);
4232 case PROP_DST_ROI_X:
4233 xvimagesink->dst_roi.x = g_value_get_int (value);
4235 case PROP_DST_ROI_Y:
4236 xvimagesink->dst_roi.y = g_value_get_int (value);
4238 case PROP_DST_ROI_W:
4239 xvimagesink->dst_roi.w = g_value_get_int (value);
4241 case PROP_DST_ROI_H:
4242 xvimagesink->dst_roi.h = g_value_get_int (value);
4244 case PROP_STOP_VIDEO:
4245 xvimagesink->stop_video = g_value_get_int (value);
4246 g_mutex_lock( xvimagesink->flow_lock );
4248 if( xvimagesink->stop_video )
4250 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
4251 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
4254 g_mutex_unlock( xvimagesink->flow_lock );
4256 #endif /* GST_EXT_XV_ENHANCEMENT */
4258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4264 gst_xvimagesink_get_property (GObject * object, guint prop_id,
4265 GValue * value, GParamSpec * pspec)
4267 GstXvImageSink *xvimagesink;
4269 g_return_if_fail (GST_IS_XVIMAGESINK (object));
4271 xvimagesink = GST_XVIMAGESINK (object);
4275 g_value_set_int (value, xvimagesink->hue);
4278 g_value_set_int (value, xvimagesink->contrast);
4280 case PROP_BRIGHTNESS:
4281 g_value_set_int (value, xvimagesink->brightness);
4283 case PROP_SATURATION:
4284 g_value_set_int (value, xvimagesink->saturation);
4287 g_value_set_string (value, xvimagesink->display_name);
4289 case PROP_SYNCHRONOUS:
4290 g_value_set_boolean (value, xvimagesink->synchronous);
4292 case PROP_PIXEL_ASPECT_RATIO:
4293 if (xvimagesink->par)
4294 g_value_transform (xvimagesink->par, value);
4296 case PROP_FORCE_ASPECT_RATIO:
4297 g_value_set_boolean (value, xvimagesink->keep_aspect);
4299 case PROP_HANDLE_EVENTS:
4300 g_value_set_boolean (value, xvimagesink->handle_events);
4304 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
4306 g_value_set_string (value, adaptor_no_s);
4307 g_free (adaptor_no_s);
4310 case PROP_DEVICE_NAME:
4311 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
4312 g_value_set_string (value,
4313 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
4315 g_value_set_string (value, NULL);
4318 case PROP_HANDLE_EXPOSE:
4319 g_value_set_boolean (value, xvimagesink->handle_expose);
4321 case PROP_DOUBLE_BUFFER:
4322 g_value_set_boolean (value, xvimagesink->double_buffer);
4324 case PROP_AUTOPAINT_COLORKEY:
4325 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
4328 g_value_set_int (value, xvimagesink->colorkey);
4330 case PROP_DRAW_BORDERS:
4331 g_value_set_boolean (value, xvimagesink->draw_borders);
4333 case PROP_WINDOW_WIDTH:
4334 if (xvimagesink->xwindow)
4335 g_value_set_uint64 (value, xvimagesink->xwindow->width);
4337 g_value_set_uint64 (value, 0);
4339 case PROP_WINDOW_HEIGHT:
4340 if (xvimagesink->xwindow)
4341 g_value_set_uint64 (value, xvimagesink->xwindow->height);
4343 g_value_set_uint64 (value, 0);
4345 #ifdef GST_EXT_XV_ENHANCEMENT
4346 case PROP_DISPLAY_MODE:
4347 g_value_set_enum (value, xvimagesink->display_mode);
4349 case PROP_DISPLAY_GEOMETRY_METHOD:
4350 g_value_set_enum (value, xvimagesink->display_geometry_method);
4352 case PROP_ROTATE_ANGLE:
4353 g_value_set_enum (value, xvimagesink->rotate_angle);
4356 g_value_set_boolean (value, xvimagesink->visible);
4359 g_value_set_int (value, xvimagesink->zoom);
4361 case PROP_DST_ROI_X:
4362 g_value_set_int (value, xvimagesink->dst_roi.x);
4364 case PROP_DST_ROI_Y:
4365 g_value_set_int (value, xvimagesink->dst_roi.y);
4367 case PROP_DST_ROI_W:
4368 g_value_set_int (value, xvimagesink->dst_roi.w);
4370 case PROP_DST_ROI_H:
4371 g_value_set_int (value, xvimagesink->dst_roi.h);
4373 case PROP_STOP_VIDEO:
4374 g_value_set_int (value, xvimagesink->stop_video);
4376 #endif /* GST_EXT_XV_ENHANCEMENT */
4378 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4384 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
4388 GST_OBJECT_LOCK (xvimagesink);
4389 xvimagesink->running = FALSE;
4390 /* grab thread and mark it as NULL */
4391 thread = xvimagesink->event_thread;
4392 xvimagesink->event_thread = NULL;
4393 GST_OBJECT_UNLOCK (xvimagesink);
4395 /* invalidate the pool, current allocations continue, new buffer_alloc fails
4396 * with wrong_state */
4397 g_mutex_lock (xvimagesink->pool_lock);
4398 xvimagesink->pool_invalid = TRUE;
4399 g_mutex_unlock (xvimagesink->pool_lock);
4401 /* Wait for our event thread to finish before we clean up our stuff. */
4403 g_thread_join (thread);
4405 if (xvimagesink->cur_image) {
4406 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
4407 xvimagesink->cur_image = NULL;
4409 if (xvimagesink->xvimage) {
4410 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
4411 xvimagesink->xvimage = NULL;
4414 gst_xvimagesink_imagepool_clear (xvimagesink);
4416 if (xvimagesink->xwindow) {
4417 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
4418 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
4419 xvimagesink->xwindow = NULL;
4422 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
4423 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
4424 xvimagesink->have_render_rect = FALSE;
4426 gst_xvimagesink_xcontext_clear (xvimagesink);
4429 /* Finalize is called only once, dispose can be called multiple times.
4430 * We use mutexes and don't reset stuff to NULL here so let's register
4433 gst_xvimagesink_finalize (GObject * object)
4435 GstXvImageSink *xvimagesink;
4437 xvimagesink = GST_XVIMAGESINK (object);
4439 gst_xvimagesink_reset (xvimagesink);
4441 if (xvimagesink->display_name) {
4442 g_free (xvimagesink->display_name);
4443 xvimagesink->display_name = NULL;
4446 if (xvimagesink->par) {
4447 g_free (xvimagesink->par);
4448 xvimagesink->par = NULL;
4450 if (xvimagesink->x_lock) {
4451 g_mutex_free (xvimagesink->x_lock);
4452 xvimagesink->x_lock = NULL;
4454 if (xvimagesink->flow_lock) {
4455 g_mutex_free (xvimagesink->flow_lock);
4456 xvimagesink->flow_lock = NULL;
4458 if (xvimagesink->pool_lock) {
4459 g_mutex_free (xvimagesink->pool_lock);
4460 xvimagesink->pool_lock = NULL;
4463 g_free (xvimagesink->media_title);
4465 G_OBJECT_CLASS (parent_class)->finalize (object);
4469 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
4470 GstXvImageSinkClass * xvimagesinkclass)
4472 xvimagesink->display_name = NULL;
4473 xvimagesink->adaptor_no = 0;
4474 xvimagesink->xcontext = NULL;
4475 xvimagesink->xwindow = NULL;
4476 xvimagesink->xvimage = NULL;
4477 xvimagesink->cur_image = NULL;
4479 xvimagesink->hue = xvimagesink->saturation = 0;
4480 xvimagesink->contrast = xvimagesink->brightness = 0;
4481 xvimagesink->cb_changed = FALSE;
4483 xvimagesink->fps_n = 0;
4484 xvimagesink->fps_d = 0;
4485 xvimagesink->video_width = 0;
4486 xvimagesink->video_height = 0;
4488 xvimagesink->x_lock = g_mutex_new ();
4489 xvimagesink->flow_lock = g_mutex_new ();
4491 xvimagesink->image_pool = NULL;
4492 xvimagesink->pool_lock = g_mutex_new ();
4494 xvimagesink->synchronous = FALSE;
4495 xvimagesink->double_buffer = TRUE;
4496 xvimagesink->running = FALSE;
4497 xvimagesink->keep_aspect = FALSE;
4498 xvimagesink->handle_events = TRUE;
4499 xvimagesink->par = NULL;
4500 xvimagesink->handle_expose = TRUE;
4501 xvimagesink->autopaint_colorkey = TRUE;
4503 /* on 16bit displays this becomes r,g,b = 1,2,3
4504 * on 24bit displays this becomes r,g,b = 8,8,16
4505 * as a port atom value
4507 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
4508 xvimagesink->draw_borders = TRUE;
4510 #ifdef GST_EXT_XV_ENHANCEMENT
4511 xvimagesink->display_mode = DISPLAY_MODE_DEFAULT;
4512 xvimagesink->rotate_changed = TRUE;
4513 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
4514 xvimagesink->rotate_angle = DEGREE_270;
4515 xvimagesink->visible = TRUE;
4516 xvimagesink->zoom = 1;
4517 xvimagesink->rotation = -1;
4518 xvimagesink->dst_roi.x = 0;
4519 xvimagesink->dst_roi.y = 0;
4520 xvimagesink->dst_roi.w = 0;
4521 xvimagesink->dst_roi.h = 0;
4522 xvimagesink->xim_transparenter = NULL;
4523 xvimagesink->scr_w = 0;
4524 xvimagesink->scr_h = 0;
4525 xvimagesink->aligned_width = 0;
4526 xvimagesink->aligned_height = 0;
4527 xvimagesink->stop_video = FALSE;
4528 xvimagesink->is_hided = FALSE;
4529 #endif /* GST_EXT_XV_ENHANCEMENT */
4533 gst_xvimagesink_base_init (gpointer g_class)
4535 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
4537 gst_element_class_set_details_simple (element_class,
4538 "Video sink", "Sink/Video",
4539 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
4541 gst_element_class_add_static_pad_template (element_class,
4542 &gst_xvimagesink_sink_template_factory);
4546 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
4548 GObjectClass *gobject_class;
4549 GstElementClass *gstelement_class;
4550 GstBaseSinkClass *gstbasesink_class;
4551 GstVideoSinkClass *videosink_class;
4553 gobject_class = (GObjectClass *) klass;
4554 gstelement_class = (GstElementClass *) klass;
4555 gstbasesink_class = (GstBaseSinkClass *) klass;
4556 videosink_class = (GstVideoSinkClass *) klass;
4558 gobject_class->set_property = gst_xvimagesink_set_property;
4559 gobject_class->get_property = gst_xvimagesink_get_property;
4561 g_object_class_install_property (gobject_class, PROP_CONTRAST,
4562 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
4563 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4564 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
4565 g_param_spec_int ("brightness", "Brightness",
4566 "The brightness of the video", -1000, 1000, 0,
4567 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4568 g_object_class_install_property (gobject_class, PROP_HUE,
4569 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
4570 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4571 g_object_class_install_property (gobject_class, PROP_SATURATION,
4572 g_param_spec_int ("saturation", "Saturation",
4573 "The saturation of the video", -1000, 1000, 0,
4574 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4575 g_object_class_install_property (gobject_class, PROP_DISPLAY,
4576 g_param_spec_string ("display", "Display", "X Display name", NULL,
4577 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4578 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
4579 g_param_spec_boolean ("synchronous", "Synchronous",
4580 "When enabled, runs the X display in synchronous mode. "
4581 "(unrelated to A/V sync, used only for debugging)", FALSE,
4582 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4583 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
4584 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
4585 "The pixel aspect ratio of the device", "1/1",
4586 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4587 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
4588 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
4589 "When enabled, scaling will respect original aspect ratio", FALSE,
4590 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4591 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
4592 g_param_spec_boolean ("handle-events", "Handle XEvents",
4593 "When enabled, XEvents will be selected and handled", TRUE,
4594 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4595 g_object_class_install_property (gobject_class, PROP_DEVICE,
4596 g_param_spec_string ("device", "Adaptor number",
4597 "The number of the video adaptor", "0",
4598 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4599 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
4600 g_param_spec_string ("device-name", "Adaptor name",
4601 "The name of the video adaptor", NULL,
4602 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4604 * GstXvImageSink:handle-expose
4606 * When enabled, the current frame will always be drawn in response to X
4611 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
4612 g_param_spec_boolean ("handle-expose", "Handle expose",
4614 "the current frame will always be drawn in response to X Expose "
4615 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4618 * GstXvImageSink:double-buffer
4620 * Whether to double-buffer the output.
4624 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
4625 g_param_spec_boolean ("double-buffer", "Double-buffer",
4626 "Whether to double-buffer the output", TRUE,
4627 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4629 * GstXvImageSink:autopaint-colorkey
4631 * Whether to autofill overlay with colorkey
4635 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
4636 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
4637 "Whether to autofill overlay with colorkey", TRUE,
4638 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4640 * GstXvImageSink:colorkey
4642 * Color to use for the overlay mask.
4646 g_object_class_install_property (gobject_class, PROP_COLORKEY,
4647 g_param_spec_int ("colorkey", "Colorkey",
4648 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
4649 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4652 * GstXvImageSink:draw-borders
4654 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
4655 * unused parts of the video area.
4659 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
4660 g_param_spec_boolean ("draw-borders", "Colorkey",
4661 "Draw black borders to fill unused area in force-aspect-ratio mode",
4662 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4665 * GstXvImageSink:window-width
4667 * Actual width of the video window.
4671 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
4672 g_param_spec_uint64 ("window-width", "window-width",
4673 "Width of the window", 0, G_MAXUINT64, 0,
4674 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4677 * GstXvImageSink:window-height
4679 * Actual height of the video window.
4683 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
4684 g_param_spec_uint64 ("window-height", "window-height",
4685 "Height of the window", 0, G_MAXUINT64, 0,
4686 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4688 #ifdef GST_EXT_XV_ENHANCEMENT
4690 * GstXvImageSink:display-mode
4692 * select display mode
4694 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
4695 g_param_spec_enum("display-mode", "Display Mode",
4696 "Display device setting",
4697 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
4698 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4701 * GstXvImageSink:display-geometry-method
4703 * Display geometrical method setting
4705 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
4706 g_param_spec_enum("display-geometry-method", "Display geometry method",
4707 "Geometrical method for display",
4708 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
4709 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4712 * GstXvImageSink:rotate
4714 * Draw rotation angle setting
4716 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
4717 g_param_spec_enum("rotate", "Rotate angle",
4718 "Rotate angle of display output",
4719 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
4720 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4723 * GstXvImageSink:visible
4725 * Whether reserve original src size or not
4727 g_object_class_install_property (gobject_class, PROP_VISIBLE,
4728 g_param_spec_boolean ("visible", "Visible",
4729 "Draws screen or blacks out, true means visible, false blacks out",
4730 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4733 * GstXvImageSink:zoom
4735 * Scale small area of screen to 2X, 3X, ... , 9X
4737 g_object_class_install_property (gobject_class, PROP_ZOOM,
4738 g_param_spec_int ("zoom", "Zoom",
4739 "Zooms screen as nX", 1, 9, 1,
4740 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4743 * GstXvImageSink:dst-roi-x
4745 * X value of Destination ROI
4747 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
4748 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
4749 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
4750 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4753 * GstXvImageSink:dst-roi-y
4755 * Y value of Destination ROI
4757 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
4758 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
4759 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
4760 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4763 * GstXvImageSink:dst-roi-w
4765 * W value of Destination ROI
4767 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
4768 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
4769 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
4770 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4773 * GstXvImageSink:dst-roi-h
4775 * H value of Destination ROI
4777 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
4778 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
4779 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
4780 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4783 * GstXvImageSink:stop-video
4785 * Stop video for releasing video source buffer
4787 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
4788 g_param_spec_int ("stop-video", "Stop-Video",
4789 "Stop video for releasing video source buffer", 0, 1, 0,
4790 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4791 #endif /* GST_EXT_XV_ENHANCEMENT */
4793 gobject_class->finalize = gst_xvimagesink_finalize;
4795 gstelement_class->change_state =
4796 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
4798 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
4799 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
4800 gstbasesink_class->buffer_alloc =
4801 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
4802 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
4803 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
4805 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
4808 /* ============================================================= */
4810 /* Public Methods */
4812 /* ============================================================= */
4814 /* =========================================== */
4816 /* Object typing & Creation */
4818 /* =========================================== */
4820 gst_xvimagesink_init_interfaces (GType type)
4822 static const GInterfaceInfo iface_info = {
4823 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
4827 static const GInterfaceInfo navigation_info = {
4828 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
4832 static const GInterfaceInfo overlay_info = {
4833 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
4837 static const GInterfaceInfo colorbalance_info = {
4838 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
4842 static const GInterfaceInfo propertyprobe_info = {
4843 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
4848 g_type_add_interface_static (type,
4849 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
4850 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
4851 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
4852 g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
4853 &colorbalance_info);
4854 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
4855 &propertyprobe_info);
4857 /* register type and create class in a more safe place instead of at
4858 * runtime since the type registration and class creation is not
4860 g_type_class_ref (gst_xvimage_buffer_get_type ());
4864 plugin_init (GstPlugin * plugin)
4866 if (!gst_element_register (plugin, "xvimagesink",
4867 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
4870 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
4871 "xvimagesink element");
4872 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
4877 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
4880 "XFree86 video output plugin using Xv extension",
4881 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)