2 * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3 * <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
4 * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * * Modifications by Samsung Electronics Co., Ltd.
22 * 1. Add display related properties
23 * 2. Support samsung extension format to improve performance
24 * 3. Support video texture overlay of OSP layer
28 * SECTION:element-xvimagesink
30 * XvImageSink renders video frames to a drawable (XWindow) on a local display
31 * using the XVideo extension. Rendering to a remote display is theoretically
32 * possible but i doubt that the XVideo extension is actually available when
33 * connecting to a remote display. This element can receive a Window ID from the
34 * application through the XOverlay interface and will then render video frames
35 * in this drawable. If no Window ID was provided by the application, the
36 * element will create its own internal window and render into it.
39 * <title>Scaling</title>
41 * The XVideo extension, when it's available, handles hardware accelerated
42 * scaling of video frames. This means that the element will just accept
43 * incoming video frames no matter their geometry and will then put them to the
44 * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
45 * property it is possible to enforce scaling with a constant aspect ratio,
46 * which means drawing black borders around the video frame.
50 * <title>Events</title>
52 * XvImageSink creates a thread to handle events coming from the drawable. There
53 * are several kind of events that can be grouped in 2 big categories: input
54 * events and window state related events. Input events will be translated to
55 * navigation events and pushed upstream for other elements to react on them.
56 * This includes events such as pointer moves, key press/release, clicks etc...
57 * Other events are used to handle the drawable appearance even when the data
58 * is not flowing (GST_STATE_PAUSED). That means that even when the element is
59 * paused, it will receive expose events from the drawable and draw the latest
60 * frame with correct borders/aspect-ratio.
64 * <title>Pixel aspect ratio</title>
66 * When changing state to GST_STATE_READY, XvImageSink will open a connection to
67 * the display specified in the #GstXvImageSink:display property or the
68 * default display if nothing specified. Once this connection is open it will
69 * inspect the display configuration including the physical display geometry and
70 * then calculate the pixel aspect ratio. When receiving video frames with a
71 * different pixel aspect ratio, XvImageSink will use hardware scaling to
72 * display the video frames correctly on display's pixel aspect ratio.
73 * Sometimes the calculated pixel aspect ratio can be wrong, it is
74 * then possible to enforce a specific pixel aspect ratio using the
75 * #GstXvImageSink:pixel-aspect-ratio property.
79 * <title>Examples</title>
81 * gst-launch -v videotestsrc ! xvimagesink
82 * ]| A pipeline to test hardware scaling.
83 * When the test video signal appears you can resize the window and see that
84 * video frames are scaled through hardware (no extra CPU cost).
86 * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
87 * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
88 * You can observe the borders drawn around the scaled image respecting aspect
91 * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
92 * ]| A pipeline to test navigation events.
93 * While moving the mouse pointer over the test signal you will see a black box
94 * following the mouse pointer. If you press the mouse button somewhere on the
95 * video and release it somewhere else a green box will appear where you pressed
96 * the button and a red one where you released it. (The navigationtest element
97 * is part of gst-plugins-good.) You can observe here that even if the images
98 * are scaled through hardware the pointer coordinates are converted back to the
99 * original video frame geometry so that the box can be drawn to the correct
100 * position. This also handles borders correctly, limiting coordinates to the
103 * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
104 * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
105 * videotestsrc, in most cases the pixel aspect ratio of the display will be
106 * 1/1. This means that XvImageSink will have to do the scaling to convert
107 * incoming frames to a size that will match the display pixel aspect ratio
108 * (from 320x240 to 320x180 in this case). Note that you might have to escape
109 * some characters for your shell like '\(fraction\)'.
111 * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
112 * ]| Demonstrates how to use the colorbalance interface.
116 /* for developers: there are two useful tools : xvinfo and xvattr */
123 #include <gst/interfaces/navigation.h>
124 #include <gst/interfaces/xoverlay.h>
125 #include <gst/interfaces/colorbalance.h>
126 #include <gst/interfaces/propertyprobe.h>
127 /* Helper functions */
128 #include <gst/video/video.h>
131 #include "xvimagesink.h"
133 #ifdef GST_EXT_XV_ENHANCEMENT
134 /* Samsung extension headers */
135 /* For xv extension header for buffer transfer (output) */
136 #include "xv_types.h"
138 /* headers for drm */
139 #include <sys/stat.h>
140 #include <sys/ioctl.h>
144 #include <xf86drmMode.h>
146 #include <dri2/dri2.h>
147 #include <tbm_bufmgr.h>
149 /* for performance checking */
153 SECURE_PATH_INIT = -1,
164 BUF_SHARE_METHOD_PADDR = 0,
166 BUF_SHARE_METHOD_TIZEN_BUFFER,
167 BUF_SHARE_METHOD_FLUSH_BUFFER
168 } buf_share_method_t;
170 #define _CHECK_DISPLAYED_BUFFER_COUNT 15
171 #define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */
173 /* max channel count *********************************************************/
174 #define SCMN_IMGB_MAX_PLANE (4)
176 /* image buffer definition ***************************************************
178 +------------------------------------------+ ---
181 | +---------------------------+ --- | |
183 | |<---------- w[] ---------->| | | |
191 | +---------------------------+ --- | |
193 +------------------------------------------+ ---
195 |<----------------- s[] ------------------>|
200 /* width of each image plane */
201 int w[SCMN_IMGB_MAX_PLANE];
202 /* height of each image plane */
203 int h[SCMN_IMGB_MAX_PLANE];
204 /* stride of each image plane */
205 int s[SCMN_IMGB_MAX_PLANE];
206 /* elevation of each image plane */
207 int e[SCMN_IMGB_MAX_PLANE];
208 /* user space address of each image plane */
209 void *a[SCMN_IMGB_MAX_PLANE];
210 /* physical address of each image plane, if needs */
211 void *p[SCMN_IMGB_MAX_PLANE];
212 /* color space type of image */
214 /* left postion, if needs */
216 /* top position, if needs */
218 /* to align memory */
223 int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
224 /* buffer share method */
225 int buf_share_method;
226 /* Y plane size in case of ST12 */
228 /* UV plane size in case of ST12 */
230 /* Tizen buffer object */
231 void *bo[SCMN_IMGB_MAX_PLANE];
236 /* TZ memory buffer */
240 static void _release_flush_buffer(GstXvImageSink *xvimagesink);
241 static void _remove_last_buffer(GstXvImageSink *xvimagesink);
242 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink);
243 #endif /* GST_EXT_XV_ENHANCEMENT */
245 /* Debugging category */
246 #include <gst/gstinfo.h>
248 #include "gst/glib-compat-private.h"
250 GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
251 #define GST_CAT_DEFAULT gst_debug_xvimagesink
252 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
254 #ifdef GST_EXT_XV_ENHANCEMENT
255 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
256 #define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
259 gst_xvimagesink_display_mode_get_type(void)
261 static GType xvimagesink_display_mode_type = 0;
262 static const GEnumValue display_mode_type[] = {
263 { 0, "Default mode", "DEFAULT"},
264 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
265 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
269 if (!xvimagesink_display_mode_type) {
270 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
273 return xvimagesink_display_mode_type;
277 gst_xvimagesink_csc_range_get_type(void)
279 static GType xvimagesink_csc_range_type = 0;
280 static const GEnumValue csc_range_type[] = {
281 { 0, "Narrow range", "NARROW"},
282 { 1, "Wide range", "WIDE"},
286 if (!xvimagesink_csc_range_type) {
287 xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
290 return xvimagesink_csc_range_type;
301 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
304 gst_xvimagesink_rotate_angle_get_type(void)
306 static GType xvimagesink_rotate_angle_type = 0;
307 static const GEnumValue rotate_angle_type[] = {
308 { 0, "No rotate", "DEGREE_0"},
309 { 1, "Rotate 90 degree", "DEGREE_90"},
310 { 2, "Rotate 180 degree", "DEGREE_180"},
311 { 3, "Rotate 270 degree", "DEGREE_270"},
315 if (!xvimagesink_rotate_angle_type) {
316 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
319 return xvimagesink_rotate_angle_type;
323 DISP_GEO_METHOD_LETTER_BOX = 0,
324 DISP_GEO_METHOD_ORIGIN_SIZE,
325 DISP_GEO_METHOD_FULL_SCREEN,
326 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
327 DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
328 DISP_GEO_METHOD_CUSTOM_DST_ROI,
333 ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
334 ROI_DISP_GEO_METHOD_LETTER_BOX,
335 ROI_DISP_GEO_METHOD_NUM,
338 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
339 #define DEF_ROI_DISPLAY_GEOMETRY_METHOD ROI_DISP_GEO_METHOD_FULL_SCREEN
348 #define DEF_DISPLAY_FLIP FLIP_NONE
350 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
351 #define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
352 #define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type())
355 gst_xvimagesink_display_geometry_method_get_type(void)
357 static GType xvimagesink_display_geometry_method_type = 0;
358 static const GEnumValue display_geometry_method_type[] = {
359 { 0, "Letter box", "LETTER_BOX"},
360 { 1, "Origin size", "ORIGIN_SIZE"},
361 { 2, "Full-screen", "FULL_SCREEN"},
362 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
363 { 4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"},
364 { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
368 if (!xvimagesink_display_geometry_method_type) {
369 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
372 return xvimagesink_display_geometry_method_type;
376 gst_xvimagesink_roi_display_geometry_method_get_type(void)
378 static GType xvimagesink_roi_display_geometry_method_type = 0;
379 static const GEnumValue roi_display_geometry_method_type[] = {
380 { 0, "ROI-Full-screen", "FULL_SCREEN"},
381 { 1, "ROI-Letter box", "LETTER_BOX"},
385 if (!xvimagesink_roi_display_geometry_method_type) {
386 xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
389 return xvimagesink_roi_display_geometry_method_type;
393 gst_xvimagesink_flip_get_type(void)
395 static GType xvimagesink_flip_type = 0;
396 static const GEnumValue flip_type[] = {
397 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
398 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
399 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
400 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
401 { FLIP_NUM, NULL, NULL},
404 if (!xvimagesink_flip_type) {
405 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
408 return xvimagesink_flip_type;
411 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
413 gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure,
414 GValue *return_value G_GNUC_UNUSED,
415 guint n_param_values,
416 const GValue *param_values,
417 gpointer invocation_hint G_GNUC_UNUSED,
418 gpointer marshal_data)
420 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
423 register GMarshalFunc_BOOLEAN__POINTER callback;
424 register GCClosure *cc = (GCClosure*) closure;
425 register gpointer data1, data2;
429 g_return_if_fail (return_value != NULL);
430 g_return_if_fail (n_param_values == 2);
432 if (G_CCLOSURE_SWAP_DATA (closure)) {
433 data1 = closure->data;
434 data2 = g_value_peek_pointer (param_values + 0);
436 data1 = g_value_peek_pointer (param_values + 0);
437 data2 = closure->data;
439 callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
441 v_return = callback (data1,
442 g_marshal_value_peek_pointer (param_values + 1),
445 g_value_set_boolean (return_value, v_return);
450 SIGNAL_FRAME_RENDER_ERROR,
453 static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
455 #endif /* GST_EXT_XV_ENHANCEMENT */
460 unsigned long functions;
461 unsigned long decorations;
463 unsigned long status;
465 MotifWmHints, MwmHints;
467 #define MWM_HINTS_DECORATIONS (1L << 1)
469 #ifdef GST_EXT_XV_ENHANCEMENT
470 #define MAX_DISPLAY_IN_XVIMAGESINK 20
471 static Display *g_display_id[MAX_DISPLAY_IN_XVIMAGESINK] = {0};
474 static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
476 static GstBufferClass *xvimage_buffer_parent_class = NULL;
477 static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
479 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
481 static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
483 static void gst_xvimagesink_expose (GstXOverlay * overlay);
485 #ifdef GST_EXT_XV_ENHANCEMENT
486 static XImage *make_transparent_image(Display *d, Window win, int w, int h);
487 static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
488 static gboolean set_csc_range(GstXContext *xcontext, int set_range);
489 static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
490 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
491 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
492 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
493 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
494 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
495 #endif /* GST_EXT_XV_ENHANCEMENT */
497 /* Default template - initiated with class struct to allow gst-register to work
499 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
500 GST_STATIC_PAD_TEMPLATE ("sink",
503 GST_STATIC_CAPS ("video/x-raw-rgb, "
504 "framerate = (fraction) [ 0, MAX ], "
505 "width = (int) [ 1, MAX ], "
506 "height = (int) [ 1, MAX ]; "
508 "framerate = (fraction) [ 0, MAX ], "
509 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
521 PROP_PIXEL_ASPECT_RATIO,
522 PROP_FORCE_ASPECT_RATIO,
528 PROP_AUTOPAINT_COLORKEY,
533 #ifdef GST_EXT_XV_ENHANCEMENT
538 PROP_DISPLAY_GEOMETRY_METHOD,
544 PROP_DST_ROI_ORIENTATION,
555 PROP_PIXMAP_CB_USER_DATA,
556 PROP_ENABLE_FLUSH_BUFFER,
558 #endif /* GST_EXT_XV_ENHANCEMENT */
561 static void gst_xvimagesink_init_interfaces (GType type);
563 GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
564 GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
567 /* ============================================================= */
569 /* Private Methods */
571 /* ============================================================= */
573 /* xvimage buffers */
575 #define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
577 #define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
578 #define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
579 #define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
581 /* This function destroys a GstXvImage handling XShm availability */
583 gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
585 GstXvImageSink *xvimagesink;
587 GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
589 xvimagesink = xvimage->xvimagesink;
590 if (G_UNLIKELY (xvimagesink == NULL))
593 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
595 GST_OBJECT_LOCK (xvimagesink);
597 /* If the destroyed image is the current one we destroy our reference too */
598 if (xvimagesink->cur_image == xvimage)
599 xvimagesink->cur_image = NULL;
601 /* We might have some buffers destroyed after changing state to NULL */
602 if (xvimagesink->xcontext == NULL) {
603 GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
605 /* Need to free the shared memory segment even if the x context
606 * was already cleaned up */
607 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
608 shmdt (xvimage->SHMInfo.shmaddr);
614 g_mutex_lock (xvimagesink->x_lock);
617 if (xvimagesink->xcontext->use_xshm) {
618 if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
619 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
620 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
621 XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
622 XSync (xvimagesink->xcontext->disp, FALSE);
624 shmdt (xvimage->SHMInfo.shmaddr);
626 if (xvimage->xvimage)
627 XFree (xvimage->xvimage);
629 #endif /* HAVE_XSHM */
631 if (xvimage->xvimage) {
632 if (xvimage->xvimage->data) {
633 g_free (xvimage->xvimage->data);
635 XFree (xvimage->xvimage);
639 XSync (xvimagesink->xcontext->disp, FALSE);
641 g_mutex_unlock (xvimagesink->x_lock);
644 GST_OBJECT_UNLOCK (xvimagesink);
645 xvimage->xvimagesink = NULL;
646 gst_object_unref (xvimagesink);
648 GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
655 GST_WARNING ("no sink found");
661 gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
663 GstXvImageSink *xvimagesink;
666 xvimagesink = xvimage->xvimagesink;
667 if (G_UNLIKELY (xvimagesink == NULL))
670 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
672 GST_OBJECT_LOCK (xvimagesink);
673 running = xvimagesink->running;
674 GST_OBJECT_UNLOCK (xvimagesink);
676 /* If our geometry changed we can't reuse that image. */
677 if (running == FALSE) {
678 GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
679 gst_xvimage_buffer_destroy (xvimage);
680 } else if ((xvimage->width != xvimagesink->video_width) ||
681 (xvimage->height != xvimagesink->video_height)) {
682 GST_LOG_OBJECT (xvimage,
683 "destroy image as its size changed %dx%d vs current %dx%d",
684 xvimage->width, xvimage->height,
685 xvimagesink->video_width, xvimagesink->video_height);
686 gst_xvimage_buffer_destroy (xvimage);
688 /* In that case we can reuse the image and add it to our image pool. */
689 GST_LOG_OBJECT (xvimage, "recycling image in pool");
690 /* need to increment the refcount again to recycle */
691 gst_buffer_ref (GST_BUFFER_CAST (xvimage));
692 g_mutex_lock (xvimagesink->pool_lock);
693 xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
695 g_mutex_unlock (xvimagesink->pool_lock);
701 GST_WARNING ("no sink found");
707 gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
709 /* make sure it is not recycled */
711 xvimage->height = -1;
712 gst_buffer_unref (GST_BUFFER (xvimage));
716 gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
719 xvimage->SHMInfo.shmaddr = ((void *) -1);
720 xvimage->SHMInfo.shmid = -1;
725 gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
727 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
729 xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
731 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
732 gst_xvimage_buffer_finalize;
736 gst_xvimage_buffer_get_type (void)
738 static GType _gst_xvimage_buffer_type;
740 if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
741 static const GTypeInfo xvimage_buffer_info = {
742 sizeof (GstBufferClass),
745 gst_xvimage_buffer_class_init,
748 sizeof (GstXvImageBuffer),
750 (GInstanceInitFunc) gst_xvimage_buffer_init,
753 _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
754 "GstXvImageBuffer", &xvimage_buffer_info, 0);
756 return _gst_xvimage_buffer_type;
761 static gboolean error_caught = FALSE;
764 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
766 char error_msg[1024];
768 XGetErrorText (display, xevent->error_code, error_msg, 1024);
769 #ifndef GST_EXT_XV_ENHANCEMENT
770 GST_DEBUG ("xvimagesink triggered an XError. error: %s, display(%p)", error_msg, display);
774 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
775 if (g_display_id[i] == display) {
776 GST_ERROR ("xvimagesink triggered an XError. error: %s, display(%p), xevent->request_code: %d", error_msg, display, xevent->request_code);
781 if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
782 GST_ERROR ("xvimagesink triggered an XError. error: %s, xevent->request_code: %d, but the display(%p) was not created in xvimagesink, skip it...", error_msg, xevent->request_code, display);
790 /* This function checks that it is actually really possible to create an image
793 gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
796 XShmSegmentInfo SHMInfo;
798 int (*handler) (Display *, XErrorEvent *);
799 gboolean result = FALSE;
800 gboolean did_attach = FALSE;
802 g_return_val_if_fail (xcontext != NULL, FALSE);
804 /* Sync to ensure any older errors are already processed */
805 XSync (xcontext->disp, FALSE);
807 /* Set defaults so we don't free these later unnecessarily */
808 SHMInfo.shmaddr = ((void *) -1);
811 /* Setting an error handler to catch failure */
812 error_caught = FALSE;
813 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
815 /* Trying to create a 1x1 picture */
816 GST_DEBUG ("XvShmCreateImage of 1x1");
817 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
818 xcontext->im_format, NULL, 1, 1, &SHMInfo);
820 /* Might cause an error, sync to ensure it is noticed */
821 XSync (xcontext->disp, FALSE);
822 if (!xvimage || error_caught) {
823 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
826 size = xvimage->data_size;
828 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
829 if (SHMInfo.shmid == -1) {
830 GST_WARNING ("could not get shared memory of %d bytes", size);
831 GST_ERROR("Failed to shmget: %s", g_strerror (errno));
835 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
836 if (SHMInfo.shmaddr == ((void *) -1)) {
837 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
838 /* Clean up the shared memory segment */
839 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
843 xvimage->data = SHMInfo.shmaddr;
844 SHMInfo.readOnly = FALSE;
846 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
847 GST_WARNING ("Failed to XShmAttach");
848 /* Clean up the shared memory segment */
849 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
853 /* Sync to ensure we see any errors we caused */
854 XSync (xcontext->disp, FALSE);
856 /* Delete the shared memory segment as soon as everyone is attached.
857 * This way, it will be deleted as soon as we detach later, and not
858 * leaked if we crash. */
859 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
862 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
866 /* store whether we succeeded in result */
869 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
870 "Not using shared memory.");
874 /* Sync to ensure we swallow any errors we caused and reset error_caught */
875 XSync (xcontext->disp, FALSE);
877 error_caught = FALSE;
878 XSetErrorHandler (handler);
881 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
882 SHMInfo.shmid, SHMInfo.shmseg);
883 XShmDetach (xcontext->disp, &SHMInfo);
884 XSync (xcontext->disp, FALSE);
886 if (SHMInfo.shmaddr != ((void *) -1))
887 shmdt (SHMInfo.shmaddr);
892 #endif /* HAVE_XSHM */
894 /* This function handles GstXvImage creation depending on XShm availability */
895 static GstXvImageBuffer *
896 gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
898 GstXvImageBuffer *xvimage = NULL;
899 GstStructure *structure = NULL;
900 gboolean succeeded = FALSE;
901 int (*handler) (Display *, XErrorEvent *);
903 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
908 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
909 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
911 structure = gst_caps_get_structure (caps, 0);
913 if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
914 !gst_structure_get_int (structure, "height", &xvimage->height)) {
915 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
918 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
920 #ifdef GST_EXT_XV_ENHANCEMENT
921 GST_LOG_OBJECT(xvimagesink, "aligned size %dx%d",
922 xvimagesink->aligned_width, xvimagesink->aligned_height);
923 if (xvimagesink->aligned_width == 0 || xvimagesink->aligned_height == 0) {
924 GST_INFO_OBJECT(xvimagesink, "aligned size is zero. set size of caps.");
925 xvimagesink->aligned_width = xvimage->width;
926 xvimagesink->aligned_height = xvimage->height;
928 #endif /* GST_EXT_XV_ENHANCEMENT */
930 xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
931 if (xvimage->im_format == -1) {
932 GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
933 GST_PTR_FORMAT, caps);
934 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
935 ("Failed to create output image buffer of %dx%d pixels",
936 xvimage->width, xvimage->height), ("Invalid input caps"));
939 xvimage->xvimagesink = gst_object_ref (xvimagesink);
941 g_mutex_lock (xvimagesink->x_lock);
943 #ifdef GST_EXT_XV_ENHANCEMENT
944 XSync (xvimagesink->xcontext->disp, FALSE);
945 #endif /* GST_EXT_XV_ENHANCEMENT */
946 /* Setting an error handler to catch failure */
947 error_caught = FALSE;
948 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
951 if (xvimagesink->xcontext->use_xshm) {
954 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
955 xvimagesink->xcontext->xv_port_id,
956 xvimage->im_format, NULL,
957 #ifdef GST_EXT_XV_ENHANCEMENT
958 xvimagesink->aligned_width, xvimagesink->aligned_height, &xvimage->SHMInfo);
959 #else /* GST_EXT_XV_ENHANCEMENT */
960 xvimage->width, xvimage->height, &xvimage->SHMInfo);
961 #endif /* GST_EXT_XV_ENHANCEMENT */
962 if (!xvimage->xvimage || error_caught) {
963 g_mutex_unlock (xvimagesink->x_lock);
965 /* Reset error flag */
966 error_caught = FALSE;
969 GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
970 ("Failed to create output image buffer of %dx%d pixels",
971 xvimage->width, xvimage->height),
972 ("could not XvShmCreateImage a %dx%d image",
973 xvimage->width, xvimage->height));
975 #ifdef GST_EXT_XV_ENHANCEMENT
976 /* must not change "use_xshm",
977 because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
979 #else /* GST_EXT_XV_ENHANCEMENT */
980 /* Retry without XShm */
981 xvimagesink->xcontext->use_xshm = FALSE;
983 /* Hold X mutex again to try without XShm */
984 g_mutex_lock (xvimagesink->x_lock);
986 #endif /* GST_EXT_XV_ENHANCEMENT */
989 /* we have to use the returned data_size for our shm size */
990 xvimage->size = xvimage->xvimage->data_size;
991 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
994 /* calculate the expected size. This is only for sanity checking the
995 * number we get from X. */
996 switch (xvimage->im_format) {
997 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
998 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
1005 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
1006 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
1007 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
1009 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
1010 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
1013 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
1015 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1016 GST_DEBUG_OBJECT (xvimagesink,
1017 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
1018 plane, pitches[plane], offsets[plane]);
1022 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
1023 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
1024 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
1027 #ifdef GST_EXT_XV_ENHANCEMENT
1028 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
1029 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
1030 case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
1031 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
1032 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
1033 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
1034 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
1035 expected_size = sizeof(SCMN_IMGB);
1037 #endif /* GST_EXT_XV_ENHANCEMENT */
1042 if (expected_size != 0 && xvimage->size != expected_size) {
1043 GST_WARNING_OBJECT (xvimagesink,
1044 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
1045 xvimage->size, expected_size);
1048 /* Be verbose about our XvImage stride */
1052 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1053 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
1054 "offset of %d", plane, xvimage->xvimage->pitches[plane],
1055 xvimage->xvimage->offsets[plane]);
1059 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
1061 if (xvimage->SHMInfo.shmid == -1) {
1062 g_mutex_unlock (xvimagesink->x_lock);
1063 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1064 ("Failed to create output image buffer of %dx%d pixels",
1065 xvimage->width, xvimage->height),
1066 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1068 GST_ERROR_OBJECT(xvimagesink, "Failed to shmget: %s", g_strerror (errno));
1069 goto beach_unlocked;
1072 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1073 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1074 g_mutex_unlock (xvimagesink->x_lock);
1075 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1076 ("Failed to create output image buffer of %dx%d pixels",
1077 xvimage->width, xvimage->height),
1078 ("Failed to shmat: %s", g_strerror (errno)));
1079 /* Clean up the shared memory segment */
1080 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1081 goto beach_unlocked;
1084 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1085 xvimage->SHMInfo.readOnly = FALSE;
1087 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1088 /* Clean up the shared memory segment */
1089 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1091 g_mutex_unlock (xvimagesink->x_lock);
1092 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1093 ("Failed to create output image buffer of %dx%d pixels",
1094 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1095 goto beach_unlocked;
1098 XSync (xvimagesink->xcontext->disp, FALSE);
1100 /* Delete the shared memory segment as soon as we everyone is attached.
1101 * This way, it will be deleted as soon as we detach later, and not
1102 * leaked if we crash. */
1103 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1105 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1106 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1108 #ifndef GST_EXT_XV_ENHANCEMENT
1110 #endif /* GST_EXT_XV_ENHANCEMENT */
1111 #endif /* HAVE_XSHM */
1113 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1114 xvimagesink->xcontext->xv_port_id,
1115 #ifdef GST_EXT_XV_ENHANCEMENT
1116 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1117 #else /* GST_EXT_XV_ENHANCEMENT */
1118 xvimage->im_format, NULL, xvimage->width, xvimage->height);
1119 #endif /* GST_EXT_XV_ENHANCEMENT */
1120 if (!xvimage->xvimage || error_caught) {
1121 g_mutex_unlock (xvimagesink->x_lock);
1122 /* Reset error handler */
1123 error_caught = FALSE;
1124 XSetErrorHandler (handler);
1126 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1127 ("Failed to create outputimage buffer of %dx%d pixels",
1128 xvimage->width, xvimage->height),
1129 ("could not XvCreateImage a %dx%d image",
1130 xvimage->width, xvimage->height));
1131 goto beach_unlocked;
1134 /* we have to use the returned data_size for our image size */
1135 xvimage->size = xvimage->xvimage->data_size;
1136 xvimage->xvimage->data = g_malloc (xvimage->size);
1138 XSync (xvimagesink->xcontext->disp, FALSE);
1141 /* Reset error handler */
1142 error_caught = FALSE;
1143 XSetErrorHandler (handler);
1147 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1148 GST_BUFFER_SIZE (xvimage) = xvimage->size;
1150 g_mutex_unlock (xvimagesink->x_lock);
1154 gst_xvimage_buffer_free (xvimage);
1161 #ifdef GST_EXT_XV_ENHANCEMENT
1162 /* This function handles GstXvImage creation depending on XShm availability */
1163 static GstXvImageBuffer *
1164 gst_xvimagesink_xvimage_new_for_last_image (GstXvImageSink * xvimagesink, gint im_format)
1166 GstXvImageBuffer *xvimage = NULL;
1167 GstStructure *structure = NULL;
1168 gboolean succeeded = FALSE;
1169 int (*handler) (Display *, XErrorEvent *);
1171 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1173 xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
1174 GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer for last image");
1176 xvimage->width = xvimagesink->xvimage->width;
1177 xvimage->height = xvimagesink->xvimage->height;
1179 GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
1182 xvimage->im_format = im_format;
1183 if (xvimage->im_format == -1) {
1184 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1185 ("Failed to create output image buffer of %dx%d pixels",
1186 xvimage->width, xvimage->height), ("Invalid input caps"));
1187 goto beach_unlocked;
1189 xvimage->xvimagesink = gst_object_ref (xvimagesink);
1191 g_mutex_lock (xvimagesink->x_lock);
1193 XSync (xvimagesink->xcontext->disp, FALSE);
1195 /* Setting an error handler to catch failure */
1196 error_caught = FALSE;
1197 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
1200 if (xvimagesink->xcontext->use_xshm) {
1203 xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
1204 xvimagesink->xcontext->xv_port_id,
1205 xvimage->im_format, NULL,
1206 xvimage->width, xvimage->height, &xvimage->SHMInfo);
1207 if (!xvimage->xvimage || error_caught) {
1208 g_mutex_unlock (xvimagesink->x_lock);
1210 /* Reset error flag */
1211 error_caught = FALSE;
1213 /* Push a warning */
1214 GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
1215 ("Failed to create output image buffer of %dx%d pixels",
1216 xvimage->width, xvimage->height),
1217 ("could not XvShmCreateImage a %dx%d image",
1218 xvimage->width, xvimage->height));
1220 /* must not change "use_xshm",
1221 because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
1222 goto beach_unlocked;
1225 /* we have to use the returned data_size for our shm size */
1226 xvimage->size = xvimage->xvimage->data_size;
1227 GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
1230 /* calculate the expected size. This is only for sanity checking the
1231 * number we get from X. */
1232 switch (xvimage->im_format) {
1233 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
1234 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
1241 pitches[0] = GST_ROUND_UP_4 (xvimage->width);
1242 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
1243 pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
1245 offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
1246 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
1249 offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
1251 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1252 GST_DEBUG_OBJECT (xvimagesink,
1253 "Plane %u has a expected pitch of %d bytes, " "offset of %d",
1254 plane, pitches[plane], offsets[plane]);
1258 case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
1259 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
1260 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
1261 expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
1267 if (expected_size != 0 && xvimage->size != expected_size) {
1268 GST_WARNING_OBJECT (xvimagesink,
1269 "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
1270 xvimage->size, expected_size);
1273 /* Be verbose about our XvImage stride */
1277 for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
1278 GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
1279 "offset of %d", plane, xvimage->xvimage->pitches[plane],
1280 xvimage->xvimage->offsets[plane]);
1284 xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
1286 if (xvimage->SHMInfo.shmid == -1) {
1287 g_mutex_unlock (xvimagesink->x_lock);
1288 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1289 ("Failed to create output image buffer of %dx%d pixels",
1290 xvimage->width, xvimage->height),
1291 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
1293 GST_ERROR_OBJECT(xvimagesink, "Failed to shmget: %s", g_strerror (errno));
1294 goto beach_unlocked;
1297 xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
1298 if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
1299 g_mutex_unlock (xvimagesink->x_lock);
1300 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1301 ("Failed to create output image buffer of %dx%d pixels",
1302 xvimage->width, xvimage->height),
1303 ("Failed to shmat: %s", g_strerror (errno)));
1304 /* Clean up the shared memory segment */
1305 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1306 goto beach_unlocked;
1309 xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
1310 xvimage->SHMInfo.readOnly = FALSE;
1312 if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
1313 /* Clean up the shared memory segment */
1314 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1316 g_mutex_unlock (xvimagesink->x_lock);
1317 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1318 ("Failed to create output image buffer of %dx%d pixels",
1319 xvimage->width, xvimage->height), ("Failed to XShmAttach"));
1320 goto beach_unlocked;
1323 XSync (xvimagesink->xcontext->disp, FALSE);
1325 /* Delete the shared memory segment as soon as we everyone is attached.
1326 * This way, it will be deleted as soon as we detach later, and not
1327 * leaked if we crash. */
1328 shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
1330 GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
1331 xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
1333 #endif /* HAVE_XSHM */
1335 xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
1336 xvimagesink->xcontext->xv_port_id,
1337 xvimage->im_format, NULL, xvimagesink->aligned_width, xvimagesink->aligned_height);
1338 if (!xvimage->xvimage || error_caught) {
1339 g_mutex_unlock (xvimagesink->x_lock);
1340 /* Reset error handler */
1341 error_caught = FALSE;
1342 XSetErrorHandler (handler);
1344 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1345 ("Failed to create outputimage buffer of %dx%d pixels",
1346 xvimage->width, xvimage->height),
1347 ("could not XvCreateImage a %dx%d image",
1348 xvimage->width, xvimage->height));
1349 goto beach_unlocked;
1352 /* we have to use the returned data_size for our image size */
1353 xvimage->size = xvimage->xvimage->data_size;
1354 xvimage->xvimage->data = g_malloc (xvimage->size);
1356 XSync (xvimagesink->xcontext->disp, FALSE);
1359 /* Reset error handler */
1360 error_caught = FALSE;
1361 XSetErrorHandler (handler);
1365 GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
1366 GST_BUFFER_SIZE (xvimage) = xvimage->size;
1368 g_mutex_unlock (xvimagesink->x_lock);
1372 gst_xvimage_buffer_free (xvimage);
1380 gst_xvimagesink_xvimage_handle_last_buffer (GstXvImageSink * xvimagesink, gint im_format)
1382 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
1384 xvimagesink->last_image = gst_xvimagesink_xvimage_new_for_last_image (xvimagesink, im_format);
1385 if (!xvimagesink->last_image) {
1386 /* The create method should have posted an informative error */
1387 GST_WARNING_OBJECT (xvimagesink, "could not create last image");
1391 GST_INFO_OBJECT(xvimagesink, "last_image(%p)->xvimage->data:0x%x, last_image->size:%d",
1392 xvimagesink->last_image, xvimagesink->last_image->xvimage->data, xvimagesink->last_image->size);
1394 switch (im_format) {
1395 case GST_MAKE_FOURCC('N', 'V', '1', '2'):
1399 char *y_data = xvimagesink->last_image->xvimage->data;
1400 y_size = xvimagesink->last_image->width * xvimagesink->last_image->height;
1401 if (xvimagesink->last_image_vaddr[0]) {
1402 for(i = 0; i < xvimagesink->last_image->height; i++) {
1403 memcpy (y_data + i*xvimagesink->last_image->width, xvimagesink->last_image_vaddr[0] + i*xvimagesink->aligned_width, xvimagesink->last_image->width);
1406 if (xvimagesink->last_image_vaddr[1]) {
1407 for(i = 0; i < xvimagesink->last_image->height/2; i++) {
1408 memcpy (y_data + y_size + i*xvimagesink->last_image->width, xvimagesink->last_image_vaddr[1] + i*xvimagesink->aligned_width, xvimagesink->last_image->width);
1411 GST_LOG_OBJECT(xvimagesink, "last image was copied in NV12 format (w:%d, h:%d, y_size:%d", xvimagesink->last_image->width, xvimagesink->last_image->height, y_size);
1415 GST_ERROR_OBJECT(xvimagesink, "Not support format for last image");
1416 gst_xvimage_buffer_destroy (xvimagesink->last_image);
1417 xvimagesink->last_image = NULL;
1418 GST_WARNING_OBJECT (xvimagesink, "could not create last image");
1426 /* We are called with the x_lock taken */
1428 gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
1429 GstXWindow * xwindow, GstVideoRectangle rect)
1433 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1434 g_return_if_fail (xwindow != NULL);
1436 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
1437 xvimagesink->xcontext->black);
1440 if (rect.x > xvimagesink->render_rect.x) {
1441 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1442 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1443 rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h);
1447 t1 = rect.x + rect.w;
1448 t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w;
1450 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1451 t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h);
1455 if (rect.y > xvimagesink->render_rect.y) {
1456 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1457 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
1458 xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y);
1462 t1 = rect.y + rect.h;
1463 t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h;
1465 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
1466 xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1);
1470 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
1471 * if no window was available */
1473 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
1474 GstXvImageBuffer * xvimage)
1476 GstVideoRectangle result;
1477 gboolean draw_border = FALSE;
1479 #ifdef GST_EXT_XV_ENHANCEMENT
1480 static Atom atom_rotation = None;
1481 static Atom atom_hflip = None;
1482 static Atom atom_vflip = None;
1483 gboolean set_hflip = FALSE;
1484 gboolean set_vflip = FALSE;
1485 XWindowAttributes map_attr;
1487 GstVideoRectangle src_origin = { 0, 0, 0, 0};
1488 GstVideoRectangle src_input = { 0, 0, 0, 0};
1489 GstVideoRectangle src = { 0, 0, 0, 0};
1490 GstVideoRectangle dst = { 0, 0, 0, 0};
1492 gint res_rotate_angle = 0;
1496 int (*handler) (Display *, XErrorEvent *) = NULL;
1497 gboolean res = FALSE;
1498 XV_DATA_PTR img_data = NULL;
1499 #endif /* GST_EXT_XV_ENHANCEMENT */
1501 /* We take the flow_lock. If expose is in there we don't want to run
1502 concurrently from the data flow thread */
1503 g_mutex_lock (xvimagesink->flow_lock);
1505 #ifdef GST_EXT_XV_ENHANCEMENT
1506 if (xvimagesink->xid_updated) {
1507 if (xvimage && xvimagesink->xvimage == NULL) {
1508 GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
1511 xvimagesink->xid_updated = FALSE;
1513 #endif /* GST_EXT_XV_ENHANCEMENT */
1515 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
1516 #ifdef GST_EXT_XV_ENHANCEMENT
1517 if (xvimagesink->get_pixmap_cb) {
1518 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
1520 GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
1521 g_mutex_unlock(xvimagesink->flow_lock);
1524 #else /* GST_EXT_XV_ENHANCEMENT */
1525 g_mutex_unlock (xvimagesink->flow_lock);
1527 #endif /* GST_EXT_XV_ENHANCEMENT */
1530 #ifdef GST_EXT_XV_ENHANCEMENT
1531 /* check map status of window */
1532 if(!xvimagesink->is_pixmap) {
1533 if (xvimagesink->xcontext && xvimagesink->xwindow) {
1534 if (XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &map_attr)) {
1535 if (map_attr.map_state != IsViewable) {
1536 GST_WARNING_OBJECT(xvimagesink, "window is unmapped, skip putimage");
1537 g_mutex_unlock(xvimagesink->flow_lock);
1541 GST_WARNING_OBJECT(xvimagesink, "XGetWindowAttributes failed");
1546 /* check visible status */
1547 if (xvimagesink->visible == FALSE ||
1548 xvimagesink->is_hided && GST_STATE(xvimagesink) != GST_STATE_PLAYING) {
1549 GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
1550 xvimagesink->visible, xvimagesink->is_hided);
1551 g_mutex_unlock(xvimagesink->flow_lock);
1554 #endif /* GST_EXT_XV_ENHANCEMENT */
1556 /* Draw borders when displaying the first frame. After this
1557 draw borders only on expose event or after a size change. */
1558 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
1562 /* Store a reference to the last image we put, lose the previous one */
1563 if (xvimage && xvimagesink->cur_image != xvimage) {
1564 if (xvimagesink->cur_image) {
1565 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
1566 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
1568 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
1569 xvimagesink->cur_image =
1570 GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
1573 /* Expose sends a NULL image, we take the latest frame */
1575 #ifdef GST_EXT_XV_ENHANCEMENT
1576 g_mutex_lock(xvimagesink->display_buffer_lock);
1577 if (xvimagesink->is_zero_copy_format &&
1578 xvimagesink->displaying_buffer_count < 1) {
1579 g_mutex_unlock(xvimagesink->display_buffer_lock);
1580 g_mutex_unlock (xvimagesink->flow_lock);
1581 GST_WARNING_OBJECT(xvimagesink, "no buffer to display. skip putimage");
1584 g_mutex_unlock(xvimagesink->display_buffer_lock);
1585 #endif /* GST_EXT_XV_ENHANCEMENT */
1586 if (xvimagesink->cur_image) {
1588 xvimage = xvimagesink->cur_image;
1590 #ifdef GST_EXT_XV_ENHANCEMENT
1591 GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
1592 /* no need to release gem handle */
1593 #endif /* GST_EXT_XV_ENHANCEMENT */
1594 g_mutex_unlock (xvimagesink->flow_lock);
1599 #ifdef GST_EXT_XV_ENHANCEMENT
1600 if (!xvimagesink->get_pixmap_cb) {
1601 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
1603 /* for multi-pixmap usage for the video texture */
1604 gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
1605 idx = xvimagesink->current_pixmap_idx;
1607 g_mutex_unlock (xvimagesink->flow_lock);
1609 } else if (idx == -2) {
1610 GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
1611 g_mutex_unlock (xvimagesink->flow_lock);
1616 res_rotate_angle = xvimagesink->rotate_angle;
1619 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1621 src_input.w = src_origin.w = xvimagesink->video_width;
1622 src_input.h = src_origin.h = xvimagesink->video_height;
1624 if (xvimagesink->rotate_angle == DEGREE_0 ||
1625 xvimagesink->rotate_angle == DEGREE_180) {
1626 src.w = src_origin.w;
1627 src.h = src_origin.h;
1629 src.w = src_origin.h;
1630 src.h = src_origin.w;
1633 dst.w = xvimagesink->render_rect.w;
1634 dst.h = xvimagesink->render_rect.h;
1636 switch (xvimagesink->display_geometry_method)
1638 case DISP_GEO_METHOD_LETTER_BOX:
1639 gst_video_sink_center_rect (src, dst, &result, TRUE);
1640 result.x += xvimagesink->render_rect.x;
1641 result.y += xvimagesink->render_rect.y;
1644 case DISP_GEO_METHOD_ORIGIN_SIZE:
1645 gst_video_sink_center_rect (src, dst, &result, FALSE);
1646 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1648 if (xvimagesink->rotate_angle == DEGREE_90 ||
1649 xvimagesink->rotate_angle == DEGREE_270) {
1650 src_input.x = src_input.x ^ src_input.y;
1651 src_input.y = src_input.x ^ src_input.y;
1652 src_input.x = src_input.x ^ src_input.y;
1654 src_input.w = src_input.w ^ src_input.h;
1655 src_input.h = src_input.w ^ src_input.h;
1656 src_input.w = src_input.w ^ src_input.h;
1660 case DISP_GEO_METHOD_FULL_SCREEN:
1661 result.x = result.y = 0;
1662 if (!xvimagesink->get_pixmap_cb) {
1663 result.w = xvimagesink->xwindow->width;
1664 result.h = xvimagesink->xwindow->height;
1666 result.w = xvimagesink->xpixmap[idx]->width;
1667 result.h = xvimagesink->xpixmap[idx]->height;
1671 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1672 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1674 result.x = result.y = 0;
1678 if (xvimagesink->rotate_angle == DEGREE_90 ||
1679 xvimagesink->rotate_angle == DEGREE_270) {
1680 src_input.x = src_input.x ^ src_input.y;
1681 src_input.y = src_input.x ^ src_input.y;
1682 src_input.x = src_input.x ^ src_input.y;
1684 src_input.w = src_input.w ^ src_input.h;
1685 src_input.h = src_input.w ^ src_input.h;
1686 src_input.w = src_input.w ^ src_input.h;
1690 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
1691 if (src.w > dst.w || src.h > dst.h) {
1693 gst_video_sink_center_rect (src, dst, &result, TRUE);
1694 result.x += xvimagesink->render_rect.x;
1695 result.y += xvimagesink->render_rect.y;
1698 gst_video_sink_center_rect (src, dst, &result, FALSE);
1699 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1701 if (xvimagesink->rotate_angle == DEGREE_90 ||
1702 xvimagesink->rotate_angle == DEGREE_270) {
1703 src_input.x = src_input.x ^ src_input.y;
1704 src_input.y = src_input.x ^ src_input.y;
1705 src_input.x = src_input.x ^ src_input.y;
1707 src_input.w = src_input.w ^ src_input.h;
1708 src_input.h = src_input.w ^ src_input.h;
1709 src_input.w = src_input.w ^ src_input.h;
1714 case DISP_GEO_METHOD_CUSTOM_DST_ROI:
1716 GstVideoRectangle dst_roi_cmpns;
1717 dst_roi_cmpns.w = xvimagesink->dst_roi.w;
1718 dst_roi_cmpns.h = xvimagesink->dst_roi.h;
1719 dst_roi_cmpns.x = xvimagesink->dst_roi.x;
1720 dst_roi_cmpns.y = xvimagesink->dst_roi.y;
1722 /* setting for DST ROI mode */
1723 switch (xvimagesink->dst_roi_mode) {
1724 case ROI_DISP_GEO_METHOD_FULL_SCREEN:
1726 case ROI_DISP_GEO_METHOD_LETTER_BOX:
1728 GstVideoRectangle roi_result;
1729 if (xvimagesink->dst_roi_orientation == DEGREE_0 ||
1730 xvimagesink->dst_roi_orientation == DEGREE_180) {
1731 src.w = src_origin.w;
1732 src.h = src_origin.h;
1734 src.w = src_origin.h;
1735 src.h = src_origin.w;
1737 dst.w = xvimagesink->dst_roi.w;
1738 dst.h = xvimagesink->dst_roi.h;
1740 gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
1741 dst_roi_cmpns.w = roi_result.w;
1742 dst_roi_cmpns.h = roi_result.h;
1743 dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
1744 dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
1751 /* calculating coordinates according to rotation angle for DST ROI */
1752 switch (xvimagesink->rotate_angle) {
1754 result.w = dst_roi_cmpns.h;
1755 result.h = dst_roi_cmpns.w;
1757 result.x = dst_roi_cmpns.y;
1758 if (!xvimagesink->get_pixmap_cb) {
1759 result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1761 result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
1765 result.w = dst_roi_cmpns.w;
1766 result.h = dst_roi_cmpns.h;
1768 if (!xvimagesink->get_pixmap_cb) {
1769 result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
1770 result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
1772 result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
1773 result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
1777 result.w = dst_roi_cmpns.h;
1778 result.h = dst_roi_cmpns.w;
1780 if (!xvimagesink->get_pixmap_cb) {
1781 result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1783 result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
1785 result.y = dst_roi_cmpns.x;
1788 result.x = dst_roi_cmpns.x;
1789 result.y = dst_roi_cmpns.y;
1790 result.w = dst_roi_cmpns.w;
1791 result.h = dst_roi_cmpns.h;
1795 /* orientation setting for auto rotation in DST ROI */
1796 if (xvimagesink->dst_roi_orientation) {
1797 res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->dst_roi_orientation);
1798 if (res_rotate_angle < 0) {
1799 res_rotate_angle += DEGREE_NUM;
1801 GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
1802 xvimagesink->dst_roi_orientation, xvimagesink->rotate_angle, res_rotate_angle);
1805 GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
1806 xvimagesink->rotate_angle, xvimagesink->dst_roi_orientation, xvimagesink->dst_roi_mode,
1807 xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
1808 result.x, result.y, result.w, result.h);
1815 if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
1816 GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d]",
1817 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
1818 gfloat w = (gfloat)src_input.w;
1819 gfloat h = (gfloat)src_input.h;
1820 gint default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
1821 gint default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
1822 GST_LOG_OBJECT(xvimagesink, "default offset x:%d y:%d", default_offset_x, default_offset_y);
1823 if (xvimagesink->zoom_pos_x == -1) {
1824 src_input.x += default_offset_x;
1826 if ((gint)w/xvimagesink->zoom > w - xvimagesink->zoom_pos_x) {
1827 xvimagesink->zoom_pos_x = default_offset_x * 2;
1829 src_input.x += xvimagesink->zoom_pos_x;
1831 if (xvimagesink->zoom_pos_y == -1) {
1832 src_input.y += default_offset_y;
1834 if ((gint)h/xvimagesink->zoom > h - xvimagesink->zoom_pos_y) {
1835 xvimagesink->zoom_pos_y = default_offset_y * 2;
1837 src_input.y += xvimagesink->zoom_pos_y;
1840 src_input.w = (gint)(w/xvimagesink->zoom);
1841 src_input.h = (gint)(h/xvimagesink->zoom);
1842 GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
1843 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
1846 #else /* GST_EXT_XV_ENHANCEMENT */
1847 if (xvimagesink->keep_aspect) {
1848 GstVideoRectangle src, dst;
1850 /* We use the calculated geometry from _setcaps as a source to respect
1851 source and screen pixel aspect ratios. */
1852 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1853 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1854 dst.w = xvimagesink->render_rect.w;
1855 dst.h = xvimagesink->render_rect.h;
1857 gst_video_sink_center_rect (src, dst, &result, TRUE);
1858 result.x += xvimagesink->render_rect.x;
1859 result.y += xvimagesink->render_rect.y;
1861 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
1863 #endif /* GST_EXT_XV_ENHANCEMENT */
1865 g_mutex_lock (xvimagesink->x_lock);
1867 #ifdef GST_EXT_XV_ENHANCEMENT
1868 if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
1870 if (draw_border && xvimagesink->draw_borders) {
1871 #endif /* GST_EXT_XV_ENHANCEMENT */
1872 gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
1874 xvimagesink->redraw_border = FALSE;
1877 /* We scale to the window's geometry */
1879 if (xvimagesink->xcontext->use_xshm) {
1880 GST_LOG_OBJECT (xvimagesink,
1881 "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
1883 xvimage->width, xvimage->height,
1884 xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
1886 #ifdef GST_EXT_XV_ENHANCEMENT
1887 switch( res_rotate_angle )
1889 /* There's slightly weired code (CCW? CW?) */
1902 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
1907 /* Trim as proper size */
1908 if (src_input.w % 2 == 1) {
1911 if (src_input.h % 2 == 1) {
1915 if ((xvimagesink->display_geometry_method == DISP_GEO_METHOD_LETTER_BOX ||
1916 xvimagesink->display_geometry_method == DISP_GEO_METHOD_FULL_SCREEN) &&
1917 xvimagesink->src_crop.w && xvimagesink->src_crop.h) {
1918 GST_LOG_OBJECT(xvimagesink, "set src crop %d,%d,%dx%d -> %d,%d,%dx%d",
1919 src_input.x, src_input.y, src_input.w, src_input.h,
1920 xvimagesink->src_crop.x, xvimagesink->src_crop.y, xvimagesink->src_crop.w, xvimagesink->src_crop.h);
1921 src_input.x = xvimagesink->src_crop.x;
1922 src_input.y = xvimagesink->src_crop.y;
1923 src_input.w = xvimagesink->src_crop.w;
1924 src_input.h = xvimagesink->src_crop.h;
1927 if (!xvimagesink->get_pixmap_cb) {
1928 GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1929 xvimagesink->scr_w, xvimagesink->scr_h,
1930 xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
1931 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1932 src_origin.w, src_origin.h,
1933 dst.x, dst.y, dst.w, dst.h,
1934 src_input.x, src_input.y, src_input.w, src_input.h,
1935 result.x, result.y, result.w, result.h );
1937 GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1938 xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
1939 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
1940 src_origin.w, src_origin.h,
1941 dst.x, dst.y, dst.w, dst.h,
1942 src_input.x, src_input.y, src_input.w, src_input.h,
1943 result.x, result.y, result.w, result.h );
1945 /* skip request to render if dst rect is 0 */
1946 if (xvimagesink->is_zero_copy_format && (!result.w || !result.h)) {
1947 GST_WARNING_OBJECT(xvimagesink, "result.w[%d] or result.h[%d] is 0. Skip xvimage_put.", result.w, result.h);
1948 g_mutex_unlock(xvimagesink->x_lock);
1949 g_mutex_unlock(xvimagesink->flow_lock);
1953 /* set display rotation */
1954 if (atom_rotation == None) {
1955 atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
1956 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1959 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate);
1960 if (ret != Success) {
1961 GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1962 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
1963 g_mutex_unlock(xvimagesink->x_lock);
1964 g_mutex_unlock(xvimagesink->flow_lock);
1968 /* set display flip */
1969 if (atom_hflip == None) {
1970 atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
1971 "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1973 if (atom_vflip == None) {
1974 atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
1975 "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1978 switch (xvimagesink->flip) {
1979 case FLIP_HORIZONTAL:
1998 GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
2000 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
2001 if (ret != Success) {
2002 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
2003 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
2005 ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
2006 if (ret != Success) {
2007 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
2008 ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
2011 /* set error handler */
2012 error_caught = FALSE;
2013 handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
2015 /* src input indicates the status when degree is 0 */
2016 /* dst input indicates the area that src will be shown regardless of rotate */
2017 if (xvimagesink->visible &&
2018 ((!xvimagesink->is_hided) || (xvimagesink->is_hided && (GST_STATE(xvimagesink) == GST_STATE_PLAYING)))) {
2019 if (xvimagesink->xim_transparenter) {
2020 GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
2021 XPutImage(xvimagesink->xcontext->disp,
2022 xvimagesink->xwindow->win,
2023 xvimagesink->xwindow->gc,
2024 xvimagesink->xim_transparenter,
2026 result.x, result.y, result.w, result.h);
2030 if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data && !xvimagesink->last_image) {
2031 img_data = (XV_DATA_PTR)xvimage->xvimage->data;
2032 if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
2033 _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
2034 xvimage->current_buffer = NULL;
2038 g_mutex_lock(xvimagesink->display_buffer_lock);
2039 if (xvimagesink->displaying_buffer_count > 3) {
2040 GST_WARNING("too many buffers are not released. [displaying_buffer_count %d]", xvimagesink->displaying_buffer_count);
2042 g_mutex_unlock(xvimagesink->display_buffer_lock);
2044 if (xvimagesink->get_pixmap_cb) {
2045 gint idx = xvimagesink->current_pixmap_idx;
2046 ret = XvShmPutImage (xvimagesink->xcontext->disp,
2047 xvimagesink->xcontext->xv_port_id,
2048 xvimagesink->xpixmap[idx]->pixmap,
2049 xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
2050 src_input.x, src_input.y, src_input.w, src_input.h,
2051 result.x, result.y, result.w, result.h, FALSE);
2052 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], pixmap id[%d], idx[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xpixmap[idx]->gc, xvimagesink->xpixmap[idx]->pixmap, idx);
2054 ret = XvShmPutImage (xvimagesink->xcontext->disp,
2055 xvimagesink->xcontext->xv_port_id,
2056 xvimagesink->xwindow->win,
2057 xvimagesink->xwindow->gc, xvimage->xvimage,
2058 src_input.x, src_input.y, src_input.w, src_input.h,
2059 result.x, result.y, result.w, result.h, FALSE);
2060 GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], xid[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xwindow->gc, xvimagesink->xwindow->win);
2063 GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
2065 #else /* GST_EXT_XV_ENHANCEMENT */
2066 XvShmPutImage (xvimagesink->xcontext->disp,
2067 xvimagesink->xcontext->xv_port_id,
2068 xvimagesink->xwindow->win,
2069 xvimagesink->xwindow->gc, xvimage->xvimage,
2070 xvimagesink->disp_x, xvimagesink->disp_y,
2071 xvimagesink->disp_width, xvimagesink->disp_height,
2072 result.x, result.y, result.w, result.h, FALSE);
2073 #endif /* GST_EXT_XV_ENHANCEMENT */
2075 #endif /* HAVE_XSHM */
2077 XvPutImage (xvimagesink->xcontext->disp,
2078 xvimagesink->xcontext->xv_port_id,
2079 xvimagesink->xwindow->win,
2080 xvimagesink->xwindow->gc, xvimage->xvimage,
2081 xvimagesink->disp_x, xvimagesink->disp_y,
2082 xvimagesink->disp_width, xvimagesink->disp_height,
2083 result.x, result.y, result.w, result.h);
2086 XSync (xvimagesink->xcontext->disp, FALSE);
2089 #ifdef GST_EXT_XV_ENHANCEMENT
2090 if (ret || error_caught || xvimagesink->get_pixmap_cb) {
2091 GST_DEBUG("error or pixmap_cb");
2093 if (ret || error_caught) {
2094 GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
2095 ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
2097 if (xvimagesink->get_pixmap_cb) {
2098 g_signal_emit (G_OBJECT (xvimagesink),
2099 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
2101 &xvimagesink->xpixmap[idx]->pixmap,
2106 /* release gem handle */
2107 if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
2108 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
2109 gem_name[0] = img_data->YBuf;
2110 gem_name[1] = img_data->CbBuf;
2111 gem_name[2] = img_data->CrBuf;
2112 _remove_displaying_buffer(xvimagesink, gem_name);
2116 /* Reset error handler */
2118 error_caught = FALSE;
2119 XSetErrorHandler (handler);
2121 #endif /* GST_EXT_XV_ENHANCEMENT */
2122 #endif /* HAVE_XSHM */
2124 g_mutex_unlock (xvimagesink->x_lock);
2126 g_mutex_unlock (xvimagesink->flow_lock);
2132 gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
2133 GstXWindow * window)
2135 Atom hints_atom = None;
2136 MotifWmHints *hints;
2138 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE);
2139 g_return_val_if_fail (window != NULL, FALSE);
2141 g_mutex_lock (xvimagesink->x_lock);
2143 hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS",
2145 if (hints_atom == None) {
2146 g_mutex_unlock (xvimagesink->x_lock);
2150 hints = g_malloc0 (sizeof (MotifWmHints));
2152 hints->flags |= MWM_HINTS_DECORATIONS;
2153 hints->decorations = 1 << 0;
2155 XChangeProperty (xvimagesink->xcontext->disp, window->win,
2156 hints_atom, hints_atom, 32, PropModeReplace,
2157 (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
2159 XSync (xvimagesink->xcontext->disp, FALSE);
2161 g_mutex_unlock (xvimagesink->x_lock);
2169 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
2170 GstXWindow * xwindow, const gchar * media_title)
2173 g_free (xvimagesink->media_title);
2174 xvimagesink->media_title = g_strdup (media_title);
2177 /* we have a window */
2178 if (xwindow->internal) {
2179 XTextProperty xproperty;
2180 const gchar *app_name;
2181 const gchar *title = NULL;
2182 gchar *title_mem = NULL;
2184 /* set application name as a title */
2185 app_name = g_get_application_name ();
2187 if (app_name && xvimagesink->media_title) {
2188 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
2190 } else if (app_name) {
2192 } else if (xvimagesink->media_title) {
2193 title = xvimagesink->media_title;
2197 if ((XStringListToTextProperty (((char **) &title), 1,
2198 &xproperty)) != 0) {
2199 XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty);
2200 XFree (xproperty.value);
2209 #ifdef GST_EXT_XV_ENHANCEMENT
2210 static XImage *make_transparent_image(Display *d, Window win, int w, int h)
2214 /* create a normal ximage */
2215 xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
2217 GST_INFO("ximage %p", xim);
2219 /* allocate data for it */
2221 xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
2223 memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
2226 GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
2232 GST_ERROR("failed to create Ximage");
2238 static gboolean set_display_mode(GstXContext *xcontext, int set_mode)
2241 static gboolean is_exist = FALSE;
2242 static XvPortID current_port_id = -1;
2243 Atom atom_output = None;
2245 if (xcontext == NULL) {
2246 GST_WARNING("xcontext is NULL");
2250 /* check once per one xv_port_id */
2251 if (current_port_id != xcontext->xv_port_id) {
2252 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2255 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2256 xcontext->xv_port_id, &count);
2258 current_port_id = xcontext->xv_port_id;
2259 for (i = 0 ; i < count ; i++) {
2260 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
2262 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2268 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2269 xcontext->disp, xcontext->xv_port_id);
2274 GST_WARNING("set display mode %d", set_mode);
2275 atom_output = XInternAtom(xcontext->disp,
2276 "_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
2277 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2278 atom_output, set_mode);
2279 if (ret == Success) {
2282 GST_WARNING("display mode[%d] set failed.", set_mode);
2285 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_OUTPUT is not existed");
2292 static gboolean set_csc_range(GstXContext *xcontext, int set_range)
2295 static gboolean is_exist = FALSE;
2296 static XvPortID current_port_id = -1;
2297 Atom atom_csc_range = None;
2299 if (xcontext == NULL) {
2300 GST_WARNING("xcontext is NULL");
2304 /* check once per one xv_port_id */
2305 if (current_port_id != xcontext->xv_port_id) {
2306 /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
2309 XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
2310 xcontext->xv_port_id, &count);
2312 current_port_id = xcontext->xv_port_id;
2313 for (i = 0 ; i < count ; i++) {
2314 if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
2316 GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
2322 GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
2323 xcontext->disp, xcontext->xv_port_id);
2328 GST_WARNING("set csc range %d", set_range);
2329 atom_csc_range = XInternAtom(xcontext->disp,
2330 "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
2331 ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
2332 atom_csc_range, set_range);
2333 if (ret == Success) {
2336 GST_WARNING("csc range[%d] set failed.", set_range);
2339 GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
2346 static void drm_init(GstXvImageSink *xvimagesink)
2353 char *driverName = NULL;
2354 char *deviceName = NULL;
2355 struct drm_auth auth_arg = {0};
2357 xvimagesink->drm_fd = -1;
2359 dpy = XOpenDisplay(0);
2361 GST_ERROR("XOpenDisplay failed errno:%d", errno);
2368 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
2369 GST_ERROR("DRI2QueryExtension !!");
2370 goto DRM_INIT_ERROR;
2373 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
2374 GST_ERROR("DRI2QueryVersion !!");
2375 goto DRM_INIT_ERROR;
2378 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
2379 GST_ERROR("DRI2Connect !!");
2380 goto DRM_INIT_ERROR;
2383 if (!driverName || !deviceName) {
2384 GST_ERROR("driverName or deviceName is not valid");
2385 goto DRM_INIT_ERROR;
2388 GST_INFO("Open drm device : %s", deviceName);
2390 /* get the drm_fd though opening the deviceName */
2391 xvimagesink->drm_fd = open(deviceName, O_RDWR);
2392 if (xvimagesink->drm_fd < 0) {
2393 GST_ERROR("cannot open drm device (%s)", deviceName);
2394 goto DRM_INIT_ERROR;
2397 /* get magic from drm to authentication */
2398 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
2399 GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd);
2400 goto DRM_INIT_ERROR;
2403 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
2404 GST_ERROR("cannot get drm authentication from X");
2405 goto DRM_INIT_ERROR;
2412 xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd);
2413 if (xvimagesink->bufmgr == NULL) {
2414 GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed");
2415 goto DRM_INIT_ERROR;
2423 if (xvimagesink->drm_fd >= 0) {
2424 close(xvimagesink->drm_fd);
2425 xvimagesink->drm_fd = -1;
2440 static void drm_fini(GstXvImageSink *xvimagesink)
2442 GST_WARNING_OBJECT(xvimagesink, "START");
2444 if (xvimagesink->drm_fd >= 0) {
2448 /* close remained gem handle */
2449 g_mutex_lock(xvimagesink->display_buffer_lock);
2450 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2451 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2452 GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u",
2453 xvimagesink->displaying_buffers[i].buffer,
2454 xvimagesink->displaying_buffers[i].gem_name[0],
2455 xvimagesink->displaying_buffers[i].gem_name[1],
2456 xvimagesink->displaying_buffers[i].gem_name[2],
2457 xvimagesink->displaying_buffers[i].gem_handle[0],
2458 xvimagesink->displaying_buffers[i].gem_handle[1],
2459 xvimagesink->displaying_buffers[i].gem_handle[2]);
2461 /* release flush buffer */
2462 if (xvimagesink->flush_buffer) {
2463 if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] &&
2464 xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] &&
2465 xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) {
2466 _release_flush_buffer(xvimagesink);
2469 GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer");
2472 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2473 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2474 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2476 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2477 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2478 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2481 if (xvimagesink->displaying_buffers[i].buffer) {
2482 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2483 xvimagesink->displaying_buffers[i].buffer = NULL;
2487 g_mutex_unlock(xvimagesink->display_buffer_lock);
2489 GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager");
2490 tbm_bufmgr_deinit(xvimagesink->bufmgr);
2491 xvimagesink->bufmgr = NULL;
2493 GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd);
2494 close(xvimagesink->drm_fd);
2495 xvimagesink->drm_fd = -1;
2497 GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened");
2500 GST_WARNING_OBJECT(xvimagesink, "DONE");
2503 static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
2507 struct drm_prime_handle prime_arg = {0,};
2508 struct drm_gem_flink flink_arg = {0,};
2510 if (!xvimagesink || !gem_handle) {
2511 GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
2515 if (xvimagesink->drm_fd < 0) {
2516 GST_ERROR("DRM is not opened");
2520 if (dmabuf_fd <= 0) {
2521 GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
2525 prime_arg.fd = dmabuf_fd;
2526 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
2528 GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]",
2529 ret, dmabuf_fd, xvimagesink->drm_fd);
2533 *gem_handle = prime_arg.handle;
2534 flink_arg.handle = prime_arg.handle;
2535 ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
2537 GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]",
2538 ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd);
2542 return flink_arg.name;
2545 static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
2547 struct drm_gem_close close_arg = {0,};
2549 if (xvimagesink->drm_fd < 0 || !gem_handle) {
2550 GST_ERROR("DRM is not opened");
2554 if (*gem_handle <= 0) {
2555 GST_DEBUG("invalid gem handle %u", *gem_handle);
2559 GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
2561 close_arg.handle = *gem_handle;
2562 if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
2563 GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd);
2573 static void _remove_last_buffer(GstXvImageSink *xvimagesink)
2575 gboolean enable_last_buffer = FALSE;
2577 if (xvimagesink == NULL) {
2578 GST_ERROR("handle is NULL");
2582 /* get enable-last-buffer */
2583 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
2585 GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
2587 /* flush if enable-last-buffer is TRUE */
2588 if (enable_last_buffer) {
2589 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
2590 g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
2597 static void _release_flush_buffer(GstXvImageSink *xvimagesink)
2601 if (xvimagesink == NULL ||
2602 xvimagesink->flush_buffer == NULL) {
2603 GST_WARNING("handle is NULL");
2607 GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER");
2609 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
2610 if (xvimagesink->flush_buffer->bo[i]) {
2611 tbm_bo_unref(xvimagesink->flush_buffer->bo[i]);
2612 xvimagesink->flush_buffer->bo[i] = NULL;
2616 GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done");
2618 free(xvimagesink->flush_buffer);
2619 xvimagesink->flush_buffer = NULL;
2624 static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
2629 if (!xvimagesink || !img_data) {
2630 GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
2634 /* lock display buffer mutex */
2635 g_mutex_lock(xvimagesink->display_buffer_lock);
2637 /* increase displaying buffer count */
2638 xvimagesink->displaying_buffer_count++;
2640 /* check duplicated */
2641 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2642 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
2643 if ((img_data->dmabuf_fd[0] > 0 &&
2644 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
2645 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
2646 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
2648 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
2649 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
2650 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
2651 /* increase ref count */
2652 xvimagesink->displaying_buffers[i].ref_count++;
2654 /* set buffer info */
2655 img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
2656 img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
2657 img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
2659 if (img_data->dmabuf_fd[0] > 0) {
2660 GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
2661 img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
2662 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2664 GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
2665 img_data->bo[0], img_data->bo[1], img_data->bo[2],
2666 img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
2669 /* unlock display buffer mutex */
2670 g_mutex_unlock(xvimagesink->display_buffer_lock);
2676 /* store buffer temporarily */
2677 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2678 if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
2680 /* increase ref count of buffer */
2681 gst_buffer_ref(buffer);
2682 xvimagesink->displaying_buffers[i].buffer = buffer;
2685 if (img_data->dmabuf_fd[0] > 0) {
2686 /* convert fd to name */
2687 img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
2688 img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
2689 img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
2692 if (img_data->bo[0]) {
2693 img_data->YBuf = tbm_bo_export(img_data->bo[0]);
2695 if (img_data->bo[1]) {
2696 img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
2698 if (img_data->bo[2]) {
2699 img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
2703 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2704 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
2705 xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
2706 xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
2707 xvimagesink->displaying_buffers[i].vaddr[j] = img_data->vaddr[j];
2710 /* set buffer info */
2711 xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
2712 xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
2713 xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
2716 xvimagesink->displaying_buffers[i].ref_count = 1;
2718 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2719 GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
2720 xvimagesink->displayed_buffer_count,
2721 i, xvimagesink->displaying_buffers[i].buffer,
2722 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2723 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2724 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2725 xvimagesink->displaying_buffers[i].gem_handle[0],
2726 xvimagesink->displaying_buffers[i].gem_handle[1],
2727 xvimagesink->displaying_buffers[i].gem_handle[2],
2728 xvimagesink->displaying_buffers[i].gem_name[0],
2729 xvimagesink->displaying_buffers[i].gem_name[1],
2730 xvimagesink->displaying_buffers[i].gem_name[2]);
2732 GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u], vaddr [%p, %p, %p]",
2733 i, xvimagesink->displaying_buffers[i].buffer,
2734 xvimagesink->displaying_buffers[i].dmabuf_fd[0],
2735 xvimagesink->displaying_buffers[i].dmabuf_fd[1],
2736 xvimagesink->displaying_buffers[i].dmabuf_fd[2],
2737 xvimagesink->displaying_buffers[i].gem_handle[0],
2738 xvimagesink->displaying_buffers[i].gem_handle[1],
2739 xvimagesink->displaying_buffers[i].gem_handle[2],
2740 xvimagesink->displaying_buffers[i].gem_name[0],
2741 xvimagesink->displaying_buffers[i].gem_name[1],
2742 xvimagesink->displaying_buffers[i].gem_name[2],
2743 xvimagesink->displaying_buffers[i].vaddr[0],
2744 xvimagesink->displaying_buffers[i].vaddr[1],
2745 xvimagesink->displaying_buffers[i].vaddr[2]);
2748 /* set last added buffer index */
2749 xvimagesink->last_added_buffer_index = i;
2750 GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i);
2752 /* unlock display buffer mutex */
2753 g_mutex_unlock(xvimagesink->display_buffer_lock);
2755 /* get current time */
2756 gettimeofday(&xvimagesink->request_time[i], NULL);
2761 /* decrease displaying buffer count */
2762 xvimagesink->displaying_buffer_count--;
2764 /* unlock display buffer mutex */
2765 g_mutex_unlock(xvimagesink->display_buffer_lock);
2767 GST_ERROR("should not be reached here. buffer slot is FULL...");
2773 static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
2778 gboolean enable_last_buffer = FALSE;
2780 if (!xvimagesink || !gem_name) {
2781 GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name);
2785 /* lock display buffer mutex */
2786 g_mutex_lock(xvimagesink->display_buffer_lock);
2788 if (xvimagesink->displaying_buffer_count == 0) {
2789 GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer");
2790 /* unlock display buffer mutex */
2791 g_mutex_unlock(xvimagesink->display_buffer_lock);
2795 GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d",
2796 gem_name[0], gem_name[1], gem_name[2],
2797 xvimagesink->displaying_buffer_count);
2799 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
2800 if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
2801 xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
2802 xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
2803 struct timeval current_time;
2805 /* get current time to calculate displaying time */
2806 gettimeofday(¤t_time, NULL);
2808 GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
2809 (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
2810 (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
2812 if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
2813 xvimagesink->displayed_buffer_count++;
2814 GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2815 xvimagesink->displayed_buffer_count,
2816 i, xvimagesink->displaying_buffers[i].buffer,
2817 xvimagesink->displaying_buffers[i].gem_handle[0],
2818 xvimagesink->displaying_buffers[i].gem_handle[1],
2819 xvimagesink->displaying_buffers[i].gem_handle[2],
2820 xvimagesink->displaying_buffers[i].gem_name[0],
2821 xvimagesink->displaying_buffers[i].gem_name[1],
2822 xvimagesink->displaying_buffers[i].gem_name[2]);
2824 GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
2825 i, xvimagesink->displaying_buffers[i].buffer,
2826 xvimagesink->displaying_buffers[i].gem_handle[0],
2827 xvimagesink->displaying_buffers[i].gem_handle[1],
2828 xvimagesink->displaying_buffers[i].gem_handle[2],
2829 xvimagesink->displaying_buffers[i].gem_name[0],
2830 xvimagesink->displaying_buffers[i].gem_name[1],
2831 xvimagesink->displaying_buffers[i].gem_name[2]);
2834 /* decrease displaying buffer count */
2835 xvimagesink->displaying_buffer_count--;
2837 /* decrease ref count */
2838 xvimagesink->displaying_buffers[i].ref_count--;
2840 if (xvimagesink->displaying_buffers[i].ref_count > 0) {
2841 GST_WARNING("ref count not zero[%d], skip close gem handle",
2842 xvimagesink->displaying_buffers[i].ref_count);
2846 /* release flush buffer */
2847 if (xvimagesink->flush_buffer) {
2848 if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] &&
2849 xvimagesink->flush_buffer->gem_name[1] == gem_name[1] &&
2850 xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) {
2851 _release_flush_buffer(xvimagesink);
2855 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
2856 if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
2857 drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
2859 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
2860 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
2861 xvimagesink->displaying_buffers[i].bo[j] = NULL;
2864 /* reset last_added_buffer_index */
2865 if (xvimagesink->displaying_buffer_count < 1) {
2866 xvimagesink->last_added_buffer_index = -1;
2867 GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d",
2868 xvimagesink->displaying_buffer_count);
2869 g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
2870 if(!enable_last_buffer) {
2871 if (xvimagesink->cur_image) {
2872 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
2873 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
2874 xvimagesink->cur_image = NULL;
2879 if (xvimagesink->displaying_buffers[i].buffer) {
2880 gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
2881 xvimagesink->displaying_buffers[i].buffer = NULL;
2883 GST_WARNING("no buffer to unref");
2889 /* unlock display buffer mutex */
2890 g_mutex_unlock(xvimagesink->display_buffer_lock);
2896 static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
2902 unsigned long num_ret = 0;
2903 unsigned long bytes = 0;
2904 unsigned char *prop_ret = NULL;
2905 unsigned int data = 0;
2906 Atom atom_output_external;
2908 atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
2909 "XV_OUTPUT_EXTERNAL", False);
2910 if (atom_output_external != None) {
2911 ret = XGetWindowProperty(xvimagesink->xcontext->disp,
2912 xvimagesink->xwindow->win,
2913 atom_output_external, 0, 0x7fffffff,
2914 False, XA_CARDINAL, &type_ret, &size_ret,
2915 &num_ret, &bytes, &prop_ret);
2916 if (ret != Success) {
2917 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
2925 GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
2935 for (i = 0 ; i < num_ret ; i++) {
2936 (&data)[i] = prop_ret[i];
2940 for (i = 0 ; i < num_ret ; i++) {
2941 ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
2945 for (i = 0 ; i < num_ret ; i++) {
2946 ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
2953 GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
2957 GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
2961 GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
2966 #endif /* GST_EXT_XV_ENHANCEMENT */
2968 /* This function handles a GstXWindow creation
2969 * The width and height are the actual pixel size on the display */
2971 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
2972 gint width, gint height)
2974 GstXWindow *xwindow = NULL;
2976 #ifdef GST_EXT_XV_ENHANCEMENT
2977 XSetWindowAttributes win_attr;
2978 XWindowAttributes root_attr;
2979 #endif /* GST_EXT_XV_ENHANCEMENT */
2981 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2983 xwindow = g_new0 (GstXWindow, 1);
2985 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
2986 #ifdef GST_EXT_XV_ENHANCEMENT
2988 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
2989 xvimagesink->render_rect.w = xwindow->width = width;
2990 xvimagesink->render_rect.h = xwindow->height = height;
2993 xvimagesink->render_rect.w = xwindow->width = height;
2994 xvimagesink->render_rect.h = xwindow->height = width;
2997 if(!xvimagesink->is_pixmap)
2998 XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
3000 if (xwindow->width > root_attr.width) {
3001 GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
3002 xwindow->width, root_attr.width);
3003 xvimagesink->render_rect.w = xwindow->width = root_attr.width;
3005 if (xwindow->height > root_attr.height) {
3006 GST_INFO_OBJECT(xvimagesink, "Height[%d] is bigger than Max Height. Set Max[%d].",
3007 xwindow->height, root_attr.height);
3008 xvimagesink->render_rect.h = xwindow->height = root_attr.height;
3010 xwindow->internal = TRUE;
3012 g_mutex_lock (xvimagesink->x_lock);
3014 GST_DEBUG_OBJECT( xvimagesink, "window create [%dx%d]", xwindow->width, xwindow->height );
3016 xwindow->win = XCreateSimpleWindow(xvimagesink->xcontext->disp,
3017 xvimagesink->xcontext->root,
3018 0, 0, xwindow->width, xwindow->height,
3021 xvimagesink->xim_transparenter = make_transparent_image(xvimagesink->xcontext->disp,
3022 xvimagesink->xcontext->root,
3023 xwindow->width, xwindow->height);
3025 /* Make window manager not to change window size as Full screen */
3026 win_attr.override_redirect = True;
3028 if(!xvimagesink->is_pixmap)
3029 XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
3030 #else /* GST_EXT_XV_ENHANCEMENT */
3031 xvimagesink->render_rect.w = width;
3032 xvimagesink->render_rect.h = height;
3034 xwindow->width = width;
3035 xwindow->height = height;
3036 xwindow->internal = TRUE;
3038 g_mutex_lock (xvimagesink->x_lock);
3040 xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp,
3041 xvimagesink->xcontext->root,
3042 0, 0, width, height, 0, 0, xvimagesink->xcontext->black);
3043 #endif /* GST_EXT_XV_ENHANCEMENT */
3045 /* We have to do that to prevent X from redrawing the background on
3046 * ConfigureNotify. This takes away flickering of video when resizing. */
3047 XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None);
3049 /* set application name as a title */
3050 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
3052 if (xvimagesink->handle_events) {
3055 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
3056 StructureNotifyMask | PointerMotionMask | KeyPressMask |
3057 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
3059 /* Tell the window manager we'd like delete client messages instead of
3061 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
3062 "WM_DELETE_WINDOW", True);
3063 if (wm_delete != None) {
3064 (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win,
3069 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
3070 xwindow->win, 0, &values);
3072 XMapRaised (xvimagesink->xcontext->disp, xwindow->win);
3074 XSync (xvimagesink->xcontext->disp, FALSE);
3076 g_mutex_unlock (xvimagesink->x_lock);
3078 gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow);
3080 gst_x_overlay_got_window_handle (GST_X_OVERLAY (xvimagesink), xwindow->win);
3085 /* This function destroys a GstXWindow */
3087 gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
3088 GstXWindow * xwindow)
3090 g_return_if_fail (xwindow != NULL);
3091 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3093 g_mutex_lock (xvimagesink->x_lock);
3095 /* If we did not create that window we just free the GC and let it live */
3096 if (xwindow->internal) {
3097 XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win);
3098 if (xvimagesink->xim_transparenter) {
3099 XDestroyImage(xvimagesink->xim_transparenter);
3100 xvimagesink->xim_transparenter = NULL;
3103 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0);
3106 XFreeGC (xvimagesink->xcontext->disp, xwindow->gc);
3108 XSync (xvimagesink->xcontext->disp, FALSE);
3110 g_mutex_unlock (xvimagesink->x_lock);
3115 #ifdef GST_EXT_XV_ENHANCEMENT
3116 /* This function destroys a GstXWindow */
3118 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
3119 GstXPixmap * xpixmap)
3121 g_return_if_fail (xpixmap != NULL);
3122 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3124 g_mutex_lock (xvimagesink->x_lock);
3126 XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
3128 XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
3130 XSync (xvimagesink->xcontext->disp, FALSE);
3132 g_mutex_unlock (xvimagesink->x_lock);
3136 #endif /* GST_EXT_XV_ENHANCEMENT */
3139 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
3141 #ifdef GST_EXT_XV_ENHANCEMENT
3142 Window root_window, child_window;
3143 XWindowAttributes root_attr;
3147 unsigned int cur_win_width = 0;
3148 unsigned int cur_win_height = 0;
3149 unsigned int cur_win_border_width = 0;
3150 unsigned int cur_win_depth = 0;
3151 #else /* GST_EXT_XV_ENHANCEMENT */
3152 XWindowAttributes attr;
3153 #endif /* GST_EXT_XV_ENHANCEMENT */
3155 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3157 /* Update the window geometry */
3158 g_mutex_lock (xvimagesink->x_lock);
3159 if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
3160 g_mutex_unlock (xvimagesink->x_lock);
3164 #ifdef GST_EXT_XV_ENHANCEMENT
3165 /* Get root window and size of current window */
3166 XGetGeometry( xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &root_window,
3167 &cur_win_x, &cur_win_y, /* relative x, y */
3168 &cur_win_width, &cur_win_height,
3169 &cur_win_border_width, &cur_win_depth );
3171 xvimagesink->xwindow->width = cur_win_width;
3172 xvimagesink->xwindow->height = cur_win_height;
3174 /* Get absolute coordinates of current window */
3175 if(!xvimagesink->is_pixmap) {
3176 XTranslateCoordinates( xvimagesink->xcontext->disp,
3177 xvimagesink->xwindow->win,
3180 &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
3184 xvimagesink->xwindow->x = cur_win_x;
3185 xvimagesink->xwindow->y = cur_win_y;
3187 /* Get size of root window == size of screen */
3188 if(!xvimagesink->is_pixmap)
3189 XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
3191 xvimagesink->scr_w = root_attr.width;
3192 xvimagesink->scr_h = root_attr.height;
3194 if (!xvimagesink->have_render_rect) {
3195 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3196 xvimagesink->render_rect.w = cur_win_width;
3197 xvimagesink->render_rect.h = cur_win_height;
3200 GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
3201 xvimagesink->scr_w, xvimagesink->scr_h,
3202 xvimagesink->xwindow->x, xvimagesink->xwindow->y,
3203 xvimagesink->xwindow->width, xvimagesink->xwindow->height,
3204 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3205 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3206 #else /* GST_EXT_XV_ENHANCEMENT */
3207 XGetWindowAttributes (xvimagesink->xcontext->disp,
3208 xvimagesink->xwindow->win, &attr);
3210 xvimagesink->xwindow->width = attr.width;
3211 xvimagesink->xwindow->height = attr.height;
3213 if (!xvimagesink->have_render_rect) {
3214 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
3215 xvimagesink->render_rect.w = attr.width;
3216 xvimagesink->render_rect.h = attr.height;
3218 #endif /* GST_EXT_XV_ENHANCEMENT */
3220 g_mutex_unlock (xvimagesink->x_lock);
3224 gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
3225 GstXWindow * xwindow)
3227 g_return_if_fail (xwindow != NULL);
3228 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3230 g_mutex_lock (xvimagesink->x_lock);
3231 #ifdef GST_EXT_XV_ENHANCEMENT
3232 GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
3233 #endif /* GST_EXT_XV_ENHANCEMENT */
3235 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
3237 #ifdef GST_EXT_XV_ENHANCEMENT
3239 /* NOTE : it should be enabled in pixmap buffer case,
3240 if we can check whether if it is a pixmap or a window by X API */
3241 /* Preview area is not updated before other UI is updated in the screen. */
3242 XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
3243 xvimagesink->xcontext->black);
3245 XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
3246 xvimagesink->render_rect.x, xvimagesink->render_rect.y,
3247 xvimagesink->render_rect.w, xvimagesink->render_rect.h);
3249 #endif /* GST_EXT_XV_ENHANCEMENT */
3251 XSync (xvimagesink->xcontext->disp, FALSE);
3253 g_mutex_unlock (xvimagesink->x_lock);
3256 /* This function commits our internal colorbalance settings to our grabbed Xv
3257 port. If the xcontext is not initialized yet it simply returns */
3259 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
3261 GList *channels = NULL;
3263 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3265 /* If we haven't initialized the X context we can't update anything */
3266 if (xvimagesink->xcontext == NULL)
3269 /* Don't set the attributes if they haven't been changed, to avoid
3270 * rounding errors changing the values */
3271 if (!xvimagesink->cb_changed)
3274 /* For each channel of the colorbalance we calculate the correct value
3275 doing range conversion and then set the Xv port attribute to match our
3277 channels = xvimagesink->xcontext->channels_list;
3280 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
3281 GstColorBalanceChannel *channel = NULL;
3284 gdouble convert_coef;
3286 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
3287 g_object_ref (channel);
3289 /* Our range conversion coef */
3290 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
3292 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
3293 value = xvimagesink->hue;
3294 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
3295 value = xvimagesink->saturation;
3296 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
3297 value = xvimagesink->contrast;
3298 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
3299 value = xvimagesink->brightness;
3301 g_warning ("got an unknown channel %s", channel->label);
3302 g_object_unref (channel);
3306 /* Committing to Xv port */
3307 g_mutex_lock (xvimagesink->x_lock);
3309 XInternAtom (xvimagesink->xcontext->disp, channel->label, True);
3310 if (prop_atom != None) {
3313 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
3314 XvSetPortAttribute (xvimagesink->xcontext->disp,
3315 xvimagesink->xcontext->xv_port_id, prop_atom, xv_value);
3317 g_mutex_unlock (xvimagesink->x_lock);
3319 g_object_unref (channel);
3321 channels = g_list_next (channels);
3325 /* This function handles XEvents that might be in the queue. It generates
3326 GstEvent that will be sent upstream in the pipeline to handle interactivity
3327 and navigation. It will also listen for configure events on the window to
3328 trigger caps renegotiation so on the fly software scaling can work. */
3330 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
3333 guint pointer_x = 0, pointer_y = 0;
3334 gboolean pointer_moved = FALSE;
3335 gboolean exposed = FALSE, configured = FALSE;
3337 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
3339 #ifdef GST_EXT_XV_ENHANCEMENT
3340 GST_LOG("check x event");
3341 #endif /* GST_EXT_XV_ENHANCEMENT */
3343 /* Handle Interaction, produces navigation events */
3345 /* We get all pointer motion events, only the last position is
3347 g_mutex_lock (xvimagesink->flow_lock);
3348 g_mutex_lock (xvimagesink->x_lock);
3349 #ifdef GST_EXT_XV_ENHANCEMENT
3350 if (xvimagesink->xcontext->disp) {
3351 #endif //GST_EXT_XV_ENHANCEMENT
3352 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3353 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
3354 g_mutex_unlock (xvimagesink->x_lock);
3355 g_mutex_unlock (xvimagesink->flow_lock);
3359 pointer_x = e.xmotion.x;
3360 pointer_y = e.xmotion.y;
3361 pointer_moved = TRUE;
3366 g_mutex_lock (xvimagesink->flow_lock);
3367 g_mutex_lock (xvimagesink->x_lock);
3369 #ifdef GST_EXT_XV_ENHANCEMENT
3371 #endif //GST_EXT_XV_ENHANCEMENT
3372 if (pointer_moved) {
3373 g_mutex_unlock (xvimagesink->x_lock);
3374 g_mutex_unlock (xvimagesink->flow_lock);
3376 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
3377 pointer_x, pointer_y);
3378 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3379 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
3381 g_mutex_lock (xvimagesink->flow_lock);
3382 g_mutex_lock (xvimagesink->x_lock);
3385 /* We get all events on our window to throw them upstream */
3386 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3387 xvimagesink->xwindow->win,
3388 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
3392 /* We lock only for the X function call */
3393 g_mutex_unlock (xvimagesink->x_lock);
3394 g_mutex_unlock (xvimagesink->flow_lock);
3398 /* Mouse button pressed over our window. We send upstream
3399 events for interactivity/navigation */
3400 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
3401 e.xbutton.button, e.xbutton.x, e.xbutton.y);
3402 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3403 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3406 /* Mouse button released over our window. We send upstream
3407 events for interactivity/navigation */
3408 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
3409 e.xbutton.button, e.xbutton.x, e.xbutton.y);
3410 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
3411 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
3415 /* Key pressed/released over our window. We send upstream
3416 events for interactivity/navigation */
3417 GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d",
3418 e.xkey.keycode, e.xkey.x, e.xkey.y);
3419 g_mutex_lock (xvimagesink->x_lock);
3420 keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp,
3422 g_mutex_unlock (xvimagesink->x_lock);
3423 if (keysym != NoSymbol) {
3424 char *key_str = NULL;
3426 g_mutex_lock (xvimagesink->x_lock);
3427 key_str = XKeysymToString (keysym);
3428 g_mutex_unlock (xvimagesink->x_lock);
3429 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3430 e.type == KeyPress ? "key-press" : "key-release", key_str);
3432 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
3433 e.type == KeyPress ? "key-press" : "key-release", "unknown");
3437 GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
3439 g_mutex_lock (xvimagesink->flow_lock);
3440 g_mutex_lock (xvimagesink->x_lock);
3444 while (XCheckWindowEvent (xvimagesink->xcontext->disp,
3445 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
3450 case ConfigureNotify:
3451 g_mutex_unlock (xvimagesink->x_lock);
3452 #ifdef GST_EXT_XV_ENHANCEMENT
3453 GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
3454 #endif /* GST_EXT_XV_ENHANCEMENT */
3455 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
3456 #ifdef GST_EXT_XV_ENHANCEMENT
3457 GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
3458 #endif /* GST_EXT_XV_ENHANCEMENT */
3459 g_mutex_lock (xvimagesink->x_lock);
3467 if (xvimagesink->handle_expose && (exposed || configured)) {
3468 g_mutex_unlock (xvimagesink->x_lock);
3469 g_mutex_unlock (xvimagesink->flow_lock);
3471 gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
3473 g_mutex_lock (xvimagesink->flow_lock);
3474 g_mutex_lock (xvimagesink->x_lock);
3477 /* Handle Display events */
3478 while (XPending (xvimagesink->xcontext->disp)) {
3479 XNextEvent (xvimagesink->xcontext->disp, &e);
3482 case ClientMessage:{
3483 #ifdef GST_EXT_XV_ENHANCEMENT
3484 XClientMessageEvent *cme = (XClientMessageEvent *)&e;
3485 Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
3486 #endif /* GST_EXT_XV_ENHANCEMENT */
3489 #ifdef GST_EXT_XV_ENHANCEMENT
3490 GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
3491 if (cme->message_type == buffer_atom) {
3492 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
3494 GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
3495 cme->data.l[0], cme->data.l[1]);
3497 gem_name[0] = cme->data.l[0];
3498 gem_name[1] = cme->data.l[1];
3500 _remove_displaying_buffer(xvimagesink, gem_name);
3503 #endif /* GST_EXT_XV_ENHANCEMENT */
3505 wm_delete = XInternAtom (xvimagesink->xcontext->disp,
3506 "WM_DELETE_WINDOW", True);
3507 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
3508 /* Handle window deletion by posting an error on the bus */
3509 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
3510 ("Output window was closed"), (NULL));
3512 g_mutex_unlock (xvimagesink->x_lock);
3513 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
3514 xvimagesink->xwindow = NULL;
3515 g_mutex_lock (xvimagesink->x_lock);
3519 #ifdef GST_EXT_XV_ENHANCEMENT
3520 case VisibilityNotify:
3521 if (xvimagesink->xwindow &&
3522 (e.xvisibility.window == xvimagesink->xwindow->win)) {
3523 if (e.xvisibility.state == VisibilityFullyObscured) {
3526 GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
3528 if (!_is_connected_to_external_display(xvimagesink)) {
3530 atom_stream = XInternAtom(xvimagesink->xcontext->disp,
3531 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
3533 GST_WARNING_OBJECT(xvimagesink, "call STREAM_OFF");
3535 xvimagesink->is_hided = TRUE;
3536 atom_stream = XInternAtom(xvimagesink->xcontext->disp,
3537 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
3538 if (atom_stream != None) {
3539 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
3540 xvimagesink->xcontext->xv_port_id,
3541 atom_stream, 0) != Success) {
3542 GST_WARNING_OBJECT(xvimagesink, "STREAM OFF failed");
3546 GST_WARNING_OBJECT(xvimagesink, "atom_stream is NONE");
3549 xvimagesink->is_hided = TRUE;
3550 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
3551 XSync(xvimagesink->xcontext->disp, FALSE);
3553 GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip STREAM_OFF");
3556 GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
3558 if (xvimagesink->is_hided) {
3559 g_mutex_unlock(xvimagesink->x_lock);
3560 g_mutex_unlock(xvimagesink->flow_lock);
3562 xvimagesink->is_hided = FALSE;
3563 gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
3565 g_mutex_lock(xvimagesink->flow_lock);
3566 g_mutex_lock(xvimagesink->x_lock);
3568 GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
3573 #endif /* GST_EXT_XV_ENHANCEMENT */
3579 g_mutex_unlock (xvimagesink->x_lock);
3580 g_mutex_unlock (xvimagesink->flow_lock);
3584 gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
3585 XvAdaptorInfo * adaptors, int adaptor_no)
3590 /* Do we support XvImageMask ? */
3591 if (!(adaptors[adaptor_no].type & XvImageMask)) {
3592 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
3593 adaptors[adaptor_no].name);
3597 /* We found such an adaptor, looking for an available port */
3598 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
3599 /* We try to grab the port */
3600 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
3601 if (Success == res) {
3602 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
3603 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name,
3604 adaptors[adaptor_no].num_ports);
3606 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
3607 adaptors[adaptor_no].name, res);
3612 /* This function generates a caps with all supported format by the first
3613 Xv grabable port we find. We store each one of the supported formats in a
3614 format list and append the format to a newly created caps that we return
3615 If this function does not return NULL because of an error, it also grabs
3616 the port via XvGrabPort */
3618 gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
3619 GstXContext * xcontext)
3622 XvAdaptorInfo *adaptors;
3624 XvImageFormatValues *formats = NULL;
3626 XvEncodingInfo *encodings = NULL;
3627 gulong max_w = G_MAXINT, max_h = G_MAXINT;
3628 GstCaps *caps = NULL;
3629 GstCaps *rgb_caps = NULL;
3631 g_return_val_if_fail (xcontext != NULL, NULL);
3633 /* First let's check that XVideo extension is available */
3634 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
3635 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3636 ("Could not initialise Xv output"),
3637 ("XVideo extension is not available"));
3641 /* Then we get adaptors list */
3642 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
3643 &xcontext->nb_adaptors, &adaptors)) {
3644 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
3645 ("Could not initialise Xv output"),
3646 ("Failed getting XV adaptors list"));
3650 xcontext->xv_port_id = 0;
3652 GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
3654 xcontext->adaptors =
3655 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
3657 /* Now fill up our adaptor name array */
3658 for (i = 0; i < xcontext->nb_adaptors; i++) {
3659 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
3662 if (xvimagesink->adaptor_no >= 0 &&
3663 xvimagesink->adaptor_no < xcontext->nb_adaptors) {
3664 /* Find xv port from user defined adaptor */
3665 gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
3666 xvimagesink->adaptor_no);
3669 if (!xcontext->xv_port_id) {
3670 /* Now search for an adaptor that supports XvImageMask */
3671 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
3672 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
3673 xvimagesink->adaptor_no = i;
3677 XvFreeAdaptorInfo (adaptors);
3679 if (!xcontext->xv_port_id) {
3680 xvimagesink->adaptor_no = -1;
3681 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
3682 ("Could not initialise Xv output"), ("No port available"));
3686 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
3688 int count, todo = 3;
3689 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
3690 xcontext->xv_port_id, &count);
3691 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
3692 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
3693 static const char colorkey[] = "XV_COLORKEY";
3695 GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count);
3697 xvimagesink->have_autopaint_colorkey = FALSE;
3698 xvimagesink->have_double_buffer = FALSE;
3699 xvimagesink->have_colorkey = FALSE;
3701 for (i = 0; ((i < count) && todo); i++)
3702 if (!strcmp (attr[i].name, autopaint)) {
3703 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
3705 /* turn on autopaint colorkey */
3706 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3707 (xvimagesink->autopaint_colorkey ? 1 : 0));
3709 xvimagesink->have_autopaint_colorkey = TRUE;
3710 } else if (!strcmp (attr[i].name, dbl_buffer)) {
3711 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
3713 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3714 (xvimagesink->double_buffer ? 1 : 0));
3716 xvimagesink->have_double_buffer = TRUE;
3717 } else if (!strcmp (attr[i].name, colorkey)) {
3718 /* Set the colorkey, default is something that is dark but hopefully
3719 * won't randomly appear on the screen elsewhere (ie not black or greys)
3720 * can be overridden by setting "colorkey" property
3722 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
3724 gboolean set_attr = TRUE;
3727 /* set a colorkey in the right format RGB565/RGB888
3728 * We only handle these 2 cases, because they're the only types of
3729 * devices we've encountered. If we don't recognise it, leave it alone
3731 cr = (xvimagesink->colorkey >> 16);
3732 cg = (xvimagesink->colorkey >> 8) & 0xFF;
3733 cb = (xvimagesink->colorkey) & 0xFF;
3734 switch (xcontext->depth) {
3735 case 16: /* RGB 565 */
3739 ckey = (cr << 11) | (cg << 5) | cb;
3742 case 32: /* RGB 888 / ARGB 8888 */
3743 ckey = (cr << 16) | (cg << 8) | cb;
3746 GST_DEBUG_OBJECT (xvimagesink,
3747 "Unknown bit depth %d for Xv Colorkey - not adjusting",
3754 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
3755 (guint32) attr[i].max_value);
3756 GST_LOG_OBJECT (xvimagesink,
3757 "Setting color key for display depth %d to 0x%x",
3758 xcontext->depth, ckey);
3760 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
3764 xvimagesink->have_colorkey = TRUE;
3770 /* Get the list of encodings supported by the adapter and look for the
3771 * XV_IMAGE encoding so we can determine the maximum width and height
3773 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
3776 for (i = 0; i < nb_encodings; i++) {
3777 GST_LOG_OBJECT (xvimagesink,
3778 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
3779 i, encodings[i].name, encodings[i].width, encodings[i].height,
3780 encodings[i].rate.numerator, encodings[i].rate.denominator);
3781 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
3782 max_w = encodings[i].width;
3783 max_h = encodings[i].height;
3784 #ifdef GST_EXT_XV_ENHANCEMENT
3785 xvimagesink->scr_w = max_w;
3786 xvimagesink->scr_h = max_h;
3787 #endif /* GST_EXT_XV_ENHANCEMENT */
3791 XvFreeEncodingInfo (encodings);
3793 /* We get all image formats supported by our port */
3794 formats = XvListImageFormats (xcontext->disp,
3795 xcontext->xv_port_id, &nb_formats);
3796 caps = gst_caps_new_empty ();
3797 for (i = 0; i < nb_formats; i++) {
3798 GstCaps *format_caps = NULL;
3799 gboolean is_rgb_format = FALSE;
3801 /* We set the image format of the xcontext to an existing one. This
3802 is just some valid image format for making our xshm calls check before
3803 caps negotiation really happens. */
3804 xcontext->im_format = formats[i].id;
3806 switch (formats[i].type) {
3809 XvImageFormatValues *fmt = &(formats[i]);
3810 gint endianness = G_BIG_ENDIAN;
3812 if (fmt->byte_order == LSBFirst) {
3813 /* our caps system handles 24/32bpp RGB as big-endian. */
3814 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
3815 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
3816 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
3817 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
3819 if (fmt->bits_per_pixel == 24) {
3820 fmt->red_mask >>= 8;
3821 fmt->green_mask >>= 8;
3822 fmt->blue_mask >>= 8;
3825 endianness = G_LITTLE_ENDIAN;
3828 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
3829 #ifdef GST_EXT_XV_ENHANCEMENT
3830 "format", GST_TYPE_FOURCC, formats[i].id,
3831 #endif /* GST_EXT_XV_ENHANCEMENT */
3832 "endianness", G_TYPE_INT, endianness,
3833 "depth", G_TYPE_INT, fmt->depth,
3834 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
3835 "red_mask", G_TYPE_INT, fmt->red_mask,
3836 "green_mask", G_TYPE_INT, fmt->green_mask,
3837 "blue_mask", G_TYPE_INT, fmt->blue_mask,
3838 "width", GST_TYPE_INT_RANGE, 1, max_w,
3839 "height", GST_TYPE_INT_RANGE, 1, max_h,
3840 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3842 is_rgb_format = TRUE;
3846 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
3847 "format", GST_TYPE_FOURCC, formats[i].id,
3848 "width", GST_TYPE_INT_RANGE, 1, max_w,
3849 "height", GST_TYPE_INT_RANGE, 1, max_h,
3850 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3853 g_assert_not_reached ();
3858 GstXvImageFormat *format = NULL;
3860 format = g_new0 (GstXvImageFormat, 1);
3862 format->format = formats[i].id;
3863 format->caps = gst_caps_copy (format_caps);
3864 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
3867 if (is_rgb_format) {
3868 if (rgb_caps == NULL)
3869 rgb_caps = format_caps;
3871 gst_caps_append (rgb_caps, format_caps);
3873 gst_caps_append (caps, format_caps);
3877 /* Collected all caps into either the caps or rgb_caps structures.
3878 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
3880 gst_caps_append (caps, rgb_caps);
3885 GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
3887 if (gst_caps_is_empty (caps)) {
3888 gst_caps_unref (caps);
3889 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
3890 GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
3891 ("No supported format found"));
3899 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
3901 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
3903 GST_OBJECT_LOCK (xvimagesink);
3904 while (xvimagesink->running) {
3905 GST_OBJECT_UNLOCK (xvimagesink);
3907 if (xvimagesink->xwindow) {
3908 gst_xvimagesink_handle_xevents (xvimagesink);
3911 #ifdef GST_EXT_XV_ENHANCEMENT
3912 g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
3913 #else /* GST_EXT_XV_ENHANCEMENT */
3914 /* FIXME: do we want to align this with the framerate or anything else? */
3915 g_usleep (G_USEC_PER_SEC / 20);
3916 #endif /* GST_EXT_XV_ENHANCEMENT */
3918 GST_OBJECT_LOCK (xvimagesink);
3920 GST_OBJECT_UNLOCK (xvimagesink);
3926 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
3928 GThread *thread = NULL;
3930 /* don't start the thread too early */
3931 if (xvimagesink->xcontext == NULL) {
3935 GST_OBJECT_LOCK (xvimagesink);
3936 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
3937 if (!xvimagesink->event_thread) {
3938 /* Setup our event listening thread */
3939 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
3940 xvimagesink->handle_expose, xvimagesink->handle_events);
3941 xvimagesink->running = TRUE;
3942 #if !GLIB_CHECK_VERSION (2, 31, 0)
3943 xvimagesink->event_thread = g_thread_create (
3944 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL);
3946 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
3947 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
3951 if (xvimagesink->event_thread) {
3952 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
3953 xvimagesink->handle_expose, xvimagesink->handle_events);
3954 xvimagesink->running = FALSE;
3955 /* grab thread and mark it as NULL */
3956 thread = xvimagesink->event_thread;
3957 xvimagesink->event_thread = NULL;
3960 GST_OBJECT_UNLOCK (xvimagesink);
3962 /* Wait for our event thread to finish */
3964 g_thread_join (thread);
3969 #ifdef GST_EXT_XV_ENHANCEMENT
3971 * gst_xvimagesink_prepare_xid:
3972 * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
3974 * This will post a "prepare-xid" element message with video size and display size on the bus
3975 * to give applications an opportunity to call
3976 * gst_x_overlay_set_xwindow_id() before a plugin creates its own
3979 * This function should only be used by video overlay plugin developers.
3982 gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
3987 g_return_if_fail (overlay != NULL);
3988 g_return_if_fail (GST_IS_X_OVERLAY (overlay));
3990 GstXvImageSink *xvimagesink;
3991 xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
3993 GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
3994 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
3996 GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
3997 s = gst_structure_new ("prepare-xid",
3998 "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
3999 "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
4000 "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
4001 "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
4003 msg = gst_message_new_element (GST_OBJECT (overlay), s);
4004 gst_element_post_message (GST_ELEMENT (overlay), msg);
4006 #endif /* GST_EXT_XV_ENHANCEMENT */
4009 /* This function calculates the pixel aspect ratio based on the properties
4010 * in the xcontext structure and stores it there. */
4012 gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
4014 static const gint par[][2] = {
4015 {1, 1}, /* regular screen */
4016 {16, 15}, /* PAL TV */
4017 {11, 10}, /* 525 line Rec.601 video */
4018 {54, 59}, /* 625 line Rec.601 video */
4019 {64, 45}, /* 1280x1024 on 16:9 display */
4020 {5, 3}, /* 1280x1024 on 4:3 display */
4021 {4, 3} /* 800x600 on 16:9 display */
4028 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
4030 /* first calculate the "real" ratio based on the X values;
4031 * which is the "physical" w/h divided by the w/h in pixels of the display */
4032 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
4033 / (xcontext->heightmm * xcontext->width);
4035 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
4037 if (xcontext->width == 720 && xcontext->height == 576) {
4038 ratio = 4.0 * 576 / (3.0 * 720);
4040 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
4041 /* now find the one from par[][2] with the lowest delta to the real one */
4045 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
4046 gdouble this_delta = DELTA (i);
4048 if (this_delta < delta) {
4054 GST_DEBUG ("Decided on index %d (%d/%d)", index,
4055 par[index][0], par[index][1]);
4057 g_free (xcontext->par);
4058 xcontext->par = g_new0 (GValue, 1);
4059 g_value_init (xcontext->par, GST_TYPE_FRACTION);
4060 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
4061 GST_DEBUG ("set xcontext PAR to %d/%d",
4062 gst_value_get_fraction_numerator (xcontext->par),
4063 gst_value_get_fraction_denominator (xcontext->par));
4066 /* This function gets the X Display and global info about it. Everything is
4067 stored in our object and will be cleaned when the object is disposed. Note
4068 here that caps for supported format are generated without any window or
4070 static GstXContext *
4071 gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
4073 GstXContext *xcontext = NULL;
4074 XPixmapFormatValues *px_formats = NULL;
4075 gint nb_formats = 0, i, j, N_attr;
4076 XvAttribute *xv_attr = NULL;
4078 const char *channels[4] = { "XV_HUE", "XV_SATURATION",
4079 "XV_BRIGHTNESS", "XV_CONTRAST"
4082 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
4084 xcontext = g_new0 (GstXContext, 1);
4085 xcontext->im_format = 0;
4087 g_mutex_lock (xvimagesink->x_lock);
4089 xcontext->disp = XOpenDisplay (xvimagesink->display_name);
4091 if (!xcontext->disp) {
4092 g_mutex_unlock (xvimagesink->x_lock);
4094 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
4095 ("Could not initialise Xv output"), ("Could not open display"));
4099 #ifdef GST_EXT_XV_ENHANCEMENT
4102 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4103 if (g_display_id[i] == NULL) {
4104 g_display_id[i] = xcontext->disp;
4105 GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
4109 if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
4110 GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
4115 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
4116 xcontext->screen_num = DefaultScreen (xcontext->disp);
4117 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
4118 xcontext->root = DefaultRootWindow (xcontext->disp);
4119 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
4120 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
4121 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
4123 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
4124 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
4125 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
4126 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
4128 GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm",
4129 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
4131 gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
4132 /* We get supported pixmap formats at supported depth */
4133 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
4136 #ifdef GST_EXT_XV_ENHANCEMENT
4139 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4140 if (g_display_id[i] == xcontext->disp) {
4141 g_display_id[i] = NULL;
4146 XCloseDisplay (xcontext->disp);
4147 g_mutex_unlock (xvimagesink->x_lock);
4148 g_free (xcontext->par);
4150 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
4151 ("Could not initialise Xv output"), ("Could not get pixel formats"));
4155 /* We get bpp value corresponding to our running depth */
4156 for (i = 0; i < nb_formats; i++) {
4157 if (px_formats[i].depth == xcontext->depth)
4158 xcontext->bpp = px_formats[i].bits_per_pixel;
4163 xcontext->endianness =
4164 (ImageByteOrder (xcontext->disp) ==
4165 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
4167 /* our caps system handles 24/32bpp RGB as big-endian. */
4168 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
4169 xcontext->endianness == G_LITTLE_ENDIAN) {
4170 xcontext->endianness = G_BIG_ENDIAN;
4171 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
4172 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
4173 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
4174 if (xcontext->bpp == 24) {
4175 xcontext->visual->red_mask >>= 8;
4176 xcontext->visual->green_mask >>= 8;
4177 xcontext->visual->blue_mask >>= 8;
4181 xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
4183 if (!xcontext->caps) {
4184 #ifdef GST_EXT_XV_ENHANCEMENT
4187 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4188 if (g_display_id[i] == xcontext->disp) {
4189 g_display_id[i] = NULL;
4194 XCloseDisplay (xcontext->disp);
4195 g_mutex_unlock (xvimagesink->x_lock);
4196 g_free (xcontext->par);
4198 /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
4202 /* Search for XShm extension support */
4203 if (XShmQueryExtension (xcontext->disp) &&
4204 gst_xvimagesink_check_xshm_calls (xcontext)) {
4205 xcontext->use_xshm = TRUE;
4206 GST_DEBUG ("xvimagesink is using XShm extension");
4208 #endif /* HAVE_XSHM */
4210 xcontext->use_xshm = FALSE;
4211 GST_DEBUG ("xvimagesink is not using XShm extension");
4214 xv_attr = XvQueryPortAttributes (xcontext->disp,
4215 xcontext->xv_port_id, &N_attr);
4218 /* Generate the channels list */
4219 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
4220 XvAttribute *matching_attr = NULL;
4222 /* Retrieve the property atom if it exists. If it doesn't exist,
4223 * the attribute itself must not either, so we can skip */
4224 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
4225 if (prop_atom == None)
4228 if (xv_attr != NULL) {
4229 for (j = 0; j < N_attr && matching_attr == NULL; ++j)
4230 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
4231 matching_attr = xv_attr + j;
4234 if (matching_attr) {
4235 GstColorBalanceChannel *channel;
4237 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
4238 channel->label = g_strdup (channels[i]);
4239 channel->min_value = matching_attr->min_value;
4240 channel->max_value = matching_attr->max_value;
4242 xcontext->channels_list = g_list_append (xcontext->channels_list,
4245 /* If the colorbalance settings have not been touched we get Xv values
4246 as defaults and update our internal variables */
4247 if (!xvimagesink->cb_changed) {
4250 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
4252 /* Normalize val to [-1000, 1000] */
4253 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
4254 (double) (channel->max_value - channel->min_value));
4256 if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
4257 xvimagesink->hue = val;
4258 else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
4259 xvimagesink->saturation = val;
4260 else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
4261 xvimagesink->brightness = val;
4262 else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
4263 xvimagesink->contrast = val;
4271 #ifdef GST_EXT_XV_ENHANCEMENT
4272 set_display_mode(xcontext, xvimagesink->display_mode);
4273 set_csc_range(xcontext, xvimagesink->csc_range);
4274 #endif /* GST_EXT_XV_ENHANCEMENT */
4276 g_mutex_unlock (xvimagesink->x_lock);
4281 /* This function cleans the X context. Closing the Display, releasing the XV
4282 port and unrefing the caps for supported formats. */
4284 gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
4286 GList *formats_list, *channels_list = NULL;
4287 GstXContext *xcontext;
4290 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
4292 GST_OBJECT_LOCK (xvimagesink);
4293 if (xvimagesink->xcontext == NULL) {
4294 GST_OBJECT_UNLOCK (xvimagesink);
4298 /* Take the XContext from the sink and clean it up */
4299 xcontext = xvimagesink->xcontext;
4300 xvimagesink->xcontext = NULL;
4302 GST_OBJECT_UNLOCK (xvimagesink);
4305 formats_list = xcontext->formats_list;
4307 while (formats_list) {
4308 GstXvImageFormat *format = formats_list->data;
4310 gst_caps_unref (format->caps);
4312 formats_list = g_list_next (formats_list);
4315 if (xcontext->formats_list)
4316 g_list_free (xcontext->formats_list);
4318 channels_list = xcontext->channels_list;
4320 while (channels_list) {
4321 GstColorBalanceChannel *channel = channels_list->data;
4323 g_object_unref (channel);
4324 channels_list = g_list_next (channels_list);
4327 if (xcontext->channels_list)
4328 g_list_free (xcontext->channels_list);
4330 gst_caps_unref (xcontext->caps);
4331 if (xcontext->last_caps)
4332 gst_caps_replace (&xcontext->last_caps, NULL);
4334 for (i = 0; i < xcontext->nb_adaptors; i++) {
4335 g_free (xcontext->adaptors[i]);
4338 g_free (xcontext->adaptors);
4340 g_free (xcontext->par);
4342 g_mutex_lock (xvimagesink->x_lock);
4344 GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context");
4346 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
4348 #ifdef GST_EXT_XV_ENHANCEMENT
4351 for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
4352 if (g_display_id[i] == xcontext->disp) {
4353 g_display_id[i] = NULL;
4358 XCloseDisplay (xcontext->disp);
4360 g_mutex_unlock (xvimagesink->x_lock);
4366 gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
4368 g_mutex_lock (xvimagesink->pool_lock);
4370 while (xvimagesink->image_pool) {
4371 GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
4373 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
4374 xvimagesink->image_pool);
4375 gst_xvimage_buffer_free (xvimage);
4378 g_mutex_unlock (xvimagesink->pool_lock);
4383 /* This function tries to get a format matching with a given caps in the
4384 supported list of formats we generated in gst_xvimagesink_get_xv_support */
4386 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
4391 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
4393 list = xvimagesink->xcontext->formats_list;
4396 GstXvImageFormat *format = list->data;
4399 if (gst_caps_can_intersect (caps, format->caps)) {
4400 return format->format;
4403 list = g_list_next (list);
4410 gst_xvimagesink_getcaps (GstBaseSink * bsink)
4412 GstXvImageSink *xvimagesink;
4414 xvimagesink = GST_XVIMAGESINK (bsink);
4416 if (xvimagesink->xcontext)
4417 return gst_caps_ref (xvimagesink->xcontext->caps);
4420 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
4425 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
4427 GstXvImageSink *xvimagesink;
4428 GstStructure *structure;
4429 guint32 im_format = 0;
4431 gint video_width, video_height;
4432 gint disp_x, disp_y;
4433 gint disp_width, disp_height;
4434 gint video_par_n, video_par_d; /* video's PAR */
4435 gint display_par_n, display_par_d; /* display's PAR */
4436 const GValue *caps_par;
4437 const GValue *caps_disp_reg;
4440 #ifdef GST_EXT_XV_ENHANCEMENT
4441 gboolean enable_last_buffer;
4442 gchar *str_in = gst_caps_to_string(caps);
4443 if(str_in == NULL) {
4444 GST_ERROR("gst_caps_to_string() returns NULL...");
4446 GST_INFO("In setcaps. incaps:%s", str_in);
4450 #endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
4452 xvimagesink = GST_XVIMAGESINK (bsink);
4454 GST_DEBUG_OBJECT (xvimagesink,
4455 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
4456 GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
4458 if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
4459 goto incompatible_caps;
4461 structure = gst_caps_get_structure (caps, 0);
4462 ret = gst_structure_get_int (structure, "width", &video_width);
4463 ret &= gst_structure_get_int (structure, "height", &video_height);
4464 fps = gst_structure_get_value (structure, "framerate");
4465 ret &= (fps != NULL);
4468 goto incomplete_caps;
4470 #ifdef GST_EXT_XV_ENHANCEMENT
4471 xvimagesink->aligned_width = video_width;
4472 xvimagesink->aligned_height = video_height;
4474 /*get combine prop of hevc*/
4475 if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
4477 GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
4481 /*Not need to combine data, just directly copy*/
4482 xvimagesink->need_combine_data = 0;
4485 _remove_last_buffer(xvimagesink);
4486 #endif /* GST_EXT_XV_ENHANCEMENT */
4488 xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
4489 xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
4491 xvimagesink->video_width = video_width;
4492 xvimagesink->video_height = video_height;
4494 im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
4495 if (im_format == -1)
4496 goto invalid_format;
4498 /* get aspect ratio from caps if it's present, and
4499 * convert video width and height to a display width and height
4500 * using wd / hd = wv / hv * PARv / PARd */
4502 /* get video's PAR */
4503 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
4505 video_par_n = gst_value_get_fraction_numerator (caps_par);
4506 video_par_d = gst_value_get_fraction_denominator (caps_par);
4511 /* get display's PAR */
4512 if (xvimagesink->par) {
4513 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
4514 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
4520 /* get the display region */
4521 caps_disp_reg = gst_structure_get_value (structure, "display-region");
4522 if (caps_disp_reg) {
4523 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
4524 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
4525 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
4527 g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
4529 disp_x = disp_y = 0;
4530 disp_width = video_width;
4531 disp_height = video_height;
4534 if (!gst_video_calculate_display_ratio (&num, &den, video_width,
4535 video_height, video_par_n, video_par_d, display_par_n, display_par_d))
4538 xvimagesink->disp_x = disp_x;
4539 xvimagesink->disp_y = disp_y;
4540 xvimagesink->disp_width = disp_width;
4541 xvimagesink->disp_height = disp_height;
4543 GST_DEBUG_OBJECT (xvimagesink,
4544 "video width/height: %dx%d, calculated display ratio: %d/%d",
4545 video_width, video_height, num, den);
4547 /* now find a width x height that respects this display ratio.
4548 * prefer those that have one of w/h the same as the incoming video
4549 * using wd / hd = num / den */
4551 /* start with same height, because of interlaced video */
4552 /* check hd / den is an integer scale factor, and scale wd with the PAR */
4553 if (video_height % den == 0) {
4554 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
4555 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4556 gst_util_uint64_scale_int (video_height, num, den);
4557 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4558 } else if (video_width % num == 0) {
4559 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
4560 GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width;
4561 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
4562 gst_util_uint64_scale_int (video_width, den, num);
4564 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
4565 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
4566 gst_util_uint64_scale_int (video_height, num, den);
4567 GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height;
4569 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
4570 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
4572 /* Notify application to set xwindow id now */
4573 g_mutex_lock (xvimagesink->flow_lock);
4574 #ifdef GST_EXT_XV_ENHANCEMENT
4575 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4576 g_mutex_unlock (xvimagesink->flow_lock);
4577 gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
4579 if (!xvimagesink->xwindow) {
4580 g_mutex_unlock (xvimagesink->flow_lock);
4581 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
4584 g_mutex_unlock (xvimagesink->flow_lock);
4587 /* Creating our window and our image with the display size in pixels */
4588 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
4589 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
4590 goto no_display_size;
4592 g_mutex_lock (xvimagesink->flow_lock);
4593 #ifdef GST_EXT_XV_ENHANCEMENT
4594 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
4595 GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
4597 if (!xvimagesink->xwindow) {
4599 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
4600 GST_VIDEO_SINK_WIDTH (xvimagesink),
4601 GST_VIDEO_SINK_HEIGHT (xvimagesink));
4604 /* After a resize, we want to redraw the borders in case the new frame size
4605 * doesn't cover the same area */
4606 xvimagesink->redraw_border = TRUE;
4608 /* We renew our xvimage only if size or format changed;
4609 * the xvimage is the same size as the video pixel size */
4610 if ((xvimagesink->xvimage) &&
4611 ((im_format != xvimagesink->xvimage->im_format) ||
4612 (video_width != xvimagesink->xvimage->width) ||
4613 (video_height != xvimagesink->xvimage->height))) {
4614 GST_DEBUG_OBJECT (xvimagesink,
4615 "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
4616 GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
4617 GST_FOURCC_ARGS (im_format));
4618 GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
4619 gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
4620 xvimagesink->xvimage = NULL;
4623 g_mutex_unlock (xvimagesink->flow_lock);
4630 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
4635 GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
4636 "height or framerate from intersected caps");
4641 GST_DEBUG_OBJECT (xvimagesink,
4642 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
4647 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4648 ("Error calculating the output display ratio of the video."));
4653 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
4654 ("Error calculating the output display ratio of the video."));
4659 static GstStateChangeReturn
4660 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
4662 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4663 GstXvImageSink *xvimagesink;
4664 GstXContext *xcontext = NULL;
4665 #ifdef GST_EXT_XV_ENHANCEMENT
4666 Atom atom_preemption = None;
4667 #endif /* GST_EXT_XV_ENHANCEMENT */
4669 xvimagesink = GST_XVIMAGESINK (element);
4671 switch (transition) {
4672 case GST_STATE_CHANGE_NULL_TO_READY:
4673 #ifdef GST_EXT_XV_ENHANCEMENT
4674 GST_WARNING("NULL_TO_READY start");
4675 #endif /* GST_EXT_XV_ENHANCEMENT */
4676 /* Initializing the XContext */
4677 if (xvimagesink->xcontext == NULL) {
4678 xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
4679 if (xcontext == NULL)
4680 return GST_STATE_CHANGE_FAILURE;
4681 GST_OBJECT_LOCK (xvimagesink);
4683 xvimagesink->xcontext = xcontext;
4684 GST_OBJECT_UNLOCK (xvimagesink);
4687 /* update object's par with calculated one if not set yet */
4688 if (!xvimagesink->par) {
4689 xvimagesink->par = g_new0 (GValue, 1);
4690 gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par);
4691 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
4693 /* call XSynchronize with the current value of synchronous */
4694 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
4695 xvimagesink->synchronous ? "TRUE" : "FALSE");
4696 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
4697 gst_xvimagesink_update_colorbalance (xvimagesink);
4698 gst_xvimagesink_manage_event_thread (xvimagesink);
4699 #ifdef GST_EXT_XV_ENHANCEMENT
4700 GST_WARNING("NULL_TO_READY done");
4701 #endif /* GST_EXT_XV_ENHANCEMENT */
4703 case GST_STATE_CHANGE_READY_TO_PAUSED:
4704 #ifdef GST_EXT_XV_ENHANCEMENT
4705 GST_WARNING("READY_TO_PAUSED start");
4706 #endif /* GST_EXT_XV_ENHANCEMENT */
4707 g_mutex_lock (xvimagesink->pool_lock);
4708 xvimagesink->pool_invalid = FALSE;
4709 g_mutex_unlock (xvimagesink->pool_lock);
4710 #ifdef GST_EXT_XV_ENHANCEMENT
4711 GST_WARNING("READY_TO_PAUSED done");
4712 #endif /* GST_EXT_XV_ENHANCEMENT */
4714 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4715 #ifdef GST_EXT_XV_ENHANCEMENT
4716 GST_WARNING("PAUSED_TO_PLAYING start");
4717 #if 0 /* This is removed in Xorg */
4718 g_mutex_lock (xvimagesink->x_lock);
4719 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4720 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4721 if (atom_preemption != None) {
4722 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4723 xvimagesink->xcontext->xv_port_id,
4724 atom_preemption, 1 ) != Success) {
4725 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4727 XSync (xvimagesink->xcontext->disp, FALSE);
4729 g_mutex_unlock (xvimagesink->x_lock);
4731 GST_WARNING("PAUSED_TO_PLAYING done");
4732 #endif /* GST_EXT_XV_ENHANCEMENT */
4734 case GST_STATE_CHANGE_PAUSED_TO_READY:
4735 #ifdef GST_EXT_XV_ENHANCEMENT
4736 GST_WARNING("PAUSED_TO_READY start");
4737 #endif /* GST_EXT_XV_ENHANCEMENT */
4738 g_mutex_lock (xvimagesink->pool_lock);
4739 xvimagesink->pool_invalid = TRUE;
4740 g_mutex_unlock (xvimagesink->pool_lock);
4746 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4748 switch (transition) {
4749 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4750 #ifdef GST_EXT_XV_ENHANCEMENT
4751 GST_WARNING("PLAYING_TO_PAUSED start");
4752 #if 0 /* This is removed in Xorg */
4753 g_mutex_lock (xvimagesink->x_lock);
4754 atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
4755 "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
4756 if (atom_preemption != None) {
4757 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
4758 xvimagesink->xcontext->xv_port_id,
4759 atom_preemption, 0 ) != Success) {
4760 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
4762 XSync (xvimagesink->xcontext->disp, FALSE);
4764 g_mutex_unlock (xvimagesink->x_lock);
4766 /* init displayed buffer count */
4767 xvimagesink->displayed_buffer_count = 0;
4769 GST_WARNING("PLAYING_TO_PAUSED done");
4770 #endif /* GST_EXT_XV_ENHANCEMENT */
4772 case GST_STATE_CHANGE_PAUSED_TO_READY:
4773 #ifdef GST_EXT_XV_ENHANCEMENT
4774 GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
4775 xvimagesink->is_zero_copy_format,
4776 xvimagesink->enable_flush_buffer,
4777 xvimagesink->secure_path,
4778 xvimagesink->get_pixmap_cb);
4780 if ((xvimagesink->enable_flush_buffer == FALSE ||
4781 xvimagesink->secure_path == SECURE_PATH_ON) &&
4782 xvimagesink->xcontext && xvimagesink->xwindow) {
4783 GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
4784 g_mutex_lock(xvimagesink->x_lock);
4785 XvStopVideo(xvimagesink->xcontext->disp,
4786 xvimagesink->xcontext->xv_port_id,
4787 xvimagesink->xwindow->win);
4788 XSync(xvimagesink->xcontext->disp, FALSE);
4789 g_mutex_unlock(xvimagesink->x_lock);
4790 _remove_last_buffer(xvimagesink);
4791 } else if (xvimagesink->is_zero_copy_format &&
4792 xvimagesink->xvimage &&
4793 xvimagesink->xvimage->xvimage &&
4794 !xvimagesink->get_pixmap_cb) {
4795 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
4797 int is_existed = FALSE;
4798 XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
4799 memset(img_data, 0x0, sizeof(XV_DATA));
4800 XV_INIT_DATA(img_data);
4802 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
4803 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
4804 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
4806 gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
4808 GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
4810 /* check whether putimage is succeeded or not */
4811 g_mutex_lock(xvimagesink->display_buffer_lock);
4813 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
4814 if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
4815 if ((img_data->dmabuf_fd[0] > 0 &&
4816 xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
4817 xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
4818 xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
4820 xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
4821 xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
4822 xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
4823 GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
4829 if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
4830 GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
4831 _release_flush_buffer(xvimagesink);
4833 _remove_last_buffer(xvimagesink);
4836 g_mutex_unlock(xvimagesink->display_buffer_lock);
4839 #endif /* GST_EXT_XV_ENHANCEMENT */
4840 xvimagesink->fps_n = 0;
4841 xvimagesink->fps_d = 1;
4842 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
4843 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
4844 #ifdef GST_EXT_XV_ENHANCEMENT
4846 drm_fini(xvimagesink);
4848 /* init displaying_buffer_count */
4849 xvimagesink->displaying_buffer_count = 0;
4851 GST_WARNING("PAUSED_TO_READY done");
4852 #endif /* GST_EXT_XV_ENHANCEMENT */
4854 case GST_STATE_CHANGE_READY_TO_NULL:
4855 #ifdef GST_EXT_XV_ENHANCEMENT
4856 GST_WARNING("READY_TO_NULL start");
4857 #endif /* GST_EXT_XV_ENHANCEMENT */
4858 gst_xvimagesink_reset (xvimagesink);
4859 #ifdef GST_EXT_XV_ENHANCEMENT
4860 GST_WARNING("READY_TO_NULL done");
4861 #endif /* GST_EXT_XV_ENHANCEMENT */
4871 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
4872 GstClockTime * start, GstClockTime * end)
4874 GstXvImageSink *xvimagesink;
4876 xvimagesink = GST_XVIMAGESINK (bsink);
4878 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
4879 *start = GST_BUFFER_TIMESTAMP (buf);
4880 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
4881 *end = *start + GST_BUFFER_DURATION (buf);
4883 if (xvimagesink->fps_n > 0) {
4885 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
4886 xvimagesink->fps_n);
4893 gst_xvimagesink_generate_YUV420_black_frame(int width, int height, unsigned char *buf, unsigned int *buf_size)
4899 y_len = width * height;
4900 yuv_len = (width * height * 3) >> 1;
4902 for (i = 0; i < y_len; i++)
4907 for (; i < yuv_len ; i++)
4912 *buf_size = yuv_len;
4913 GST_DEBUG("Black frame generated end");
4918 gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
4920 unsigned int outsize = 0;
4921 unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
4922 SCMN_IMGB *imgb = NULL;
4923 int stride, w, h, i;
4926 if(GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LAST))
4928 /*Gerate Black Frame data*/
4929 GST_DEBUG("General black frame ");
4930 gst_xvimagesink_generate_YUV420_black_frame(xvimagesink->xvimage->width, xvimagesink->xvimage->height, xvimagesink->xvimage->xvimage->data, &(xvimagesink->xvimage->size));
4932 GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_LAST);
4936 imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
4937 if(imgb == NULL || imgb->a[0] == NULL)
4942 stride = GST_ROUND_UP_4 (imgb->w[0]);
4946 for (i = 0; i < h; i++)
4948 memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
4951 temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
4953 stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
4954 h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
4955 w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
4957 for (i = 0; i < h; i++)
4959 memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
4962 temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
4963 /* Same stride, height, width as above */
4965 for (i = 0; i < h; i++)
4967 memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
4970 outsize = imgb->w[0] * imgb->h[0]* 3 >> 1;
4971 xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
4977 #ifdef GST_EXT_XV_ENHANCEMENT
4978 static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
4980 GstXvImageFlushBuffer *flush_buffer = NULL;
4981 GstXvImageDisplayingBuffer *display_buffer = NULL;
4983 tbm_bo temp_bo = NULL;
4988 if (xvimagesink == NULL) {
4989 GST_ERROR("handle is NULL");
4993 if (xvimagesink->last_added_buffer_index == -1) {
4994 GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
4998 if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
4999 GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
5000 xvimagesink->drm_fd, xvimagesink->bufmgr);
5004 flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
5005 if (flush_buffer == NULL) {
5006 GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
5010 memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
5012 display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
5013 GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
5014 xvimagesink->last_added_buffer_index);
5016 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5017 if (display_buffer->bo[i] || display_buffer->dmabuf_fd[i] > 0) {
5018 tbm_bo_handle vaddr_src;
5019 tbm_bo_handle vaddr_dst;
5021 /* get bo/fd size */
5022 if (display_buffer->bo[i]) {
5023 size = tbm_bo_size(display_buffer->bo[i]);
5024 } else if (display_buffer->dmabuf_fd[i] > 0 && display_buffer->gem_name[i] > 0) {
5025 temp_bo = tbm_bo_import(xvimagesink->bufmgr, display_buffer->gem_name[i]);
5027 size = tbm_bo_size(temp_bo);
5028 tbm_bo_unref(temp_bo);
5031 GST_ERROR_OBJECT(xvimagesink, "failed to import bo - name %u", display_buffer->gem_name[i]);
5034 GST_ERROR_OBJECT(xvimagesink, "bo %p, gem handle %u, name %u",
5035 display_buffer->bo[i],
5036 display_buffer->gem_handle[i],
5037 display_buffer->gem_name[i]);
5041 bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_NONCACHABLE);
5043 GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
5044 goto FLUSH_BUFFER_FAILED;
5047 GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
5049 flush_buffer->gem_name[i] = tbm_bo_export(bo);
5050 flush_buffer->bo[i] = bo;
5052 /* get virtual address */
5053 if (display_buffer->bo[i]) {
5054 vaddr_src = tbm_bo_get_handle(display_buffer->bo[i], TBM_DEVICE_CPU);
5055 } else if (display_buffer->vaddr[i]) {
5056 vaddr_src.ptr = display_buffer->vaddr[i];
5058 vaddr_src.ptr = NULL;
5060 vaddr_dst = tbm_bo_get_handle(bo, TBM_DEVICE_CPU);
5061 if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
5062 GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
5063 vaddr_src.ptr, vaddr_dst.ptr);
5064 goto FLUSH_BUFFER_FAILED;
5068 memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
5070 GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
5072 xvimagesink->flush_buffer = flush_buffer;
5080 FLUSH_BUFFER_FAILED:
5082 tbm_bo_unref(temp_bo);
5087 for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
5088 if (flush_buffer->bo[i]) {
5089 tbm_bo_unref(flush_buffer->bo[i]);
5090 flush_buffer->bo[i] = NULL;
5094 flush_buffer = NULL;
5099 #endif /* GST_EXT_XV_ENHANCEMENT */
5102 static GstFlowReturn
5103 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
5105 GstXvImageSink *xvimagesink;
5107 #ifdef GST_EXT_XV_ENHANCEMENT
5108 XV_DATA_PTR img_data = NULL;
5109 SCMN_IMGB *scmn_imgb = NULL;
5111 gboolean ret = FALSE;
5112 #endif /* GST_EXT_XV_ENHANCEMENT */
5114 xvimagesink = GST_XVIMAGESINK (vsink);
5116 #ifdef GST_EXT_XV_ENHANCEMENT
5117 if (xvimagesink->stop_video) {
5118 GST_INFO( "Stop video is TRUE. so skip show frame..." );
5121 #endif /* GST_EXT_XV_ENHANCEMENT */
5123 /* If this buffer has been allocated using our buffer management we simply
5124 put the ximage which is in the PRIVATE pointer */
5125 if (GST_IS_XVIMAGE_BUFFER (buf)) {
5126 GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
5127 #ifdef GST_EXT_XV_ENHANCEMENT
5128 xvimagesink->xid_updated = FALSE;
5129 #endif /* GST_EXT_XV_ENHANCEMENT */
5130 if (!gst_xvimagesink_xvimage_put (xvimagesink,
5131 GST_XVIMAGE_BUFFER_CAST (buf)))
5134 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
5135 "slow copy into bufferpool buffer %p", buf);
5136 /* Else we have to copy the data into our private image, */
5137 /* if we have one... */
5138 #ifdef GST_EXT_XV_ENHANCEMENT
5139 g_mutex_lock (xvimagesink->flow_lock);
5140 #endif /* GST_EXT_XV_ENHANCEMENT */
5141 if (!xvimagesink->xvimage) {
5142 GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
5144 #ifdef GST_EXT_XV_ENHANCEMENT
5145 format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
5147 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
5148 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
5149 case GST_MAKE_FOURCC('S', 'N', '2', '1'):
5150 case GST_MAKE_FOURCC('S', '4', '2', '0'):
5151 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
5152 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
5153 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
5154 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
5155 case GST_MAKE_FOURCC('S', 'R', '3', '2'):
5156 case GST_MAKE_FOURCC('S', 'V', '1', '2'):
5157 xvimagesink->is_zero_copy_format = TRUE;
5158 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5159 if(scmn_imgb == NULL) {
5160 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5161 g_mutex_unlock (xvimagesink->flow_lock);
5165 /* skip buffer if aligned size is smaller than size of caps */
5166 if (scmn_imgb->s[0] < xvimagesink->video_width ||
5167 scmn_imgb->e[0] < xvimagesink->video_height) {
5168 GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
5169 xvimagesink->video_width, xvimagesink->video_height,
5170 scmn_imgb->s[0], scmn_imgb->e[0]);
5171 g_mutex_unlock (xvimagesink->flow_lock);
5175 xvimagesink->aligned_width = scmn_imgb->s[0];
5176 xvimagesink->aligned_height = scmn_imgb->e[0];
5177 GST_INFO_OBJECT(xvimagesink, "Use aligned width,height[%dx%d]",
5178 xvimagesink->aligned_width, xvimagesink->aligned_height);
5181 xvimagesink->is_zero_copy_format = FALSE;
5182 GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
5186 GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
5187 #endif /* GST_EXT_XV_ENHANCEMENT */
5189 xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
5190 GST_BUFFER_CAPS (buf));
5192 if (!xvimagesink->xvimage)
5193 /* The create method should have posted an informative error */
5196 #ifdef GST_EXT_XV_ENHANCEMENT
5197 if ((xvimagesink->is_zero_copy_format == FALSE &&
5198 xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
5199 (xvimagesink->is_zero_copy_format &&
5200 xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
5201 #else /* GST_EXT_XV_ENHANCEMENT */
5202 if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
5203 #endif /* GST_EXT_XV_ENHANCEMENT */
5204 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
5205 ("Failed to create output image buffer of %dx%d pixels",
5206 xvimagesink->xvimage->width, xvimagesink->xvimage->height),
5207 ("XServer allocated buffer size did not match input buffer"));
5209 gst_xvimage_buffer_destroy (xvimagesink->xvimage);
5210 xvimagesink->xvimage = NULL;
5215 #ifdef GST_EXT_XV_ENHANCEMENT
5216 if (xvimagesink->is_zero_copy_format) {
5217 /* Cases for specified formats of Samsung extension */
5218 GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
5219 xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
5220 xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
5221 xvimagesink->display_mode, xvimagesink->rotate_angle);
5223 if (xvimagesink->xvimage->xvimage->data) {
5225 img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
5226 memset(img_data, 0x0, sizeof(XV_DATA));
5227 XV_INIT_DATA(img_data);
5229 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
5230 if (scmn_imgb == NULL) {
5231 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
5232 g_mutex_unlock (xvimagesink->flow_lock);
5236 /* Keep the vaddr of current image for copying last image */
5237 if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
5238 for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
5239 xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
5241 GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5242 xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
5245 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
5246 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
5247 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
5248 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
5249 img_data->BufType = XV_BUF_TYPE_LEGACY;
5251 /* set virtual address */
5252 img_data->vaddr[0] = scmn_imgb->a[0];
5253 img_data->vaddr[1] = scmn_imgb->a[1];
5254 img_data->vaddr[2] = scmn_imgb->a[2];
5256 GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
5257 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
5258 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
5259 scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
5260 gboolean do_set_secure = FALSE;
5262 /* open drm to use gem */
5263 if (xvimagesink->drm_fd < 0) {
5264 drm_init(xvimagesink);
5267 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
5268 /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
5269 img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
5270 img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
5271 img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
5272 img_data->BufType = XV_BUF_TYPE_DMABUF;
5273 GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
5275 /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
5276 img_data->bo[0] = scmn_imgb->bo[0];
5277 img_data->bo[1] = scmn_imgb->bo[1];
5278 img_data->bo[2] = scmn_imgb->bo[2];
5279 GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
5282 /* set virtual address */
5283 img_data->vaddr[0] = scmn_imgb->a[0];
5284 img_data->vaddr[1] = scmn_imgb->a[1];
5285 img_data->vaddr[2] = scmn_imgb->a[2];
5287 /* check secure contents path */
5288 if (scmn_imgb->tz_enable) {
5289 if (xvimagesink->secure_path != SECURE_PATH_ON) {
5290 xvimagesink->secure_path = SECURE_PATH_ON;
5291 do_set_secure = TRUE;
5294 if (xvimagesink->secure_path != SECURE_PATH_OFF) {
5295 xvimagesink->secure_path = SECURE_PATH_OFF;
5296 do_set_secure = TRUE;
5300 if (do_set_secure) {
5301 Atom atom_secure = None;
5302 g_mutex_lock (xvimagesink->x_lock);
5303 atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
5304 if (atom_secure != None) {
5305 if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
5306 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
5308 GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
5310 XSync (xvimagesink->xcontext->disp, FALSE);
5312 GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
5314 g_mutex_unlock (xvimagesink->x_lock);
5317 if (xvimagesink->drm_level) {
5318 Atom atom_drm = None;
5319 g_mutex_lock (xvimagesink->x_lock);
5320 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5321 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5322 if (atom_drm != None) {
5323 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5324 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5325 xvimagesink->xcontext->xv_port_id,
5326 atom_drm, xvimagesink->drm_level ) != Success) {
5327 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5329 XSync (xvimagesink->xcontext->disp, FALSE);
5330 g_mutex_unlock (xvimagesink->x_lock);
5331 xvimagesink->drm_level = DRM_LEVEL_0;
5335 /* set current buffer */
5336 xvimagesink->xvimage->current_buffer = buf;
5337 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER && !xvimagesink->get_pixmap_cb) {
5338 /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
5339 GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
5340 if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
5341 img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
5342 img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
5343 img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
5345 g_mutex_unlock(xvimagesink->flow_lock);
5349 GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
5350 scmn_imgb->buf_share_method);
5351 g_mutex_unlock (xvimagesink->flow_lock);
5355 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
5356 g_mutex_unlock (xvimagesink->flow_lock);
5360 GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
5362 if(xvimagesink->need_combine_data == 1)
5364 gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
5368 memcpy (xvimagesink->xvimage->xvimage->data,
5369 GST_BUFFER_DATA (buf),
5370 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5374 g_mutex_unlock (xvimagesink->flow_lock);
5375 ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
5379 #else /* GST_EXT_XV_ENHANCEMENT */
5380 memcpy (xvimagesink->xvimage->xvimage->data,
5381 GST_BUFFER_DATA (buf),
5382 MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
5384 if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
5386 #endif /* GST_EXT_XV_ENHANCEMENT */
5394 /* No image available. That's very bad ! */
5395 GST_WARNING_OBJECT (xvimagesink, "could not create image");
5396 #ifdef GST_EXT_XV_ENHANCEMENT
5397 g_mutex_unlock (xvimagesink->flow_lock);
5399 return GST_FLOW_ERROR;
5403 /* No Window available to put our image into */
5404 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
5405 return GST_FLOW_ERROR;
5410 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
5412 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
5414 switch (GST_EVENT_TYPE (event)) {
5415 case GST_EVENT_TAG:{
5417 gchar *title = NULL;
5419 gst_event_parse_tag (event, &l);
5420 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
5423 #ifdef GST_EXT_XV_ENHANCEMENT
5424 if (!xvimagesink->get_pixmap_cb) {
5426 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
5427 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
5431 #ifdef GST_EXT_XV_ENHANCEMENT
5437 #ifdef GST_EXT_XV_ENHANCEMENT
5438 case GST_EVENT_CUSTOM_DOWNSTREAM:
5440 const GstStructure *st = NULL;
5441 st = gst_event_get_structure (event);
5443 GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
5445 if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
5446 GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
5447 xvimagesink->drm_level = DRM_LEVEL_1;
5448 if (xvimagesink->drm_level && xvimagesink->xcontext) {
5449 Atom atom_drm = None;
5450 g_mutex_lock (xvimagesink->x_lock);
5451 atom_drm = XInternAtom( xvimagesink->xcontext->disp,
5452 "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
5453 if (atom_drm != None) {
5454 GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
5455 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
5456 xvimagesink->xcontext->xv_port_id,
5457 atom_drm, xvimagesink->drm_level ) != Success) {
5458 GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
5460 XSync (xvimagesink->xcontext->disp, FALSE);
5461 xvimagesink->drm_level = DRM_LEVEL_0;
5463 g_mutex_unlock (xvimagesink->x_lock);
5473 if (GST_BASE_SINK_CLASS (parent_class)->event)
5474 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
5479 /* Buffer management */
5482 gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
5485 GstCaps *intersection;
5489 gint par_n = 1, par_d = 1;
5493 new_caps = gst_caps_copy (caps);
5495 s = gst_caps_get_structure (new_caps, 0);
5497 gst_structure_get_int (s, "width", &width);
5498 gst_structure_get_int (s, "height", &height);
5499 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
5501 gst_structure_remove_field (s, "width");
5502 gst_structure_remove_field (s, "height");
5503 gst_structure_remove_field (s, "pixel-aspect-ratio");
5505 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5506 gst_caps_unref (new_caps);
5508 if (gst_caps_is_empty (intersection))
5509 return intersection;
5511 s = gst_caps_get_structure (intersection, 0);
5513 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
5515 /* xvimagesink supports all PARs */
5517 gst_structure_fixate_field_nearest_int (s, "width", width);
5518 gst_structure_fixate_field_nearest_int (s, "height", height);
5519 gst_structure_get_int (s, "width", &w);
5520 gst_structure_get_int (s, "height", &h);
5522 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
5523 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
5526 return intersection;
5529 static GstFlowReturn
5530 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
5531 GstCaps * caps, GstBuffer ** buf)
5533 GstFlowReturn ret = GST_FLOW_OK;
5534 GstXvImageSink *xvimagesink;
5535 GstXvImageBuffer *xvimage = NULL;
5536 GstCaps *intersection = NULL;
5537 GstStructure *structure = NULL;
5538 gint width, height, image_format;
5540 xvimagesink = GST_XVIMAGESINK (bsink);
5542 if (G_UNLIKELY (!caps))
5545 g_mutex_lock (xvimagesink->pool_lock);
5546 if (G_UNLIKELY (xvimagesink->pool_invalid))
5549 if (G_LIKELY (xvimagesink->xcontext->last_caps &&
5550 gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
5551 GST_LOG_OBJECT (xvimagesink,
5552 "buffer alloc for same last_caps, reusing caps");
5553 intersection = gst_caps_ref (caps);
5554 image_format = xvimagesink->xcontext->last_format;
5555 width = xvimagesink->xcontext->last_width;
5556 height = xvimagesink->xcontext->last_height;
5558 goto reuse_last_caps;
5561 GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
5562 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
5563 caps, xvimagesink->xcontext->caps);
5565 /* Check the caps against our xcontext */
5566 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
5568 GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
5569 GST_PTR_FORMAT, intersection);
5571 if (gst_caps_is_empty (intersection)) {
5574 gst_caps_unref (intersection);
5576 /* So we don't support this kind of buffer, let's define one we'd like */
5577 new_caps = gst_caps_copy (caps);
5579 structure = gst_caps_get_structure (new_caps, 0);
5580 if (!gst_structure_has_field (structure, "width") ||
5581 !gst_structure_has_field (structure, "height")) {
5582 gst_caps_unref (new_caps);
5586 /* Try different dimensions */
5588 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5590 if (gst_caps_is_empty (intersection)) {
5591 /* Try with different YUV formats first */
5592 gst_structure_set_name (structure, "video/x-raw-yuv");
5594 /* Remove format specific fields */
5595 gst_structure_remove_field (structure, "format");
5596 gst_structure_remove_field (structure, "endianness");
5597 gst_structure_remove_field (structure, "depth");
5598 gst_structure_remove_field (structure, "bpp");
5599 gst_structure_remove_field (structure, "red_mask");
5600 gst_structure_remove_field (structure, "green_mask");
5601 gst_structure_remove_field (structure, "blue_mask");
5602 gst_structure_remove_field (structure, "alpha_mask");
5604 /* Reuse intersection with Xcontext */
5605 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5608 if (gst_caps_is_empty (intersection)) {
5609 /* Try with different dimensions and YUV formats */
5611 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5614 if (gst_caps_is_empty (intersection)) {
5615 /* Now try with RGB */
5616 gst_structure_set_name (structure, "video/x-raw-rgb");
5617 /* And interset again */
5618 gst_caps_unref (intersection);
5619 intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
5622 if (gst_caps_is_empty (intersection)) {
5623 /* Try with different dimensions and RGB formats */
5625 gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
5628 /* Clean this copy */
5629 gst_caps_unref (new_caps);
5631 if (gst_caps_is_empty (intersection))
5635 /* Ensure the returned caps are fixed */
5636 gst_caps_truncate (intersection);
5638 GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
5639 GST_PTR_FORMAT, intersection);
5640 if (gst_caps_is_equal (intersection, caps)) {
5641 /* Things work better if we return a buffer with the same caps ptr
5642 * as was asked for when we can */
5643 gst_caps_replace (&intersection, caps);
5646 /* Get image format from caps */
5647 image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
5650 /* Get geometry from caps */
5651 structure = gst_caps_get_structure (intersection, 0);
5652 if (!gst_structure_get_int (structure, "width", &width) ||
5653 !gst_structure_get_int (structure, "height", &height) ||
5657 /* Store our caps and format as the last_caps to avoid expensive
5658 * caps intersection next time */
5659 gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
5660 xvimagesink->xcontext->last_format = image_format;
5661 xvimagesink->xcontext->last_width = width;
5662 xvimagesink->xcontext->last_height = height;
5666 /* Walking through the pool cleaning unusable images and searching for a
5668 while (xvimagesink->image_pool) {
5669 xvimage = xvimagesink->image_pool->data;
5672 /* Removing from the pool */
5673 xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
5674 xvimagesink->image_pool);
5676 /* We check for geometry or image format changes */
5677 if ((xvimage->width != width) ||
5678 (xvimage->height != height) || (xvimage->im_format != image_format)) {
5679 /* This image is unusable. Destroying... */
5680 gst_xvimage_buffer_free (xvimage);
5683 /* We found a suitable image */
5684 GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
5691 #ifdef GST_EXT_XV_ENHANCEMENT
5692 /* init aligned size */
5693 xvimagesink->aligned_width = 0;
5694 xvimagesink->aligned_height = 0;
5695 #endif /* GST_EXT_XV_ENHANCEMENT */
5697 /* We found no suitable image in the pool. Creating... */
5698 GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
5699 xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
5701 g_mutex_unlock (xvimagesink->pool_lock);
5704 /* Make sure the buffer is cleared of any previously used flags */
5705 GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
5706 gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
5709 *buf = GST_BUFFER_CAST (xvimage);
5713 gst_caps_unref (intersection);
5721 GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
5722 ret = GST_FLOW_WRONG_STATE;
5723 g_mutex_unlock (xvimagesink->pool_lock);
5728 GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
5729 "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
5730 " are completely incompatible with those caps", caps,
5731 xvimagesink->xcontext->caps);
5732 ret = GST_FLOW_NOT_NEGOTIATED;
5733 g_mutex_unlock (xvimagesink->pool_lock);
5738 GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
5739 GST_PTR_FORMAT, intersection);
5740 ret = GST_FLOW_NOT_NEGOTIATED;
5741 g_mutex_unlock (xvimagesink->pool_lock);
5746 GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
5753 /* Interfaces stuff */
5756 gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type)
5758 if (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY ||
5759 type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE)
5766 gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
5768 klass->supported = gst_xvimagesink_interface_supported;
5772 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
5773 GstStructure * structure)
5775 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
5778 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
5780 GstVideoRectangle src, dst, result;
5781 gdouble x, y, xscale = 1.0, yscale = 1.0;
5783 event = gst_event_new_navigation (structure);
5785 /* We take the flow_lock while we look at the window */
5786 g_mutex_lock (xvimagesink->flow_lock);
5788 if (!xvimagesink->xwindow) {
5789 g_mutex_unlock (xvimagesink->flow_lock);
5793 if (xvimagesink->keep_aspect) {
5794 /* We get the frame position using the calculated geometry from _setcaps
5795 that respect pixel aspect ratios */
5796 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
5797 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
5798 dst.w = xvimagesink->render_rect.w;
5799 dst.h = xvimagesink->render_rect.h;
5801 gst_video_sink_center_rect (src, dst, &result, TRUE);
5802 result.x += xvimagesink->render_rect.x;
5803 result.y += xvimagesink->render_rect.y;
5805 memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle));
5808 g_mutex_unlock (xvimagesink->flow_lock);
5810 /* We calculate scaling using the original video frames geometry to include
5811 pixel aspect ratio scaling. */
5812 xscale = (gdouble) xvimagesink->video_width / result.w;
5813 yscale = (gdouble) xvimagesink->video_height / result.h;
5815 /* Converting pointer coordinates to the non scaled geometry */
5816 if (gst_structure_get_double (structure, "pointer_x", &x)) {
5817 x = MIN (x, result.x + result.w);
5818 x = MAX (x - result.x, 0);
5819 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
5820 (gdouble) x * xscale, NULL);
5822 if (gst_structure_get_double (structure, "pointer_y", &y)) {
5823 y = MIN (y, result.y + result.h);
5824 y = MAX (y - result.y, 0);
5825 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
5826 (gdouble) y * yscale, NULL);
5829 gst_pad_send_event (peer, event);
5830 gst_object_unref (peer);
5835 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
5837 iface->send_event = gst_xvimagesink_navigation_send_event;
5840 #ifdef GST_EXT_XV_ENHANCEMENT
5842 gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
5846 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5847 GstXPixmap *xpixmap = NULL;
5848 int (*handler) (Display *, XErrorEvent *);
5850 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
5852 /* If the element has not initialized the X11 context try to do so */
5853 if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
5854 /* we have thrown a GST_ELEMENT_ERROR now */
5858 gst_xvimagesink_update_colorbalance (xvimagesink);
5860 GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
5862 /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
5863 if (pixmap_id == 0) {
5864 xvimagesink->current_pixmap_idx = -2;
5868 g_mutex_lock (xvimagesink->x_lock);
5870 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
5871 if (!xvimagesink->xpixmap[i]) {
5875 unsigned int cur_win_width = 0;
5876 unsigned int cur_win_height = 0;
5877 unsigned int cur_win_border_width = 0;
5878 unsigned int cur_win_depth = 0;
5880 GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
5882 xpixmap = g_new0 (GstXPixmap, 1);
5884 xpixmap->pixmap = pixmap_id;
5886 /* Get root window and size of current window */
5887 XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
5888 &cur_win_x, &cur_win_y, /* relative x, y */
5889 &cur_win_width, &cur_win_height,
5890 &cur_win_border_width, &cur_win_depth);
5891 if (!cur_win_width || !cur_win_height) {
5892 GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
5893 g_mutex_unlock (xvimagesink->x_lock);
5896 xpixmap->width = cur_win_width;
5897 xpixmap->height = cur_win_height;
5899 if (!xvimagesink->render_rect.w)
5900 xvimagesink->render_rect.w = cur_win_width;
5901 if (!xvimagesink->render_rect.h)
5902 xvimagesink->render_rect.h = cur_win_height;
5904 /* Setting an error handler to catch failure */
5905 error_caught = FALSE;
5906 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
5909 xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
5911 XSync(xvimagesink->xcontext->disp, FALSE);
5913 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
5916 error_caught = FALSE;
5917 XSetErrorHandler (handler);
5920 xvimagesink->xpixmap[i] = xpixmap;
5921 xvimagesink->current_pixmap_idx = i;
5923 GST_ERROR("failed to create xpixmap errno: %d", errno);
5926 g_mutex_unlock (xvimagesink->x_lock);
5929 } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
5930 GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
5931 xvimagesink->current_pixmap_idx = i;
5933 g_mutex_unlock (xvimagesink->x_lock);
5941 GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
5942 xvimagesink->current_pixmap_idx = -1;
5944 g_mutex_unlock (xvimagesink->x_lock);
5947 #endif /* GST_EXT_XV_ENHANCEMENT */
5950 gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
5952 XID xwindow_id = id;
5953 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
5954 GstXWindow *xwindow = NULL;
5955 #ifdef GST_EXT_XV_ENHANCEMENT
5956 GstState current_state = GST_STATE_NULL;
5957 int (*handler) (Display *, XErrorEvent *);
5958 #endif /* GST_EXT_XV_ENHANCEMENT */
5960 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
5962 g_mutex_lock (xvimagesink->flow_lock);
5964 #ifdef GST_EXT_XV_ENHANCEMENT
5965 gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
5966 GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
5967 xwindow_id, current_state);
5968 #endif /* GST_EXT_XV_ENHANCEMENT */
5970 /* If we already use that window return */
5971 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
5972 g_mutex_unlock (xvimagesink->flow_lock);
5976 /* If the element has not initialized the X11 context try to do so */
5977 if (!xvimagesink->xcontext &&
5978 !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
5979 g_mutex_unlock (xvimagesink->flow_lock);
5980 /* we have thrown a GST_ELEMENT_ERROR now */
5984 gst_xvimagesink_update_colorbalance (xvimagesink);
5986 /* Clear image pool as the images are unusable anyway */
5987 gst_xvimagesink_imagepool_clear (xvimagesink);
5989 /* Clear the xvimage */
5990 if (xvimagesink->xvimage) {
5991 gst_xvimage_buffer_free (xvimagesink->xvimage);
5992 xvimagesink->xvimage = NULL;
5995 /* If a window is there already we destroy it */
5996 if (xvimagesink->xwindow) {
5997 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
5998 xvimagesink->xwindow = NULL;
6001 /* If the xid is 0 we go back to an internal window */
6002 if (xwindow_id == 0) {
6003 /* If no width/height caps nego did not happen window will be created
6004 during caps nego then */
6005 #ifdef GST_EXT_XV_ENHANCEMENT
6006 GST_INFO_OBJECT( xvimagesink, "xid is 0. create window[%dx%d]",
6007 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink) );
6008 #endif /* GST_EXT_XV_ENHANCEMENT */
6009 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
6010 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
6012 gst_xvimagesink_xwindow_new (xvimagesink,
6013 GST_VIDEO_SINK_WIDTH (xvimagesink),
6014 GST_VIDEO_SINK_HEIGHT (xvimagesink));
6017 XWindowAttributes attr;
6019 xwindow = g_new0 (GstXWindow, 1);
6020 xwindow->win = xwindow_id;
6022 /* Set the event we want to receive and create a GC */
6023 g_mutex_lock (xvimagesink->x_lock);
6025 if(!xvimagesink->is_pixmap)
6026 XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
6028 xwindow->width = attr.width;
6029 xwindow->height = attr.height;
6030 xwindow->internal = FALSE;
6031 if (!xvimagesink->have_render_rect) {
6032 xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0;
6033 xvimagesink->render_rect.w = attr.width;
6034 xvimagesink->render_rect.h = attr.height;
6036 if (xvimagesink->handle_events) {
6037 XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
6038 StructureNotifyMask | PointerMotionMask | KeyPressMask |
6042 #ifdef GST_EXT_XV_ENHANCEMENT
6043 /* Setting an error handler to catch failure */
6044 error_caught = FALSE;
6045 handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
6047 xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
6048 xwindow->win, 0, NULL);
6049 #ifdef GST_EXT_XV_ENHANCEMENT
6050 XSync(xvimagesink->xcontext->disp, FALSE);
6052 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
6055 error_caught = FALSE;
6056 XSetErrorHandler (handler);
6059 g_mutex_unlock (xvimagesink->x_lock);
6063 xvimagesink->xwindow = xwindow;
6065 #ifdef GST_EXT_XV_ENHANCEMENT
6066 xvimagesink->xid_updated = TRUE;
6067 #endif /* GST_EXT_XV_ENHANCEMENT */
6069 g_mutex_unlock (xvimagesink->flow_lock);
6071 #ifdef GST_EXT_XV_ENHANCEMENT
6072 if (current_state == GST_STATE_PAUSED) {
6073 GstBuffer *last_buffer = NULL;
6074 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
6075 GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
6077 gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
6078 gst_buffer_unref(last_buffer);
6082 #endif /* GST_EXT_XV_ENHANCEMENT */
6086 gst_xvimagesink_expose (GstXOverlay * overlay)
6088 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6090 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
6091 #ifdef GST_EXT_XV_ENHANCEMENT
6092 GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
6093 #endif /* GST_EXT_XV_ENHANCEMENT */
6094 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
6099 gst_xvimagesink_set_event_handling (GstXOverlay * overlay,
6100 gboolean handle_events)
6102 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6104 xvimagesink->handle_events = handle_events;
6106 g_mutex_lock (xvimagesink->flow_lock);
6108 if (G_UNLIKELY (!xvimagesink->xwindow)) {
6109 g_mutex_unlock (xvimagesink->flow_lock);
6113 g_mutex_lock (xvimagesink->x_lock);
6115 if (handle_events) {
6116 if (xvimagesink->xwindow->internal) {
6117 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6118 #ifdef GST_EXT_XV_ENHANCEMENT
6119 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
6120 #else /* GST_EXT_XV_ENHANCEMENT */
6121 ExposureMask | StructureNotifyMask | PointerMotionMask |
6122 #endif /* GST_EXT_XV_ENHANCEMENT */
6123 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
6125 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
6126 #ifdef GST_EXT_XV_ENHANCEMENT
6127 ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask |
6128 #else /* GST_EXT_XV_ENHANCEMENT */
6129 ExposureMask | StructureNotifyMask | PointerMotionMask |
6130 #endif /* GST_EXT_XV_ENHANCEMENT */
6131 KeyPressMask | KeyReleaseMask);
6134 XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0);
6137 g_mutex_unlock (xvimagesink->x_lock);
6139 g_mutex_unlock (xvimagesink->flow_lock);
6143 gst_xvimagesink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
6144 gint width, gint height)
6146 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
6148 /* FIXME: how about some locking? */
6149 if (width >= 0 && height >= 0) {
6150 xvimagesink->render_rect.x = x;
6151 xvimagesink->render_rect.y = y;
6152 xvimagesink->render_rect.w = width;
6153 xvimagesink->render_rect.h = height;
6154 xvimagesink->have_render_rect = TRUE;
6156 xvimagesink->render_rect.x = 0;
6157 xvimagesink->render_rect.y = 0;
6158 xvimagesink->render_rect.w = xvimagesink->xwindow->width;
6159 xvimagesink->render_rect.h = xvimagesink->xwindow->height;
6160 xvimagesink->have_render_rect = FALSE;
6165 gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface)
6167 iface->set_window_handle = gst_xvimagesink_set_window_handle;
6168 iface->expose = gst_xvimagesink_expose;
6169 iface->handle_events = gst_xvimagesink_set_event_handling;
6170 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
6173 static const GList *
6174 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
6176 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6178 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
6180 if (xvimagesink->xcontext)
6181 return xvimagesink->xcontext->channels_list;
6187 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
6188 GstColorBalanceChannel * channel, gint value)
6190 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6192 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
6193 g_return_if_fail (channel->label != NULL);
6195 xvimagesink->cb_changed = TRUE;
6197 /* Normalize val to [-1000, 1000] */
6198 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
6199 (double) (channel->max_value - channel->min_value));
6201 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6202 xvimagesink->hue = value;
6203 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6204 xvimagesink->saturation = value;
6205 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6206 xvimagesink->contrast = value;
6207 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6208 xvimagesink->brightness = value;
6210 g_warning ("got an unknown channel %s", channel->label);
6214 gst_xvimagesink_update_colorbalance (xvimagesink);
6218 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
6219 GstColorBalanceChannel * channel)
6221 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
6224 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
6225 g_return_val_if_fail (channel->label != NULL, 0);
6227 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
6228 value = xvimagesink->hue;
6229 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
6230 value = xvimagesink->saturation;
6231 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
6232 value = xvimagesink->contrast;
6233 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
6234 value = xvimagesink->brightness;
6236 g_warning ("got an unknown channel %s", channel->label);
6239 /* Normalize val to [channel->min_value, channel->max_value] */
6240 value = channel->min_value + (channel->max_value - channel->min_value) *
6241 (value + 1000) / 2000;
6247 gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface)
6249 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
6250 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
6251 iface->set_value = gst_xvimagesink_colorbalance_set_value;
6252 iface->get_value = gst_xvimagesink_colorbalance_get_value;
6255 static const GList *
6256 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
6258 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
6259 static GList *list = NULL;
6262 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
6264 g_list_append (list, g_object_class_find_property (klass,
6265 "autopaint-colorkey"));
6267 g_list_append (list, g_object_class_find_property (klass,
6270 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
6277 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
6278 guint prop_id, const GParamSpec * pspec)
6280 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6284 case PROP_AUTOPAINT_COLORKEY:
6285 case PROP_DOUBLE_BUFFER:
6287 GST_DEBUG_OBJECT (xvimagesink,
6288 "probing device list and get capabilities");
6289 if (!xvimagesink->xcontext) {
6290 GST_DEBUG_OBJECT (xvimagesink, "generating xcontext");
6291 xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
6295 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6301 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
6302 guint prop_id, const GParamSpec * pspec)
6304 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6305 gboolean ret = FALSE;
6309 case PROP_AUTOPAINT_COLORKEY:
6310 case PROP_DOUBLE_BUFFER:
6312 if (xvimagesink->xcontext != NULL) {
6319 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6326 static GValueArray *
6327 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
6328 guint prop_id, const GParamSpec * pspec)
6330 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
6331 GValueArray *array = NULL;
6333 if (G_UNLIKELY (!xvimagesink->xcontext)) {
6334 GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't "
6343 GValue value = { 0 };
6345 array = g_value_array_new (xvimagesink->xcontext->nb_adaptors);
6346 g_value_init (&value, G_TYPE_STRING);
6348 for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) {
6349 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
6351 g_value_set_string (&value, adaptor_id_s);
6352 g_value_array_append (array, &value);
6353 g_free (adaptor_id_s);
6355 g_value_unset (&value);
6358 case PROP_AUTOPAINT_COLORKEY:
6359 if (xvimagesink->have_autopaint_colorkey) {
6360 GValue value = { 0 };
6362 array = g_value_array_new (2);
6363 g_value_init (&value, G_TYPE_BOOLEAN);
6364 g_value_set_boolean (&value, FALSE);
6365 g_value_array_append (array, &value);
6366 g_value_set_boolean (&value, TRUE);
6367 g_value_array_append (array, &value);
6368 g_value_unset (&value);
6371 case PROP_DOUBLE_BUFFER:
6372 if (xvimagesink->have_double_buffer) {
6373 GValue value = { 0 };
6375 array = g_value_array_new (2);
6376 g_value_init (&value, G_TYPE_BOOLEAN);
6377 g_value_set_boolean (&value, FALSE);
6378 g_value_array_append (array, &value);
6379 g_value_set_boolean (&value, TRUE);
6380 g_value_array_append (array, &value);
6381 g_value_unset (&value);
6385 if (xvimagesink->have_colorkey) {
6386 GValue value = { 0 };
6388 array = g_value_array_new (1);
6389 g_value_init (&value, GST_TYPE_INT_RANGE);
6390 gst_value_set_int_range (&value, 0, 0xffffff);
6391 g_value_array_append (array, &value);
6392 g_value_unset (&value);
6396 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
6405 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
6408 iface->get_properties = gst_xvimagesink_probe_get_properties;
6409 iface->probe_property = gst_xvimagesink_probe_probe_property;
6410 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
6411 iface->get_values = gst_xvimagesink_probe_get_values;
6414 /* =========================================== */
6416 /* Init & Class init */
6418 /* =========================================== */
6421 gst_xvimagesink_set_property (GObject * object, guint prop_id,
6422 const GValue * value, GParamSpec * pspec)
6424 GstXvImageSink *xvimagesink;
6426 g_return_if_fail (GST_IS_XVIMAGESINK (object));
6428 xvimagesink = GST_XVIMAGESINK (object);
6432 xvimagesink->hue = g_value_get_int (value);
6433 xvimagesink->cb_changed = TRUE;
6434 gst_xvimagesink_update_colorbalance (xvimagesink);
6437 xvimagesink->contrast = g_value_get_int (value);
6438 xvimagesink->cb_changed = TRUE;
6439 gst_xvimagesink_update_colorbalance (xvimagesink);
6441 case PROP_BRIGHTNESS:
6442 xvimagesink->brightness = g_value_get_int (value);
6443 xvimagesink->cb_changed = TRUE;
6444 gst_xvimagesink_update_colorbalance (xvimagesink);
6446 case PROP_SATURATION:
6447 xvimagesink->saturation = g_value_get_int (value);
6448 xvimagesink->cb_changed = TRUE;
6449 gst_xvimagesink_update_colorbalance (xvimagesink);
6452 xvimagesink->display_name = g_strdup (g_value_get_string (value));
6454 case PROP_SYNCHRONOUS:
6455 xvimagesink->synchronous = g_value_get_boolean (value);
6456 if (xvimagesink->xcontext) {
6457 XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
6458 GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
6459 xvimagesink->synchronous ? "TRUE" : "FALSE");
6462 case PROP_PIXEL_ASPECT_RATIO:
6463 g_free (xvimagesink->par);
6464 xvimagesink->par = g_new0 (GValue, 1);
6465 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
6466 if (!g_value_transform (value, xvimagesink->par)) {
6467 g_warning ("Could not transform string to aspect ratio");
6468 gst_value_set_fraction (xvimagesink->par, 1, 1);
6470 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
6471 gst_value_get_fraction_numerator (xvimagesink->par),
6472 gst_value_get_fraction_denominator (xvimagesink->par));
6474 case PROP_FORCE_ASPECT_RATIO:
6475 xvimagesink->keep_aspect = g_value_get_boolean (value);
6477 case PROP_HANDLE_EVENTS:
6478 gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink),
6479 g_value_get_boolean (value));
6480 gst_xvimagesink_manage_event_thread (xvimagesink);
6483 xvimagesink->adaptor_no = atoi (g_value_get_string (value));
6485 case PROP_HANDLE_EXPOSE:
6486 xvimagesink->handle_expose = g_value_get_boolean (value);
6487 gst_xvimagesink_manage_event_thread (xvimagesink);
6489 case PROP_DOUBLE_BUFFER:
6490 xvimagesink->double_buffer = g_value_get_boolean (value);
6492 case PROP_AUTOPAINT_COLORKEY:
6493 xvimagesink->autopaint_colorkey = g_value_get_boolean (value);
6496 xvimagesink->colorkey = g_value_get_int (value);
6498 case PROP_DRAW_BORDERS:
6499 xvimagesink->draw_borders = g_value_get_boolean (value);
6501 #ifdef GST_EXT_XV_ENHANCEMENT
6502 case PROP_DISPLAY_MODE:
6504 int set_mode = g_value_get_enum (value);
6506 g_mutex_lock(xvimagesink->flow_lock);
6507 g_mutex_lock(xvimagesink->x_lock);
6509 if (xvimagesink->display_mode != set_mode) {
6510 if (xvimagesink->xcontext) {
6511 /* set display mode */
6512 if (set_display_mode(xvimagesink->xcontext, set_mode)) {
6513 xvimagesink->display_mode = set_mode;
6515 GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
6518 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6519 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
6520 xvimagesink->display_mode = set_mode;
6523 GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
6526 g_mutex_unlock(xvimagesink->x_lock);
6527 g_mutex_unlock(xvimagesink->flow_lock);
6530 case PROP_CSC_RANGE:
6532 int set_range = g_value_get_enum (value);
6534 g_mutex_lock(xvimagesink->flow_lock);
6535 g_mutex_lock(xvimagesink->x_lock);
6537 if (xvimagesink->csc_range != set_range) {
6538 if (xvimagesink->xcontext) {
6539 /* set color space range */
6540 if (set_csc_range(xvimagesink->xcontext, set_range)) {
6541 xvimagesink->csc_range = set_range;
6543 GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
6546 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
6547 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
6548 xvimagesink->csc_range = set_range;
6551 GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
6554 g_mutex_unlock(xvimagesink->x_lock);
6555 g_mutex_unlock(xvimagesink->flow_lock);
6558 case PROP_DISPLAY_GEOMETRY_METHOD:
6559 xvimagesink->display_geometry_method = g_value_get_enum (value);
6560 GST_LOG("Overlay geometry changed. update it");
6561 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
6562 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6566 xvimagesink->flip = g_value_get_enum(value);
6568 case PROP_ROTATE_ANGLE:
6569 xvimagesink->rotate_angle = g_value_get_enum (value);
6570 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
6571 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6575 g_mutex_lock( xvimagesink->flow_lock );
6576 g_mutex_lock( xvimagesink->x_lock );
6578 GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
6580 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
6581 if (xvimagesink->xcontext) {
6583 Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
6584 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
6585 if (atom_stream != None) {
6586 GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
6587 if (XvSetPortAttribute(xvimagesink->xcontext->disp,
6588 xvimagesink->xcontext->xv_port_id,
6589 atom_stream, 0 ) != Success) {
6590 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
6594 xvimagesink->visible = g_value_get_boolean (value);
6595 if ( xvimagesink->get_pixmap_cb ) {
6596 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6597 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6600 if(xvimagesink->xwindow->win)
6601 XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
6603 XSync( xvimagesink->xcontext->disp, FALSE );
6605 GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
6606 xvimagesink->visible = g_value_get_boolean (value);
6608 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
6609 g_mutex_unlock( xvimagesink->x_lock );
6610 g_mutex_unlock( xvimagesink->flow_lock );
6611 xvimagesink->visible = g_value_get_boolean (value);
6612 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
6613 g_mutex_lock( xvimagesink->flow_lock );
6614 g_mutex_lock( xvimagesink->x_lock );
6617 GST_INFO("set visible(%d) done", xvimagesink->visible);
6619 g_mutex_unlock( xvimagesink->x_lock );
6620 g_mutex_unlock( xvimagesink->flow_lock );
6623 xvimagesink->zoom = g_value_get_float (value);
6625 case PROP_ZOOM_POS_X:
6626 xvimagesink->zoom_pos_x = g_value_get_int (value);
6628 case PROP_ZOOM_POS_Y:
6629 xvimagesink->zoom_pos_y = g_value_get_int (value);
6631 case PROP_DST_ROI_MODE:
6632 xvimagesink->dst_roi_mode = g_value_get_enum (value);
6633 GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
6635 case PROP_DST_ROI_ORIENTATION:
6636 xvimagesink->dst_roi_orientation = g_value_get_enum (value);
6637 GST_INFO("Orientation(%d) of ROI is changed", xvimagesink->dst_roi_orientation);
6639 case PROP_DST_ROI_X:
6640 xvimagesink->dst_roi.x = g_value_get_int (value);
6642 case PROP_DST_ROI_Y:
6643 xvimagesink->dst_roi.y = g_value_get_int (value);
6645 case PROP_DST_ROI_W:
6646 xvimagesink->dst_roi.w = g_value_get_int (value);
6648 case PROP_DST_ROI_H:
6649 xvimagesink->dst_roi.h = g_value_get_int (value);
6651 case PROP_SRC_CROP_X:
6652 xvimagesink->src_crop.x = g_value_get_int (value);
6654 case PROP_SRC_CROP_Y:
6655 xvimagesink->src_crop.y = g_value_get_int (value);
6657 case PROP_SRC_CROP_W:
6658 xvimagesink->src_crop.w = g_value_get_int (value);
6660 case PROP_SRC_CROP_H:
6661 xvimagesink->src_crop.h = g_value_get_int (value);
6663 case PROP_STOP_VIDEO:
6664 xvimagesink->stop_video = g_value_get_int (value);
6665 g_mutex_lock( xvimagesink->flow_lock );
6667 if( xvimagesink->stop_video )
6669 if ( xvimagesink->get_pixmap_cb ) {
6670 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6671 g_mutex_lock (xvimagesink->x_lock);
6672 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6673 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6674 g_mutex_unlock (xvimagesink->x_lock);
6677 GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
6678 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6682 g_mutex_unlock( xvimagesink->flow_lock );
6684 case PROP_PIXMAP_CB:
6687 cb_func = g_value_get_pointer(value);
6689 if (xvimagesink->get_pixmap_cb) {
6691 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6692 g_mutex_lock (xvimagesink->x_lock);
6693 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6694 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6695 g_mutex_unlock (xvimagesink->x_lock);
6697 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6698 if (xvimagesink->xpixmap[i]) {
6699 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6700 xvimagesink->xpixmap[i] = NULL;
6704 xvimagesink->get_pixmap_cb = cb_func;
6705 GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
6709 case PROP_PIXMAP_CB_USER_DATA:
6712 user_data = g_value_get_pointer(value);
6714 xvimagesink->get_pixmap_cb_user_data = user_data;
6715 GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
6719 case PROP_ENABLE_FLUSH_BUFFER:
6720 xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
6723 xvimagesink->is_pixmap = g_value_get_boolean(value);
6725 #endif /* GST_EXT_XV_ENHANCEMENT */
6727 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6733 gst_xvimagesink_get_property (GObject * object, guint prop_id,
6734 GValue * value, GParamSpec * pspec)
6736 GstXvImageSink *xvimagesink;
6738 g_return_if_fail (GST_IS_XVIMAGESINK (object));
6740 xvimagesink = GST_XVIMAGESINK (object);
6744 g_value_set_int (value, xvimagesink->hue);
6747 g_value_set_int (value, xvimagesink->contrast);
6749 case PROP_BRIGHTNESS:
6750 g_value_set_int (value, xvimagesink->brightness);
6752 case PROP_SATURATION:
6753 g_value_set_int (value, xvimagesink->saturation);
6756 g_value_set_string (value, xvimagesink->display_name);
6758 case PROP_SYNCHRONOUS:
6759 g_value_set_boolean (value, xvimagesink->synchronous);
6761 case PROP_PIXEL_ASPECT_RATIO:
6762 if (xvimagesink->par)
6763 g_value_transform (xvimagesink->par, value);
6765 case PROP_FORCE_ASPECT_RATIO:
6766 g_value_set_boolean (value, xvimagesink->keep_aspect);
6768 case PROP_HANDLE_EVENTS:
6769 g_value_set_boolean (value, xvimagesink->handle_events);
6773 char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no);
6775 g_value_set_string (value, adaptor_no_s);
6776 g_free (adaptor_no_s);
6779 case PROP_DEVICE_NAME:
6780 if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) {
6781 g_value_set_string (value,
6782 xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]);
6784 g_value_set_string (value, NULL);
6787 case PROP_HANDLE_EXPOSE:
6788 g_value_set_boolean (value, xvimagesink->handle_expose);
6790 case PROP_DOUBLE_BUFFER:
6791 g_value_set_boolean (value, xvimagesink->double_buffer);
6793 case PROP_AUTOPAINT_COLORKEY:
6794 g_value_set_boolean (value, xvimagesink->autopaint_colorkey);
6797 g_value_set_int (value, xvimagesink->colorkey);
6799 case PROP_DRAW_BORDERS:
6800 g_value_set_boolean (value, xvimagesink->draw_borders);
6802 case PROP_WINDOW_WIDTH:
6803 if (xvimagesink->xwindow)
6804 g_value_set_uint64 (value, xvimagesink->xwindow->width);
6806 g_value_set_uint64 (value, 0);
6808 case PROP_WINDOW_HEIGHT:
6809 if (xvimagesink->xwindow)
6810 g_value_set_uint64 (value, xvimagesink->xwindow->height);
6812 g_value_set_uint64 (value, 0);
6814 #ifdef GST_EXT_XV_ENHANCEMENT
6815 case PROP_DISPLAY_MODE:
6816 g_value_set_enum (value, xvimagesink->display_mode);
6818 case PROP_CSC_RANGE:
6819 g_value_set_enum (value, xvimagesink->csc_range);
6821 case PROP_DISPLAY_GEOMETRY_METHOD:
6822 g_value_set_enum (value, xvimagesink->display_geometry_method);
6825 g_value_set_enum(value, xvimagesink->flip);
6827 case PROP_ROTATE_ANGLE:
6828 g_value_set_enum (value, xvimagesink->rotate_angle);
6831 g_value_set_boolean (value, xvimagesink->visible);
6834 g_value_set_float (value, xvimagesink->zoom);
6836 case PROP_ZOOM_POS_X:
6837 g_value_set_int (value, xvimagesink->zoom_pos_x);
6839 case PROP_ZOOM_POS_Y:
6840 g_value_set_int (value, xvimagesink->zoom_pos_y);
6842 case PROP_DST_ROI_MODE:
6843 g_value_set_enum (value, xvimagesink->dst_roi_mode);
6845 case PROP_DST_ROI_ORIENTATION:
6846 g_value_set_enum (value, xvimagesink->dst_roi_orientation);
6848 case PROP_DST_ROI_X:
6849 g_value_set_int (value, xvimagesink->dst_roi.x);
6851 case PROP_DST_ROI_Y:
6852 g_value_set_int (value, xvimagesink->dst_roi.y);
6854 case PROP_DST_ROI_W:
6855 g_value_set_int (value, xvimagesink->dst_roi.w);
6857 case PROP_DST_ROI_H:
6858 g_value_set_int (value, xvimagesink->dst_roi.h);
6860 case PROP_SRC_CROP_X:
6861 g_value_set_int (value, xvimagesink->src_crop.x);
6863 case PROP_SRC_CROP_Y:
6864 g_value_set_int (value, xvimagesink->src_crop.y);
6866 case PROP_SRC_CROP_W:
6867 g_value_set_int (value, xvimagesink->src_crop.w);
6869 case PROP_SRC_CROP_H:
6870 g_value_set_int (value, xvimagesink->src_crop.h);
6872 case PROP_STOP_VIDEO:
6873 g_value_set_int (value, xvimagesink->stop_video);
6875 case PROP_PIXMAP_CB:
6876 g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
6878 case PROP_PIXMAP_CB_USER_DATA:
6879 g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
6881 case PROP_ENABLE_FLUSH_BUFFER:
6882 g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
6885 g_value_set_boolean(value, xvimagesink->is_pixmap);
6888 #endif /* GST_EXT_XV_ENHANCEMENT */
6890 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6896 gst_xvimagesink_reset (GstXvImageSink * xvimagesink)
6900 GST_OBJECT_LOCK (xvimagesink);
6901 xvimagesink->running = FALSE;
6902 /* grab thread and mark it as NULL */
6903 thread = xvimagesink->event_thread;
6904 xvimagesink->event_thread = NULL;
6905 GST_OBJECT_UNLOCK (xvimagesink);
6907 /* invalidate the pool, current allocations continue, new buffer_alloc fails
6908 * with wrong_state */
6909 g_mutex_lock (xvimagesink->pool_lock);
6910 xvimagesink->pool_invalid = TRUE;
6911 g_mutex_unlock (xvimagesink->pool_lock);
6913 /* Wait for our event thread to finish before we clean up our stuff. */
6915 g_thread_join (thread);
6917 if (xvimagesink->cur_image) {
6918 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
6919 xvimagesink->cur_image = NULL;
6921 if (xvimagesink->xvimage) {
6922 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
6923 xvimagesink->xvimage = NULL;
6925 #ifdef GST_EXT_XV_ENHANCEMENT
6926 if (xvimagesink->last_image) {
6927 gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->last_image));
6928 xvimagesink->last_image = NULL;
6930 #endif /* GST_EXT_XV_ENHANCEMENT */
6932 gst_xvimagesink_imagepool_clear (xvimagesink);
6934 if (xvimagesink->xwindow) {
6935 gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
6936 gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
6937 xvimagesink->xwindow = NULL;
6939 #ifdef GST_EXT_XV_ENHANCEMENT
6940 if (xvimagesink->get_pixmap_cb) {
6942 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
6943 g_mutex_lock (xvimagesink->x_lock);
6944 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
6945 XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
6946 g_mutex_unlock (xvimagesink->x_lock);
6948 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
6949 if (xvimagesink->xpixmap[i]) {
6950 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
6951 xvimagesink->xpixmap[i] = NULL;
6954 xvimagesink->get_pixmap_cb = NULL;
6955 xvimagesink->get_pixmap_cb_user_data = NULL;
6957 #endif /* GST_EXT_XV_ENHANCEMENT */
6958 xvimagesink->render_rect.x = xvimagesink->render_rect.y =
6959 xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
6960 xvimagesink->have_render_rect = FALSE;
6962 gst_xvimagesink_xcontext_clear (xvimagesink);
6965 /* Finalize is called only once, dispose can be called multiple times.
6966 * We use mutexes and don't reset stuff to NULL here so let's register
6969 gst_xvimagesink_finalize (GObject * object)
6971 GstXvImageSink *xvimagesink;
6973 xvimagesink = GST_XVIMAGESINK (object);
6975 gst_xvimagesink_reset (xvimagesink);
6977 if (xvimagesink->display_name) {
6978 g_free (xvimagesink->display_name);
6979 xvimagesink->display_name = NULL;
6982 if (xvimagesink->par) {
6983 g_free (xvimagesink->par);
6984 xvimagesink->par = NULL;
6986 if (xvimagesink->x_lock) {
6987 g_mutex_free (xvimagesink->x_lock);
6988 xvimagesink->x_lock = NULL;
6990 if (xvimagesink->flow_lock) {
6991 g_mutex_free (xvimagesink->flow_lock);
6992 xvimagesink->flow_lock = NULL;
6994 if (xvimagesink->pool_lock) {
6995 g_mutex_free (xvimagesink->pool_lock);
6996 xvimagesink->pool_lock = NULL;
6998 #ifdef GST_EXT_XV_ENHANCEMENT
6999 if (xvimagesink->display_buffer_lock) {
7000 g_mutex_free (xvimagesink->display_buffer_lock);
7001 xvimagesink->display_buffer_lock = NULL;
7003 #endif /* GST_EXT_XV_ENHANCEMENT */
7005 g_free (xvimagesink->media_title);
7007 G_OBJECT_CLASS (parent_class)->finalize (object);
7011 gst_xvimagesink_init (GstXvImageSink * xvimagesink,
7012 GstXvImageSinkClass * xvimagesinkclass)
7014 #ifdef GST_EXT_XV_ENHANCEMENT
7017 #endif /* GST_EXT_XV_ENHANCEMENT */
7019 xvimagesink->display_name = NULL;
7020 xvimagesink->adaptor_no = 0;
7021 xvimagesink->xcontext = NULL;
7022 xvimagesink->xwindow = NULL;
7023 xvimagesink->xvimage = NULL;
7024 xvimagesink->cur_image = NULL;
7025 #ifdef GST_EXT_XV_ENHANCEMENT
7026 xvimagesink->last_image = NULL;
7027 #endif /* GST_EXT_XV_ENHANCEMENT */
7029 xvimagesink->hue = xvimagesink->saturation = 0;
7030 xvimagesink->contrast = xvimagesink->brightness = 0;
7031 xvimagesink->cb_changed = FALSE;
7033 xvimagesink->fps_n = 0;
7034 xvimagesink->fps_d = 0;
7035 xvimagesink->video_width = 0;
7036 xvimagesink->video_height = 0;
7038 xvimagesink->x_lock = g_mutex_new ();
7039 xvimagesink->flow_lock = g_mutex_new ();
7041 xvimagesink->image_pool = NULL;
7042 xvimagesink->pool_lock = g_mutex_new ();
7044 xvimagesink->synchronous = FALSE;
7045 xvimagesink->double_buffer = TRUE;
7046 xvimagesink->running = FALSE;
7047 xvimagesink->keep_aspect = FALSE;
7048 xvimagesink->handle_events = TRUE;
7049 xvimagesink->par = NULL;
7050 xvimagesink->handle_expose = TRUE;
7051 xvimagesink->autopaint_colorkey = TRUE;
7053 /* on 16bit displays this becomes r,g,b = 1,2,3
7054 * on 24bit displays this becomes r,g,b = 8,8,16
7055 * as a port atom value
7057 xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16;
7058 xvimagesink->draw_borders = TRUE;
7060 #ifdef GST_EXT_XV_ENHANCEMENT
7061 xvimagesink->xid_updated = FALSE;
7062 xvimagesink->display_mode = DISPLAY_MODE_DEFAULT;
7063 xvimagesink->csc_range = CSC_RANGE_NARROW;
7064 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
7065 xvimagesink->flip = DEF_DISPLAY_FLIP;
7066 xvimagesink->rotate_angle = DEGREE_270;
7067 xvimagesink->visible = TRUE;
7068 xvimagesink->zoom = 1.0;
7069 xvimagesink->zoom_pos_x = -1;
7070 xvimagesink->zoom_pos_y = -1;
7071 xvimagesink->rotation = -1;
7072 xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
7073 xvimagesink->dst_roi_orientation = DEGREE_0;
7074 xvimagesink->dst_roi.x = 0;
7075 xvimagesink->dst_roi.y = 0;
7076 xvimagesink->dst_roi.w = 0;
7077 xvimagesink->dst_roi.h = 0;
7078 xvimagesink->src_crop.x = 0;
7079 xvimagesink->src_crop.y = 0;
7080 xvimagesink->src_crop.w = 0;
7081 xvimagesink->src_crop.h = 0;
7082 xvimagesink->xim_transparenter = NULL;
7083 xvimagesink->scr_w = 0;
7084 xvimagesink->scr_h = 0;
7085 xvimagesink->aligned_width = 0;
7086 xvimagesink->aligned_height = 0;
7087 xvimagesink->stop_video = FALSE;
7088 xvimagesink->is_hided = FALSE;
7089 xvimagesink->drm_fd = -1;
7090 xvimagesink->current_pixmap_idx = -1;
7091 xvimagesink->get_pixmap_cb = NULL;
7092 xvimagesink->get_pixmap_cb_user_data = NULL;
7094 for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
7095 xvimagesink->displaying_buffers[i].buffer = NULL;
7096 for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
7097 xvimagesink->displaying_buffers[i].gem_name[j] = 0;
7098 xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
7099 xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
7100 xvimagesink->displaying_buffers[i].ref_count = 0;
7104 xvimagesink->display_buffer_lock = g_mutex_new ();
7106 xvimagesink->displayed_buffer_count = 0;
7107 xvimagesink->displaying_buffer_count = 0;
7108 xvimagesink->is_zero_copy_format = FALSE;
7109 xvimagesink->secure_path = SECURE_PATH_INIT;
7110 xvimagesink->drm_level = DRM_LEVEL_0;
7111 xvimagesink->last_added_buffer_index = -1;
7112 xvimagesink->bufmgr = NULL;
7113 xvimagesink->flush_buffer = NULL;
7114 xvimagesink->enable_flush_buffer = TRUE;
7116 GST_WARNING("FAIL to call XInitThreads()");
7117 #endif /* GST_EXT_XV_ENHANCEMENT */
7121 gst_xvimagesink_base_init (gpointer g_class)
7123 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
7125 gst_element_class_set_details_simple (element_class,
7126 "Video sink", "Sink/Video",
7127 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
7129 gst_element_class_add_static_pad_template (element_class,
7130 &gst_xvimagesink_sink_template_factory);
7134 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
7136 GObjectClass *gobject_class;
7137 GstElementClass *gstelement_class;
7138 GstBaseSinkClass *gstbasesink_class;
7139 GstVideoSinkClass *videosink_class;
7141 gobject_class = (GObjectClass *) klass;
7142 gstelement_class = (GstElementClass *) klass;
7143 gstbasesink_class = (GstBaseSinkClass *) klass;
7144 videosink_class = (GstVideoSinkClass *) klass;
7146 gobject_class->set_property = gst_xvimagesink_set_property;
7147 gobject_class->get_property = gst_xvimagesink_get_property;
7149 g_object_class_install_property (gobject_class, PROP_CONTRAST,
7150 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
7151 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7152 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
7153 g_param_spec_int ("brightness", "Brightness",
7154 "The brightness of the video", -1000, 1000, 0,
7155 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7156 g_object_class_install_property (gobject_class, PROP_HUE,
7157 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
7158 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7159 g_object_class_install_property (gobject_class, PROP_SATURATION,
7160 g_param_spec_int ("saturation", "Saturation",
7161 "The saturation of the video", -1000, 1000, 0,
7162 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7163 g_object_class_install_property (gobject_class, PROP_DISPLAY,
7164 g_param_spec_string ("display", "Display", "X Display name", NULL,
7165 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7166 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
7167 g_param_spec_boolean ("synchronous", "Synchronous",
7168 "When enabled, runs the X display in synchronous mode. "
7169 "(unrelated to A/V sync, used only for debugging)", FALSE,
7170 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7171 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
7172 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
7173 "The pixel aspect ratio of the device", "1/1",
7174 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7175 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
7176 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
7177 "When enabled, scaling will respect original aspect ratio", FALSE,
7178 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7179 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
7180 g_param_spec_boolean ("handle-events", "Handle XEvents",
7181 "When enabled, XEvents will be selected and handled", TRUE,
7182 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7183 g_object_class_install_property (gobject_class, PROP_DEVICE,
7184 g_param_spec_string ("device", "Adaptor number",
7185 "The number of the video adaptor", "0",
7186 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7187 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
7188 g_param_spec_string ("device-name", "Adaptor name",
7189 "The name of the video adaptor", NULL,
7190 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7192 * GstXvImageSink:handle-expose
7194 * When enabled, the current frame will always be drawn in response to X
7199 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
7200 g_param_spec_boolean ("handle-expose", "Handle expose",
7202 "the current frame will always be drawn in response to X Expose "
7203 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7206 * GstXvImageSink:double-buffer
7208 * Whether to double-buffer the output.
7212 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
7213 g_param_spec_boolean ("double-buffer", "Double-buffer",
7214 "Whether to double-buffer the output", TRUE,
7215 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7217 * GstXvImageSink:autopaint-colorkey
7219 * Whether to autofill overlay with colorkey
7223 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
7224 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
7225 "Whether to autofill overlay with colorkey", TRUE,
7226 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7228 * GstXvImageSink:colorkey
7230 * Color to use for the overlay mask.
7234 g_object_class_install_property (gobject_class, PROP_COLORKEY,
7235 g_param_spec_int ("colorkey", "Colorkey",
7236 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
7237 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7240 * GstXvImageSink:draw-borders
7242 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
7243 * unused parts of the video area.
7247 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
7248 g_param_spec_boolean ("draw-borders", "Colorkey",
7249 "Draw black borders to fill unused area in force-aspect-ratio mode",
7250 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7253 * GstXvImageSink:window-width
7255 * Actual width of the video window.
7259 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
7260 g_param_spec_uint64 ("window-width", "window-width",
7261 "Width of the window", 0, G_MAXUINT64, 0,
7262 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7265 * GstXvImageSink:window-height
7267 * Actual height of the video window.
7271 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
7272 g_param_spec_uint64 ("window-height", "window-height",
7273 "Height of the window", 0, G_MAXUINT64, 0,
7274 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
7276 #ifdef GST_EXT_XV_ENHANCEMENT
7278 * GstXvImageSink:display-mode
7280 * select display mode
7282 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
7283 g_param_spec_enum("display-mode", "Display Mode",
7284 "Display device setting",
7285 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
7286 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7289 * GstXvImageSink:csc-range
7291 * select color space range
7293 g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
7294 g_param_spec_enum("csc-range", "Color Space Range",
7295 "Color space range setting",
7296 GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
7297 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7300 * GstXvImageSink:display-geometry-method
7302 * Display geometrical method setting
7304 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
7305 g_param_spec_enum("display-geometry-method", "Display geometry method",
7306 "Geometrical method for display",
7307 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
7308 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7311 * GstXvImageSink:display-flip
7313 * Display flip setting
7315 g_object_class_install_property(gobject_class, PROP_FLIP,
7316 g_param_spec_enum("flip", "Display flip",
7318 GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
7319 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7322 * GstXvImageSink:rotate
7324 * Draw rotation angle setting
7326 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
7327 g_param_spec_enum("rotate", "Rotate angle",
7328 "Rotate angle of display output",
7329 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
7330 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7333 * GstXvImageSink:visible
7335 * Whether reserve original src size or not
7337 g_object_class_install_property (gobject_class, PROP_VISIBLE,
7338 g_param_spec_boolean ("visible", "Visible",
7339 "Draws screen or blacks out, true means visible, false blacks out",
7340 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7343 * GstXvImageSink:zoom
7345 * Scale small area of screen to 1X~ 9X
7347 g_object_class_install_property (gobject_class, PROP_ZOOM,
7348 g_param_spec_float ("zoom", "Zoom",
7349 "Zooms screen as nX", 1.0, 9.0, 1.0,
7350 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7353 * GstXvImageSink:zoom-pos-x
7355 * Standard x-position of zoom
7357 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
7358 g_param_spec_int ("zoom-pos-x", "Zoom Position X",
7359 "Standard x-position of zoom", -1, 3840, -1,
7360 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7363 * GstXvImageSink:zoom-pos-y
7365 * Standard y-position of zoom
7367 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
7368 g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
7369 "Standard y-position of zoom", -1, 3840, -1,
7370 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7373 * GstXvImageSink:dst-roi-mode
7375 * Display geometrical method of ROI setting
7377 g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
7378 g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
7379 "Geometrical method of ROI for display",
7380 GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
7381 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7384 * GstXvImageSink:dst-roi-orientation
7386 * Orientation information which will be used for ROI/ZOOM
7388 g_object_class_install_property(gobject_class, PROP_DST_ROI_ORIENTATION,
7389 g_param_spec_enum("dst-roi-orientation", "Orientation information used for ROI/ZOOM",
7390 "Orientation information for display",
7391 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
7392 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7395 * GstXvImageSink:dst-roi-x
7397 * X value of Destination ROI
7399 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
7400 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
7401 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7402 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7405 * GstXvImageSink:dst-roi-y
7407 * Y value of Destination ROI
7409 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
7410 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
7411 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7412 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7415 * GstXvImageSink:dst-roi-w
7417 * W value of Destination ROI
7419 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
7420 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
7421 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
7422 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7425 * GstXvImageSink:dst-roi-h
7427 * H value of Destination ROI
7429 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
7430 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
7431 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
7432 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7435 * GstXvImageSink:stop-video
7437 * Stop video for releasing video source buffer
7439 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
7440 g_param_spec_int ("stop-video", "Stop-Video",
7441 "Stop video for releasing video source buffer", 0, 1, 0,
7442 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7444 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
7445 g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
7446 "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
7448 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
7449 g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
7450 "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
7453 * GstXvImageSink:src-crop-x
7455 * X value of video source crop
7457 g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
7458 g_param_spec_int ("src-crop-x", "Source Crop X",
7459 "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7460 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7463 * GstXvImageSink:src-crop-y
7465 * Y value of video source crop
7467 g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
7468 g_param_spec_int ("src-crop-y", "Source Crop X",
7469 "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7470 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7473 * GstXvImageSink:src-crop-w
7475 * Width value of video source crop
7477 g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
7478 g_param_spec_int ("src-crop-w", "Source Crop Width",
7479 "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7480 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7483 * GstXvImageSink:src-crop-h
7485 * Height value of video source crop
7487 g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
7488 g_param_spec_int ("src-crop-h", "Source Crop Height",
7489 "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
7490 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7493 * GstXvImageSink:enable-flush-buffer
7495 * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
7497 g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
7498 g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
7499 "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
7500 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7503 * GstXvImageSink:is-pixmap
7505 * Check using pixmap id for blocking X api
7507 g_object_class_install_property (gobject_class, PROP_PIXMAP,
7508 g_param_spec_boolean("is-pixmap", "Check if use pixmap",
7509 "Check using pixmap id for blocking X api",
7510 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
7513 * GstXvImageSink::frame-render-error
7515 gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
7516 "frame-render-error",
7517 G_TYPE_FROM_CLASS (klass),
7522 gst_xvimagesink_BOOLEAN__POINTER,
7527 #endif /* GST_EXT_XV_ENHANCEMENT */
7529 gobject_class->finalize = gst_xvimagesink_finalize;
7531 gstelement_class->change_state =
7532 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
7534 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
7535 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
7536 gstbasesink_class->buffer_alloc =
7537 GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
7538 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
7539 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
7541 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
7544 /* ============================================================= */
7546 /* Public Methods */
7548 /* ============================================================= */
7550 /* =========================================== */
7552 /* Object typing & Creation */
7554 /* =========================================== */
7556 gst_xvimagesink_init_interfaces (GType type)
7558 static const GInterfaceInfo iface_info = {
7559 (GInterfaceInitFunc) gst_xvimagesink_interface_init,
7563 static const GInterfaceInfo navigation_info = {
7564 (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
7568 static const GInterfaceInfo overlay_info = {
7569 (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
7573 static const GInterfaceInfo colorbalance_info = {
7574 (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
7578 static const GInterfaceInfo propertyprobe_info = {
7579 (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
7584 g_type_add_interface_static (type,
7585 GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
7586 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
7587 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
7588 g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
7589 &colorbalance_info);
7590 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
7591 &propertyprobe_info);
7593 /* register type and create class in a more safe place instead of at
7594 * runtime since the type registration and class creation is not
7596 g_type_class_ref (gst_xvimage_buffer_get_type ());
7600 plugin_init (GstPlugin * plugin)
7602 if (!gst_element_register (plugin, "xvimagesink",
7603 GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
7606 GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
7607 "xvimagesink element");
7608 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
7613 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
7616 "XFree86 video output plugin using Xv extension",
7617 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)