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 theorically
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 */
185 /* Debugging category */
186 #include <gst/gstinfo.h>
187 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
188 #define GST_CAT_DEFAULT gst_debug_xvimagesink
189 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
191 #ifdef GST_EXT_XV_ENHANCEMENT
192 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
195 gst_xvimagesink_display_mode_get_type(void)
197 static GType xvimagesink_display_mode_type = 0;
198 static const GEnumValue display_mode_type[] = {
199 { 1, "Display to both TV and LCD", "BOTH"},
200 { 2, "Display to TV", "TVONLY"},
201 { 3, "Display to LCD", "LCDONLY"},
202 { 4, "Display caption on TV", "TVCAPTION"},
206 if (!xvimagesink_display_mode_type) {
207 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
210 return xvimagesink_display_mode_type;
221 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
224 gst_xvimagesink_rotate_angle_get_type(void)
226 static GType xvimagesink_rotate_angle_type = 0;
227 static const GEnumValue rotate_angle_type[] = {
228 { 0, "No rotate", "DEGREE_0"},
229 { 1, "Rotate 90 degree", "DEGREE_90"},
230 { 2, "Rotate 180 degree", "DEGREE_180"},
231 { 3, "Rotate 270 degree", "DEGREE_270"},
235 if (!xvimagesink_rotate_angle_type) {
236 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
239 return xvimagesink_rotate_angle_type;
243 DISP_GEO_METHOD_LETTER_BOX = 0,
244 DISP_GEO_METHOD_ORIGIN_SIZE,
245 DISP_GEO_METHOD_FULL_SCREEN,
246 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
247 DISP_GEO_METHOD_CUSTOM_ROI,
251 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
253 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
256 gst_xvimagesink_display_geometry_method_get_type(void)
258 static GType xvimagesink_display_geometry_method_type = 0;
259 static const GEnumValue display_geometry_method_type[] = {
260 { 0, "Letter box", "LETTER_BOX"},
261 { 1, "Origin size", "ORIGIN_SIZE"},
262 { 2, "Full-screen", "FULL_SCREEN"},
263 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
264 { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
268 if (!xvimagesink_display_geometry_method_type) {
269 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
272 return xvimagesink_display_geometry_method_type;
274 #endif /* GST_EXT_XV_ENHANCEMENT */
279 unsigned long functions;
280 unsigned long decorations;
282 unsigned long status;
284 MotifWmHints, MwmHints;
286 #define MWM_HINTS_DECORATIONS (1L << 1)
288 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
290 static GstBufferClass *xvimage_buffer_parent_class = NULL;
291 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
293 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
295 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
297 static void gst_xvimagesink_expose (GstXOverlay * overlay);
299 #ifdef GST_EXT_XV_ENHANCEMENT
300 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
303 /* Default template - initiated with class struct to allow gst-register to work
305 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
306 GST_STATIC_PAD_TEMPLATE ("sink",
309 GST_STATIC_CAPS ("video/x-raw-rgb, "
310 "framerate = (fraction) [ 0, MAX ], "
311 "width = (int) [ 1, MAX ], "
312 "height = (int) [ 1, MAX ]; "
314 "framerate = (fraction) [ 0, MAX ], "
315 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
327 PROP_PIXEL_ASPECT_RATIO,
328 PROP_FORCE_ASPECT_RATIO,
334 PROP_AUTOPAINT_COLORKEY,
339 #ifdef GST_EXT_XV_ENHANCEMENT
342 PROP_DISPLAY_GEOMETRY_METHOD,
353 static GstVideoSinkClass *parent_class = NULL;
355 /* ============================================================= */
357 /* Private Methods */
359 /* ============================================================= */
361 /* xvimage buffers */
363 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
365 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
366 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
367 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
369 /* This function destroys a GstXvImage handling XShm availability */
371 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
373 GstXvImageSink *xvimagesink;
375 GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
377 xvimagesink = xvimage->xvimagesink;
378 if (G_UNLIKELY (xvimagesink == NULL))
381 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
383 GST_OBJECT_LOCK (xvimagesink);
385 /* If the destroyed image is the current one we destroy our reference too */
386 if (xvimagesink->cur_image == xvimage)
387 xvimagesink->cur_image = NULL;
389 /* We might have some buffers destroyed after changing state to NULL */
390 if (xvimagesink->xcontext == NULL) {
391 GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
393 /* Need to free the shared memory segment even if the x context
394 * was already cleaned up */
395 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
396 shmdt (xvimage->SHMInfo.shmaddr);
402 g_mutex_lock (xvimagesink->x_lock);
405 if (xvimagesink->xcontext->use_xshm) {
406 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
407 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
408 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
409 XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
410 XSync (xvimagesink->xcontext->disp, FALSE);
412 shmdt (xvimage->SHMInfo.shmaddr);
414 if (xvimage->xvimage)
415 XFree (xvimage->xvimage);
417 #endif /* HAVE_XSHM */
419 if (xvimage->xvimage) {
420 if (xvimage->xvimage->data) {
421 g_free (xvimage->xvimage->data);
423 XFree (xvimage->xvimage);
427 XSync (xvimagesink->xcontext->disp, FALSE);
429 g_mutex_unlock (xvimagesink->x_lock);
432 GST_OBJECT_UNLOCK (xvimagesink);
433 xvimage->xvimagesink = NULL;
434 gst_object_unref (xvimagesink);
436 GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
443 GST_WARNING ("no sink found");
449 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
451 GstXvImageSink *xvimagesink;
454 xvimagesink = xvimage->xvimagesink;
455 if (G_UNLIKELY (xvimagesink == NULL))
458 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
460 GST_OBJECT_LOCK (xvimagesink);
461 running = xvimagesink->running;
462 GST_OBJECT_UNLOCK (xvimagesink);
464 /* If our geometry changed we can't reuse that image. */
465 if (running == FALSE) {
466 GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
467 gst_xvimage_buffer_destroy (xvimage);
468 } else if ((xvimage->width != xvimagesink->video_width) ||
469 (xvimage->height != xvimagesink->video_height)) {
470 GST_LOG_OBJECT (xvimage,
471 "destroy image as its size changed %dx%d vs current %dx%d",
472 xvimage->width, xvimage->height,
473 xvimagesink->video_width, xvimagesink->video_height);
474 gst_xvimage_buffer_destroy (xvimage);
476 /* In that case we can reuse the image and add it to our image pool. */
477 GST_LOG_OBJECT (xvimage, "recycling image in pool");
478 /* need to increment the refcount again to recycle */
479 gst_buffer_ref (GST_BUFFER_CAST (xvimage));
480 g_mutex_lock (xvimagesink->pool_lock);
481 xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
483 g_mutex_unlock (xvimagesink->pool_lock);
489 GST_WARNING ("no sink found");
495 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
497 /* make sure it is not recycled */
499 xvimage->height = -1;
500 gst_buffer_unref (GST_BUFFER (xvimage));
504 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
507 xvimage->SHMInfo.shmaddr = ((void *) -1);
508 xvimage->SHMInfo.shmid = -1;
513 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
515 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
517 xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
519 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
520 gst_xvimage_buffer_finalize;
524 gst_xvimage_buffer_get_type (void)
526 static GType _gst_xvimage_buffer_type;
528 if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
529 static const GTypeInfo xvimage_buffer_info = {
530 sizeof (GstBufferClass),
533 gst_xvimage_buffer_class_init,
536 sizeof (GstXvImageBuffer),
538 (GInstanceInitFunc) gst_xvimage_buffer_init,
541 _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
542 "GstXvImageBuffer", &xvimage_buffer_info, 0);
544 return _gst_xvimage_buffer_type;
549 static gboolean error_caught = FALSE;
552 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
554 char error_msg[1024];
556 XGetErrorText (display, xevent->error_code, error_msg, 1024);
557 GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
563 /* This function checks that it is actually really possible to create an image
566 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
569 XShmSegmentInfo SHMInfo;
571 int (*handler) (Display *, XErrorEvent *);
572 gboolean result = FALSE;
573 gboolean did_attach = FALSE;
575 g_return_val_if_fail (xcontext != NULL, FALSE);
577 /* Sync to ensure any older errors are already processed */
578 XSync (xcontext->disp, FALSE);
580 /* Set defaults so we don't free these later unnecessarily */
581 SHMInfo.shmaddr = ((void *) -1);
584 /* Setting an error handler to catch failure */
585 error_caught = FALSE;
586 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
588 /* Trying to create a 1x1 picture */
589 GST_DEBUG ("XvShmCreateImage of 1x1");
590 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
591 xcontext->im_format, NULL, 1, 1, &SHMInfo);
593 /* Might cause an error, sync to ensure it is noticed */
594 XSync (xcontext->disp, FALSE);
595 if (!xvimage || error_caught) {
596 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
599 size = xvimage->data_size;
601 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
602 if (SHMInfo.shmid == -1) {
603 GST_WARNING ("could not get shared memory of %d bytes", size);
607 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
608 if (SHMInfo.shmaddr == ((void *) -1)) {
609 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
610 /* Clean up the shared memory segment */
611 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
615 xvimage->data = SHMInfo.shmaddr;
616 SHMInfo.readOnly = FALSE;
618 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
619 GST_WARNING ("Failed to XShmAttach");
620 /* Clean up the shared memory segment */
621 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
625 /* Sync to ensure we see any errors we caused */
626 XSync (xcontext->disp, FALSE);
628 /* Delete the shared memory segment as soon as everyone is attached.
629 * This way, it will be deleted as soon as we detach later, and not
630 * leaked if we crash. */
631 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
634 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
638 /* store whether we succeeded in result */
641 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
642 "Not using shared memory.");
646 /* Sync to ensure we swallow any errors we caused and reset error_caught */
647 XSync (xcontext->disp, FALSE);
649 error_caught = FALSE;
650 XSetErrorHandler (handler);
653 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
654 SHMInfo.shmid, SHMInfo.shmseg);
655 XShmDetach (xcontext->disp, &SHMInfo);
656 XSync (xcontext->disp, FALSE);
658 if (SHMInfo.shmaddr != ((void *) -1))
659 shmdt (SHMInfo.shmaddr);
664 #endif /* HAVE_XSHM */
666 /* This function handles GstXvImage creation depending on XShm availability */
667 static GstXvImageBuffer *
668 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
670 GstXvImageBuffer *xvimage = NULL;
671 GstStructure *structure = NULL;
672 gboolean succeeded = FALSE;
673 int (*handler) (Display *, XErrorEvent *);
675 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
680 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
681 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
683 structure = gst_caps_get_structure (caps, 0);
685 if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
686 !gst_structure_get_int (structure, "height", &xvimage->height)) {
687 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
690 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
692 #ifdef GST_EXT_XV_ENHANCEMENT
693 GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
694 xvimagesink->aligned_width, xvimagesink->aligned_height);
695 if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
696 GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
697 xvimagesink->aligned_width = xvimage->width;
698 xvimagesink->aligned_height = xvimage->height;
702 xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
703 if (xvimage->im_format == -1) {
704 GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
705 GST_PTR_FORMAT, caps);
706 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
707 ("Failed to create output image buffer of %dx%d pixels",
708 xvimage->width, xvimage->height), ("Invalid input caps"));
711 xvimage->xvimagesink = gst_object_ref (xvimagesink);
713 g_mutex_lock (xvimagesink->x_lock);
715 /* Setting an error handler to catch failure */
716 error_caught = FALSE;
717 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
720 if (xvimagesink->xcontext->use_xshm) {
723 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
724 xvimagesink->xcontext->xv_port_id,
725 xvimage->im_format, NULL,
726 #ifdef GST_EXT_XV_ENHANCEMENT
727 xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
729 xvimage->width, xvimage->height, &xvimage->SHMInfo);
731 if (!xvimage->xvimage || error_caught) {
732 g_mutex_unlock (xvimagesink->x_lock);
733 /* Reset error handler */
734 error_caught = FALSE;
735 XSetErrorHandler (handler);
737 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
738 ("Failed to create output image buffer of %dx%d pixels",
739 xvimage->width, xvimage->height),
740 ("could not XvShmCreateImage a %dx%d image",
741 xvimage->width, xvimage->height));
745 /* we have to use the returned data_size for our shm size */
746 xvimage->size = xvimage->xvimage->data_size;
747 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
750 /* calculate the expected size. This is only for sanity checking the
751 * number we get from X. */
752 switch (xvimage->im_format) {
753 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
754 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
761 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
762 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
763 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
765 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
766 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
769 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
771 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
772 GST_DEBUG_OBJECT (xvimagesink,
773 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
774 plane, pitches[plane], offsets[plane]);
778 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
779 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
780 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
783 #ifdef GST_EXT_XV_ENHANCEMENT
784 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
785 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
786 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
787 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
788 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
789 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
790 expected_size = sizeof(SCMN_IMGB);
797 if (expected_size != 0 && xvimage->size != expected_size) {
798 GST_WARNING_OBJECT (xvimagesink,
799 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
800 xvimage->size, expected_size);
803 /* Be verbose about our XvImage stride */
807 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
808 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
809 "offset of %d", plane, xvimage->xvimage->pitches[plane],
810 xvimage->xvimage->offsets[plane]);
814 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
816 if (xvimage->SHMInfo.shmid == -1) {
817 g_mutex_unlock (xvimagesink->x_lock);
818 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
819 ("Failed to create output image buffer of %dx%d pixels",
820 xvimage->width, xvimage->height),
821 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
826 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
827 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
828 g_mutex_unlock (xvimagesink->x_lock);
829 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
830 ("Failed to create output image buffer of %dx%d pixels",
831 xvimage->width, xvimage->height),
832 ("Failed to shmat: %s", g_strerror (errno)));
833 /* Clean up the shared memory segment */
834 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
838 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
839 xvimage->SHMInfo.readOnly = FALSE;
841 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
842 /* Clean up the shared memory segment */
843 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
845 g_mutex_unlock (xvimagesink->x_lock);
846 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
847 ("Failed to create output image buffer of %dx%d pixels",
848 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
852 XSync (xvimagesink->xcontext->disp, FALSE);
854 /* Delete the shared memory segment as soon as we everyone is attached.
855 * This way, it will be deleted as soon as we detach later, and not
856 * leaked if we crash. */
857 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
859 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
860 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
862 #endif /* HAVE_XSHM */
864 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
865 xvimagesink->xcontext->xv_port_id,
866 #ifdef GST_EXT_XV_ENHANCEMENT
867 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
869 xvimage->im_format, NULL, xvimage->width, xvimage->height);
871 if (!xvimage->xvimage || error_caught) {
872 g_mutex_unlock (xvimagesink->x_lock);
873 /* Reset error handler */
874 error_caught = FALSE;
875 XSetErrorHandler (handler);
877 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
878 ("Failed to create outputimage buffer of %dx%d pixels",
879 xvimage->width, xvimage->height),
880 ("could not XvCreateImage a %dx%d image",
881 xvimage->width, xvimage->height));
885 /* we have to use the returned data_size for our image size */
886 xvimage->size = xvimage->xvimage->data_size;
887 xvimage->xvimage->data = g_malloc (xvimage->size);
889 XSync (xvimagesink->xcontext->disp, FALSE);
892 /* Reset error handler */
893 error_caught = FALSE;
894 XSetErrorHandler (handler);
898 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
899 GST_BUFFER_SIZE (xvimage) = xvimage->size;
901 g_mutex_unlock (xvimagesink->x_lock);
905 gst_xvimage_buffer_free (xvimage);
912 /* We are called with the x_lock taken */
914 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
915 GstXWindow * xwindow, GstVideoRectangle rect)
919 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
920 g_return_if_fail (xwindow != NULL);
922 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
923 xvimagesink->xcontext->black);
926 if (rect.x > xvimagesink->render_rect.x) {
927 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
928 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
929 rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
933 t1 = rect.x + rect.w;
934 t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
936 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
937 t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
941 if (rect.y > xvimagesink->render_rect.y) {
942 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
943 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
944 xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
948 t1 = rect.y + rect.h;
949 t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
951 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
952 xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
956 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
957 * if no window was available */
959 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
960 GstXvImageBuffer * xvimage)
962 GstVideoRectangle result;
963 gboolean draw_border = FALSE;
965 #ifdef GST_EXT_XV_ENHANCEMENT
966 static Atom atom = None;
968 GstVideoRectangle src_origin = { 0, 0, 0, 0};
969 GstVideoRectangle src_input = { 0, 0, 0, 0};
970 GstVideoRectangle src = { 0, 0, 0, 0};
971 GstVideoRectangle dst = { 0, 0, 0, 0};
975 //int window_rotate = 0;
978 /* We take the flow_lock. If expose is in there we don't want to run
979 concurrently from the data flow thread */
980 g_mutex_lock (xvimagesink->flow_lock);
982 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
983 #ifdef GST_EXT_XV_ENHANCEMENT
984 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
986 g_mutex_unlock (xvimagesink->flow_lock);
990 #ifdef GST_EXT_XV_ENHANCEMENT
991 if( xvimagesink->visible == FALSE )
993 GST_INFO_OBJECT( xvimagesink, "visible is FALSE. Skip xvimage_put." );
994 g_mutex_unlock( xvimagesink->flow_lock );
999 /* Draw borders when displaying the first frame. After this
1000 draw borders only on expose event or after a size change. */
1001 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1005 /* Store a reference to the last image we put, lose the previous one */
1006 if (xvimage && xvimagesink->cur_image != xvimage) {
1007 if (xvimagesink->cur_image) {
1008 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1009 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1011 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1012 xvimagesink->cur_image =
1013 GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1016 /* Expose sends a NULL image, we take the latest frame */
1018 if (xvimagesink->cur_image) {
1020 xvimage = xvimagesink->cur_image;
1022 #ifdef GST_EXT_XV_ENHANCEMENT
1023 GST_INFO_OBJECT( xvimagesink, "cur_image is NULL. Skip xvimage_put." );
1025 g_mutex_unlock (xvimagesink->flow_lock);
1030 #ifdef GST_EXT_XV_ENHANCEMENT
1031 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1034 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1036 src_input.w = src_origin.w = xvimagesink->video_width;
1037 src_input.h = src_origin.h = xvimagesink->video_height;
1039 if (xvimagesink->rotate_angle == DEGREE_0 ||
1040 xvimagesink->rotate_angle == DEGREE_180) {
1041 src.w = src_origin.w;
1042 src.h = src_origin.h;
1044 src.w = src_origin.h;
1045 src.h = src_origin.w;
1048 dst.w = xvimagesink->render_rect.w;
1049 dst.h = xvimagesink->render_rect.h;
1051 switch (xvimagesink->display_geometry_method)
1053 case DISP_GEO_METHOD_LETTER_BOX:
1054 gst_video_sink_center_rect (src, dst, &result, TRUE);
1055 result.x += xvimagesink->render_rect.x;
1056 result.y += xvimagesink->render_rect.y;
1059 case DISP_GEO_METHOD_ORIGIN_SIZE:
1060 gst_video_sink_center_rect (src, dst, &result, FALSE);
1061 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1063 if (xvimagesink->rotate_angle == DEGREE_90 ||
1064 xvimagesink->rotate_angle == DEGREE_270) {
1065 src_input.x = src_input.x ^ src_input.y;
1066 src_input.y = src_input.x ^ src_input.y;
1067 src_input.x = src_input.x ^ src_input.y;
1069 src_input.w = src_input.w ^ src_input.h;
1070 src_input.h = src_input.w ^ src_input.h;
1071 src_input.w = src_input.w ^ src_input.h;
1075 case DISP_GEO_METHOD_FULL_SCREEN:
1076 result.x = result.y = 0;
1077 result.w = xvimagesink->xwindow->width;
1078 result.h = xvimagesink->xwindow->height;
1081 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1082 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1084 result.x = result.y = 0;
1088 if (xvimagesink->rotate_angle == DEGREE_90 ||
1089 xvimagesink->rotate_angle == DEGREE_270) {
1090 src_input.x = src_input.x ^ src_input.y;
1091 src_input.y = src_input.x ^ src_input.y;
1092 src_input.x = src_input.x ^ src_input.y;
1094 src_input.w = src_input.w ^ src_input.h;
1095 src_input.h = src_input.w ^ src_input.h;
1096 src_input.w = src_input.w ^ src_input.h;
1100 case DISP_GEO_METHOD_CUSTOM_ROI:
1101 result.x = xvimagesink->dst_roi.x;
1102 result.y = xvimagesink->dst_roi.y;
1103 result.w = xvimagesink->dst_roi.w;
1104 result.h = xvimagesink->dst_roi.h;
1106 if (xvimagesink->rotate_angle == DEGREE_90 ||
1107 xvimagesink->rotate_angle == DEGREE_270) {
1108 result.w = xvimagesink->dst_roi.h;
1109 result.h = xvimagesink->dst_roi.w;
1117 if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) {
1118 src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1;
1119 src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1;
1120 src_input.w /= xvimagesink->zoom;
1121 src_input.h /= xvimagesink->zoom;
1124 if (xvimagesink->keep_aspect) {
1125 GstVideoRectangle src, dst;
1127 /* We use the calculated geometry from _setcaps as a source to respect
1128 source and screen pixel aspect ratios. */
1129 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1130 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1131 dst.w = xvimagesink->render_rect.w;
1132 dst.h = xvimagesink->render_rect.h;
1134 gst_video_sink_center_rect (src, dst, &result, TRUE);
1135 result.x += xvimagesink->render_rect.x;
1136 result.y += xvimagesink->render_rect.y;
1138 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1142 g_mutex_lock (xvimagesink->x_lock);
1144 if (draw_border && xvimagesink->draw_borders) {
1145 gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1147 xvimagesink->redraw_border = FALSE;
1150 /* We scale to the window's geometry */
1152 if (xvimagesink->xcontext->use_xshm) {
1153 GST_LOG_OBJECT (xvimagesink,
1154 "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1156 xvimage->width, xvimage->height,
1157 xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1159 #ifdef GST_EXT_XV_ENHANCEMENT
1160 switch( xvimagesink->rotate_angle )
1162 /* There's slightly weired code (CCW? CW?) */
1175 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1176 xvimagesink->rotate_angle );
1180 /* Trim as proper size */
1181 if (src_input.w % 2 == 1) {
1184 if (src_input.h % 2 == 1) {
1188 GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1189 xvimagesink->scr_w, xvimagesink->scr_h,
1190 xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1191 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom,
1192 src_origin.w, src_origin.h,
1193 dst.x, dst.y, dst.w, dst.h,
1194 src_input.x, src_input.y, src_input.w, src_input.h,
1195 result.x, result.y, result.w, result.h );
1198 atom = XInternAtom( xvimagesink->xcontext->disp,
1199 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False );
1202 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom, rotate );
1203 if (ret != Success) {
1204 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1205 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom, rotate );
1209 /* src input indicates the status when degree is 0 */
1210 /* dst input indicates the area that src will be shown regardless of rotate */
1212 if (xvimagesink->visible && !xvimagesink->is_hided) {
1213 if (xvimagesink->xim_transparenter) {
1214 GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
1215 XPutImage(xvimagesink->xcontext->disp,
1216 xvimagesink->xwindow->win,
1217 xvimagesink->xwindow->gc,
1218 xvimagesink->xim_transparenter,
1220 result.x, result.y, result.w, result.h);
1223 ret = XvShmPutImage (xvimagesink->xcontext->disp,
1224 xvimagesink->xcontext->xv_port_id,
1225 xvimagesink->xwindow->win,
1226 xvimagesink->xwindow->gc, xvimage->xvimage,
1227 src_input.x, src_input.y, src_input.w, src_input.h,
1228 result.x, result.y, result.w, result.h, FALSE);
1229 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret );
1231 GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
1233 #else /* GST_EXT_XV_ENHANCEMENT */
1234 XvShmPutImage (xvimagesink->xcontext->disp,
1235 xvimagesink->xcontext->xv_port_id,
1236 xvimagesink->xwindow->win,
1237 xvimagesink->xwindow->gc, xvimage->xvimage,
1238 xvimagesink->disp_x, xvimagesink->disp_y,
1239 xvimagesink->disp_width, xvimagesink->disp_height,
1240 result.x, result.y, result.w, result.h, FALSE);
1241 #endif /* GST_EXT_XV_ENHANCEMENT */
1243 #endif /* HAVE_XSHM */
1245 XvPutImage (xvimagesink->xcontext->disp,
1246 xvimagesink->xcontext->xv_port_id,
1247 xvimagesink->xwindow->win,
1248 xvimagesink->xwindow->gc, xvimage->xvimage,
1249 xvimagesink->disp_x, xvimagesink->disp_y,
1250 xvimagesink->disp_width, xvimagesink->disp_height,
1251 result.x, result.y, result.w, result.h);
1254 XSync (xvimagesink->xcontext->disp, FALSE);
1256 g_mutex_unlock (xvimagesink->x_lock);
1258 g_mutex_unlock (xvimagesink->flow_lock);
1264 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
1265 GstXWindow * window)
1267 Atom hints_atom = None;
1268 MotifWmHints *hints;
1270 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
1271 g_return_val_if_fail (window != NULL, FALSE);
1273 g_mutex_lock (xvimagesink->x_lock);
1275 hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
1277 if (hints_atom == None) {
1278 g_mutex_unlock (xvimagesink->x_lock);
1282 hints = g_malloc0 (sizeof (MotifWmHints));
1284 hints->flags |= MWM_HINTS_DECORATIONS;
1285 hints->decorations = 1 << 0;
1287 XChangeProperty (xvimagesink->xcontext->disp, window->win,
1288 hints_atom, hints_atom, 32, PropModeReplace,
1289 (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
1291 XSync (xvimagesink->xcontext->disp, FALSE);
1293 g_mutex_unlock (xvimagesink->x_lock);
1301 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1302 GstXWindow * xwindow, const gchar * media_title)
1305 g_free (xvimagesink->media_title);
1306 xvimagesink->media_title = g_strdup (media_title);
1309 /* we have a window */
1310 if (xwindow->internal) {
1311 XTextProperty xproperty;
1312 const gchar *app_name;
1313 const gchar *title = NULL;
1314 gchar *title_mem = NULL;
1316 /* set application name as a title */
1317 app_name = g_get_application_name ();
1319 if (app_name && xvimagesink->media_title) {
1320 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1322 } else if (app_name) {
1324 } else if (xvimagesink->media_title) {
1325 title = xvimagesink->media_title;
1329 if ((XStringListToTextProperty (((char **) &title), 1,
1330 &xproperty)) != 0) {
1331 XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
1332 XFree (xproperty.value);
1341 #ifdef GST_EXT_XV_ENHANCEMENT
1342 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
1346 /* create a normal ximage */
1347 xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
1349 /* allocate data for it */
1351 xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
1354 memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
1355 if (!xim || !xim->data) {
1356 /* failed to create XImage or allocate data memory */
1368 /* This function handles a GstXWindow creation
1369 * The width and height are the actual pixel size on the display */
1371 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
1372 gint width, gint height)
1374 GstXWindow *xwindow = NULL;
1376 #ifdef GST_EXT_XV_ENHANCEMENT
1377 XSetWindowAttributes win_attr;
1378 XWindowAttributes root_attr;
1381 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1383 xwindow = g_new0 (GstXWindow, 1);
1385 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1386 #ifdef GST_EXT_XV_ENHANCEMENT
1388 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
1389 xvimagesink->render_rect.w = xwindow->width = width;
1390 xvimagesink->render_rect.h = xwindow->height = height;
1393 xvimagesink->render_rect.w = xwindow->width = height;
1394 xvimagesink->render_rect.h = xwindow->height = width;
1397 XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
1399 if (xwindow->width > root_attr.width) {
1400 GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
1401 xwindow->width, root_attr.width);
1402 xvimagesink->render_rect.w = xwindow->width = root_attr.width;
1404 if (xwindow->height > root_attr.height) {
1405 GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
1406 xwindow->height, root_attr.height);
1407 xvimagesink->render_rect.h = xwindow->height = root_attr.height;
1409 xwindow->internal = TRUE;
1411 g_mutex_lock (xvimagesink->x_lock);
1413 GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
1415 xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
1416 xvimagesink->xcontext->root,
1417 0, 0, xwindow->width, xwindow->height,
1420 xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
1421 xvimagesink->xcontext->root,
1422 xwindow->width, xwindow->height);
1424 /* Make window manager not to change window size as Full screen */
1425 win_attr.override_redirect = True;
1426 XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
1428 xvimagesink->render_rect.w = width;
1429 xvimagesink->render_rect.h = height;
1431 xwindow->width = width;
1432 xwindow->height = height;
1433 xwindow->internal = TRUE;
1435 g_mutex_lock (xvimagesink->x_lock);
1437 xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
1438 xvimagesink->xcontext->root,
1439 0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
1442 /* We have to do that to prevent X from redrawing the background on
1443 * ConfigureNotify. This takes away flickering of video when resizing. */
1444 XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
1446 /* set application name as a title */
1447 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
1449 if (xvimagesink->handle_events) {
1452 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
1453 StructureNotifyMask | PointerMotionMask | KeyPressMask |
1454 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
1456 /* Tell the window manager we'd like delete client messages instead of
1458 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
1459 "WM_DELETE_WINDOW", True);
1460 if (wm_delete != None) {
1461 (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
1466 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
1467 xwindow->win, 0, &values);
1469 XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
1471 XSync (xvimagesink->xcontext->disp, FALSE);
1473 g_mutex_unlock (xvimagesink->x_lock);
1475 gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
1477 gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
1482 /* This function destroys a GstXWindow */
1484 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
1485 GstXWindow * xwindow)
1487 g_return_if_fail (xwindow != NULL);
1488 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1490 g_mutex_lock (xvimagesink->x_lock);
1492 /* If we did not create that window we just free the GC and let it live */
1493 if (xwindow->internal)
1494 XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
1496 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
1498 XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
1500 XSync (xvimagesink->xcontext->disp, FALSE);
1502 g_mutex_unlock (xvimagesink->x_lock);
1508 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
1510 #ifdef GST_EXT_XV_ENHANCEMENT
1511 Window root_window, child_window;
1512 XWindowAttributes root_attr;
1516 unsigned int cur_win_width = 0;
1517 unsigned int cur_win_height = 0;
1518 unsigned int cur_win_border_width = 0;
1519 unsigned int cur_win_depth = 0;
1521 XWindowAttributes attr;
1524 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1526 /* Update the window geometry */
1527 g_mutex_lock (xvimagesink->x_lock);
1528 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1529 g_mutex_unlock (xvimagesink->x_lock);
1533 #ifdef GST_EXT_XV_ENHANCEMENT
1534 /* Get root window and size of current window */
1535 XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
1536 &cur_win_x, &cur_win_y, /* relative x, y */
1537 &cur_win_width, &cur_win_height,
1538 &cur_win_border_width, &cur_win_depth );
1540 xvimagesink->xwindow->width = cur_win_width;
1541 xvimagesink->xwindow->height = cur_win_height;
1543 /* Get absolute coordinates of current window */
1544 XTranslateCoordinates( xvimagesink->xcontext->disp,
1545 xvimagesink->xwindow->win,
1548 &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
1551 xvimagesink->xwindow->x = cur_win_x;
1552 xvimagesink->xwindow->y = cur_win_y;
1554 /* Get size of root window == size of screen */
1555 XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
1557 xvimagesink->scr_w = root_attr.width;
1558 xvimagesink->scr_h = root_attr.height;
1560 if (!xvimagesink->have_render_rect) {
1561 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1562 xvimagesink->render_rect.w = cur_win_width;
1563 xvimagesink->render_rect.h = cur_win_height;
1566 GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
1567 xvimagesink->scr_w, xvimagesink->scr_h,
1568 xvimagesink->xwindow->x, xvimagesink->xwindow->y,
1569 xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1570 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1571 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
1573 XGetWindowAttributes (xvimagesink->xcontext->disp,
1574 xvimagesink->xwindow->win, &attr);
1576 xvimagesink->xwindow->width = attr.width;
1577 xvimagesink->xwindow->height = attr.height;
1580 if (!xvimagesink->have_render_rect) {
1581 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
1582 xvimagesink->render_rect.w = attr.width;
1583 xvimagesink->render_rect.h = attr.height;
1587 g_mutex_unlock (xvimagesink->x_lock);
1591 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
1592 GstXWindow * xwindow)
1594 g_return_if_fail (xwindow != NULL);
1595 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1597 g_mutex_lock (xvimagesink->x_lock);
1599 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
1601 #ifndef GST_EXT_XV_ENHANCEMENT
1602 /* Preview area is not updated before other UI is updated in the screen. */
1603 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1604 xvimagesink->xcontext->black);
1606 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1607 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1608 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
1611 XSync (xvimagesink->xcontext->disp, FALSE);
1613 g_mutex_unlock (xvimagesink->x_lock);
1616 /* This function commits our internal colorbalance settings to our grabbed Xv
1617 port. If the xcontext is not initialized yet it simply returns */
1619 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
1621 GList *channels = NULL;
1623 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1625 /* If we haven't initialized the X context we can't update anything */
1626 if (xvimagesink->xcontext == NULL)
1629 /* Don't set the attributes if they haven't been changed, to avoid
1630 * rounding errors changing the values */
1631 if (!xvimagesink->cb_changed)
1634 /* For each channel of the colorbalance we calculate the correct value
1635 doing range conversion and then set the Xv port attribute to match our
1637 channels = xvimagesink->xcontext->channels_list;
1640 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
1641 GstColorBalanceChannel *channel = NULL;
1644 gdouble convert_coef;
1646 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
1647 g_object_ref (channel);
1649 /* Our range conversion coef */
1650 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
1652 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
1653 value = xvimagesink->hue;
1654 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
1655 value = xvimagesink->saturation;
1656 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
1657 value = xvimagesink->contrast;
1658 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
1659 value = xvimagesink->brightness;
1661 g_warning ("got an unknown channel %s", channel->label);
1662 g_object_unref (channel);
1666 /* Committing to Xv port */
1667 g_mutex_lock (xvimagesink->x_lock);
1669 XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
1670 if (prop_atom != None) {
1673 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
1674 XvSetPortAttribute (xvimagesink->xcontext->disp,
1675 xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
1677 g_mutex_unlock (xvimagesink->x_lock);
1679 g_object_unref (channel);
1681 channels = g_list_next (channels);
1685 /* This function handles XEvents that might be in the queue. It generates
1686 GstEvent that will be sent upstream in the pipeline to handle interactivity
1687 and navigation. It will also listen for configure events on the window to
1688 trigger caps renegotiation so on the fly software scaling can work. */
1690 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
1693 guint pointer_x = 0, pointer_y = 0;
1694 gboolean pointer_moved = FALSE;
1695 gboolean exposed = FALSE, configured = FALSE;
1697 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1699 /* Handle Interaction, produces navigation events */
1701 /* We get all pointer motion events, only the last position is
1703 g_mutex_lock (xvimagesink->flow_lock);
1704 g_mutex_lock (xvimagesink->x_lock);
1705 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1706 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
1707 g_mutex_unlock (xvimagesink->x_lock);
1708 g_mutex_unlock (xvimagesink->flow_lock);
1712 pointer_x = e.xmotion.x;
1713 pointer_y = e.xmotion.y;
1714 pointer_moved = TRUE;
1719 g_mutex_lock (xvimagesink->flow_lock);
1720 g_mutex_lock (xvimagesink->x_lock);
1722 if (pointer_moved) {
1723 g_mutex_unlock (xvimagesink->x_lock);
1724 g_mutex_unlock (xvimagesink->flow_lock);
1726 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
1727 pointer_x, pointer_y);
1728 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1729 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
1731 g_mutex_lock (xvimagesink->flow_lock);
1732 g_mutex_lock (xvimagesink->x_lock);
1735 /* We get all events on our window to throw them upstream */
1736 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1737 xvimagesink->xwindow->win,
1738 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
1742 /* We lock only for the X function call */
1743 g_mutex_unlock (xvimagesink->x_lock);
1744 g_mutex_unlock (xvimagesink->flow_lock);
1748 /* Mouse button pressed over our window. We send upstream
1749 events for interactivity/navigation */
1750 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
1751 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1752 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1753 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1756 /* Mouse button released over our window. We send upstream
1757 events for interactivity/navigation */
1758 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
1759 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1760 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1761 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1765 /* Key pressed/released over our window. We send upstream
1766 events for interactivity/navigation */
1767 GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
1768 e.xkey.keycode, e.xkey.x, e.xkey.y);
1769 g_mutex_lock (xvimagesink->x_lock);
1770 keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
1772 g_mutex_unlock (xvimagesink->x_lock);
1773 if (keysym != NoSymbol) {
1774 char *key_str = NULL;
1776 g_mutex_lock (xvimagesink->x_lock);
1777 key_str = XKeysymToString (keysym);
1778 g_mutex_unlock (xvimagesink->x_lock);
1779 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1780 e.type == KeyPress ? "key-press" : "key-release", key_str);
1782 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1783 e.type == KeyPress ? "key-press" : "key-release", "unknown");
1787 GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
1789 g_mutex_lock (xvimagesink->flow_lock);
1790 g_mutex_lock (xvimagesink->x_lock);
1794 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
1795 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
1800 case ConfigureNotify:
1801 g_mutex_unlock (xvimagesink->x_lock);
1802 GST_INFO_OBJECT (xvimagesink, "Call gst_xvimagesink_xwindow_update_geometry!");
1803 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
1804 g_mutex_lock (xvimagesink->x_lock);
1812 if (xvimagesink->handle_expose && (exposed || configured)) {
1813 g_mutex_unlock (xvimagesink->x_lock);
1814 g_mutex_unlock (xvimagesink->flow_lock);
1816 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
1818 g_mutex_lock (xvimagesink->flow_lock);
1819 g_mutex_lock (xvimagesink->x_lock);
1822 /* Handle Display events */
1823 while (XPending (xvimagesink->xcontext->disp)) {
1824 XNextEvent (xvimagesink->xcontext->disp, &e);
1826 case ClientMessage:{
1827 #ifdef GST_EXT_XV_ENHANCEMENT
1828 int active_pid, deactive_pid;
1829 Atom active_win_atom;
1830 Atom deactive_win_atom;
1835 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
1836 "WM_DELETE_WINDOW", True);
1837 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
1838 /* Handle window deletion by posting an error on the bus */
1839 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
1840 ("Output window was closed"), (NULL));
1842 g_mutex_unlock (xvimagesink->x_lock);
1843 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
1844 xvimagesink->xwindow = NULL;
1845 g_mutex_lock (xvimagesink->x_lock);
1847 #ifdef GST_EXT_XV_ENHANCEMENT
1848 GST_INFO_OBJECT( xvimagesink, "message type : %d", e.xclient.message_type );
1850 active_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_ACTIVATE_WINDOW", False);
1851 deactive_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_DEACTIVATE_WINDOW", False);
1853 if( !active_win_atom || !deactive_win_atom )
1855 GST_WARNING_OBJECT( xvimagesink, "Can NOT get active[%d] or deactive[%d] win atom",
1856 active_win_atom, deactive_win_atom );
1860 /* Window is DEACTIVATED */
1861 if( e.xclient.message_type == deactive_win_atom )
1863 /* Get pid of activated/deactivated window */
1864 active_pid = e.xclient.data.l[1];
1865 deactive_pid = e.xclient.data.l[3];
1867 if( active_pid != deactive_pid )
1869 GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window DEACTIVATED" );
1871 xvimagesink->is_hided = TRUE;
1872 atom_stream = XInternAtom( xvimagesink->xcontext->disp,
1873 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
1874 if( atom_stream != None )
1876 if( XvSetPortAttribute( xvimagesink->xcontext->disp,
1877 xvimagesink->xcontext->xv_port_id,
1878 atom_stream, 0 ) != Success )
1880 GST_WARNING_OBJECT( xvimagesink, "STREAM OFF failed" );
1882 XSync( xvimagesink->xcontext->disp, FALSE );
1887 GST_INFO_OBJECT( xvimagesink, "Window is DEACTIVATED, but same process. so Do not clear screen." );
1890 /* Window is ACTIVATED */
1891 else if( e.xclient.message_type == active_win_atom )
1893 /* Get pid of activated/deactivated window */
1894 active_pid = e.xclient.data.l[1];
1895 deactive_pid = e.xclient.data.l[3];
1897 if( active_pid != deactive_pid )
1899 GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window ACTIVATED" );
1901 g_mutex_unlock (xvimagesink->x_lock);
1902 g_mutex_unlock (xvimagesink->flow_lock);
1904 xvimagesink->is_hided = FALSE;
1905 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
1907 g_mutex_lock (xvimagesink->flow_lock);
1908 g_mutex_lock (xvimagesink->x_lock);
1912 GST_INFO_OBJECT( xvimagesink, "Window is ACTIVATED, but same process. so Do not redraw screen." );
1924 g_mutex_unlock (xvimagesink->x_lock);
1925 g_mutex_unlock (xvimagesink->flow_lock);
1929 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
1930 XvAdaptorInfo * adaptors, int adaptor_no)
1935 /* Do we support XvImageMask ? */
1936 if (!(adaptors[adaptor_no].type & XvImageMask)) {
1937 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
1938 adaptors[adaptor_no].name);
1942 /* We found such an adaptor, looking for an available port */
1943 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
1944 /* We try to grab the port */
1945 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
1946 if (Success == res) {
1947 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
1948 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
1949 adaptors[adaptor_no].num_ports);
1951 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
1952 adaptors[adaptor_no].name, res);
1957 /* This function generates a caps with all supported format by the first
1958 Xv grabable port we find. We store each one of the supported formats in a
1959 format list and append the format to a newly created caps that we return
1960 If this function does not return NULL because of an error, it also grabs
1961 the port via XvGrabPort */
1963 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
1964 GstXContext * xcontext)
1967 XvAdaptorInfo *adaptors;
1969 XvImageFormatValues *formats = NULL;
1971 XvEncodingInfo *encodings = NULL;
1972 gulong max_w = G_MAXINT, max_h = G_MAXINT;
1973 GstCaps *caps = NULL;
1974 GstCaps *rgb_caps = NULL;
1976 g_return_val_if_fail (xcontext != NULL, NULL);
1978 /* First let's check that XVideo extension is available */
1979 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
1980 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
1981 ("Could not initialise Xv output"),
1982 ("XVideo extension is not available"));
1986 /* Then we get adaptors list */
1987 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
1988 &xcontext->nb_adaptors, &adaptors)) {
1989 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
1990 ("Could not initialise Xv output"),
1991 ("Failed getting XV adaptors list"));
1995 xcontext->xv_port_id = 0;
1997 GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors);
1999 xcontext->adaptors =
2000 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
2002 /* Now fill up our adaptor name array */
2003 for (i = 0; i < xcontext->nb_adaptors; i++) {
2004 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
2007 if (xvimagesink->adaptor_no >= 0 &&
2008 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
2009 /* Find xv port from user defined adaptor */
2010 gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
2011 xvimagesink->adaptor_no);
2014 if (!xcontext->xv_port_id) {
2015 /* Now search for an adaptor that supports XvImageMask */
2016 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
2017 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
2018 xvimagesink->adaptor_no = i;
2022 XvFreeAdaptorInfo (adaptors);
2024 if (!xcontext->xv_port_id) {
2025 xvimagesink->adaptor_no = -1;
2026 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
2027 ("Could not initialise Xv output"), ("No port available"));
2031 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
2033 int count, todo = 3;
2034 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
2035 xcontext->xv_port_id, &count);
2036 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
2037 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
2038 static const char colorkey[] = "XV_COLORKEY";
2040 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
2042 xvimagesink->have_autopaint_colorkey = FALSE;
2043 xvimagesink->have_double_buffer = FALSE;
2044 xvimagesink->have_colorkey = FALSE;
2046 for (i = 0; ((i < count) && todo); i++)
2047 if (!strcmp (attr[i].name, autopaint)) {
2048 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
2050 /* turn on autopaint colorkey */
2051 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2052 (xvimagesink->autopaint_colorkey ? 1 : 0));
2054 xvimagesink->have_autopaint_colorkey = TRUE;
2055 } else if (!strcmp (attr[i].name, dbl_buffer)) {
2056 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
2058 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2059 (xvimagesink->double_buffer ? 1 : 0));
2061 xvimagesink->have_double_buffer = TRUE;
2062 } else if (!strcmp (attr[i].name, colorkey)) {
2063 /* Set the colorkey, default is something that is dark but hopefully
2064 * won't randomly appear on the screen elsewhere (ie not black or greys)
2065 * can be overridden by setting "colorkey" property
2067 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
2069 gboolean set_attr = TRUE;
2072 /* set a colorkey in the right format RGB565/RGB888
2073 * We only handle these 2 cases, because they're the only types of
2074 * devices we've encountered. If we don't recognise it, leave it alone
2076 cr = (xvimagesink->colorkey >> 16);
2077 cg = (xvimagesink->colorkey >> 8) & 0xFF;
2078 cb = (xvimagesink->colorkey) & 0xFF;
2079 switch (xcontext->depth) {
2080 case 16: /* RGB 565 */
2084 ckey = (cr << 11) | (cg << 5) | cb;
2087 case 32: /* RGB 888 / ARGB 8888 */
2088 ckey = (cr << 16) | (cg << 8) | cb;
2091 GST_DEBUG_OBJECT (xvimagesink,
2092 "Unknown bit depth %d for Xv Colorkey - not adjusting",
2099 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
2100 (guint32) attr[i].max_value);
2101 GST_LOG_OBJECT (xvimagesink,
2102 "Setting color key for display depth %d to 0x%x",
2103 xcontext->depth, ckey);
2105 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
2109 xvimagesink->have_colorkey = TRUE;
2115 /* Get the list of encodings supported by the adapter and look for the
2116 * XV_IMAGE encoding so we can determine the maximum width and height
2118 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
2121 for (i = 0; i < nb_encodings; i++) {
2122 GST_LOG_OBJECT (xvimagesink,
2123 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
2124 i, encodings[i].name, encodings[i].width, encodings[i].height,
2125 encodings[i].rate.numerator, encodings[i].rate.denominator);
2126 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
2127 max_w = encodings[i].width;
2128 max_h = encodings[i].height;
2129 #ifdef GST_EXT_XV_ENHANCEMENT
2130 xvimagesink->scr_w = max_w;
2131 xvimagesink->scr_h = max_h;
2136 XvFreeEncodingInfo (encodings);
2138 /* We get all image formats supported by our port */
2139 formats = XvListImageFormats (xcontext->disp,
2140 xcontext->xv_port_id, &nb_formats);
2141 caps = gst_caps_new_empty ();
2142 for (i = 0; i < nb_formats; i++) {
2143 GstCaps *format_caps = NULL;
2144 gboolean is_rgb_format = FALSE;
2146 /* We set the image format of the xcontext to an existing one. This
2147 is just some valid image format for making our xshm calls check before
2148 caps negotiation really happens. */
2149 xcontext->im_format = formats[i].id;
2151 switch (formats[i].type) {
2154 XvImageFormatValues *fmt = &(formats[i]);
2155 gint endianness = G_BIG_ENDIAN;
2157 if (fmt->byte_order == LSBFirst) {
2158 /* our caps system handles 24/32bpp RGB as big-endian. */
2159 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
2160 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
2161 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
2162 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
2164 if (fmt->bits_per_pixel == 24) {
2165 fmt->red_mask >>= 8;
2166 fmt->green_mask >>= 8;
2167 fmt->blue_mask >>= 8;
2170 endianness = G_LITTLE_ENDIAN;
2173 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
2174 "endianness", G_TYPE_INT, endianness,
2175 "depth", G_TYPE_INT, fmt->depth,
2176 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
2177 "red_mask", G_TYPE_INT, fmt->red_mask,
2178 "green_mask", G_TYPE_INT, fmt->green_mask,
2179 "blue_mask", G_TYPE_INT, fmt->blue_mask,
2180 "width", GST_TYPE_INT_RANGE, 1, max_w,
2181 "height", GST_TYPE_INT_RANGE, 1, max_h,
2182 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2184 is_rgb_format = TRUE;
2188 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
2189 "format", GST_TYPE_FOURCC, formats[i].id,
2190 "width", GST_TYPE_INT_RANGE, 1, max_w,
2191 "height", GST_TYPE_INT_RANGE, 1, max_h,
2192 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2195 g_assert_not_reached ();
2200 GstXvImageFormat *format = NULL;
2202 format = g_new0 (GstXvImageFormat, 1);
2204 format->format = formats[i].id;
2205 format->caps = gst_caps_copy (format_caps);
2206 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
2209 if (is_rgb_format) {
2210 if (rgb_caps == NULL)
2211 rgb_caps = format_caps;
2213 gst_caps_append (rgb_caps, format_caps);
2215 gst_caps_append (caps, format_caps);
2219 /* Collected all caps into either the caps or rgb_caps structures.
2220 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
2222 gst_caps_append (caps, rgb_caps);
2227 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
2229 if (gst_caps_is_empty (caps)) {
2230 gst_caps_unref (caps);
2231 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2232 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
2233 ("No supported format found"));
2241 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
2243 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2245 GST_OBJECT_LOCK (xvimagesink);
2246 while (xvimagesink->running) {
2247 GST_OBJECT_UNLOCK (xvimagesink);
2249 if (xvimagesink->xwindow) {
2250 gst_xvimagesink_handle_xevents (xvimagesink);
2252 /* FIXME: do we want to align this with the framerate or anything else? */
2253 g_usleep (G_USEC_PER_SEC / 20);
2255 GST_OBJECT_LOCK (xvimagesink);
2257 GST_OBJECT_UNLOCK (xvimagesink);
2263 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
2265 GThread *thread = NULL;
2267 /* don't start the thread too early */
2268 if (xvimagesink->xcontext == NULL) {
2272 GST_OBJECT_LOCK (xvimagesink);
2273 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
2274 if (!xvimagesink->event_thread) {
2275 /* Setup our event listening thread */
2276 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
2277 xvimagesink->handle_expose, xvimagesink->handle_events);
2278 xvimagesink->running = TRUE;
2279 xvimagesink->event_thread = g_thread_create (
2280 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
2283 if (xvimagesink->event_thread) {
2284 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
2285 xvimagesink->handle_expose, xvimagesink->handle_events);
2286 xvimagesink->running = FALSE;
2287 /* grab thread and mark it as NULL */
2288 thread = xvimagesink->event_thread;
2289 xvimagesink->event_thread = NULL;
2292 GST_OBJECT_UNLOCK (xvimagesink);
2294 /* Wait for our event thread to finish */
2296 g_thread_join (thread);
2301 /* This function calculates the pixel aspect ratio based on the properties
2302 * in the xcontext structure and stores it there. */
2304 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
2306 static const gint par[][2] = {
2307 {1, 1}, /* regular screen */
2308 {16, 15}, /* PAL TV */
2309 {11, 10}, /* 525 line Rec.601 video */
2310 {54, 59}, /* 625 line Rec.601 video */
2311 {64, 45}, /* 1280x1024 on 16:9 display */
2312 {5, 3}, /* 1280x1024 on 4:3 display */
2313 {4, 3} /* 800x600 on 16:9 display */
2320 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
2322 /* first calculate the "real" ratio based on the X values;
2323 * which is the "physical" w/h divided by the w/h in pixels of the display */
2324 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
2325 / (xcontext->heightmm * xcontext->width);
2327 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
2329 if (xcontext->width == 720 && xcontext->height == 576) {
2330 ratio = 4.0 * 576 / (3.0 * 720);
2332 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
2333 /* now find the one from par[][2] with the lowest delta to the real one */
2337 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
2338 gdouble this_delta = DELTA (i);
2340 if (this_delta < delta) {
2346 GST_DEBUG ("Decided on index %d (%d/%d)", index,
2347 par[index][0], par[index][1]);
2349 g_free (xcontext->par);
2350 xcontext->par = g_new0 (GValue, 1);
2351 g_value_init (xcontext->par, GST_TYPE_FRACTION);
2352 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
2353 GST_DEBUG ("set xcontext PAR to %d/%d",
2354 gst_value_get_fraction_numerator (xcontext->par),
2355 gst_value_get_fraction_denominator (xcontext->par));
2358 /* This function gets the X Display and global info about it. Everything is
2359 stored in our object and will be cleaned when the object is disposed. Note
2360 here that caps for supported format are generated without any window or
2362 static GstXContext *
2363 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
2365 GstXContext *xcontext = NULL;
2366 XPixmapFormatValues *px_formats = NULL;
2367 gint nb_formats = 0, i, j, N_attr;
2368 XvAttribute *xv_attr;
2370 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
2371 "XV_BRIGHTNESS", "XV_CONTRAST"
2374 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2376 xcontext = g_new0 (GstXContext, 1);
2377 xcontext->im_format = 0;
2379 g_mutex_lock (xvimagesink->x_lock);
2381 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
2383 if (!xcontext->disp) {
2384 g_mutex_unlock (xvimagesink->x_lock);
2386 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
2387 ("Could not initialise Xv output"), ("Could not open display"));
2391 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
2392 xcontext->screen_num = DefaultScreen (xcontext->disp);
2393 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
2394 xcontext->root = DefaultRootWindow (xcontext->disp);
2395 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
2396 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
2397 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
2399 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
2400 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
2401 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
2402 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
2404 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
2405 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
2407 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
2408 /* We get supported pixmap formats at supported depth */
2409 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
2412 XCloseDisplay (xcontext->disp);
2413 g_mutex_unlock (xvimagesink->x_lock);
2414 g_free (xcontext->par);
2416 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
2417 ("Could not initialise Xv output"), ("Could not get pixel formats"));
2421 /* We get bpp value corresponding to our running depth */
2422 for (i = 0; i < nb_formats; i++) {
2423 if (px_formats[i].depth == xcontext->depth)
2424 xcontext->bpp = px_formats[i].bits_per_pixel;
2429 xcontext->endianness =
2430 (ImageByteOrder (xcontext->disp) ==
2431 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
2433 /* our caps system handles 24/32bpp RGB as big-endian. */
2434 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
2435 xcontext->endianness == G_LITTLE_ENDIAN) {
2436 xcontext->endianness = G_BIG_ENDIAN;
2437 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
2438 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
2439 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
2440 if (xcontext->bpp == 24) {
2441 xcontext->visual->red_mask >>= 8;
2442 xcontext->visual->green_mask >>= 8;
2443 xcontext->visual->blue_mask >>= 8;
2447 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
2449 if (!xcontext->caps) {
2450 XCloseDisplay (xcontext->disp);
2451 g_mutex_unlock (xvimagesink->x_lock);
2452 g_free (xcontext->par);
2454 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
2458 /* Search for XShm extension support */
2459 if (XShmQueryExtension (xcontext->disp) &&
2460 gst_xvimagesink_check_xshm_calls (xcontext)) {
2461 xcontext->use_xshm = TRUE;
2462 GST_DEBUG ("xvimagesink is using XShm extension");
2464 #endif /* HAVE_XSHM */
2466 xcontext->use_xshm = FALSE;
2467 GST_DEBUG ("xvimagesink is not using XShm extension");
2470 xv_attr = XvQueryPortAttributes (xcontext->disp,
2471 xcontext->xv_port_id, &N_attr);
2474 /* Generate the channels list */
2475 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
2476 XvAttribute *matching_attr = NULL;
2478 /* Retrieve the property atom if it exists. If it doesn't exist,
2479 * the attribute itself must not either, so we can skip */
2480 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
2481 if (prop_atom == None)
2484 if (xv_attr != NULL) {
2485 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
2486 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
2487 matching_attr = xv_attr + j;
2490 if (matching_attr) {
2491 GstColorBalanceChannel *channel;
2493 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
2494 channel->label = g_strdup (channels[i]);
2495 channel->min_value = matching_attr ? matching_attr->min_value : -1000;
2496 channel->max_value = matching_attr ? matching_attr->max_value : 1000;
2498 xcontext->channels_list = g_list_append (xcontext->channels_list,
2501 /* If the colorbalance settings have not been touched we get Xv values
2502 as defaults and update our internal variables */
2503 if (!xvimagesink->cb_changed) {
2506 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
2508 /* Normalize val to [-1000, 1000] */
2509 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
2510 (double) (channel->max_value - channel->min_value));
2512 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
2513 xvimagesink->hue = val;
2514 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
2515 xvimagesink->saturation = val;
2516 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
2517 xvimagesink->brightness = val;
2518 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
2519 xvimagesink->contrast = val;
2527 g_mutex_unlock (xvimagesink->x_lock);
2532 /* This function cleans the X context. Closing the Display, releasing the XV
2533 port and unrefing the caps for supported formats. */
2535 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
2537 GList *formats_list, *channels_list;
2538 GstXContext *xcontext;
2541 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2543 GST_OBJECT_LOCK (xvimagesink);
2544 if (xvimagesink->xcontext == NULL) {
2545 GST_OBJECT_UNLOCK (xvimagesink);
2549 /* Take the XContext from the sink and clean it up */
2550 xcontext = xvimagesink->xcontext;
2551 xvimagesink->xcontext = NULL;
2553 GST_OBJECT_UNLOCK (xvimagesink);
2556 formats_list = xcontext->formats_list;
2558 while (formats_list) {
2559 GstXvImageFormat *format = formats_list->data;
2561 gst_caps_unref (format->caps);
2563 formats_list = g_list_next (formats_list);
2566 if (xcontext->formats_list)
2567 g_list_free (xcontext->formats_list);
2569 channels_list = xcontext->channels_list;
2571 while (channels_list) {
2572 GstColorBalanceChannel *channel = channels_list->data;
2574 g_object_unref (channel);
2575 channels_list = g_list_next (channels_list);
2578 if (xcontext->channels_list)
2579 g_list_free (xcontext->channels_list);
2581 gst_caps_unref (xcontext->caps);
2582 if (xcontext->last_caps)
2583 gst_caps_replace (&xcontext->last_caps, NULL);
2585 for (i = 0; i < xcontext->nb_adaptors; i++) {
2586 g_free (xcontext->adaptors[i]);
2589 g_free (xcontext->adaptors);
2591 g_free (xcontext->par);
2593 g_mutex_lock (xvimagesink->x_lock);
2595 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
2597 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2599 XCloseDisplay (xcontext->disp);
2601 g_mutex_unlock (xvimagesink->x_lock);
2607 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
2609 g_mutex_lock (xvimagesink->pool_lock);
2611 while (xvimagesink->image_pool) {
2612 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
2614 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
2615 xvimagesink->image_pool);
2616 gst_xvimage_buffer_free (xvimage);
2619 g_mutex_unlock (xvimagesink->pool_lock);
2624 /* This function tries to get a format matching with a given caps in the
2625 supported list of formats we generated in gst_xvimagesink_get_xv_support */
2627 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
2632 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
2634 list = xvimagesink->xcontext->formats_list;
2637 GstXvImageFormat *format = list->data;
2640 if (gst_caps_can_intersect (caps, format->caps)) {
2641 return format->format;
2644 list = g_list_next (list);
2651 gst_xvimagesink_getcaps (GstBaseSink * bsink)
2653 GstXvImageSink *xvimagesink;
2655 xvimagesink = GST_XVIMAGESINK (bsink);
2657 if (xvimagesink->xcontext)
2658 return gst_caps_ref (xvimagesink->xcontext->caps);
2661 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
2666 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
2668 GstXvImageSink *xvimagesink;
2669 GstStructure *structure;
2670 guint32 im_format = 0;
2672 gint video_width, video_height;
2673 gint disp_x, disp_y;
2674 gint disp_width, disp_height;
2675 gint video_par_n, video_par_d; /* video's PAR */
2676 gint display_par_n, display_par_d; /* display's PAR */
2677 const GValue *caps_par;
2678 const GValue *caps_disp_reg;
2682 xvimagesink = GST_XVIMAGESINK (bsink);
2684 GST_DEBUG_OBJECT (xvimagesink,
2685 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
2686 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
2688 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
2689 goto incompatible_caps;
2691 structure = gst_caps_get_structure (caps, 0);
2692 ret = gst_structure_get_int (structure, "width", &video_width);
2693 ret &= gst_structure_get_int (structure, "height", &video_height);
2694 fps = gst_structure_get_value (structure, "framerate");
2695 ret &= (fps != NULL);
2698 goto incomplete_caps;
2700 #ifdef GST_EXT_XV_ENHANCEMENT
2701 xvimagesink->aligned_width = video_width;
2702 xvimagesink->aligned_height = video_height;
2705 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
2706 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
2708 xvimagesink->video_width = video_width;
2709 xvimagesink->video_height = video_height;
2711 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
2712 if (im_format == -1)
2713 goto invalid_format;
2715 /* get aspect ratio from caps if it's present, and
2716 * convert video width and height to a display width and height
2717 * using wd / hd = wv / hv * PARv / PARd */
2719 /* get video's PAR */
2720 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
2722 video_par_n = gst_value_get_fraction_numerator (caps_par);
2723 video_par_d = gst_value_get_fraction_denominator (caps_par);
2728 /* get display's PAR */
2729 if (xvimagesink->par) {
2730 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
2731 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
2737 /* get the display region */
2738 caps_disp_reg = gst_structure_get_value (structure, "display-region");
2739 if (caps_disp_reg) {
2740 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
2741 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
2742 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
2744 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
2746 disp_x = disp_y = 0;
2747 disp_width = video_width;
2748 disp_height = video_height;
2751 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
2752 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
2755 xvimagesink->disp_x = disp_x;
2756 xvimagesink->disp_y = disp_y;
2757 xvimagesink->disp_width = disp_width;
2758 xvimagesink->disp_height = disp_height;
2760 GST_DEBUG_OBJECT (xvimagesink,
2761 "video width/height: %dx%d, calculated display ratio: %d/%d",
2762 video_width, video_height, num, den);
2764 /* now find a width x height that respects this display ratio.
2765 * prefer those that have one of w/h the same as the incoming video
2766 * using wd / hd = num / den */
2768 /* start with same height, because of interlaced video */
2769 /* check hd / den is an integer scale factor, and scale wd with the PAR */
2770 if (video_height % den == 0) {
2771 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
2772 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
2773 gst_util_uint64_scale_int (video_height, num, den);
2774 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
2775 } else if (video_width % num == 0) {
2776 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
2777 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
2778 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
2779 gst_util_uint64_scale_int (video_width, den, num);
2781 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
2782 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
2783 gst_util_uint64_scale_int (video_height, num, den);
2784 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
2786 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
2787 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
2789 /* Notify application to set xwindow id now */
2790 g_mutex_lock (xvimagesink->flow_lock);
2791 if (!xvimagesink->xwindow) {
2792 g_mutex_unlock (xvimagesink->flow_lock);
2793 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
2795 g_mutex_unlock (xvimagesink->flow_lock);
2798 /* Creating our window and our image with the display size in pixels */
2799 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
2800 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
2801 goto no_display_size;
2803 g_mutex_lock (xvimagesink->flow_lock);
2804 if (!xvimagesink->xwindow) {
2805 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
2806 GST_VIDEO_SINK_WIDTH (xvimagesink),
2807 GST_VIDEO_SINK_HEIGHT (xvimagesink));
2810 /* After a resize, we want to redraw the borders in case the new frame size
2811 * doesn't cover the same area */
2812 xvimagesink->redraw_border = TRUE;
2814 /* We renew our xvimage only if size or format changed;
2815 * the xvimage is the same size as the video pixel size */
2816 if ((xvimagesink->xvimage) &&
2817 ((im_format != xvimagesink->xvimage->im_format) ||
2818 (video_width != xvimagesink->xvimage->width) ||
2819 (video_height != xvimagesink->xvimage->height))) {
2820 GST_DEBUG_OBJECT (xvimagesink,
2821 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
2822 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
2823 GST_FOURCC_ARGS (im_format));
2824 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
2825 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
2826 xvimagesink->xvimage = NULL;
2829 g_mutex_unlock (xvimagesink->flow_lock);
2836 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
2841 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
2842 "height or framerate from intersected caps");
2847 GST_DEBUG_OBJECT (xvimagesink,
2848 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
2853 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
2854 ("Error calculating the output display ratio of the video."));
2859 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
2860 ("Error calculating the output display ratio of the video."));
2865 static GstStateChangeReturn
2866 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
2868 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2869 GstXvImageSink *xvimagesink;
2870 GstXContext *xcontext = NULL;
2871 #ifdef GST_EXT_XV_ENHANCEMENT
2872 Atom atom_preemption = None;
2875 xvimagesink = GST_XVIMAGESINK (element);
2877 switch (transition) {
2878 case GST_STATE_CHANGE_NULL_TO_READY:
2879 /* Initializing the XContext */
2880 if (xvimagesink->xcontext == NULL) {
2881 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
2882 if (xcontext == NULL)
2883 return GST_STATE_CHANGE_FAILURE;
2884 GST_OBJECT_LOCK (xvimagesink);
2886 xvimagesink->xcontext = xcontext;
2887 GST_OBJECT_UNLOCK (xvimagesink);
2890 /* update object's par with calculated one if not set yet */
2891 if (!xvimagesink->par) {
2892 xvimagesink->par = g_new0 (GValue, 1);
2893 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
2894 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
2896 /* call XSynchronize with the current value of synchronous */
2897 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
2898 xvimagesink->synchronous ? "TRUE" : "FALSE");
2899 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
2900 gst_xvimagesink_update_colorbalance (xvimagesink);
2901 gst_xvimagesink_manage_event_thread (xvimagesink);
2903 case GST_STATE_CHANGE_READY_TO_PAUSED:
2904 g_mutex_lock (xvimagesink->pool_lock);
2905 xvimagesink->pool_invalid = FALSE;
2906 g_mutex_unlock (xvimagesink->pool_lock);
2908 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2909 #ifdef GST_EXT_XV_ENHANCEMENT
2910 g_mutex_lock (xvimagesink->x_lock);
2911 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
2912 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
2913 if(atom_preemption != None)
2915 if( XvSetPortAttribute( xvimagesink->xcontext->disp,
2916 xvimagesink->xcontext->xv_port_id,
2917 atom_preemption, 1 ) != Success )
2919 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
2921 XSync (xvimagesink->xcontext->disp, FALSE);
2923 g_mutex_unlock (xvimagesink->x_lock);
2926 case GST_STATE_CHANGE_PAUSED_TO_READY:
2927 g_mutex_lock (xvimagesink->pool_lock);
2928 xvimagesink->pool_invalid = TRUE;
2929 g_mutex_unlock (xvimagesink->pool_lock);
2935 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2937 switch (transition) {
2938 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2939 #ifdef GST_EXT_XV_ENHANCEMENT
2940 xvimagesink->rotate_changed = TRUE;
2941 g_mutex_lock (xvimagesink->x_lock);
2942 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
2943 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
2944 if(atom_preemption != None)
2946 if( XvSetPortAttribute( xvimagesink->xcontext->disp,
2947 xvimagesink->xcontext->xv_port_id,
2948 atom_preemption, 0 ) != Success )
2950 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
2952 XSync (xvimagesink->xcontext->disp, FALSE);
2954 g_mutex_unlock (xvimagesink->x_lock);
2957 case GST_STATE_CHANGE_PAUSED_TO_READY:
2958 xvimagesink->fps_n = 0;
2959 xvimagesink->fps_d = 1;
2960 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
2961 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
2963 case GST_STATE_CHANGE_READY_TO_NULL:
2964 gst_xvimagesink_reset (xvimagesink);
2974 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
2975 GstClockTime * start, GstClockTime * end)
2977 GstXvImageSink *xvimagesink;
2979 xvimagesink = GST_XVIMAGESINK (bsink);
2981 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2982 *start = GST_BUFFER_TIMESTAMP (buf);
2983 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2984 *end = *start + GST_BUFFER_DURATION (buf);
2986 if (xvimagesink->fps_n > 0) {
2988 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
2989 xvimagesink->fps_n);
2995 static GstFlowReturn
2996 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
2998 GstXvImageSink *xvimagesink;
3000 #ifdef GST_EXT_XV_ENHANCEMENT
3001 XV_PUTIMAGE_DATA_PTR img_data = NULL;
3002 SCMN_IMGB *scmn_imgb = NULL;
3003 GstMultiPlaneImageBuffer* mp_buf = NULL;
3008 xvimagesink = GST_XVIMAGESINK (vsink);
3010 #ifdef GST_EXT_XV_ENHANCEMENT
3011 if( xvimagesink->stop_video )
3013 GST_INFO( "Stop video is TRUE. so skip show frame..." );
3018 /* If this buffer has been allocated using our buffer management we simply
3019 put the ximage which is in the PRIVATE pointer */
3020 if (GST_IS_XVIMAGE_BUFFER (buf)) {
3021 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
3022 if (!gst_xvimagesink_xvimage_put (xvimagesink,
3023 GST_XVIMAGE_BUFFER_CAST (buf)))
3026 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
3027 "slow copy into bufferpool buffer %p", buf);
3028 /* Else we have to copy the data into our private image, */
3029 /* if we have one... */
3030 if (!xvimagesink->xvimage) {
3031 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
3033 #ifdef GST_EXT_XV_ENHANCEMENT
3034 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
3036 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
3037 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
3038 case GST_MAKE_FOURCC('S', '4', '2', '0'):
3039 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
3040 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
3041 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
3042 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
3043 if(scmn_imgb == NULL) {
3044 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
3047 xvimagesink->aligned_width = scmn_imgb->s[0];
3048 xvimagesink->aligned_height = scmn_imgb->e[0];
3049 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
3050 xvimagesink->aligned_width, xvimagesink->aligned_height);
3053 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
3058 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
3059 GST_BUFFER_CAPS (buf));
3061 if (!xvimagesink->xvimage)
3062 /* The create method should have posted an informative error */
3065 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
3066 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
3067 ("Failed to create output image buffer of %dx%d pixels",
3068 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
3069 ("XServer allocated buffer size did not match input buffer"));
3071 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
3072 xvimagesink->xvimage = NULL;
3077 #ifdef GST_EXT_XV_ENHANCEMENT
3079 switch (xvimagesink->xvimage->im_format) {
3080 /* Cases for specified formats of Samsung extension */
3081 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
3082 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
3083 case GST_MAKE_FOURCC('S', '4', '2', '0'):
3084 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
3085 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
3086 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
3088 GST_DEBUG("Samsung extension display format activated. fourcc:%d,display mode:%d,Rotate angle:%d",
3089 xvimagesink->xvimage->im_format, xvimagesink->display_mode, xvimagesink->rotate_angle);
3091 if (xvimagesink->xvimage->xvimage->data) {
3092 img_data = (XV_PUTIMAGE_DATA_PTR) xvimagesink->xvimage->xvimage->data;
3093 XV_PUTIMAGE_INIT_DATA(img_data);
3095 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
3096 if (scmn_imgb == NULL) {
3097 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
3101 img_data->YPhyAddr = (unsigned int)scmn_imgb->p[0];
3102 img_data->CbPhyAddr = (unsigned int)scmn_imgb->p[1];
3103 img_data->CrPhyAddr = (unsigned int)scmn_imgb->p[2];
3105 GST_LOG_OBJECT(xvimagesink, "Ypaddr[%p],CbPaddr[%p],CrPaddr[%p]",
3106 img_data->YPhyAddr, img_data->CbPhyAddr, img_data->CrPhyAddr );
3108 img_data->RotAngle = xvimagesink->rotate_angle;
3109 img_data->VideoMode = xvimagesink->display_mode;
3111 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
3118 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
3119 memcpy (xvimagesink->xvimage->xvimage->data,
3120 GST_BUFFER_DATA (buf),
3121 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
3126 memcpy (xvimagesink->xvimage->xvimage->data,
3127 GST_BUFFER_DATA (buf),
3128 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
3130 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
3139 /* No image available. That's very bad ! */
3140 GST_WARNING_OBJECT (xvimagesink, "could not create image");
3141 return GST_FLOW_ERROR;
3145 /* No Window available to put our image into */
3146 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
3147 return GST_FLOW_ERROR;
3152 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
3154 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
3156 switch (GST_EVENT_TYPE (event)) {
3157 case GST_EVENT_TAG:{
3159 gchar *title = NULL;
3161 gst_event_parse_tag (event, &l);
3162 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
3165 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
3166 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
3176 if (GST_BASE_SINK_CLASS (parent_class)->event)
3177 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
3182 /* Buffer management */
3185 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
3188 GstCaps *intersection;
3192 gint par_n = 1, par_d = 1;
3196 new_caps = gst_caps_copy (caps);
3198 s = gst_caps_get_structure (new_caps, 0);
3200 gst_structure_get_int (s, "width", &width);
3201 gst_structure_get_int (s, "height", &height);
3202 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
3204 gst_structure_remove_field (s, "width");
3205 gst_structure_remove_field (s, "height");
3206 gst_structure_remove_field (s, "pixel-aspect-ratio");
3208 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3209 gst_caps_unref (new_caps);
3211 if (gst_caps_is_empty (intersection))
3212 return intersection;
3214 s = gst_caps_get_structure (intersection, 0);
3216 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
3218 /* xvimagesink supports all PARs */
3220 gst_structure_fixate_field_nearest_int (s, "width", width);
3221 gst_structure_fixate_field_nearest_int (s, "height", height);
3222 gst_structure_get_int (s, "width", &w);
3223 gst_structure_get_int (s, "height", &h);
3225 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
3226 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
3229 return intersection;
3232 static GstFlowReturn
3233 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
3234 GstCaps * caps, GstBuffer ** buf)
3236 GstFlowReturn ret = GST_FLOW_OK;
3237 GstXvImageSink *xvimagesink;
3238 GstXvImageBuffer *xvimage = NULL;
3239 GstCaps *intersection = NULL;
3240 GstStructure *structure = NULL;
3241 gint width, height, image_format;
3243 xvimagesink = GST_XVIMAGESINK (bsink);
3245 if (G_UNLIKELY (!caps))
3248 g_mutex_lock (xvimagesink->pool_lock);
3249 if (G_UNLIKELY (xvimagesink->pool_invalid))
3252 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
3253 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
3254 GST_LOG_OBJECT (xvimagesink,
3255 "buffer alloc for same last_caps, reusing caps");
3256 intersection = gst_caps_ref (caps);
3257 image_format = xvimagesink->xcontext->last_format;
3258 width = xvimagesink->xcontext->last_width;
3259 height = xvimagesink->xcontext->last_height;
3261 goto reuse_last_caps;
3264 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
3265 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
3266 caps, xvimagesink->xcontext->caps);
3268 /* Check the caps against our xcontext */
3269 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
3271 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
3272 GST_PTR_FORMAT, intersection);
3274 if (gst_caps_is_empty (intersection)) {
3277 gst_caps_unref (intersection);
3279 /* So we don't support this kind of buffer, let's define one we'd like */
3280 new_caps = gst_caps_copy (caps);
3282 structure = gst_caps_get_structure (new_caps, 0);
3283 if (!gst_structure_has_field (structure, "width") ||
3284 !gst_structure_has_field (structure, "height")) {
3285 gst_caps_unref (new_caps);
3289 /* Try different dimensions */
3291 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3293 if (gst_caps_is_empty (intersection)) {
3294 /* Try with different YUV formats first */
3295 gst_structure_set_name (structure, "video/x-raw-yuv");
3297 /* Remove format specific fields */
3298 gst_structure_remove_field (structure, "format");
3299 gst_structure_remove_field (structure, "endianness");
3300 gst_structure_remove_field (structure, "depth");
3301 gst_structure_remove_field (structure, "bpp");
3302 gst_structure_remove_field (structure, "red_mask");
3303 gst_structure_remove_field (structure, "green_mask");
3304 gst_structure_remove_field (structure, "blue_mask");
3305 gst_structure_remove_field (structure, "alpha_mask");
3307 /* Reuse intersection with Xcontext */
3308 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3311 if (gst_caps_is_empty (intersection)) {
3312 /* Try with different dimensions and YUV formats */
3314 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3317 if (gst_caps_is_empty (intersection)) {
3318 /* Now try with RGB */
3319 gst_structure_set_name (structure, "video/x-raw-rgb");
3320 /* And interset again */
3321 gst_caps_unref (intersection);
3322 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
3325 if (gst_caps_is_empty (intersection)) {
3326 /* Try with different dimensions and RGB formats */
3328 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
3331 /* Clean this copy */
3332 gst_caps_unref (new_caps);
3334 if (gst_caps_is_empty (intersection))
3338 /* Ensure the returned caps are fixed */
3339 gst_caps_truncate (intersection);
3341 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
3342 GST_PTR_FORMAT, intersection);
3343 if (gst_caps_is_equal (intersection, caps)) {
3344 /* Things work better if we return a buffer with the same caps ptr
3345 * as was asked for when we can */
3346 gst_caps_replace (&intersection, caps);
3349 /* Get image format from caps */
3350 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
3353 /* Get geometry from caps */
3354 structure = gst_caps_get_structure (intersection, 0);
3355 if (!gst_structure_get_int (structure, "width", &width) ||
3356 !gst_structure_get_int (structure, "height", &height) ||
3360 /* Store our caps and format as the last_caps to avoid expensive
3361 * caps intersection next time */
3362 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
3363 xvimagesink->xcontext->last_format = image_format;
3364 xvimagesink->xcontext->last_width = width;
3365 xvimagesink->xcontext->last_height = height;
3369 /* Walking through the pool cleaning unusable images and searching for a
3371 while (xvimagesink->image_pool) {
3372 xvimage = xvimagesink->image_pool->data;
3374 /* Removing from the pool */
3375 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
3376 xvimagesink->image_pool);
3378 /* We check for geometry or image format changes */
3379 if ((xvimage->width != width) ||
3380 (xvimage->height != height) || (xvimage->im_format != image_format)) {
3381 /* This image is unusable. Destroying... */
3382 gst_xvimage_buffer_free (xvimage);
3385 /* We found a suitable image */
3386 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
3393 /* We found no suitable image in the pool. Creating... */
3394 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
3395 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
3397 g_mutex_unlock (xvimagesink->pool_lock);
3400 /* Make sure the buffer is cleared of any previously used flags */
3401 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
3402 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
3405 *buf = GST_BUFFER_CAST (xvimage);
3409 gst_caps_unref (intersection);
3417 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
3418 ret = GST_FLOW_WRONG_STATE;
3419 g_mutex_unlock (xvimagesink->pool_lock);
3424 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
3425 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
3426 " are completely incompatible with those caps", caps,
3427 xvimagesink->xcontext->caps);
3428 ret = GST_FLOW_NOT_NEGOTIATED;
3429 g_mutex_unlock (xvimagesink->pool_lock);
3434 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
3435 GST_PTR_FORMAT, intersection);
3436 ret = GST_FLOW_NOT_NEGOTIATED;
3437 g_mutex_unlock (xvimagesink->pool_lock);
3442 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
3449 /* Interfaces stuff */
3452 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
3454 g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
3455 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE);
3460 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
3462 klass->supported = gst_xvimagesink_interface_supported;
3466 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
3467 GstStructure * structure)
3469 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
3472 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
3474 GstVideoRectangle src, dst, result;
3475 gdouble x, y, xscale = 1.0, yscale = 1.0;
3477 event = gst_event_new_navigation (structure);
3479 /* We take the flow_lock while we look at the window */
3480 g_mutex_lock (xvimagesink->flow_lock);
3482 if (!xvimagesink->xwindow) {
3483 g_mutex_unlock (xvimagesink->flow_lock);
3487 if (xvimagesink->keep_aspect) {
3488 /* We get the frame position using the calculated geometry from _setcaps
3489 that respect pixel aspect ratios */
3490 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
3491 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
3492 dst.w = xvimagesink->render_rect.w;
3493 dst.h = xvimagesink->render_rect.h;
3495 gst_video_sink_center_rect (src, dst, &result, TRUE);
3496 result.x += xvimagesink->render_rect.x;
3497 result.y += xvimagesink->render_rect.y;
3499 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
3502 g_mutex_unlock (xvimagesink->flow_lock);
3504 /* We calculate scaling using the original video frames geometry to include
3505 pixel aspect ratio scaling. */
3506 xscale = (gdouble) xvimagesink->video_width / result.w;
3507 yscale = (gdouble) xvimagesink->video_height / result.h;
3509 /* Converting pointer coordinates to the non scaled geometry */
3510 if (gst_structure_get_double (structure, "pointer_x", &x)) {
3511 x = MIN (x, result.x + result.w);
3512 x = MAX (x - result.x, 0);
3513 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
3514 (gdouble) x * xscale, NULL);
3516 if (gst_structure_get_double (structure, "pointer_y", &y)) {
3517 y = MIN (y, result.y + result.h);
3518 y = MAX (y - result.y, 0);
3519 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
3520 (gdouble) y * yscale, NULL);
3523 gst_pad_send_event (peer, event);
3524 gst_object_unref (peer);
3529 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
3531 iface->send_event = gst_xvimagesink_navigation_send_event;
3535 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
3537 XID xwindow_id = id;
3538 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3539 GstXWindow *xwindow = NULL;
3541 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3543 g_mutex_lock (xvimagesink->flow_lock);
3545 #ifdef GST_EXT_XV_ENHANCEMENT
3546 GST_INFO_OBJECT( xvimagesink, "ENTER, id : %d", xwindow_id );
3549 /* If we already use that window return */
3550 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
3551 g_mutex_unlock (xvimagesink->flow_lock);
3555 /* If the element has not initialized the X11 context try to do so */
3556 if (!xvimagesink->xcontext &&
3557 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
3558 g_mutex_unlock (xvimagesink->flow_lock);
3559 /* we have thrown a GST_ELEMENT_ERROR now */
3563 gst_xvimagesink_update_colorbalance (xvimagesink);
3565 /* Clear image pool as the images are unusable anyway */
3566 gst_xvimagesink_imagepool_clear (xvimagesink);
3568 /* Clear the xvimage */
3569 if (xvimagesink->xvimage) {
3570 gst_xvimage_buffer_free (xvimagesink->xvimage);
3571 xvimagesink->xvimage = NULL;
3574 /* If a window is there already we destroy it */
3575 if (xvimagesink->xwindow) {
3576 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
3577 xvimagesink->xwindow = NULL;
3580 /* If the xid is 0 we go back to an internal window */
3581 if (xwindow_id == 0) {
3582 /* If no width/height caps nego did not happen window will be created
3583 during caps nego then */
3584 #ifdef GST_EXT_XV_ENHANCEMENT
3585 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
3586 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
3588 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
3589 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
3591 gst_xvimagesink_xwindow_new (xvimagesink,
3592 GST_VIDEO_SINK_WIDTH (xvimagesink),
3593 GST_VIDEO_SINK_HEIGHT (xvimagesink));
3596 XWindowAttributes attr;
3598 xwindow = g_new0 (GstXWindow, 1);
3599 xwindow->win = xwindow_id;
3601 /* Set the event we want to receive and create a GC */
3602 g_mutex_lock (xvimagesink->x_lock);
3604 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
3606 xwindow->width = attr.width;
3607 xwindow->height = attr.height;
3608 xwindow->internal = FALSE;
3609 if (!xvimagesink->have_render_rect) {
3610 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3611 xvimagesink->render_rect.w = attr.width;
3612 xvimagesink->render_rect.h = attr.height;
3614 if (xvimagesink->handle_events) {
3615 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
3616 StructureNotifyMask | PointerMotionMask | KeyPressMask |
3620 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
3621 xwindow->win, 0, NULL);
3622 g_mutex_unlock (xvimagesink->x_lock);
3626 xvimagesink->xwindow = xwindow;
3628 g_mutex_unlock (xvimagesink->flow_lock);
3632 gst_xvimagesink_expose (GstXOverlay * overlay)
3634 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3636 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
3637 #ifdef GST_EXT_XV_ENHANCEMENT
3638 GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it");
3639 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
3641 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
3646 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
3647 gboolean handle_events)
3649 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3651 xvimagesink->handle_events = handle_events;
3653 g_mutex_lock (xvimagesink->flow_lock);
3655 if (G_UNLIKELY (!xvimagesink->xwindow)) {
3656 g_mutex_unlock (xvimagesink->flow_lock);
3660 g_mutex_lock (xvimagesink->x_lock);
3662 if (handle_events) {
3663 if (xvimagesink->xwindow->internal) {
3664 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
3665 ExposureMask | StructureNotifyMask | PointerMotionMask |
3666 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
3668 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
3669 ExposureMask | StructureNotifyMask | PointerMotionMask |
3670 KeyPressMask | KeyReleaseMask);
3673 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
3676 g_mutex_unlock (xvimagesink->x_lock);
3678 g_mutex_unlock (xvimagesink->flow_lock);
3682 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
3683 gint width, gint height)
3685 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
3687 /* FIXME: how about some locking? */
3688 if (width >= 0 && height >= 0) {
3689 xvimagesink->render_rect.x = x;
3690 xvimagesink->render_rect.y = y;
3691 xvimagesink->render_rect.w = width;
3692 xvimagesink->render_rect.h = height;
3693 xvimagesink->have_render_rect = TRUE;
3695 xvimagesink->render_rect.x = 0;
3696 xvimagesink->render_rect.y = 0;
3697 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
3698 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
3699 xvimagesink->have_render_rect = FALSE;
3704 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
3706 iface->set_window_handle = gst_xvimagesink_set_window_handle;
3707 iface->expose = gst_xvimagesink_expose;
3708 iface->handle_events = gst_xvimagesink_set_event_handling;
3709 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
3712 static const GList *
3713 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
3715 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3717 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3719 if (xvimagesink->xcontext)
3720 return xvimagesink->xcontext->channels_list;
3726 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
3727 GstColorBalanceChannel * channel, gint value)
3729 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3731 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3732 g_return_if_fail (channel->label != NULL);
3734 xvimagesink->cb_changed = TRUE;
3736 /* Normalize val to [-1000, 1000] */
3737 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
3738 (double) (channel->max_value - channel->min_value));
3740 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3741 xvimagesink->hue = value;
3742 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3743 xvimagesink->saturation = value;
3744 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3745 xvimagesink->contrast = value;
3746 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3747 xvimagesink->brightness = value;
3749 g_warning ("got an unknown channel %s", channel->label);
3753 gst_xvimagesink_update_colorbalance (xvimagesink);
3757 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
3758 GstColorBalanceChannel * channel)
3760 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
3763 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
3764 g_return_val_if_fail (channel->label != NULL, 0);
3766 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3767 value = xvimagesink->hue;
3768 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3769 value = xvimagesink->saturation;
3770 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3771 value = xvimagesink->contrast;
3772 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3773 value = xvimagesink->brightness;
3775 g_warning ("got an unknown channel %s", channel->label);
3778 /* Normalize val to [channel->min_value, channel->max_value] */
3779 value = channel->min_value + (channel->max_value - channel->min_value) *
3780 (value + 1000) / 2000;
3786 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
3788 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
3789 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
3790 iface->set_value = gst_xvimagesink_colorbalance_set_value;
3791 iface->get_value = gst_xvimagesink_colorbalance_get_value;
3794 static const GList *
3795 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
3797 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
3798 static GList *list = NULL;
3801 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
3803 g_list_append (list, g_object_class_find_property (klass,
3804 "autopaint-colorkey"));
3806 g_list_append (list, g_object_class_find_property (klass,
3809 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
3816 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
3817 guint prop_id, const GParamSpec * pspec)
3819 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3823 case PROP_AUTOPAINT_COLORKEY:
3824 case PROP_DOUBLE_BUFFER:
3826 GST_DEBUG_OBJECT (xvimagesink,
3827 "probing device list and get capabilities");
3828 if (!xvimagesink->xcontext) {
3829 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
3830 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
3834 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3840 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
3841 guint prop_id, const GParamSpec * pspec)
3843 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3844 gboolean ret = FALSE;
3848 case PROP_AUTOPAINT_COLORKEY:
3849 case PROP_DOUBLE_BUFFER:
3851 if (xvimagesink->xcontext != NULL) {
3858 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3865 static GValueArray *
3866 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
3867 guint prop_id, const GParamSpec * pspec)
3869 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
3870 GValueArray *array = NULL;
3872 if (G_UNLIKELY (!xvimagesink->xcontext)) {
3873 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
3882 GValue value = { 0 };
3884 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
3885 g_value_init (&value, G_TYPE_STRING);
3887 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
3888 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
3890 g_value_set_string (&value, adaptor_id_s);
3891 g_value_array_append (array, &value);
3892 g_free (adaptor_id_s);
3894 g_value_unset (&value);
3897 case PROP_AUTOPAINT_COLORKEY:
3898 if (xvimagesink->have_autopaint_colorkey) {
3899 GValue value = { 0 };
3901 array = g_value_array_new (2);
3902 g_value_init (&value, G_TYPE_BOOLEAN);
3903 g_value_set_boolean (&value, FALSE);
3904 g_value_array_append (array, &value);
3905 g_value_set_boolean (&value, TRUE);
3906 g_value_array_append (array, &value);
3907 g_value_unset (&value);
3910 case PROP_DOUBLE_BUFFER:
3911 if (xvimagesink->have_double_buffer) {
3912 GValue value = { 0 };
3914 array = g_value_array_new (2);
3915 g_value_init (&value, G_TYPE_BOOLEAN);
3916 g_value_set_boolean (&value, FALSE);
3917 g_value_array_append (array, &value);
3918 g_value_set_boolean (&value, TRUE);
3919 g_value_array_append (array, &value);
3920 g_value_unset (&value);
3924 if (xvimagesink->have_colorkey) {
3925 GValue value = { 0 };
3927 array = g_value_array_new (1);
3928 g_value_init (&value, GST_TYPE_INT_RANGE);
3929 gst_value_set_int_range (&value, 0, 0xffffff);
3930 g_value_array_append (array, &value);
3931 g_value_unset (&value);
3935 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3944 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
3947 iface->get_properties = gst_xvimagesink_probe_get_properties;
3948 iface->probe_property = gst_xvimagesink_probe_probe_property;
3949 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
3950 iface->get_values = gst_xvimagesink_probe_get_values;
3953 /* =========================================== */
3955 /* Init & Class init */
3957 /* =========================================== */
3960 gst_xvimagesink_set_property (GObject * object, guint prop_id,
3961 const GValue * value, GParamSpec * pspec)
3963 GstXvImageSink *xvimagesink;
3965 g_return_if_fail (GST_IS_XVIMAGESINK (object));
3967 xvimagesink = GST_XVIMAGESINK (object);
3971 xvimagesink->hue = g_value_get_int (value);
3972 xvimagesink->cb_changed = TRUE;
3973 gst_xvimagesink_update_colorbalance (xvimagesink);
3976 xvimagesink->contrast = g_value_get_int (value);
3977 xvimagesink->cb_changed = TRUE;
3978 gst_xvimagesink_update_colorbalance (xvimagesink);
3980 case PROP_BRIGHTNESS:
3981 xvimagesink->brightness = g_value_get_int (value);
3982 xvimagesink->cb_changed = TRUE;
3983 gst_xvimagesink_update_colorbalance (xvimagesink);
3985 case PROP_SATURATION:
3986 xvimagesink->saturation = g_value_get_int (value);
3987 xvimagesink->cb_changed = TRUE;
3988 gst_xvimagesink_update_colorbalance (xvimagesink);
3991 xvimagesink->display_name = g_strdup (g_value_get_string (value));
3993 case PROP_SYNCHRONOUS:
3994 xvimagesink->synchronous = g_value_get_boolean (value);
3995 if (xvimagesink->xcontext) {
3996 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
3997 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
3998 xvimagesink->synchronous ? "TRUE" : "FALSE");
4001 case PROP_PIXEL_ASPECT_RATIO:
4002 g_free (xvimagesink->par);
4003 xvimagesink->par = g_new0 (GValue, 1);
4004 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
4005 if (!g_value_transform (value, xvimagesink->par)) {
4006 g_warning ("Could not transform string to aspect ratio");
4007 gst_value_set_fraction (xvimagesink->par, 1, 1);
4009 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
4010 gst_value_get_fraction_numerator (xvimagesink->par),
4011 gst_value_get_fraction_denominator (xvimagesink->par));
4013 case PROP_FORCE_ASPECT_RATIO:
4014 xvimagesink->keep_aspect = g_value_get_boolean (value);
4016 case PROP_HANDLE_EVENTS:
4017 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
4018 g_value_get_boolean (value));
4019 gst_xvimagesink_manage_event_thread (xvimagesink);
4022 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
4024 case PROP_HANDLE_EXPOSE:
4025 xvimagesink->handle_expose = g_value_get_boolean (value);
4026 gst_xvimagesink_manage_event_thread (xvimagesink);
4028 case PROP_DOUBLE_BUFFER:
4029 xvimagesink->double_buffer = g_value_get_boolean (value);
4031 case PROP_AUTOPAINT_COLORKEY:
4032 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
4035 xvimagesink->colorkey = g_value_get_int (value);
4037 case PROP_DRAW_BORDERS:
4038 xvimagesink->draw_borders = g_value_get_boolean (value);
4040 #ifdef GST_EXT_XV_ENHANCEMENT
4041 case PROP_DISPLAY_MODE:
4042 xvimagesink->display_mode = g_value_get_enum (value);
4044 case PROP_DISPLAY_GEOMETRY_METHOD:
4045 xvimagesink->display_geometry_method = g_value_get_enum (value);
4046 GST_LOG("Overlay geometry changed. update it");
4047 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
4049 case PROP_ROTATE_ANGLE:
4050 xvimagesink->rotate_angle = g_value_get_enum (value);
4051 xvimagesink->rotate_changed = TRUE;
4054 g_mutex_lock( xvimagesink->flow_lock );
4055 g_mutex_lock( xvimagesink->x_lock );
4057 if( xvimagesink->visible && ( g_value_get_boolean( value ) == FALSE ) )
4059 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
4060 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
4061 if( atom_stream != None )
4063 if( XvSetPortAttribute( xvimagesink->xcontext->disp,
4064 xvimagesink->xcontext->xv_port_id,
4065 atom_stream, 0 ) != Success )
4067 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
4070 XSync( xvimagesink->xcontext->disp, FALSE );
4073 else if( !xvimagesink->visible && ( g_value_get_boolean( value ) == TRUE ) )
4075 g_mutex_unlock( xvimagesink->x_lock );
4076 g_mutex_unlock( xvimagesink->flow_lock );
4077 GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." );
4078 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
4079 g_mutex_lock( xvimagesink->flow_lock );
4080 g_mutex_lock( xvimagesink->x_lock );
4083 xvimagesink->visible = g_value_get_boolean (value);
4085 g_mutex_unlock( xvimagesink->x_lock );
4086 g_mutex_unlock( xvimagesink->flow_lock );
4089 xvimagesink->zoom = g_value_get_int (value);
4091 case PROP_DST_ROI_X:
4092 xvimagesink->dst_roi.x = g_value_get_int (value);
4094 case PROP_DST_ROI_Y:
4095 xvimagesink->dst_roi.y = g_value_get_int (value);
4097 case PROP_DST_ROI_W:
4098 xvimagesink->dst_roi.w = g_value_get_int (value);
4100 case PROP_DST_ROI_H:
4101 xvimagesink->dst_roi.h = g_value_get_int (value);
4103 case PROP_STOP_VIDEO:
4104 xvimagesink->stop_video = g_value_get_int (value);
4105 g_mutex_lock( xvimagesink->flow_lock );
4107 if( xvimagesink->stop_video )
4109 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
4110 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
4113 g_mutex_unlock( xvimagesink->flow_lock );
4117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4123 gst_xvimagesink_get_property (GObject * object, guint prop_id,
4124 GValue * value, GParamSpec * pspec)
4126 GstXvImageSink *xvimagesink;
4128 g_return_if_fail (GST_IS_XVIMAGESINK (object));
4130 xvimagesink = GST_XVIMAGESINK (object);
4134 g_value_set_int (value, xvimagesink->hue);
4137 g_value_set_int (value, xvimagesink->contrast);
4139 case PROP_BRIGHTNESS:
4140 g_value_set_int (value, xvimagesink->brightness);
4142 case PROP_SATURATION:
4143 g_value_set_int (value, xvimagesink->saturation);
4146 g_value_set_string (value, xvimagesink->display_name);
4148 case PROP_SYNCHRONOUS:
4149 g_value_set_boolean (value, xvimagesink->synchronous);
4151 case PROP_PIXEL_ASPECT_RATIO:
4152 if (xvimagesink->par)
4153 g_value_transform (xvimagesink->par, value);
4155 case PROP_FORCE_ASPECT_RATIO:
4156 g_value_set_boolean (value, xvimagesink->keep_aspect);
4158 case PROP_HANDLE_EVENTS:
4159 g_value_set_boolean (value, xvimagesink->handle_events);
4163 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
4165 g_value_set_string (value, adaptor_no_s);
4166 g_free (adaptor_no_s);
4169 case PROP_DEVICE_NAME:
4170 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
4171 g_value_set_string (value,
4172 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
4174 g_value_set_string (value, NULL);
4177 case PROP_HANDLE_EXPOSE:
4178 g_value_set_boolean (value, xvimagesink->handle_expose);
4180 case PROP_DOUBLE_BUFFER:
4181 g_value_set_boolean (value, xvimagesink->double_buffer);
4183 case PROP_AUTOPAINT_COLORKEY:
4184 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
4187 g_value_set_int (value, xvimagesink->colorkey);
4189 case PROP_DRAW_BORDERS:
4190 g_value_set_boolean (value, xvimagesink->draw_borders);
4192 case PROP_WINDOW_WIDTH:
4193 if (xvimagesink->xwindow)
4194 g_value_set_uint64 (value, xvimagesink->xwindow->width);
4196 g_value_set_uint64 (value, 0);
4198 case PROP_WINDOW_HEIGHT:
4199 if (xvimagesink->xwindow)
4200 g_value_set_uint64 (value, xvimagesink->xwindow->height);
4202 g_value_set_uint64 (value, 0);
4204 #ifdef GST_EXT_XV_ENHANCEMENT
4205 case PROP_DISPLAY_MODE:
4206 g_value_set_enum (value, xvimagesink->display_mode);
4208 case PROP_DISPLAY_GEOMETRY_METHOD:
4209 g_value_set_enum (value, xvimagesink->display_geometry_method);
4211 case PROP_ROTATE_ANGLE:
4212 g_value_set_enum (value, xvimagesink->rotate_angle);
4215 g_value_set_boolean (value, xvimagesink->visible);
4218 g_value_set_int (value, xvimagesink->zoom);
4220 case PROP_DST_ROI_X:
4221 g_value_set_int (value, xvimagesink->dst_roi.x);
4223 case PROP_DST_ROI_Y:
4224 g_value_set_int (value, xvimagesink->dst_roi.y);
4226 case PROP_DST_ROI_W:
4227 g_value_set_int (value, xvimagesink->dst_roi.w);
4229 case PROP_DST_ROI_H:
4230 g_value_set_int (value, xvimagesink->dst_roi.h);
4232 case PROP_STOP_VIDEO:
4233 g_value_set_int (value, xvimagesink->stop_video);
4237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4243 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
4247 GST_OBJECT_LOCK (xvimagesink);
4248 xvimagesink->running = FALSE;
4249 /* grab thread and mark it as NULL */
4250 thread = xvimagesink->event_thread;
4251 xvimagesink->event_thread = NULL;
4252 GST_OBJECT_UNLOCK (xvimagesink);
4254 /* invalidate the pool, current allocations continue, new buffer_alloc fails
4255 * with wrong_state */
4256 g_mutex_lock (xvimagesink->pool_lock);
4257 xvimagesink->pool_invalid = TRUE;
4258 g_mutex_unlock (xvimagesink->pool_lock);
4260 /* Wait for our event thread to finish before we clean up our stuff. */
4262 g_thread_join (thread);
4264 if (xvimagesink->cur_image) {
4265 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
4266 xvimagesink->cur_image = NULL;
4268 if (xvimagesink->xvimage) {
4269 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
4270 xvimagesink->xvimage = NULL;
4273 gst_xvimagesink_imagepool_clear (xvimagesink);
4275 if (xvimagesink->xwindow) {
4276 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
4277 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
4278 xvimagesink->xwindow = NULL;
4281 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
4282 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
4283 xvimagesink->have_render_rect = FALSE;
4285 gst_xvimagesink_xcontext_clear (xvimagesink);
4288 /* Finalize is called only once, dispose can be called multiple times.
4289 * We use mutexes and don't reset stuff to NULL here so let's register
4292 gst_xvimagesink_finalize (GObject * object)
4294 GstXvImageSink *xvimagesink;
4296 xvimagesink = GST_XVIMAGESINK (object);
4298 gst_xvimagesink_reset (xvimagesink);
4300 if (xvimagesink->display_name) {
4301 g_free (xvimagesink->display_name);
4302 xvimagesink->display_name = NULL;
4305 if (xvimagesink->par) {
4306 g_free (xvimagesink->par);
4307 xvimagesink->par = NULL;
4309 if (xvimagesink->x_lock) {
4310 g_mutex_free (xvimagesink->x_lock);
4311 xvimagesink->x_lock = NULL;
4313 if (xvimagesink->flow_lock) {
4314 g_mutex_free (xvimagesink->flow_lock);
4315 xvimagesink->flow_lock = NULL;
4317 if (xvimagesink->pool_lock) {
4318 g_mutex_free (xvimagesink->pool_lock);
4319 xvimagesink->pool_lock = NULL;
4322 g_free (xvimagesink->media_title);
4324 G_OBJECT_CLASS (parent_class)->finalize (object);
4329 gst_xvimagesink_init (GstXvImageSink * xvimagesink)
4331 xvimagesink->display_name = NULL;
4332 xvimagesink->adaptor_no = 0;
4333 xvimagesink->xcontext = NULL;
4334 xvimagesink->xwindow = NULL;
4335 xvimagesink->xvimage = NULL;
4336 xvimagesink->cur_image = NULL;
4338 xvimagesink->hue = xvimagesink->saturation = 0;
4339 xvimagesink->contrast = xvimagesink->brightness = 0;
4340 xvimagesink->cb_changed = FALSE;
4342 xvimagesink->fps_n = 0;
4343 xvimagesink->fps_d = 0;
4344 xvimagesink->video_width = 0;
4345 xvimagesink->video_height = 0;
4347 xvimagesink->x_lock = g_mutex_new ();
4348 xvimagesink->flow_lock = g_mutex_new ();
4350 xvimagesink->image_pool = NULL;
4351 xvimagesink->pool_lock = g_mutex_new ();
4353 xvimagesink->synchronous = FALSE;
4354 xvimagesink->double_buffer = TRUE;
4355 xvimagesink->running = FALSE;
4356 xvimagesink->keep_aspect = FALSE;
4357 xvimagesink->handle_events = TRUE;
4358 xvimagesink->par = NULL;
4359 xvimagesink->handle_expose = TRUE;
4360 xvimagesink->autopaint_colorkey = TRUE;
4362 /* on 16bit displays this becomes r,g,b = 1,2,3
4363 * on 24bit displays this becomes r,g,b = 8,8,16
4364 * as a port atom value
4366 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
4367 xvimagesink->draw_borders = TRUE;
4369 #ifdef GST_EXT_XV_ENHANCEMENT
4370 xvimagesink->display_mode = VIDEO_MODE_LCDONLY;
4371 xvimagesink->rotate_changed = TRUE;
4372 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
4373 xvimagesink->rotate_angle = DEGREE_270;
4374 xvimagesink->visible = TRUE;
4375 xvimagesink->zoom = 1;
4376 xvimagesink->rotation = -1;
4377 xvimagesink->dst_roi.x = 0;
4378 xvimagesink->dst_roi.y = 0;
4379 xvimagesink->dst_roi.w = 0;
4380 xvimagesink->dst_roi.h = 0;
4381 xvimagesink->xim_transparenter = NULL;
4382 xvimagesink->scr_w = 0;
4383 xvimagesink->scr_h = 0;
4384 xvimagesink->aligned_width = 0;
4385 xvimagesink->aligned_height = 0;
4386 xvimagesink->stop_video = FALSE;
4387 xvimagesink->is_hided = FALSE;
4392 gst_xvimagesink_base_init (gpointer g_class)
4394 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
4396 gst_element_class_set_details_simple (element_class,
4397 "Video sink", "Sink/Video",
4398 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
4400 gst_element_class_add_pad_template (element_class,
4401 gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory));
4405 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
4407 GObjectClass *gobject_class;
4408 GstElementClass *gstelement_class;
4409 GstBaseSinkClass *gstbasesink_class;
4410 GstVideoSinkClass *videosink_class;
4412 gobject_class = (GObjectClass *) klass;
4413 gstelement_class = (GstElementClass *) klass;
4414 gstbasesink_class = (GstBaseSinkClass *) klass;
4415 videosink_class = (GstVideoSinkClass *) klass;
4417 parent_class = g_type_class_peek_parent (klass);
4419 gobject_class->set_property = gst_xvimagesink_set_property;
4420 gobject_class->get_property = gst_xvimagesink_get_property;
4422 g_object_class_install_property (gobject_class, PROP_CONTRAST,
4423 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
4424 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4425 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
4426 g_param_spec_int ("brightness", "Brightness",
4427 "The brightness of the video", -1000, 1000, 0,
4428 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4429 g_object_class_install_property (gobject_class, PROP_HUE,
4430 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
4431 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4432 g_object_class_install_property (gobject_class, PROP_SATURATION,
4433 g_param_spec_int ("saturation", "Saturation",
4434 "The saturation of the video", -1000, 1000, 0,
4435 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4436 g_object_class_install_property (gobject_class, PROP_DISPLAY,
4437 g_param_spec_string ("display", "Display", "X Display name", NULL,
4438 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4439 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
4440 g_param_spec_boolean ("synchronous", "Synchronous",
4441 "When enabled, runs "
4442 "the X display in synchronous mode. (used only for debugging)", FALSE,
4443 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4444 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
4445 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
4446 "The pixel aspect ratio of the device", "1/1",
4447 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4448 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
4449 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
4450 "When enabled, scaling will respect original aspect ratio", FALSE,
4451 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4452 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
4453 g_param_spec_boolean ("handle-events", "Handle XEvents",
4454 "When enabled, XEvents will be selected and handled", TRUE,
4455 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4456 g_object_class_install_property (gobject_class, PROP_DEVICE,
4457 g_param_spec_string ("device", "Adaptor number",
4458 "The number of the video adaptor", "0",
4459 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4460 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
4461 g_param_spec_string ("device-name", "Adaptor name",
4462 "The name of the video adaptor", NULL,
4463 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4465 * GstXvImageSink:handle-expose
4467 * When enabled, the current frame will always be drawn in response to X
4472 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
4473 g_param_spec_boolean ("handle-expose", "Handle expose",
4475 "the current frame will always be drawn in response to X Expose "
4476 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4479 * GstXvImageSink:double-buffer
4481 * Whether to double-buffer the output.
4485 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
4486 g_param_spec_boolean ("double-buffer", "Double-buffer",
4487 "Whether to double-buffer the output", TRUE,
4488 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4490 * GstXvImageSink:autopaint-colorkey
4492 * Whether to autofill overlay with colorkey
4496 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
4497 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
4498 "Whether to autofill overlay with colorkey", TRUE,
4499 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4501 * GstXvImageSink:colorkey
4503 * Color to use for the overlay mask.
4507 g_object_class_install_property (gobject_class, PROP_COLORKEY,
4508 g_param_spec_int ("colorkey", "Colorkey",
4509 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
4510 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4513 * GstXvImageSink:draw-borders
4515 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
4516 * unused parts of the video area.
4520 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
4521 g_param_spec_boolean ("draw-borders", "Colorkey",
4522 "Draw black borders to fill unused area in force-aspect-ratio mode",
4523 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4526 * GstXvImageSink:window-width
4528 * Actual width of the video window.
4532 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
4533 g_param_spec_uint64 ("window-width", "window-width",
4534 "Width of the window", 0, G_MAXUINT64, 0,
4535 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4538 * GstXvImageSink:window-height
4540 * Actual height of the video window.
4544 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
4545 g_param_spec_uint64 ("window-height", "window-height",
4546 "Height of the window", 0, G_MAXUINT64, 0,
4547 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4549 #ifdef GST_EXT_XV_ENHANCEMENT
4551 * GstXvImageSink:display-mode
4553 * select display mode
4555 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
4556 g_param_spec_enum("display-mode", "Display Mode",
4557 "Display device setting",
4558 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, VIDEO_MODE_LCDONLY,
4559 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4562 * GstXvImageSink:display-geometry-method
4564 * Display geometrical method setting
4566 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
4567 g_param_spec_enum("display-geometry-method", "Display geometry method",
4568 "Geometrical method for display",
4569 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
4570 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4573 * GstXvImageSink:rotate
4575 * Draw rotation angle setting
4577 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
4578 g_param_spec_enum("rotate", "Rotate angle",
4579 "Rotate angle of display output",
4580 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
4581 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4584 * GstXvImageSink:visible
4586 * Whether reserve original src size or not
4588 g_object_class_install_property (gobject_class, PROP_VISIBLE,
4589 g_param_spec_boolean ("visible", "Visible",
4590 "Draws screen or blacks out, true means visible, false blacks out",
4591 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4594 * GstXvImageSink:zoom
4596 * Scale small area of screen to 2X, 3X, ... , 9X
4598 g_object_class_install_property (gobject_class, PROP_ZOOM,
4599 g_param_spec_int ("zoom", "Zoom",
4600 "Zooms screen as nX", 1, 9, 1,
4601 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4604 * GstXvImageSink:dst-roi-x
4606 * X value of Destination ROI
4608 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
4609 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
4610 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
4611 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4614 * GstXvImageSink:dst-roi-y
4616 * Y value of Destination ROI
4618 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
4619 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
4620 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
4621 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4624 * GstXvImageSink:dst-roi-w
4626 * W value of Destination ROI
4628 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
4629 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
4630 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
4631 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4634 * GstXvImageSink:dst-roi-h
4636 * H value of Destination ROI
4638 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
4639 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
4640 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
4641 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4644 * GstXvImageSink:stop-video
4646 * Stop video for releasing video source buffer
4648 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
4649 g_param_spec_int ("stop-video", "Stop-Video",
4650 "Stop video for releasing video source buffer", 0, 1, 0,
4651 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4654 gobject_class->finalize = gst_xvimagesink_finalize;
4656 gstelement_class->change_state =
4657 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
4659 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
4660 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
4661 gstbasesink_class->buffer_alloc =
4662 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
4663 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
4664 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
4666 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
4669 /* ============================================================= */
4671 /* Public Methods */
4673 /* ============================================================= */
4675 /* =========================================== */
4677 /* Object typing & Creation */
4679 /* =========================================== */
4682 gst_xvimagesink_get_type (void)
4684 static GType xvimagesink_type = 0;
4686 if (!xvimagesink_type) {
4687 static const GTypeInfo xvimagesink_info = {
4688 sizeof (GstXvImageSinkClass),
4689 gst_xvimagesink_base_init,
4691 (GClassInitFunc) gst_xvimagesink_class_init,
4694 sizeof (GstXvImageSink),
4696 (GInstanceInitFunc) gst_xvimagesink_init,
4698 static const GInterfaceInfo iface_info = {
4699 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
4703 static const GInterfaceInfo navigation_info = {
4704 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
4708 static const GInterfaceInfo overlay_info = {
4709 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
4713 static const GInterfaceInfo colorbalance_info = {
4714 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
4718 static const GInterfaceInfo propertyprobe_info = {
4719 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
4723 xvimagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
4724 "GstXvImageSink", &xvimagesink_info, 0);
4726 g_type_add_interface_static (xvimagesink_type,
4727 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
4728 g_type_add_interface_static (xvimagesink_type, GST_TYPE_NAVIGATION,
4730 g_type_add_interface_static (xvimagesink_type, GST_TYPE_X_OVERLAY,
4732 g_type_add_interface_static (xvimagesink_type, GST_TYPE_COLOR_BALANCE,
4733 &colorbalance_info);
4734 g_type_add_interface_static (xvimagesink_type, GST_TYPE_PROPERTY_PROBE,
4735 &propertyprobe_info);
4738 /* register type and create class in a more safe place instead of at
4739 * runtime since the type registration and class creation is not
4741 g_type_class_ref (gst_xvimage_buffer_get_type ());
4744 return xvimagesink_type;
4748 plugin_init (GstPlugin * plugin)
4750 if (!gst_element_register (plugin, "xvimagesink",
4751 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
4754 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
4755 "xvimagesink element");
4756 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
4761 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
4764 "XFree86 video output plugin using Xv extension",
4765 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)