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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, 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 #GstVideoOverlay interface and will then render
35 * video frames in this drawable. If no Window ID was provided by the
36 * application, the element will create its own internal window and render
40 * <title>Scaling</title>
42 * The XVideo extension, when it's available, handles hardware accelerated
43 * scaling of video frames. This means that the element will just accept
44 * incoming video frames no matter their geometry and will then put them to the
45 * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio
46 * property it is possible to enforce scaling with a constant aspect ratio,
47 * which means drawing black borders around the video frame.
51 * <title>Events</title>
53 * XvImageSink creates a thread to handle events coming from the drawable. There
54 * are several kind of events that can be grouped in 2 big categories: input
55 * events and window state related events. Input events will be translated to
56 * navigation events and pushed upstream for other elements to react on them.
57 * This includes events such as pointer moves, key press/release, clicks etc...
58 * Other events are used to handle the drawable appearance even when the data
59 * is not flowing (GST_STATE_PAUSED). That means that even when the element is
60 * paused, it will receive expose events from the drawable and draw the latest
61 * frame with correct borders/aspect-ratio.
65 * <title>Pixel aspect ratio</title>
67 * When changing state to GST_STATE_READY, XvImageSink will open a connection to
68 * the display specified in the #GstXvImageSink:display property or the
69 * default display if nothing specified. Once this connection is open it will
70 * inspect the display configuration including the physical display geometry and
71 * then calculate the pixel aspect ratio. When receiving video frames with a
72 * different pixel aspect ratio, XvImageSink will use hardware scaling to
73 * display the video frames correctly on display's pixel aspect ratio.
74 * Sometimes the calculated pixel aspect ratio can be wrong, it is
75 * then possible to enforce a specific pixel aspect ratio using the
76 * #GstXvImageSink:pixel-aspect-ratio property.
80 * <title>Examples</title>
82 * gst-launch -v videotestsrc ! xvimagesink
83 * ]| A pipeline to test hardware scaling.
84 * When the test video signal appears you can resize the window and see that
85 * video frames are scaled through hardware (no extra CPU cost).
87 * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true
88 * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true
89 * You can observe the borders drawn around the scaled image respecting aspect
92 * gst-launch -v videotestsrc ! navigationtest ! xvimagesink
93 * ]| A pipeline to test navigation events.
94 * While moving the mouse pointer over the test signal you will see a black box
95 * following the mouse pointer. If you press the mouse button somewhere on the
96 * video and release it somewhere else a green box will appear where you pressed
97 * the button and a red one where you released it. (The navigationtest element
98 * is part of gst-plugins-good.) You can observe here that even if the images
99 * are scaled through hardware the pointer coordinates are converted back to the
100 * original video frame geometry so that the box can be drawn to the correct
101 * position. This also handles borders correctly, limiting coordinates to the
104 * gst-launch -v videotestsrc ! video/x-raw, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink
105 * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by
106 * videotestsrc, in most cases the pixel aspect ratio of the display will be
107 * 1/1. This means that XvImageSink will have to do the scaling to convert
108 * incoming frames to a size that will match the display pixel aspect ratio
109 * (from 320x240 to 320x180 in this case). Note that you might have to escape
110 * some characters for your shell like '\(fraction\)'.
112 * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100
113 * ]| Demonstrates how to use the colorbalance interface.
117 /* for developers: there are two useful tools : xvinfo and xvattr */
124 #include <gst/video/navigation.h>
125 #include <gst/video/videooverlay.h>
126 #include <gst/video/colorbalance.h>
127 /* Helper functions */
128 #include <gst/video/gstvideometa.h>
131 #include "xvimagesink.h"
132 #include "xvimageallocator.h"
134 #ifdef GST_EXT_XV_ENHANCEMENT
135 /* Samsung extension headers */
136 /* For xv extension header for buffer transfer (output) */
137 #include "xv_types.h"
139 /* for performance checking */
143 BUF_SHARE_METHOD_PADDR = 0,
145 BUF_SHARE_METHOD_TIZEN_BUFFER
146 } buf_share_method_t;
148 #define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */
149 #endif /* GST_EXT_XV_ENHANCEMENT */
152 /* Debugging category */
153 #include <gst/gstinfo.h>
155 /* for XkbKeycodeToKeysym */
156 #include <X11/XKBlib.h>
158 GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagesink);
159 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
160 #define GST_CAT_DEFAULT gst_debug_xvimagesink
162 #ifdef GST_EXT_XV_ENHANCEMENT
163 #define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
166 gst_xvimagesink_display_mode_get_type(void)
168 static GType xvimagesink_display_mode_type = 0;
169 static const GEnumValue display_mode_type[] = {
170 { 0, "Default mode", "DEFAULT"},
171 { 1, "Primary video ON and Secondary video FULL SCREEN mode", "PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN"},
172 { 2, "Primary video OFF and Secondary video FULL SCREEN mode", "PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN"},
176 if (!xvimagesink_display_mode_type) {
177 xvimagesink_display_mode_type = g_enum_register_static("GstXVImageSinkDisplayModeType", display_mode_type);
180 return xvimagesink_display_mode_type;
191 #define GST_TYPE_XVIMAGESINK_ROTATE_ANGLE (gst_xvimagesink_rotate_angle_get_type())
194 gst_xvimagesink_rotate_angle_get_type(void)
196 static GType xvimagesink_rotate_angle_type = 0;
197 static const GEnumValue rotate_angle_type[] = {
198 { 0, "No rotate", "DEGREE_0"},
199 { 1, "Rotate 90 degree", "DEGREE_90"},
200 { 2, "Rotate 180 degree", "DEGREE_180"},
201 { 3, "Rotate 270 degree", "DEGREE_270"},
205 if (!xvimagesink_rotate_angle_type) {
206 xvimagesink_rotate_angle_type = g_enum_register_static("GstXVImageSinkRotateAngleType", rotate_angle_type);
209 return xvimagesink_rotate_angle_type;
213 DISP_GEO_METHOD_LETTER_BOX = 0,
214 DISP_GEO_METHOD_ORIGIN_SIZE,
215 DISP_GEO_METHOD_FULL_SCREEN,
216 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
217 DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
218 DISP_GEO_METHOD_CUSTOM_DST_ROI,
223 ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
224 ROI_DISP_GEO_METHOD_LETTER_BOX,
225 ROI_DISP_GEO_METHOD_NUM,
228 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
229 #define DEF_ROI_DISPLAY_GEOMETRY_METHOD ROI_DISP_GEO_METHOD_FULL_SCREEN
238 #define DEF_DISPLAY_FLIP FLIP_NONE
240 #define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
241 #define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
242 #define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type())
245 gst_xvimagesink_display_geometry_method_get_type(void)
247 static GType xvimagesink_display_geometry_method_type = 0;
248 static const GEnumValue display_geometry_method_type[] = {
249 { 0, "Letter box", "LETTER_BOX"},
250 { 1, "Origin size", "ORIGIN_SIZE"},
251 { 2, "Full-screen", "FULL_SCREEN"},
252 { 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
253 { 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"},
254 { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
258 if (!xvimagesink_display_geometry_method_type) {
259 xvimagesink_display_geometry_method_type = g_enum_register_static("GstXVImageSinkDisplayGeometryMethodType", display_geometry_method_type);
262 return xvimagesink_display_geometry_method_type;
266 gst_xvimagesink_roi_display_geometry_method_get_type(void)
268 static GType xvimagesink_roi_display_geometry_method_type = 0;
269 static const GEnumValue roi_display_geometry_method_type[] = {
270 { 0, "ROI-Full-screen", "FULL_SCREEN"},
271 { 1, "ROI-Letter box", "LETTER_BOX"},
275 if (!xvimagesink_roi_display_geometry_method_type) {
276 xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
279 return xvimagesink_roi_display_geometry_method_type;
283 gst_xvimagesink_flip_get_type(void)
285 static GType xvimagesink_flip_type = 0;
286 static const GEnumValue flip_type[] = {
287 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
288 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
289 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
290 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
291 { FLIP_NUM, NULL, NULL},
294 if (!xvimagesink_flip_type) {
295 xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
298 return xvimagesink_flip_type;
301 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
303 gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure,
304 GValue *return_value G_GNUC_UNUSED,
305 guint n_param_values,
306 const GValue *param_values,
307 gpointer invocation_hint G_GNUC_UNUSED,
308 gpointer marshal_data)
310 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
313 register GMarshalFunc_BOOLEAN__POINTER callback;
314 register GCClosure *cc = (GCClosure*) closure;
315 register gpointer data1, data2;
319 g_return_if_fail (return_value != NULL);
320 g_return_if_fail (n_param_values == 2);
322 if (G_CCLOSURE_SWAP_DATA (closure)) {
323 data1 = closure->data;
324 data2 = g_value_peek_pointer (param_values + 0);
326 data1 = g_value_peek_pointer (param_values + 0);
327 data2 = closure->data;
329 callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
331 v_return = callback (data1,
332 g_marshal_value_peek_pointer (param_values + 1),
335 g_value_set_boolean (return_value, v_return);
340 SIGNAL_FRAME_RENDER_ERROR,
343 #endif /* GST_EXT_XV_ENHANCEMENT */
348 unsigned long functions;
349 unsigned long decorations;
351 unsigned long status;
353 MotifWmHints, MwmHints;
355 #define MWM_HINTS_DECORATIONS (1L << 1)
357 static gboolean gst_xvimagesink_open (GstXvImageSink * xvimagesink);
358 static void gst_xvimagesink_close (GstXvImageSink * xvimagesink);
359 static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
361 static void gst_xvimagesink_expose (GstVideoOverlay * overlay);
362 #ifdef GST_EXT_XV_ENHANCEMENT
363 static void gst_xvimagesink_set_pixmap_handle (GstVideoOverlay * overlay, guintptr id);
364 static void gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,GstXPixmap * xpixmap);
365 static int gst_xvimage_pixmap_xerror (Display * display, XErrorEvent * xevent);
368 /* Default template - initiated with class struct to allow gst-register to work
370 static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
371 GST_STATIC_PAD_TEMPLATE ("sink",
374 GST_STATIC_CAPS ("video/x-raw, "
375 "framerate = (fraction) [ 0, MAX ], "
376 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
388 PROP_PIXEL_ASPECT_RATIO,
389 PROP_FORCE_ASPECT_RATIO,
395 PROP_AUTOPAINT_COLORKEY,
400 #ifdef GST_EXT_XV_ENHANCEMENT
404 PROP_DISPLAY_GEOMETRY_METHOD,
415 #ifdef ENABLE_STOP_VIDEO
419 PROP_PIXMAP_CB_USER_DATA
420 #endif /* GST_EXT_XV_ENHANCEMENT */
423 /* ============================================================= */
427 /* ============================================================= */
429 /* =========================================== */
431 /* Object typing & Creation */
433 /* =========================================== */
434 static void gst_xvimagesink_navigation_init (GstNavigationInterface * iface);
435 static void gst_xvimagesink_video_overlay_init (GstVideoOverlayInterface *
437 static void gst_xvimagesink_colorbalance_init (GstColorBalanceInterface *
439 #define gst_xvimagesink_parent_class parent_class
440 G_DEFINE_TYPE_WITH_CODE (GstXvImageSink, gst_xvimagesink, GST_TYPE_VIDEO_SINK,
441 G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
442 gst_xvimagesink_navigation_init);
443 G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
444 gst_xvimagesink_video_overlay_init);
445 G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
446 gst_xvimagesink_colorbalance_init));
449 /* ============================================================= */
451 /* Private Methods */
453 /* ============================================================= */
454 #ifdef GST_EXT_XV_ENHANCEMENT
456 static gboolean error_caught = FALSE;
459 gst_xvimage_pixmap_xerror (Display * display, XErrorEvent * xevent)
461 char error_msg[1024];
463 XGetErrorText (display, xevent->error_code, error_msg, 1024);
464 GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg);
470 gst_xvimagesink_pixmap_render(GstXvImageMemory * mem, GstVideoRectangle * src_input,
471 GstVideoRectangle * result, gboolean draw_border, GstXvImageSink * xvimagesink)
473 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
474 g_return_if_fail (src_input != NULL);
475 g_return_if_fail (result != NULL);
476 g_return_if_fail (mem != NULL);
478 if (!xvimagesink->get_pixmap_cb) {
485 int (*handler) (Display *, XErrorEvent *) = NULL;
486 XV_DATA_PTR img_data = NULL;
487 g_mutex_lock (&xvimagesink->context->lock);
488 xvimage = gst_xvimage_memory_get_xvimage (mem);
489 idx = xvimagesink->current_pixmap_idx;
492 if (xvimagesink->context->use_xshm) {
494 /* set error handler */
495 error_caught = FALSE;
496 handler = XSetErrorHandler(gst_xvimage_pixmap_xerror);
498 g_mutex_lock(xvimagesink->context->display_buffer_lock);
499 if (xvimagesink->context->displaying_buffer_count > 3) {
500 GST_WARNING("too many buffers are pushed. skip this... [displaying_buffer_count %d]",
501 xvimagesink->context->displaying_buffer_count);
503 g_mutex_unlock(xvimagesink->context->display_buffer_lock);
505 ret = XvShmPutImage (xvimagesink->context->disp,
506 xvimagesink->context->xv_port_id,
507 xvimagesink->xpixmap[idx]->pixmap,
508 xvimagesink->xpixmap[idx]->gc, xvimage,
509 src_input->x, src_input->y, src_input->w, src_input->h,
510 result->x, result->y, result->w, result->h, FALSE);
511 GST_LOG_OBJECT( mem, "XvShmPutImage return value [%d]", ret );
513 XSync (xvimagesink->context->disp, FALSE);
515 if (ret || error_caught) {
516 GST_WARNING("putimage error : ret %d, error_caught %d, displaying buffer count %d",
517 ret, error_caught, xvimagesink->context->displaying_buffer_count);
519 /* release gem handle */
520 img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage(mem)->data;
522 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
523 gem_name[0] = img_data->YBuf;
524 gem_name[1] = img_data->CbBuf;
525 gem_name[2] = img_data->CrBuf;
526 gst_xvcontext_remove_displaying_buffer(xvimagesink->context, gem_name);
530 /* Reset error handler */
531 error_caught = FALSE;
532 XSetErrorHandler (handler);
534 g_mutex_unlock (&xvimagesink->context->lock);
540 /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
541 * if no window was available */
543 gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
545 GstXvImageMemory *mem;
546 GstVideoCropMeta *crop;
547 GstVideoRectangle result;
548 gboolean draw_border = FALSE;
549 GstVideoRectangle src, dst;
550 GstVideoRectangle mem_crop;
552 #ifdef GST_EXT_XV_ENHANCEMENT
553 static Atom atom_rotation = None;
554 static Atom atom_hflip = None;
555 static Atom atom_vflip = None;
556 gboolean set_hflip = FALSE;
557 gboolean set_vflip = FALSE;
559 GstVideoRectangle src_origin = { 0, 0, 0, 0};
560 GstVideoRectangle src_input = { 0, 0, 0, 0};
562 gint res_rotate_angle = 0;
567 if (!xvimagesink->get_pixmap_cb){
568 gst_xvimagesink_xwindow_update_geometry( xvimagesink );
570 #endif /* GST_EXT_XV_ENHANCEMENT */
572 /* We take the flow_lock. If expose is in there we don't want to run
573 concurrently from the data flow thread */
574 g_mutex_lock (&xvimagesink->flow_lock);
576 #ifdef GST_EXT_XV_ENHANCEMENT
577 if (xvimagesink->xid_updated) {
579 GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
582 xvimagesink->xid_updated = FALSE;
584 #endif /* GST_EXT_XV_ENHANCEMENT */
586 #ifdef GST_EXT_XV_ENHANCEMENT
587 if (G_UNLIKELY ((xwindow = xvimagesink->xwindow) == NULL)) {
588 if (xvimagesink->get_pixmap_cb){
589 GST_INFO("xwindow is NULL, but it has get_pixmap_cb(%p), keep going..",xvimagesink->get_pixmap_cb );
591 GST_INFO("xwindow is NULL. Skip xvimage_put.");
592 g_mutex_unlock (&xvimagesink->flow_lock);
597 if (G_UNLIKELY ((xwindow = xvimagesink->xwindow) == NULL)) {
598 g_mutex_unlock (&xvimagesink->flow_lock);
602 /* Draw borders when displaying the first frame. After this
603 draw borders only on expose event or after a size change. */
604 if (!xvimagesink->cur_image || xvimagesink->redraw_border) {
605 draw_border = xvimagesink->draw_borders;
606 xvimagesink->redraw_border = FALSE;
609 /* Store a reference to the last image we put, lose the previous one */
610 if (xvimage && xvimagesink->cur_image != xvimage) {
611 if (xvimagesink->cur_image) {
612 GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
613 gst_buffer_unref (xvimagesink->cur_image);
615 GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
616 xvimagesink->cur_image = gst_buffer_ref (xvimage);
619 /* Expose sends a NULL image, we take the latest frame */
621 if (xvimagesink->cur_image) {
623 xvimage = xvimagesink->cur_image;
625 #ifdef GST_EXT_XV_ENHANCEMENT
626 GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
627 /* no need to release gem handle */
628 #endif /* GST_EXT_XV_ENHANCEMENT */
629 g_mutex_unlock (&xvimagesink->flow_lock);
634 mem = (GstXvImageMemory *) gst_buffer_peek_memory (xvimage, 0);
635 #ifdef GST_EXT_XV_ENHANCEMENT
636 if (!xvimagesink->visible) {
637 GST_INFO("visible[%d]. Skip xvimage_put.",
638 xvimagesink->visible);
639 g_mutex_unlock(&xvimagesink->flow_lock);
643 if (xvimagesink->get_pixmap_cb) {
644 gst_xvimagesink_set_pixmap_handle ((GstVideoOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
645 idx = xvimagesink->current_pixmap_idx;
647 g_mutex_unlock (&xvimagesink->flow_lock);
649 } else if (idx == -2) {
650 GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
651 g_mutex_unlock (&xvimagesink->flow_lock);
656 res_rotate_angle = xvimagesink->rotate_angle;
659 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
661 src_input.w = src_origin.w = xvimagesink->video_width;
662 src_input.h = src_origin.h = xvimagesink->video_height;
664 if (xvimagesink->rotate_angle == DEGREE_0 ||
665 xvimagesink->rotate_angle == DEGREE_180) {
666 src.w = src_origin.w;
667 src.h = src_origin.h;
669 src.w = src_origin.h;
670 src.h = src_origin.w;
672 if (xvimagesink->get_pixmap_cb) {
673 dst.w = xvimagesink->xpixmap[idx]->width;
674 dst.h = xvimagesink->xpixmap[idx]->height;
677 dst.w = xwindow->render_rect.w;
678 dst.h = xwindow->render_rect.h;
680 switch (xvimagesink->display_geometry_method)
682 case DISP_GEO_METHOD_LETTER_BOX:
683 gst_video_sink_center_rect (src, dst, &result, TRUE);
684 if (xvimagesink->get_pixmap_cb) { //?
685 result.x += xvimagesink->xpixmap[idx]->x;
686 result.y += xvimagesink->xpixmap[idx]->y;
688 result.x += xwindow->render_rect.x;
689 result.y += xwindow->render_rect.y;
693 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
694 GST_WARNING_OBJECT(xvimagesink, "not supported API, set ORIGIN_SIZE mode");
695 case DISP_GEO_METHOD_ORIGIN_SIZE:
696 gst_video_sink_center_rect (src, dst, &result, FALSE);
697 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
699 if (xvimagesink->rotate_angle == DEGREE_90 ||
700 xvimagesink->rotate_angle == DEGREE_270) {
701 src_input.x = src_input.x ^ src_input.y;
702 src_input.y = src_input.x ^ src_input.y;
703 src_input.x = src_input.x ^ src_input.y;
705 src_input.w = src_input.w ^ src_input.h;
706 src_input.h = src_input.w ^ src_input.h;
707 src_input.w = src_input.w ^ src_input.h;
711 case DISP_GEO_METHOD_FULL_SCREEN:
712 result.x = result.y = 0;
713 if (xvimagesink->get_pixmap_cb) {
714 result.w = xvimagesink->xpixmap[idx]->width;
715 result.h = xvimagesink->xpixmap[idx]->height;
717 result.w = xwindow->width;
718 result.h = xwindow->height;
722 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
723 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
725 result.x = result.y = 0;
729 if (xvimagesink->rotate_angle == DEGREE_90 ||
730 xvimagesink->rotate_angle == DEGREE_270) {
731 src_input.x = src_input.x ^ src_input.y;
732 src_input.y = src_input.x ^ src_input.y;
733 src_input.x = src_input.x ^ src_input.y;
735 src_input.w = src_input.w ^ src_input.h;
736 src_input.h = src_input.w ^ src_input.h;
737 src_input.w = src_input.w ^ src_input.h;
741 case DISP_GEO_METHOD_CUSTOM_DST_ROI:
743 GstVideoRectangle dst_roi_cmpns;
744 dst_roi_cmpns.w = xvimagesink->dst_roi.w;
745 dst_roi_cmpns.h = xvimagesink->dst_roi.h;
746 dst_roi_cmpns.x = xvimagesink->dst_roi.x;
747 dst_roi_cmpns.y = xvimagesink->dst_roi.y;
749 /* setting for DST ROI mode */
750 switch (xvimagesink->dst_roi_mode) {
751 case ROI_DISP_GEO_METHOD_FULL_SCREEN:
753 case ROI_DISP_GEO_METHOD_LETTER_BOX:
755 GstVideoRectangle roi_result;
756 if (xvimagesink->orientation == DEGREE_0 ||
757 xvimagesink->orientation == DEGREE_180) {
758 src.w = src_origin.w;
759 src.h = src_origin.h;
761 src.w = src_origin.h;
762 src.h = src_origin.w;
764 dst.w = xvimagesink->dst_roi.w;
765 dst.h = xvimagesink->dst_roi.h;
767 gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
768 dst_roi_cmpns.w = roi_result.w;
769 dst_roi_cmpns.h = roi_result.h;
770 dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
771 dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
778 /* calculating coordinates according to rotation angle for DST ROI */
779 switch (xvimagesink->rotate_angle) {
781 result.w = dst_roi_cmpns.h;
782 result.h = dst_roi_cmpns.w;
784 result.x = dst_roi_cmpns.y;
785 if (xvimagesink->get_pixmap_cb) {
786 result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
788 result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
792 result.w = dst_roi_cmpns.w;
793 result.h = dst_roi_cmpns.h;
795 if (xvimagesink->get_pixmap_cb) {
796 result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
797 result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
799 result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
800 result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
804 result.w = dst_roi_cmpns.h;
805 result.h = dst_roi_cmpns.w;
806 if (xvimagesink->get_pixmap_cb) {
807 result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
809 result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
811 result.y = dst_roi_cmpns.x;
814 result.x = dst_roi_cmpns.x;
815 result.y = dst_roi_cmpns.y;
816 result.w = dst_roi_cmpns.w;
817 result.h = dst_roi_cmpns.h;
821 /* orientation setting for auto rotation in DST ROI */
822 if (xvimagesink->orientation) {
823 res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation);
824 if (res_rotate_angle < 0) {
825 res_rotate_angle += DEGREE_NUM;
827 GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
828 xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle);
831 GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
832 xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode,
833 xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
834 result.x, result.y, result.w, result.h);
841 if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
842 GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]",
843 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
844 gint default_offset_x = 0;
845 gint default_offset_y = 0;
846 gfloat w = (gfloat)src_input.w;
847 gfloat h = (gfloat)src_input.h;
848 if (xvimagesink->orientation == DEGREE_0 ||
849 xvimagesink->orientation == DEGREE_180) {
850 default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
851 default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
853 default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1;
854 default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1;
856 GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation);
857 if (xvimagesink->zoom_pos_x == -1) {
858 src_input.x += default_offset_x;
860 if (xvimagesink->orientation == DEGREE_0 ||
861 xvimagesink->orientation == DEGREE_180) {
862 if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) {
863 xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom);
865 src_input.x += xvimagesink->zoom_pos_x;
867 if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) {
868 xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom);
870 src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x;
873 if (xvimagesink->zoom_pos_y == -1) {
874 src_input.y += default_offset_y;
876 if (xvimagesink->orientation == DEGREE_0 ||
877 xvimagesink->orientation == DEGREE_180) {
878 if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) {
879 xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom);
881 src_input.y += xvimagesink->zoom_pos_y;
883 if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) {
884 xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom);
886 src_input.x += (xvimagesink->zoom_pos_y);
889 src_input.w = (gint)(w/xvimagesink->zoom);
890 src_input.h = (gint)(h/xvimagesink->zoom);
891 GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
892 xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
895 switch( res_rotate_angle )
897 /* There's slightly weired code (CCW? CW?) */
910 GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
915 /*fix top and left green pixel of video*/
916 gst_xvimage_memory_get_crop (mem, &mem_crop);
917 src_input.x += mem_crop.x;
918 src_input.y += mem_crop.y;
920 /* Trim as proper size */
921 if (src_input.w % 2 == 1) {
924 if (src_input.h % 2 == 1) {
928 if (xvimagesink->get_pixmap_cb) {
929 GST_LOG_OBJECT( xvimagesink, "pixmap[%dx%d],method[%d],rotate[%d],zoom[%lf],dp_mode[%d],src[%d,%d,%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
930 xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
931 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->config.display_mode,
932 src_origin.x, src_origin.y, src_origin.w, src_origin.h,
933 dst.x, dst.y, dst.w, dst.h,
934 src_input.x, src_input.y, src_input.w, src_input.h,
935 result.x, result.y, result.w, result.h );
938 GST_LOG_OBJECT( xvimagesink, "window[%dx%d],method[%d],rotate[%d],zoom[%lf],dp_mode[%d],src[%d,%d,%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
939 xwindow->width, xwindow->height,
940 xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->config.display_mode,
941 src_origin.x, src_origin.y, src_origin.w, src_origin.h,
942 dst.x, dst.y, dst.w, dst.h,
943 src_input.x, src_input.y, src_input.w, src_input.h,
944 result.x, result.y, result.w, result.h );
948 /* set display rotation */
949 if (atom_rotation == None) {
950 atom_rotation = XInternAtom(xvimagesink->context->disp,
951 "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
954 GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
956 ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_rotation, rotate);
957 if (ret != Success) {
958 GST_ERROR_OBJECT( mem, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
959 ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_rotation, rotate );
963 /* set display flip */
964 if (atom_hflip == None) {
965 atom_hflip = XInternAtom(xvimagesink->context->disp,
966 "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
968 if (atom_vflip == None) {
969 atom_vflip = XInternAtom(xvimagesink->context->disp,
970 "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
973 switch (xvimagesink->flip) {
974 case FLIP_HORIZONTAL:
993 ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_hflip, set_hflip);
994 if (ret != Success) {
995 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
996 ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_hflip, set_hflip);
998 ret = XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_vflip, set_vflip);
999 if (ret != Success) {
1000 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1001 ret, xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_vflip, set_vflip);
1003 #endif /* HAVE_XSHM */
1005 if (xvimagesink->get_pixmap_cb) {
1006 gst_xvimagesink_pixmap_render(mem, &src_input, &result, draw_border, xvimagesink);
1008 gst_xvimage_memory_render (mem, &src_input, xwindow, &result, draw_border);
1010 g_mutex_unlock (&xvimagesink->flow_lock);
1014 #else /* GST_EXT_XV_ENHANCEMENT */
1015 gst_xvimage_memory_get_crop (mem, &mem_crop);
1017 crop = gst_buffer_get_video_crop_meta (xvimage);
1020 src.x = crop->x + mem_crop.x;
1021 src.y = crop->y + mem_crop.y;
1022 src.w = crop->width;
1023 src.h = crop->height;
1024 GST_LOG_OBJECT (xvimagesink,
1025 "crop %dx%d-%dx%d", crop->x, crop->y, crop->width, crop->height);
1030 if (xvimagesink->keep_aspect) {
1031 GstVideoRectangle s;
1033 /* We take the size of the source material as it was negotiated and
1034 * corrected for DAR. This size can be different from the cropped size in
1035 * which case the image will be scaled to fit the negotiated size. */
1036 s.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
1037 s.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
1038 dst.w = xwindow->render_rect.w;
1039 dst.h = xwindow->render_rect.h;
1041 gst_video_sink_center_rect (s, dst, &result, TRUE);
1042 result.x += xwindow->render_rect.x;
1043 result.y += xwindow->render_rect.y;
1045 memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle));
1047 gst_xvimage_memory_render (mem, &src, xwindow, &result, draw_border);
1048 g_mutex_unlock (&xvimagesink->flow_lock);
1051 #endif /* GST_EXT_XV_ENHANCEMENT */
1055 gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink,
1056 GstXWindow * xwindow, const gchar * media_title)
1059 g_free (xvimagesink->media_title);
1060 xvimagesink->media_title = g_strdup (media_title);
1063 /* we have a window */
1064 const gchar *app_name;
1065 const gchar *title = NULL;
1066 gchar *title_mem = NULL;
1068 /* set application name as a title */
1069 app_name = g_get_application_name ();
1071 if (app_name && xvimagesink->media_title) {
1072 title = title_mem = g_strconcat (xvimagesink->media_title, " : ",
1074 } else if (app_name) {
1076 } else if (xvimagesink->media_title) {
1077 title = xvimagesink->media_title;
1080 gst_xwindow_set_title (xwindow, title);
1085 /* This function handles a GstXWindow creation
1086 * The width and height are the actual pixel size on the display */
1088 gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
1089 gint width, gint height)
1091 GstXWindow *xwindow = NULL;
1092 GstXvContext *context;
1094 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1096 context = xvimagesink->context;
1098 #ifdef GST_EXT_XV_ENHANCEMENT
1100 if (xvimagesink->rotate_angle == 0 || xvimagesink->rotate_angle == 2) {
1101 xwindow = gst_xvcontext_create_xwindow (context, height, width);
1104 xwindow = gst_xvcontext_create_xwindow (context, width, height);
1107 xwindow = gst_xvcontext_create_xwindow (context, width, height);
1108 #endif /* GST_EXT_XV_ENHANCEMENT */
1110 /* set application name as a title */
1111 gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL);
1113 gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events);
1115 gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (xvimagesink),
1122 gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
1124 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1126 /* Update the window geometry */
1127 g_mutex_lock (&xvimagesink->flow_lock);
1128 if (G_LIKELY (xvimagesink->xwindow))
1129 gst_xwindow_update_geometry (xvimagesink->xwindow);
1130 g_mutex_unlock (&xvimagesink->flow_lock);
1133 /* This function commits our internal colorbalance settings to our grabbed Xv
1134 port. If the context is not initialized yet it simply returns */
1136 gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink)
1138 GstXvContext *context;
1140 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1142 /* If we haven't initialized the X context we can't update anything */
1143 if ((context = xvimagesink->context) == NULL)
1146 gst_xvcontext_update_colorbalance (context, &xvimagesink->config);
1149 /* This function handles XEvents that might be in the queue. It generates
1150 GstEvent that will be sent upstream in the pipeline to handle interactivity
1151 and navigation. It will also listen for configure events on the window to
1152 trigger caps renegotiation so on the fly software scaling can work. */
1154 gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink)
1157 guint pointer_x = 0, pointer_y = 0;
1158 gboolean pointer_moved = FALSE;
1159 gboolean exposed = FALSE, configured = FALSE;
1161 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
1163 #ifdef GST_EXT_XV_ENHANCEMENT
1164 GST_LOG("check x event");
1165 #endif /* GST_EXT_XV_ENHANCEMENT */
1167 /* Handle Interaction, produces navigation events */
1169 /* We get all pointer motion events, only the last position is
1171 g_mutex_lock (&xvimagesink->flow_lock);
1172 g_mutex_lock (&xvimagesink->context->lock);
1173 while (XCheckWindowEvent (xvimagesink->context->disp,
1174 xvimagesink->xwindow->win, PointerMotionMask, &e)) {
1175 g_mutex_unlock (&xvimagesink->context->lock);
1176 g_mutex_unlock (&xvimagesink->flow_lock);
1180 pointer_x = e.xmotion.x;
1181 pointer_y = e.xmotion.y;
1182 pointer_moved = TRUE;
1187 g_mutex_lock (&xvimagesink->flow_lock);
1188 g_mutex_lock (&xvimagesink->context->lock);
1191 if (pointer_moved) {
1192 g_mutex_unlock (&xvimagesink->context->lock);
1193 g_mutex_unlock (&xvimagesink->flow_lock);
1195 GST_DEBUG ("xvimagesink pointer moved over window at %d,%d",
1196 pointer_x, pointer_y);
1197 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1198 "mouse-move", 0, e.xbutton.x, e.xbutton.y);
1200 g_mutex_lock (&xvimagesink->flow_lock);
1201 g_mutex_lock (&xvimagesink->context->lock);
1204 /* We get all events on our window to throw them upstream */
1205 while (XCheckWindowEvent (xvimagesink->context->disp,
1206 xvimagesink->xwindow->win,
1207 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
1210 const char *key_str = NULL;
1212 /* We lock only for the X function call */
1213 g_mutex_unlock (&xvimagesink->context->lock);
1214 g_mutex_unlock (&xvimagesink->flow_lock);
1218 /* Mouse button pressed over our window. We send upstream
1219 events for interactivity/navigation */
1220 GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d",
1221 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1222 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1223 "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1226 /* Mouse button released over our window. We send upstream
1227 events for interactivity/navigation */
1228 GST_DEBUG ("xvimagesink button %d released over window at %d,%d",
1229 e.xbutton.button, e.xbutton.x, e.xbutton.y);
1230 gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink),
1231 "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y);
1235 /* Key pressed/released over our window. We send upstream
1236 events for interactivity/navigation */
1237 g_mutex_lock (&xvimagesink->context->lock);
1238 keysym = XkbKeycodeToKeysym (xvimagesink->context->disp,
1239 e.xkey.keycode, 0, 0);
1240 if (keysym != NoSymbol) {
1241 key_str = XKeysymToString (keysym);
1243 key_str = "unknown";
1245 g_mutex_unlock (&xvimagesink->context->lock);
1246 GST_DEBUG_OBJECT (xvimagesink,
1247 "key %d pressed over window at %d,%d (%s)",
1248 e.xkey.keycode, e.xkey.x, e.xkey.y, key_str);
1249 gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink),
1250 e.type == KeyPress ? "key-press" : "key-release", key_str);
1253 GST_DEBUG_OBJECT (xvimagesink, "xvimagesink unhandled X event (%d)",
1256 g_mutex_lock (&xvimagesink->flow_lock);
1257 g_mutex_lock (&xvimagesink->context->lock);
1261 while (XCheckWindowEvent (xvimagesink->context->disp,
1262 xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
1267 case ConfigureNotify:
1268 g_mutex_unlock (&xvimagesink->context->lock);
1269 g_mutex_unlock (&xvimagesink->flow_lock);
1271 #ifdef GST_EXT_XV_ENHANCEMENT
1272 GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
1273 #endif /* GST_EXT_XV_ENHANCEMENT */
1274 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
1275 #ifdef GST_EXT_XV_ENHANCEMENT
1276 GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
1277 #endif /* GST_EXT_XV_ENHANCEMENT */
1278 g_mutex_lock (&xvimagesink->flow_lock);
1279 g_mutex_lock (&xvimagesink->context->lock);
1287 if (xvimagesink->handle_expose && (exposed || configured)) {
1288 g_mutex_unlock (&xvimagesink->context->lock);
1289 g_mutex_unlock (&xvimagesink->flow_lock);
1291 gst_xvimagesink_expose (GST_VIDEO_OVERLAY (xvimagesink));
1293 g_mutex_lock (&xvimagesink->flow_lock);
1294 g_mutex_lock (&xvimagesink->context->lock);
1297 /* Handle Display events */
1298 while (XPending (xvimagesink->context->disp)) {
1299 XNextEvent (xvimagesink->context->disp, &e);
1302 case ClientMessage:{
1303 #ifdef GST_EXT_XV_ENHANCEMENT
1304 XClientMessageEvent *cme = (XClientMessageEvent *)&e;
1305 Atom buffer_atom = XInternAtom(xvimagesink->context->disp, "XV_RETURN_BUFFER", False);
1306 #endif /* GST_EXT_XV_ENHANCEMENT */
1309 #ifdef GST_EXT_XV_ENHANCEMENT
1310 GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
1311 if (cme->message_type == buffer_atom) {
1312 unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
1314 GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
1315 cme->data.l[0], cme->data.l[1]);
1317 gem_name[0] = cme->data.l[0];
1318 gem_name[1] = cme->data.l[1];
1320 g_mutex_unlock (&xvimagesink->context->lock);
1321 gst_xvcontext_remove_displaying_buffer(xvimagesink->context, gem_name);
1322 g_mutex_lock (&xvimagesink->context->lock);
1326 #endif /* GST_EXT_XV_ENHANCEMENT */
1328 wm_delete = XInternAtom (xvimagesink->context->disp,
1329 "WM_DELETE_WINDOW", True);
1330 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
1331 /* Handle window deletion by posting an error on the bus */
1332 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND,
1333 ("Output window was closed"), (NULL));
1335 g_mutex_unlock (&xvimagesink->context->lock);
1336 gst_xwindow_destroy (xvimagesink->xwindow);
1337 xvimagesink->xwindow = NULL;
1338 g_mutex_lock (&xvimagesink->context->lock);
1347 g_mutex_unlock (&xvimagesink->context->lock);
1348 g_mutex_unlock (&xvimagesink->flow_lock);
1352 gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink)
1354 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
1356 GST_OBJECT_LOCK (xvimagesink);
1357 while (xvimagesink->running) {
1358 GST_OBJECT_UNLOCK (xvimagesink);
1360 if (xvimagesink->xwindow) {
1361 gst_xvimagesink_handle_xevents (xvimagesink);
1364 #ifdef GST_EXT_XV_ENHANCEMENT
1365 g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
1366 #else /* GST_EXT_XV_ENHANCEMENT */
1367 /* FIXME: do we want to align this with the framerate or anything else? */
1368 g_usleep (G_USEC_PER_SEC / 20);
1369 #endif /* GST_EXT_XV_ENHANCEMENT */
1371 GST_OBJECT_LOCK (xvimagesink);
1373 GST_OBJECT_UNLOCK (xvimagesink);
1379 gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink)
1381 GThread *thread = NULL;
1383 /* don't start the thread too early */
1384 if (xvimagesink->context == NULL) {
1388 GST_OBJECT_LOCK (xvimagesink);
1389 if (xvimagesink->handle_expose || xvimagesink->handle_events) {
1390 if (!xvimagesink->event_thread) {
1391 /* Setup our event listening thread */
1392 GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d",
1393 xvimagesink->handle_expose, xvimagesink->handle_events);
1394 xvimagesink->running = TRUE;
1395 xvimagesink->event_thread = g_thread_try_new ("xvimagesink-events",
1396 (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, NULL);
1399 if (xvimagesink->event_thread) {
1400 GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d",
1401 xvimagesink->handle_expose, xvimagesink->handle_events);
1402 xvimagesink->running = FALSE;
1403 /* grab thread and mark it as NULL */
1404 thread = xvimagesink->event_thread;
1405 xvimagesink->event_thread = NULL;
1408 GST_OBJECT_UNLOCK (xvimagesink);
1410 /* Wait for our event thread to finish */
1412 g_thread_join (thread);
1419 gst_xvimagesink_getcaps (GstBaseSink * bsink, GstCaps * filter)
1421 GstXvImageSink *xvimagesink;
1424 xvimagesink = GST_XVIMAGESINK (bsink);
1426 if (xvimagesink->context) {
1428 return gst_caps_intersect_full (filter, xvimagesink->context->caps,
1429 GST_CAPS_INTERSECT_FIRST);
1431 return gst_caps_ref (xvimagesink->context->caps);
1434 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (xvimagesink));
1436 GstCaps *intersection;
1439 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1440 gst_caps_unref (caps);
1441 caps = intersection;
1447 gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
1449 GstXvImageSink *xvimagesink;
1450 GstXvContext *context;
1451 GstStructure *structure;
1452 GstBufferPool *newpool, *oldpool;
1454 guint32 im_format = 0;
1455 gint video_par_n, video_par_d; /* video's PAR */
1456 gint display_par_n, display_par_d; /* display's PAR */
1460 xvimagesink = GST_XVIMAGESINK (bsink);
1461 context = xvimagesink->context;
1463 GST_DEBUG_OBJECT (xvimagesink,
1464 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
1465 GST_PTR_FORMAT, context->caps, caps);
1467 if (!gst_caps_can_intersect (context->caps, caps))
1468 goto incompatible_caps;
1470 if (!gst_video_info_from_caps (&info, caps))
1471 goto invalid_format;
1473 xvimagesink->fps_n = info.fps_n;
1474 xvimagesink->fps_d = info.fps_d;
1476 xvimagesink->video_width = info.width;
1477 xvimagesink->video_height = info.height;
1479 im_format = gst_xvcontext_get_format_from_info (context, &info);
1480 if (im_format == -1)
1481 goto invalid_format;
1483 gst_xvcontext_set_colorimetry (context, &info.colorimetry);
1486 GST_INFO ("info.size = %d ",size);
1487 /* get aspect ratio from caps if it's present, and
1488 * convert video width and height to a display width and height
1489 * using wd / hd = wv / hv * PARv / PARd */
1491 /* get video's PAR */
1492 video_par_n = info.par_n;
1493 video_par_d = info.par_d;
1495 /* get display's PAR */
1496 if (xvimagesink->par) {
1497 display_par_n = gst_value_get_fraction_numerator (xvimagesink->par);
1498 display_par_d = gst_value_get_fraction_denominator (xvimagesink->par);
1504 if (!gst_video_calculate_display_ratio (&num, &den, info.width,
1505 info.height, video_par_n, video_par_d, display_par_n, display_par_d))
1508 GST_DEBUG_OBJECT (xvimagesink,
1509 "video width/height: %dx%d, calculated display ratio: %d/%d",
1510 info.width, info.height, num, den);
1512 /* now find a width x height that respects this display ratio.
1513 * prefer those that have one of w/h the same as the incoming video
1514 * using wd / hd = num / den */
1516 /* start with same height, because of interlaced video */
1517 /* check hd / den is an integer scale factor, and scale wd with the PAR */
1518 if (info.height % den == 0) {
1519 GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
1520 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
1521 gst_util_uint64_scale_int (info.height, num, den);
1522 GST_VIDEO_SINK_HEIGHT (xvimagesink) = info.height;
1523 } else if (info.width % num == 0) {
1524 GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
1525 GST_VIDEO_SINK_WIDTH (xvimagesink) = info.width;
1526 GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint)
1527 gst_util_uint64_scale_int (info.width, den, num);
1529 GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
1530 GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint)
1531 gst_util_uint64_scale_int (info.height, num, den);
1532 GST_VIDEO_SINK_HEIGHT (xvimagesink) = info.height;
1534 GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
1535 GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink));
1537 /* Notify application to set xwindow id now */
1538 g_mutex_lock (&xvimagesink->flow_lock);
1539 #ifdef GST_EXT_XV_ENHANCEMENT
1540 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
1542 if (!xvimagesink->xwindow) {
1544 g_mutex_unlock (&xvimagesink->flow_lock);
1545 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (xvimagesink));
1547 g_mutex_unlock (&xvimagesink->flow_lock);
1550 /* Creating our window and our image with the display size in pixels */
1551 if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
1552 GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
1553 goto no_display_size;
1555 g_mutex_lock (&xvimagesink->flow_lock);
1556 #ifdef GST_EXT_XV_ENHANCEMENT
1557 if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
1559 if (!xvimagesink->xwindow) {
1561 xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
1562 GST_VIDEO_SINK_WIDTH (xvimagesink),
1563 GST_VIDEO_SINK_HEIGHT (xvimagesink));
1566 xvimagesink->info = info;
1568 /* After a resize, we want to redraw the borders in case the new frame size
1569 * doesn't cover the same area */
1570 xvimagesink->redraw_border = TRUE;
1572 /* create a new pool for the new configuration */
1573 newpool = gst_xvimage_buffer_pool_new (xvimagesink->allocator);
1575 structure = gst_buffer_pool_get_config (newpool);
1576 gst_buffer_pool_config_set_params (structure, caps, size, 2, 0);
1577 if (!gst_buffer_pool_set_config (newpool, structure))
1580 oldpool = xvimagesink->pool;
1581 /* we don't activate the pool yet, this will be done by downstream after it
1582 * has configured the pool. If downstream does not want our pool we will
1583 * activate it when we render into it */
1584 xvimagesink->pool = newpool;
1585 g_mutex_unlock (&xvimagesink->flow_lock);
1587 /* unref the old sink */
1589 /* we don't deactivate, some elements might still be using it, it will
1590 * be deactivated when the last ref is gone */
1591 gst_object_unref (oldpool);
1599 GST_ERROR_OBJECT (xvimagesink, "caps incompatible");
1604 GST_DEBUG_OBJECT (xvimagesink,
1605 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1610 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
1611 ("Error calculating the output display ratio of the video."));
1616 GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
1617 ("Error calculating the output display ratio of the video."));
1622 GST_ERROR_OBJECT (xvimagesink, "failed to set config.");
1623 g_mutex_unlock (&xvimagesink->flow_lock);
1628 static GstStateChangeReturn
1629 gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
1631 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1632 GstXvImageSink *xvimagesink;
1634 xvimagesink = GST_XVIMAGESINK (element);
1636 switch (transition) {
1637 case GST_STATE_CHANGE_NULL_TO_READY:
1638 #ifdef GST_EXT_XV_ENHANCEMENT
1639 GST_WARNING("NULL_TO_READY start");
1640 #endif /* GST_EXT_XV_ENHANCEMENT */
1641 if (!gst_xvimagesink_open (xvimagesink))
1643 #ifdef GST_EXT_XV_ENHANCEMENT
1644 GST_WARNING("NULL_TO_READY done");
1645 #endif /* GST_EXT_XV_ENHANCEMENT */
1647 case GST_STATE_CHANGE_READY_TO_PAUSED:
1649 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1650 #ifdef GST_EXT_XV_ENHANCEMENT
1651 GST_WARNING("PAUSED_TO_PLAYING done");
1652 #endif /* GST_EXT_XV_ENHANCEMENT */
1654 case GST_STATE_CHANGE_PAUSED_TO_READY:
1660 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1662 switch (transition) {
1663 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1664 #ifdef GST_EXT_XV_ENHANCEMENT
1665 GST_WARNING("PLAYING_TO_PAUSED start");
1666 /* init displayed buffer count */
1667 xvimagesink->context->displayed_buffer_count = 0;
1669 GST_WARNING("PLAYING_TO_PAUSED done");
1670 #endif /* GST_EXT_XV_ENHANCEMENT */
1672 case GST_STATE_CHANGE_PAUSED_TO_READY:
1673 xvimagesink->fps_n = 0;
1674 xvimagesink->fps_d = 1;
1675 GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
1676 GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
1677 g_mutex_lock (&xvimagesink->flow_lock);
1678 if (xvimagesink->pool)
1679 gst_buffer_pool_set_active (xvimagesink->pool, FALSE);
1680 g_mutex_unlock (&xvimagesink->flow_lock);
1681 #ifdef GST_EXT_XV_ENHANCEMENT
1683 gst_xvcontext_drm_fini(xvimagesink->context);
1685 GST_WARNING("PAUSED_TO_READY done");
1686 #endif /* GST_EXT_XV_ENHANCEMENT */
1688 case GST_STATE_CHANGE_READY_TO_NULL:
1689 #ifdef GST_EXT_XV_ENHANCEMENT
1690 GST_WARNING("READY_TO_NULL start");
1691 #endif /* GST_EXT_XV_ENHANCEMENT */
1692 gst_xvimagesink_close (xvimagesink);
1693 #ifdef GST_EXT_XV_ENHANCEMENT
1694 GST_WARNING("READY_TO_NULL done");
1695 #endif /* GST_EXT_XV_ENHANCEMENT */
1704 return GST_STATE_CHANGE_FAILURE;
1709 gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1710 GstClockTime * start, GstClockTime * end)
1712 GstXvImageSink *xvimagesink;
1714 xvimagesink = GST_XVIMAGESINK (bsink);
1716 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1717 *start = GST_BUFFER_TIMESTAMP (buf);
1718 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1719 *end = *start + GST_BUFFER_DURATION (buf);
1721 if (xvimagesink->fps_n > 0) {
1723 gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d,
1724 xvimagesink->fps_n);
1730 static GstFlowReturn
1731 gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
1734 GstXvImageSink *xvimagesink;
1737 gboolean ret = FALSE;
1738 #ifdef GST_EXT_XV_ENHANCEMENT
1739 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1740 SCMN_IMGB *scmn_imgb = NULL;
1741 #endif /* GST_EXT_XV_ENHANCEMENT */
1743 xvimagesink = GST_XVIMAGESINK (vsink);
1745 #ifdef ENABLE_STOP_VIDEO
1746 if (xvimagesink->stop_video) {
1747 GST_INFO( "Stop video is TRUE. so skip show frame..." );
1752 if (gst_buffer_n_memory (buf) == 1 && (mem = gst_buffer_peek_memory (buf, 0))
1753 && gst_xvimage_memory_is_from_context (mem, xvimagesink->context)) {
1754 /* If this buffer has been allocated using our buffer management we simply
1755 put the ximage which is in the PRIVATE pointer */
1756 GST_LOG_OBJECT (xvimagesink, "buffer %p from our pool, writing directly",
1758 #ifdef GST_EXT_XV_ENHANCEMENT
1759 xvimagesink->xid_updated = FALSE;
1760 #endif /* GST_EXT_XV_ENHANCEMENT */
1764 GstVideoFrame src, dest;
1765 GstBufferPoolAcquireParams params = { 0, };
1767 /* Else we have to copy the data into our private image, */
1768 /* if we have one... */
1769 GST_LOG_OBJECT (xvimagesink, "buffer %p not from our pool, copying", buf);
1771 /* we should have a pool, configured in setcaps */
1772 if (xvimagesink->pool == NULL)
1775 if (!gst_buffer_pool_set_active (xvimagesink->pool, TRUE))
1776 goto activate_failed;
1778 /* take a buffer from our pool, if there is no buffer in the pool something
1779 * is seriously wrong, waiting for the pool here might deadlock when we try
1780 * to go to PAUSED because we never flush the pool then. */
1781 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
1782 res = gst_buffer_pool_acquire_buffer (xvimagesink->pool, &to_put, ¶ms);
1783 if (res != GST_FLOW_OK)
1786 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
1787 "slow copy buffer %p into bufferpool buffer %p", buf, to_put);
1788 #ifdef GST_EXT_XV_ENHANCEMENT
1789 g_mutex_lock (&xvimagesink->flow_lock);
1790 switch (GST_VIDEO_INFO_FORMAT(&xvimagesink->info)) {
1791 /* Cases for specified formats of Samsung extension */
1792 case GST_VIDEO_FORMAT_SN12:
1793 case GST_VIDEO_FORMAT_ST12:
1794 case GST_VIDEO_FORMAT_ITLV:
1796 GstXvImageMemory* img_mem = NULL;
1797 XV_DATA_PTR img_data = NULL;
1799 GST_LOG("Samsung EXT format - name:%s, display mode:%d, Rotate angle:%d", GST_VIDEO_INFO_NAME(&xvimagesink->info),
1800 xvimagesink->config.display_mode, xvimagesink->rotate_angle);
1802 img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage((GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0))->data;
1804 memset(img_data, 0x0, sizeof(XV_DATA));
1805 XV_INIT_DATA(img_data);
1807 mem = gst_buffer_peek_memory(buf, 1);
1808 gst_memory_map(mem, &mem_info, GST_MAP_READ);
1809 scmn_imgb = (SCMN_IMGB *)mem_info.data;
1810 gst_memory_unmap(mem, &mem_info);
1811 if (scmn_imgb == NULL) {
1812 GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
1813 g_mutex_unlock (&xvimagesink->flow_lock);
1818 img_mem = (GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0);
1819 img_data = (XV_DATA_PTR) gst_xvimage_memory_get_xvimage(img_mem)->data;
1821 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
1822 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
1823 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
1824 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
1825 img_data->BufType = XV_BUF_TYPE_LEGACY;
1826 } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD || scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
1827 /* open drm to use gem */
1828 if (xvimagesink->context->drm_fd < 0) {
1829 gst_xvcontext_drm_init(xvimagesink->context);
1832 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
1833 /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
1834 img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
1835 img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
1836 img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
1837 img_data->BufType = XV_BUF_TYPE_DMABUF;
1838 GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
1840 /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
1841 img_data->bo[0] = scmn_imgb->bo[0];
1842 img_data->bo[1] = scmn_imgb->bo[1];
1843 img_data->bo[2] = scmn_imgb->bo[2];
1844 GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
1847 /* check secure contents path */
1848 /* NOTE : does it need to set 0 during playing(recovery case)? */
1849 if (scmn_imgb->tz_enable) {
1850 if (!xvimagesink->is_secure_path) {
1851 Atom atom_secure = None;
1852 g_mutex_lock (&xvimagesink->context->lock);
1853 atom_secure = XInternAtom(xvimagesink->context->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
1854 if (atom_secure != None) {
1855 if (XvSetPortAttribute(xvimagesink->context->disp, xvimagesink->context->xv_port_id, atom_secure, 1) != Success) {
1856 GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.\n", atom_secure);
1858 GST_WARNING_OBJECT(xvimagesink, "secure contents path is enabled.\n");
1860 XSync (xvimagesink->context->disp, FALSE);
1862 g_mutex_unlock (&xvimagesink->context->lock);
1863 xvimagesink->is_secure_path = TRUE;
1866 /* set current buffer */
1867 gst_xvimage_memory_set_buffer((GstXvImageMemory*)gst_buffer_peek_memory(to_put, 0), buf);
1869 gst_xvcontext_add_displaying_buffer(xvimagesink->context, img_data, gst_xvimage_memory_get_buffer(img_mem));
1872 GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
1873 scmn_imgb->buf_share_method);
1874 g_mutex_unlock (&xvimagesink->flow_lock);
1879 GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
1880 g_mutex_lock (&xvimagesink->flow_lock);
1887 GST_DEBUG("Normal format activated. Name = %s", GST_VIDEO_INFO_NAME(&xvimagesink->info));
1888 if (!gst_video_frame_map (&src, &xvimagesink->info, buf, GST_MAP_READ))
1889 goto invalid_buffer;
1891 if (!gst_video_frame_map (&dest, &xvimagesink->info, to_put, GST_MAP_WRITE)) {
1892 gst_video_frame_unmap (&src);
1893 goto invalid_buffer;
1896 gst_video_frame_copy (&dest, &src);
1898 gst_video_frame_unmap (&dest);
1899 gst_video_frame_unmap (&src);
1903 g_mutex_unlock (&xvimagesink->flow_lock);
1904 #else /* GST_EXT_XV_ENHANCEMENT */
1905 if (!gst_video_frame_map (&src, &xvimagesink->info, buf, GST_MAP_READ))
1906 goto invalid_buffer;
1907 if (!gst_video_frame_map (&dest, &xvimagesink->info, to_put, GST_MAP_WRITE)) {
1908 gst_video_frame_unmap (&src);
1909 goto invalid_buffer;
1912 gst_video_frame_copy (&dest, &src);
1914 gst_video_frame_unmap (&dest);
1915 gst_video_frame_unmap (&src);
1916 #endif /* GST_EXT_XV_ENHANCEMENT */
1919 ret = gst_xvimagesink_xvimage_put(xvimagesink, to_put);
1927 gst_buffer_unref (to_put);
1934 GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
1935 ("Internal error: can't allocate images"),
1936 ("We don't have a bufferpool negotiated"));
1937 return GST_FLOW_ERROR;
1941 /* No image available. That's very bad ! */
1942 GST_WARNING_OBJECT (xvimagesink, "could not create image");
1947 /* No Window available to put our image into */
1948 GST_WARNING_OBJECT (xvimagesink, "could not map image");
1949 #ifdef GST_EXT_XV_ENHANCEMENT
1950 g_mutex_unlock (&xvimagesink->flow_lock);
1957 /* No Window available to put our image into */
1958 GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
1959 res = GST_FLOW_ERROR;
1964 GST_ERROR_OBJECT (xvimagesink, "failed to activate bufferpool.");
1965 res = GST_FLOW_ERROR;
1971 gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
1973 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
1975 switch (GST_EVENT_TYPE (event)) {
1976 case GST_EVENT_TAG:{
1978 gchar *title = NULL;
1980 gst_event_parse_tag (event, &l);
1981 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
1984 #ifdef GST_EXT_XV_ENHANCEMENT
1985 if (!xvimagesink->get_pixmap_cb) {
1988 GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
1989 gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
1993 #ifdef GST_EXT_XV_ENHANCEMENT
2003 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2007 gst_xvimagesink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
2009 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (bsink);
2010 GstBufferPool *pool;
2011 GstStructure *config;
2016 gst_query_parse_allocation (query, &caps, &need_pool);
2021 g_mutex_lock (&xvimagesink->flow_lock);
2022 if ((pool = xvimagesink->pool))
2023 gst_object_ref (pool);
2024 g_mutex_unlock (&xvimagesink->flow_lock);
2029 /* we had a pool, check caps */
2030 GST_DEBUG_OBJECT (xvimagesink, "check existing pool caps");
2031 config = gst_buffer_pool_get_config (pool);
2032 gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
2034 if (!gst_caps_is_equal (caps, pcaps)) {
2035 GST_DEBUG_OBJECT (xvimagesink, "pool has different caps");
2036 /* different caps, we can't use this pool */
2037 gst_object_unref (pool);
2040 gst_structure_free (config);
2042 if (pool == NULL && need_pool) {
2045 if (!gst_video_info_from_caps (&info, caps))
2048 GST_DEBUG_OBJECT (xvimagesink, "create new pool");
2049 pool = gst_xvimage_buffer_pool_new (xvimagesink->allocator);
2051 /* the normal size of a frame */
2054 config = gst_buffer_pool_get_config (pool);
2055 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
2056 if (!gst_buffer_pool_set_config (pool, config))
2060 /* we need at least 2 buffer because we hold on to the last one */
2061 gst_query_add_allocation_pool (query, pool, size, 2, 0);
2062 gst_object_unref (pool);
2065 /* we also support various metadata */
2066 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2067 gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
2074 GST_DEBUG_OBJECT (bsink, "no caps specified");
2079 GST_DEBUG_OBJECT (bsink, "invalid caps specified");
2084 GST_DEBUG_OBJECT (bsink, "failed setting config");
2085 gst_object_unref (pool);
2090 /* Interfaces stuff */
2092 gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
2093 GstStructure * structure)
2095 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
2098 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) {
2100 GstVideoRectangle src, dst, result;
2101 gdouble x, y, xscale = 1.0, yscale = 1.0;
2102 GstXWindow *xwindow;
2104 event = gst_event_new_navigation (structure);
2106 /* We take the flow_lock while we look at the window */
2107 g_mutex_lock (&xvimagesink->flow_lock);
2109 if (!(xwindow = xvimagesink->xwindow)) {
2110 g_mutex_unlock (&xvimagesink->flow_lock);
2114 if (xvimagesink->keep_aspect) {
2115 /* We get the frame position using the calculated geometry from _setcaps
2116 that respect pixel aspect ratios */
2117 src.w = GST_VIDEO_SINK_WIDTH (xvimagesink);
2118 src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink);
2119 dst.w = xwindow->render_rect.w;
2120 dst.h = xwindow->render_rect.h;
2122 gst_video_sink_center_rect (src, dst, &result, TRUE);
2123 result.x += xwindow->render_rect.x;
2124 result.y += xwindow->render_rect.y;
2126 memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle));
2129 g_mutex_unlock (&xvimagesink->flow_lock);
2131 /* We calculate scaling using the original video frames geometry to include
2132 pixel aspect ratio scaling. */
2133 xscale = (gdouble) xvimagesink->video_width / result.w;
2134 yscale = (gdouble) xvimagesink->video_height / result.h;
2136 /* Converting pointer coordinates to the non scaled geometry */
2137 if (gst_structure_get_double (structure, "pointer_x", &x)) {
2138 x = MIN (x, result.x + result.w);
2139 x = MAX (x - result.x, 0);
2140 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2141 (gdouble) x * xscale, NULL);
2143 if (gst_structure_get_double (structure, "pointer_y", &y)) {
2144 y = MIN (y, result.y + result.h);
2145 y = MAX (y - result.y, 0);
2146 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2147 (gdouble) y * yscale, NULL);
2150 gst_pad_send_event (peer, event);
2151 gst_object_unref (peer);
2156 gst_xvimagesink_navigation_init (GstNavigationInterface * iface)
2158 iface->send_event = gst_xvimagesink_navigation_send_event;
2162 gst_xvimagesink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
2164 XID xwindow_id = id;
2165 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2166 GstXWindow *xwindow = NULL;
2167 GstXvContext *context;
2168 #ifdef GST_EXT_XV_ENHANCEMENT
2169 GstState current_state = GST_STATE_NULL;
2170 #endif /* GST_EXT_XV_ENHANCEMENT */
2172 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2174 g_mutex_lock (&xvimagesink->flow_lock);
2176 #ifdef GST_EXT_XV_ENHANCEMENT
2177 gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
2178 GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
2179 xwindow_id, current_state);
2180 #endif /* GST_EXT_XV_ENHANCEMENT */
2182 /* If we already use that window return */
2183 if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) {
2184 g_mutex_unlock (&xvimagesink->flow_lock);
2188 /* If the element has not initialized the X11 context try to do so */
2189 if (!xvimagesink->context &&
2190 !(xvimagesink->context =
2191 gst_xvcontext_new (&xvimagesink->config, NULL))) {
2192 g_mutex_unlock (&xvimagesink->flow_lock);
2193 /* we have thrown a GST_ELEMENT_ERROR now */
2197 context = xvimagesink->context;
2199 gst_xvimagesink_update_colorbalance (xvimagesink);
2201 /* If a window is there already we destroy it */
2202 if (xvimagesink->xwindow) {
2203 gst_xwindow_destroy (xvimagesink->xwindow);
2204 xvimagesink->xwindow = NULL;
2207 /* If the xid is 0 we go back to an internal window */
2208 if (xwindow_id == 0) {
2209 /* If no width/height caps nego did not happen window will be created
2210 during caps nego then */
2211 if (GST_VIDEO_SINK_WIDTH (xvimagesink)
2212 && GST_VIDEO_SINK_HEIGHT (xvimagesink)) {
2214 gst_xvimagesink_xwindow_new (xvimagesink,
2215 GST_VIDEO_SINK_WIDTH (xvimagesink),
2216 GST_VIDEO_SINK_HEIGHT (xvimagesink));
2219 xwindow = gst_xvcontext_create_xwindow_from_xid (context, xwindow_id);
2220 gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events);
2224 xvimagesink->xwindow = xwindow;
2226 #ifdef GST_EXT_XV_ENHANCEMENT
2227 xvimagesink->xid_updated = TRUE;
2228 #endif /* GST_EXT_XV_ENHANCEMENT */
2230 g_mutex_unlock (&xvimagesink->flow_lock);
2232 #ifdef GST_EXT_XV_ENHANCEMENT
2233 if (current_state == GST_STATE_PAUSED) {
2234 GstBuffer *last_buffer = NULL;
2235 g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
2236 GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
2238 gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
2239 gst_buffer_unref(last_buffer);
2243 #endif /* GST_EXT_XV_ENHANCEMENT */
2246 #ifdef GST_EXT_XV_ENHANCEMENT
2247 /* This function destroys a GstXWindow */
2249 gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
2250 GstXPixmap * xpixmap)
2252 g_return_if_fail (xpixmap != NULL);
2253 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2255 XSelectInput (xvimagesink->context->disp, xpixmap->pixmap, 0);
2257 XFreeGC (xvimagesink->context->disp, xpixmap->gc);
2259 XSync (xvimagesink->context->disp, FALSE);
2265 gst_xvimagesink_set_pixmap_handle (GstVideoOverlay * overlay, guintptr id)
2267 GST_INFO("gst_xvimagesink_set_pixmap_handle");
2270 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2271 GstXPixmap *xpixmap = NULL;
2273 int (*handler) (Display *, XErrorEvent *);
2274 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2276 /* If the element has not initialized the X11 context try to do so */
2277 if (!xvimagesink->context && !(xvimagesink->context =
2278 gst_xvcontext_new (&xvimagesink->config, NULL))) {
2279 /* we have thrown a GST_ELEMENT_ERROR now */
2280 GST_ERROR("GST_ELEMENT_ERROR");
2283 GST_INFO("call gst_xvimagesink_update_colorbalance ");
2284 gst_xvimagesink_update_colorbalance (xvimagesink);
2286 GST_INFO("pixmap id : %d", pixmap_id );
2288 /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
2289 if (pixmap_id == 0) {
2290 xvimagesink->current_pixmap_idx = -2;
2294 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
2295 if (!xvimagesink->xpixmap[i]) {
2299 unsigned int cur_win_width = 0;
2300 unsigned int cur_win_height = 0;
2301 unsigned int cur_win_border_width = 0;
2302 unsigned int cur_win_depth = 0;
2304 GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
2306 xpixmap = g_new0 (GstXPixmap, 1);
2308 xpixmap->pixmap = pixmap_id;
2310 /* Get root window and size of current window */
2311 XGetGeometry(xvimagesink->context->disp, xpixmap->pixmap, &root_window,
2312 &cur_win_x, &cur_win_y, /* relative x, y */
2313 &cur_win_width, &cur_win_height,
2314 &cur_win_border_width, &cur_win_depth);
2315 if (!cur_win_width || !cur_win_height) {
2316 GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
2319 GST_INFO("cur_win_x(%d) cur_win_y(%d) cur_win_width(%d) cur_win_height(%d) cur_win_border_width(%d) cur_win_depth(%d)",
2320 cur_win_x, cur_win_y, cur_win_width, cur_win_height, cur_win_border_width, cur_win_depth);
2321 xpixmap->width = cur_win_width;
2322 xpixmap->height = cur_win_height;
2324 /* Setting an error handler to catch failure */
2325 error_caught = FALSE;
2326 handler = XSetErrorHandler (gst_xvimage_pixmap_xerror);
2329 xpixmap->gc = XCreateGC (xvimagesink->context->disp, xpixmap->pixmap, 0, NULL);
2331 XSync(xvimagesink->context->disp, FALSE);
2333 GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
2336 error_caught = FALSE;
2337 XSetErrorHandler (handler);
2340 xvimagesink->xpixmap[i] = xpixmap;
2341 xvimagesink->current_pixmap_idx = i;
2343 GST_ERROR("failed to create xpixmap errno: %d", errno);
2348 } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
2349 GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
2350 xvimagesink->current_pixmap_idx = i;
2357 GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
2358 xvimagesink->current_pixmap_idx = -1;
2361 #endif /* GST_EXT_XV_ENHANCEMENT */
2366 gst_xvimagesink_expose (GstVideoOverlay * overlay)
2368 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2370 GST_DEBUG ("doing expose");
2371 gst_xvimagesink_xwindow_update_geometry (xvimagesink);
2372 gst_xvimagesink_xvimage_put (xvimagesink, NULL);
2376 gst_xvimagesink_set_event_handling (GstVideoOverlay * overlay,
2377 gboolean handle_events)
2379 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2381 g_mutex_lock (&xvimagesink->flow_lock);
2382 xvimagesink->handle_events = handle_events;
2383 if (G_LIKELY (xvimagesink->xwindow))
2384 gst_xwindow_set_event_handling (xvimagesink->xwindow, handle_events);
2385 g_mutex_unlock (&xvimagesink->flow_lock);
2389 gst_xvimagesink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y,
2390 gint width, gint height)
2392 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
2394 g_mutex_lock (&xvimagesink->flow_lock);
2395 if (G_LIKELY (xvimagesink->xwindow))
2396 gst_xwindow_set_render_rectangle (xvimagesink->xwindow, x, y, width,
2398 g_mutex_unlock (&xvimagesink->flow_lock);
2402 gst_xvimagesink_video_overlay_init (GstVideoOverlayInterface * iface)
2404 iface->set_window_handle = gst_xvimagesink_set_window_handle;
2405 iface->expose = gst_xvimagesink_expose;
2406 iface->handle_events = gst_xvimagesink_set_event_handling;
2407 iface->set_render_rectangle = gst_xvimagesink_set_render_rectangle;
2410 static const GList *
2411 gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance)
2413 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2415 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
2417 if (xvimagesink->context)
2418 return xvimagesink->context->channels_list;
2424 gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance,
2425 GstColorBalanceChannel * channel, gint value)
2427 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2429 g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
2430 g_return_if_fail (channel->label != NULL);
2432 xvimagesink->config.cb_changed = TRUE;
2434 /* Normalize val to [-1000, 1000] */
2435 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
2436 (double) (channel->max_value - channel->min_value));
2438 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2439 xvimagesink->config.hue = value;
2440 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2441 xvimagesink->config.saturation = value;
2442 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2443 xvimagesink->config.contrast = value;
2444 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2445 xvimagesink->config.brightness = value;
2447 g_warning ("got an unknown channel %s", channel->label);
2451 gst_xvimagesink_update_colorbalance (xvimagesink);
2455 gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance,
2456 GstColorBalanceChannel * channel)
2458 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance);
2461 g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
2462 g_return_val_if_fail (channel->label != NULL, 0);
2464 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2465 value = xvimagesink->config.hue;
2466 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2467 value = xvimagesink->config.saturation;
2468 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2469 value = xvimagesink->config.contrast;
2470 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2471 value = xvimagesink->config.brightness;
2473 g_warning ("got an unknown channel %s", channel->label);
2476 /* Normalize val to [channel->min_value, channel->max_value] */
2477 value = channel->min_value + (channel->max_value - channel->min_value) *
2478 (value + 1000) / 2000;
2483 static GstColorBalanceType
2484 gst_xvimagesink_colorbalance_get_balance_type (GstColorBalance * balance)
2486 return GST_COLOR_BALANCE_HARDWARE;
2490 gst_xvimagesink_colorbalance_init (GstColorBalanceInterface * iface)
2492 iface->list_channels = gst_xvimagesink_colorbalance_list_channels;
2493 iface->set_value = gst_xvimagesink_colorbalance_set_value;
2494 iface->get_value = gst_xvimagesink_colorbalance_get_value;
2495 iface->get_balance_type = gst_xvimagesink_colorbalance_get_balance_type;
2499 static const GList *
2500 gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe)
2502 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
2503 static GList *list = NULL;
2506 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
2508 g_list_append (list, g_object_class_find_property (klass,
2509 "autopaint-colorkey"));
2511 g_list_append (list, g_object_class_find_property (klass,
2514 g_list_append (list, g_object_class_find_property (klass, "colorkey"));
2521 gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe,
2522 guint prop_id, const GParamSpec * pspec)
2524 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2528 case PROP_AUTOPAINT_COLORKEY:
2529 case PROP_DOUBLE_BUFFER:
2531 GST_DEBUG_OBJECT (xvimagesink,
2532 "probing device list and get capabilities");
2533 if (!xvimagesink->context) {
2534 GST_DEBUG_OBJECT (xvimagesink, "generating context");
2535 xvimagesink->context = gst_xvimagesink_context_get (xvimagesink);
2539 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2545 gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe,
2546 guint prop_id, const GParamSpec * pspec)
2548 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2549 gboolean ret = FALSE;
2553 case PROP_AUTOPAINT_COLORKEY:
2554 case PROP_DOUBLE_BUFFER:
2556 if (xvimagesink->context != NULL) {
2563 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2570 static GValueArray *
2571 gst_xvimagesink_probe_get_values (GstPropertyProbe * probe,
2572 guint prop_id, const GParamSpec * pspec)
2574 GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe);
2575 GValueArray *array = NULL;
2577 if (G_UNLIKELY (!xvimagesink->context)) {
2578 GST_WARNING_OBJECT (xvimagesink, "we don't have any context, can't "
2587 GValue value = { 0 };
2589 array = g_value_array_new (xvimagesink->context->nb_adaptors);
2590 g_value_init (&value, G_TYPE_STRING);
2592 for (i = 0; i < xvimagesink->context->nb_adaptors; i++) {
2593 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
2595 g_value_set_string (&value, adaptor_id_s);
2596 g_value_array_append (array, &value);
2597 g_free (adaptor_id_s);
2599 g_value_unset (&value);
2602 case PROP_AUTOPAINT_COLORKEY:
2603 if (xvimagesink->have_autopaint_colorkey) {
2604 GValue value = { 0 };
2606 array = g_value_array_new (2);
2607 g_value_init (&value, G_TYPE_BOOLEAN);
2608 g_value_set_boolean (&value, FALSE);
2609 g_value_array_append (array, &value);
2610 g_value_set_boolean (&value, TRUE);
2611 g_value_array_append (array, &value);
2612 g_value_unset (&value);
2615 case PROP_DOUBLE_BUFFER:
2616 if (xvimagesink->have_double_buffer) {
2617 GValue value = { 0 };
2619 array = g_value_array_new (2);
2620 g_value_init (&value, G_TYPE_BOOLEAN);
2621 g_value_set_boolean (&value, FALSE);
2622 g_value_array_append (array, &value);
2623 g_value_set_boolean (&value, TRUE);
2624 g_value_array_append (array, &value);
2625 g_value_unset (&value);
2629 if (xvimagesink->have_colorkey) {
2630 GValue value = { 0 };
2632 array = g_value_array_new (1);
2633 g_value_init (&value, GST_TYPE_INT_RANGE);
2634 gst_value_set_int_range (&value, 0, 0xffffff);
2635 g_value_array_append (array, &value);
2636 g_value_unset (&value);
2640 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2649 gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
2652 iface->get_properties = gst_xvimagesink_probe_get_properties;
2653 iface->probe_property = gst_xvimagesink_probe_probe_property;
2654 iface->needs_probe = gst_xvimagesink_probe_needs_probe;
2655 iface->get_values = gst_xvimagesink_probe_get_values;
2659 /* =========================================== */
2661 /* Init & Class init */
2663 /* =========================================== */
2666 gst_xvimagesink_set_property (GObject * object, guint prop_id,
2667 const GValue * value, GParamSpec * pspec)
2669 GstXvImageSink *xvimagesink;
2671 g_return_if_fail (GST_IS_XVIMAGESINK (object));
2673 xvimagesink = GST_XVIMAGESINK (object);
2677 xvimagesink->config.hue = g_value_get_int (value);
2678 xvimagesink->config.cb_changed = TRUE;
2679 gst_xvimagesink_update_colorbalance (xvimagesink);
2682 xvimagesink->config.contrast = g_value_get_int (value);
2683 xvimagesink->config.cb_changed = TRUE;
2684 gst_xvimagesink_update_colorbalance (xvimagesink);
2686 case PROP_BRIGHTNESS:
2687 xvimagesink->config.brightness = g_value_get_int (value);
2688 xvimagesink->config.cb_changed = TRUE;
2689 gst_xvimagesink_update_colorbalance (xvimagesink);
2691 case PROP_SATURATION:
2692 xvimagesink->config.saturation = g_value_get_int (value);
2693 xvimagesink->config.cb_changed = TRUE;
2694 gst_xvimagesink_update_colorbalance (xvimagesink);
2697 g_free (xvimagesink->config.display_name);
2698 xvimagesink->config.display_name = g_strdup (g_value_get_string (value));
2700 case PROP_SYNCHRONOUS:
2701 xvimagesink->synchronous = g_value_get_boolean (value);
2702 if (xvimagesink->context) {
2703 gst_xvcontext_set_synchronous (xvimagesink->context,
2704 xvimagesink->synchronous);
2707 case PROP_PIXEL_ASPECT_RATIO:
2708 g_free (xvimagesink->par);
2709 xvimagesink->par = g_new0 (GValue, 1);
2710 g_value_init (xvimagesink->par, GST_TYPE_FRACTION);
2711 if (!g_value_transform (value, xvimagesink->par)) {
2712 g_warning ("Could not transform string to aspect ratio");
2713 gst_value_set_fraction (xvimagesink->par, 1, 1);
2715 GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
2716 gst_value_get_fraction_numerator (xvimagesink->par),
2717 gst_value_get_fraction_denominator (xvimagesink->par));
2719 case PROP_FORCE_ASPECT_RATIO:
2720 xvimagesink->keep_aspect = g_value_get_boolean (value);
2722 case PROP_HANDLE_EVENTS:
2723 gst_xvimagesink_set_event_handling (GST_VIDEO_OVERLAY (xvimagesink),
2724 g_value_get_boolean (value));
2725 gst_xvimagesink_manage_event_thread (xvimagesink);
2728 xvimagesink->config.adaptor_nr = atoi (g_value_get_string (value));
2730 case PROP_HANDLE_EXPOSE:
2731 xvimagesink->handle_expose = g_value_get_boolean (value);
2732 gst_xvimagesink_manage_event_thread (xvimagesink);
2734 case PROP_DOUBLE_BUFFER:
2735 xvimagesink->double_buffer = g_value_get_boolean (value);
2737 case PROP_AUTOPAINT_COLORKEY:
2738 xvimagesink->config.autopaint_colorkey = g_value_get_boolean (value);
2741 xvimagesink->config.colorkey = g_value_get_int (value);
2743 case PROP_DRAW_BORDERS:
2744 xvimagesink->draw_borders = g_value_get_boolean (value);
2746 #ifdef GST_EXT_XV_ENHANCEMENT
2747 case PROP_DISPLAY_MODE:
2749 int set_mode = g_value_get_enum (value);
2751 g_mutex_lock(&xvimagesink->flow_lock);
2752 g_mutex_lock(&xvimagesink->context->lock);
2754 if (xvimagesink->config.display_mode != set_mode) {
2755 if (xvimagesink->context) {
2756 /* set display mode */
2757 if (gst_xvcontext_set_display_mode(xvimagesink->context, set_mode)) {
2758 xvimagesink->config.display_mode = set_mode;
2760 GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
2763 /* "xcontext" is not created yet. It will be applied when xcontext is created. */
2764 GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
2765 xvimagesink->config.display_mode = set_mode;
2768 GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
2771 g_mutex_unlock(&xvimagesink->context->lock);
2772 g_mutex_unlock(&xvimagesink->flow_lock);
2775 case PROP_DISPLAY_GEOMETRY_METHOD:
2776 xvimagesink->display_geometry_method = g_value_get_enum (value);
2777 GST_LOG("Overlay geometry changed. update it");
2778 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2779 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2783 xvimagesink->flip = g_value_get_enum(value);
2785 case PROP_ROTATE_ANGLE:
2786 xvimagesink->rotate_angle = g_value_get_enum (value);
2787 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2788 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2792 g_mutex_lock( &xvimagesink->flow_lock );
2794 GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
2796 if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
2797 if (xvimagesink->context) {
2798 g_mutex_lock( &xvimagesink->context->lock );
2800 Atom atom_stream = XInternAtom( xvimagesink->context->disp,
2801 "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
2802 if (atom_stream != None) {
2803 GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
2804 if (XvSetPortAttribute(xvimagesink->context->disp,
2805 xvimagesink->context->xv_port_id,
2806 atom_stream, 0 ) != Success) {
2807 GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
2811 xvimagesink->visible = g_value_get_boolean (value);
2813 if (GST_STATE (xvimagesink) > GST_STATE_READY) {
2814 if (xvimagesink->get_pixmap_cb) {
2815 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2816 XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2819 XvStopVideo(xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xwindow->win);
2822 XSync( xvimagesink->context->disp, FALSE );
2823 g_mutex_unlock( &xvimagesink->context->lock );
2825 GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
2826 xvimagesink->visible = g_value_get_boolean (value);
2829 } else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
2830 g_mutex_unlock( &xvimagesink->flow_lock );
2831 xvimagesink->visible = g_value_get_boolean (value);
2832 g_mutex_lock( &xvimagesink->flow_lock );
2835 GST_INFO("set visible(%d) done", xvimagesink->visible);
2837 g_mutex_unlock( &xvimagesink->flow_lock );
2840 xvimagesink->zoom = g_value_get_float (value);
2842 case PROP_ZOOM_POS_X:
2843 xvimagesink->zoom_pos_x = g_value_get_int (value);
2845 case PROP_ZOOM_POS_Y:
2846 xvimagesink->zoom_pos_y = g_value_get_int (value);
2847 if (GST_STATE(xvimagesink) == GST_STATE_PAUSED) {
2848 gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
2851 case PROP_ORIENTATION:
2852 xvimagesink->orientation = g_value_get_enum (value);
2853 GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
2855 case PROP_DST_ROI_MODE:
2856 xvimagesink->dst_roi_mode = g_value_get_enum (value);
2857 GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
2859 case PROP_DST_ROI_X:
2860 xvimagesink->dst_roi.x = g_value_get_int (value);
2862 case PROP_DST_ROI_Y:
2863 xvimagesink->dst_roi.y = g_value_get_int (value);
2865 case PROP_DST_ROI_W:
2866 xvimagesink->dst_roi.w = g_value_get_int (value);
2868 case PROP_DST_ROI_H:
2869 xvimagesink->dst_roi.h = g_value_get_int (value);
2871 #ifdef ENABLE_STOP_VIDEO
2872 case PROP_STOP_VIDEO:
2873 xvimagesink->stop_video = g_value_get_int (value);
2874 g_mutex_lock( &xvimagesink->flow_lock );
2875 if (xvimagesink->stop_video) {
2876 if (xvimagesink->get_pixmap_cb && xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2877 GST_INFO("calling XvStopVideo()");
2878 g_mutex_lock( &xvimagesink->context->lock );
2879 XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2880 g_mutex_unlock( &xvimagesink->context->lock );
2883 GST_INFO("Xwindow CLEAR when set video-stop property");
2884 gst_xwindow_clear (xvimagesink->xwindow);
2886 g_mutex_unlock( &xvimagesink->flow_lock );
2889 case PROP_PIXMAP_CB:
2892 cb_func = g_value_get_pointer (value);
2894 if (xvimagesink->get_pixmap_cb) {
2896 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
2897 g_mutex_lock( &xvimagesink->context->lock );
2898 XvStopVideo(xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
2899 g_mutex_unlock( &xvimagesink->context->lock );
2901 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
2902 if (xvimagesink->xpixmap[i]) {
2903 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
2904 xvimagesink->xpixmap[i] = NULL;
2908 xvimagesink->get_pixmap_cb = cb_func;
2909 GST_INFO("Set callback(%p) for getting pixmap id", xvimagesink->get_pixmap_cb);
2913 case PROP_PIXMAP_CB_USER_DATA:
2916 user_data = g_value_get_pointer (value);
2918 xvimagesink->get_pixmap_cb_user_data = user_data;
2919 GST_INFO("Set user data(%p) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
2923 #endif /* GST_EXT_XV_ENHANCEMENT */
2925 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2931 gst_xvimagesink_get_property (GObject * object, guint prop_id,
2932 GValue * value, GParamSpec * pspec)
2934 GstXvImageSink *xvimagesink;
2936 g_return_if_fail (GST_IS_XVIMAGESINK (object));
2938 xvimagesink = GST_XVIMAGESINK (object);
2942 g_value_set_int (value, xvimagesink->config.hue);
2945 g_value_set_int (value, xvimagesink->config.contrast);
2947 case PROP_BRIGHTNESS:
2948 g_value_set_int (value, xvimagesink->config.brightness);
2950 case PROP_SATURATION:
2951 g_value_set_int (value, xvimagesink->config.saturation);
2954 g_value_set_string (value, xvimagesink->config.display_name);
2956 case PROP_SYNCHRONOUS:
2957 g_value_set_boolean (value, xvimagesink->synchronous);
2959 case PROP_PIXEL_ASPECT_RATIO:
2960 if (xvimagesink->par)
2961 g_value_transform (xvimagesink->par, value);
2963 case PROP_FORCE_ASPECT_RATIO:
2964 g_value_set_boolean (value, xvimagesink->keep_aspect);
2966 case PROP_HANDLE_EVENTS:
2967 g_value_set_boolean (value, xvimagesink->handle_events);
2971 char *adaptor_nr_s =
2972 g_strdup_printf ("%u", xvimagesink->config.adaptor_nr);
2974 g_value_set_string (value, adaptor_nr_s);
2975 g_free (adaptor_nr_s);
2978 case PROP_DEVICE_NAME:
2979 if (xvimagesink->context && xvimagesink->context->adaptors) {
2980 g_value_set_string (value,
2981 xvimagesink->context->adaptors[xvimagesink->config.adaptor_nr]);
2983 g_value_set_string (value, NULL);
2986 case PROP_HANDLE_EXPOSE:
2987 g_value_set_boolean (value, xvimagesink->handle_expose);
2989 case PROP_DOUBLE_BUFFER:
2990 g_value_set_boolean (value, xvimagesink->double_buffer);
2992 case PROP_AUTOPAINT_COLORKEY:
2993 g_value_set_boolean (value, xvimagesink->config.autopaint_colorkey);
2996 g_value_set_int (value, xvimagesink->config.colorkey);
2998 case PROP_DRAW_BORDERS:
2999 g_value_set_boolean (value, xvimagesink->draw_borders);
3001 case PROP_WINDOW_WIDTH:
3002 if (xvimagesink->xwindow)
3003 g_value_set_uint64 (value, xvimagesink->xwindow->width);
3005 g_value_set_uint64 (value, 0);
3007 case PROP_WINDOW_HEIGHT:
3008 if (xvimagesink->xwindow)
3009 g_value_set_uint64 (value, xvimagesink->xwindow->height);
3011 g_value_set_uint64 (value, 0);
3013 #ifdef GST_EXT_XV_ENHANCEMENT
3014 case PROP_DISPLAY_MODE:
3015 g_value_set_enum (value, xvimagesink->config.display_mode);
3017 case PROP_DISPLAY_GEOMETRY_METHOD:
3018 g_value_set_enum (value, xvimagesink->display_geometry_method);
3021 g_value_set_enum(value, xvimagesink->flip);
3023 case PROP_ROTATE_ANGLE:
3024 g_value_set_enum (value, xvimagesink->rotate_angle);
3027 g_value_set_boolean (value, xvimagesink->visible);
3030 g_value_set_float (value, xvimagesink->zoom);
3032 case PROP_ZOOM_POS_X:
3033 g_value_set_int (value, xvimagesink->zoom_pos_x);
3035 case PROP_ZOOM_POS_Y:
3036 g_value_set_int (value, xvimagesink->zoom_pos_y);
3038 case PROP_ORIENTATION:
3039 g_value_set_enum (value, xvimagesink->orientation);
3041 case PROP_DST_ROI_MODE:
3042 g_value_set_enum (value, xvimagesink->dst_roi_mode);
3044 case PROP_DST_ROI_X:
3045 g_value_set_int (value, xvimagesink->dst_roi.x);
3047 case PROP_DST_ROI_Y:
3048 g_value_set_int (value, xvimagesink->dst_roi.y);
3050 case PROP_DST_ROI_W:
3051 g_value_set_int (value, xvimagesink->dst_roi.w);
3053 case PROP_DST_ROI_H:
3054 g_value_set_int (value, xvimagesink->dst_roi.h);
3056 #ifdef ENABLE_STOP_VIDEO
3057 case PROP_STOP_VIDEO:
3058 g_value_set_int (value, xvimagesink->stop_video);
3061 case PROP_PIXMAP_CB:
3062 g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
3064 case PROP_PIXMAP_CB_USER_DATA:
3065 g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
3067 #endif /* GST_EXT_XV_ENHANCEMENT */
3069 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3075 gst_xvimagesink_open (GstXvImageSink * xvimagesink)
3077 GError *error = NULL;
3079 /* Initializing the XvContext unless already done through GstVideoOverlay */
3080 if (!xvimagesink->context) {
3081 GstXvContext *context;
3082 if (!(context = gst_xvcontext_new (&xvimagesink->config, &error)))
3085 GST_OBJECT_LOCK (xvimagesink);
3086 xvimagesink->context = context;
3088 GST_OBJECT_LOCK (xvimagesink);
3089 /* make an allocator for this context */
3090 xvimagesink->allocator = gst_xvimage_allocator_new (xvimagesink->context);
3091 GST_OBJECT_UNLOCK (xvimagesink);
3093 /* update object's par with calculated one if not set yet */
3094 if (!xvimagesink->par) {
3095 xvimagesink->par = g_new0 (GValue, 1);
3096 gst_value_init_and_copy (xvimagesink->par, xvimagesink->context->par);
3097 GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR");
3099 /* call XSynchronize with the current value of synchronous */
3100 gst_xvcontext_set_synchronous (xvimagesink->context,
3101 xvimagesink->synchronous);
3102 gst_xvimagesink_update_colorbalance (xvimagesink);
3103 gst_xvimagesink_manage_event_thread (xvimagesink);
3109 gst_element_message_full (GST_ELEMENT (xvimagesink), GST_MESSAGE_ERROR,
3110 error->domain, error->code, g_strdup ("Could not initialise Xv output"),
3111 error->message, __FILE__, GST_FUNCTION, __LINE__);
3117 gst_xvimagesink_close (GstXvImageSink * xvimagesink)
3120 GstXvContext *context;
3122 GST_OBJECT_LOCK (xvimagesink);
3123 xvimagesink->running = FALSE;
3124 /* grab thread and mark it as NULL */
3125 thread = xvimagesink->event_thread;
3126 xvimagesink->event_thread = NULL;
3127 GST_OBJECT_UNLOCK (xvimagesink);
3129 /* Wait for our event thread to finish before we clean up our stuff. */
3131 g_thread_join (thread);
3133 if (xvimagesink->cur_image) {
3134 gst_buffer_unref (xvimagesink->cur_image);
3135 xvimagesink->cur_image = NULL;
3137 g_mutex_lock (&xvimagesink->flow_lock);
3139 #ifdef GST_EXT_XV_ENHANCEMENT
3140 if (xvimagesink->get_pixmap_cb) {
3142 if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
3143 GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
3144 XvStopVideo (xvimagesink->context->disp, xvimagesink->context->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
3146 for (i = 0; i < MAX_PIXMAP_NUM; i++) {
3147 if (xvimagesink->xpixmap[i]) {
3148 gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
3149 xvimagesink->xpixmap[i] = NULL;
3152 xvimagesink->get_pixmap_cb = NULL;
3153 xvimagesink->get_pixmap_cb_user_data = NULL;
3155 #endif /* GST_EXT_XV_ENHANCEMENT */
3157 if (xvimagesink->pool) {
3158 gst_object_unref (xvimagesink->pool);
3159 xvimagesink->pool = NULL;
3162 if (xvimagesink->xwindow) {
3163 gst_xwindow_clear (xvimagesink->xwindow);
3164 gst_xwindow_destroy (xvimagesink->xwindow);
3165 xvimagesink->xwindow = NULL;
3167 g_mutex_unlock (&xvimagesink->flow_lock);
3169 if (xvimagesink->allocator) {
3170 gst_object_unref (xvimagesink->allocator);
3171 xvimagesink->allocator = NULL;
3174 GST_OBJECT_LOCK (xvimagesink);
3175 /* grab context and mark it as NULL */
3176 context = xvimagesink->context;
3177 xvimagesink->context = NULL;
3178 GST_OBJECT_UNLOCK (xvimagesink);
3181 gst_xvcontext_unref (context);
3184 /* Finalize is called only once, dispose can be called multiple times.
3185 * We use mutexes and don't reset stuff to NULL here so let's register
3188 gst_xvimagesink_finalize (GObject * object)
3190 GstXvImageSink *xvimagesink;
3192 xvimagesink = GST_XVIMAGESINK (object);
3194 gst_xvimagesink_close (xvimagesink);
3196 gst_xvcontext_config_clear (&xvimagesink->config);
3198 if (xvimagesink->par) {
3199 g_free (xvimagesink->par);
3200 xvimagesink->par = NULL;
3202 g_mutex_clear (&xvimagesink->flow_lock);
3203 g_free (xvimagesink->media_title);
3205 G_OBJECT_CLASS (parent_class)->finalize (object);
3209 gst_xvimagesink_init (GstXvImageSink * xvimagesink)
3211 xvimagesink->config.display_name = NULL;
3212 xvimagesink->config.adaptor_nr = 0;
3213 xvimagesink->config.autopaint_colorkey = TRUE;
3214 xvimagesink->config.double_buffer = TRUE;
3215 /* on 16bit displays this becomes r,g,b = 1,2,3
3216 * on 24bit displays this becomes r,g,b = 8,8,16
3217 * as a port atom value */
3218 xvimagesink->config.colorkey = (8 << 16) | (8 << 8) | 16;
3219 xvimagesink->config.hue = xvimagesink->config.saturation = 0;
3220 xvimagesink->config.contrast = xvimagesink->config.brightness = 0;
3221 xvimagesink->config.cb_changed = FALSE;
3222 #ifdef GST_EXT_XV_ENHANCEMENT
3223 xvimagesink->config.display_mode = DISPLAY_MODE_DEFAULT;
3224 #endif /* GST_EXT_XV_ENHANCEMENT */
3226 xvimagesink->context = NULL;
3227 xvimagesink->xwindow = NULL;
3228 xvimagesink->cur_image = NULL;
3230 xvimagesink->fps_n = 0;
3231 xvimagesink->fps_d = 0;
3232 xvimagesink->video_width = 0;
3233 xvimagesink->video_height = 0;
3235 g_mutex_init (&xvimagesink->flow_lock);
3237 xvimagesink->pool = NULL;
3239 xvimagesink->synchronous = FALSE;
3240 xvimagesink->running = FALSE;
3241 xvimagesink->keep_aspect = TRUE;
3242 xvimagesink->handle_events = TRUE;
3243 xvimagesink->par = NULL;
3244 xvimagesink->handle_expose = TRUE;
3246 xvimagesink->draw_borders = TRUE;
3247 #ifdef GST_EXT_XV_ENHANCEMENT
3248 xvimagesink->xid_updated = FALSE;
3249 xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
3250 xvimagesink->flip = DEF_DISPLAY_FLIP;
3251 xvimagesink->rotate_angle = DEGREE_270;
3252 xvimagesink->visible = TRUE;
3253 xvimagesink->zoom = 1.0;
3254 xvimagesink->zoom_pos_x = -1;
3255 xvimagesink->zoom_pos_y = -1;
3256 xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
3257 xvimagesink->orientation = DEGREE_0;
3258 xvimagesink->dst_roi.x = 0;
3259 xvimagesink->dst_roi.y = 0;
3260 xvimagesink->dst_roi.w = 0;
3261 xvimagesink->dst_roi.h = 0;
3263 xvimagesink->is_zero_copy_format = FALSE;
3264 xvimagesink->is_secure_path = FALSE;
3266 xvimagesink->current_pixmap_idx = -1;
3267 xvimagesink->get_pixmap_cb = NULL;
3268 xvimagesink->get_pixmap_cb_user_data = NULL;
3269 #ifdef ENABLE_STOP_VIDEO
3270 xvimagesink->stop_video = FALSE;
3272 /*X can't gurarantee thread safe: sometimes, X can't render Video.
3273 Add XInitThread() before XOpenDisplay()*/
3275 GST_WARNING("FAIL to call XInitThreads()");
3276 #endif /* GST_EXT_XV_ENHANCEMENT */
3280 gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
3282 GObjectClass *gobject_class;
3283 GstElementClass *gstelement_class;
3284 GstBaseSinkClass *gstbasesink_class;
3285 GstVideoSinkClass *videosink_class;
3287 gobject_class = (GObjectClass *) klass;
3288 gstelement_class = (GstElementClass *) klass;
3289 gstbasesink_class = (GstBaseSinkClass *) klass;
3290 videosink_class = (GstVideoSinkClass *) klass;
3292 parent_class = g_type_class_peek_parent (klass);
3294 gobject_class->set_property = gst_xvimagesink_set_property;
3295 gobject_class->get_property = gst_xvimagesink_get_property;
3297 g_object_class_install_property (gobject_class, PROP_CONTRAST,
3298 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
3299 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3300 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
3301 g_param_spec_int ("brightness", "Brightness",
3302 "The brightness of the video", -1000, 1000, 0,
3303 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3304 g_object_class_install_property (gobject_class, PROP_HUE,
3305 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
3306 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3307 g_object_class_install_property (gobject_class, PROP_SATURATION,
3308 g_param_spec_int ("saturation", "Saturation",
3309 "The saturation of the video", -1000, 1000, 0,
3310 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3311 g_object_class_install_property (gobject_class, PROP_DISPLAY,
3312 g_param_spec_string ("display", "Display", "X Display name", NULL,
3313 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3314 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
3315 g_param_spec_boolean ("synchronous", "Synchronous",
3316 "When enabled, runs the X display in synchronous mode. "
3317 "(unrelated to A/V sync, used only for debugging)", FALSE,
3318 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3319 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
3320 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
3321 "The pixel aspect ratio of the device", "1/1",
3322 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3323 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
3324 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
3325 "When enabled, scaling will respect original aspect ratio", TRUE,
3326 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3327 g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS,
3328 g_param_spec_boolean ("handle-events", "Handle XEvents",
3329 "When enabled, XEvents will be selected and handled", TRUE,
3330 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3331 g_object_class_install_property (gobject_class, PROP_DEVICE,
3332 g_param_spec_string ("device", "Adaptor number",
3333 "The number of the video adaptor", "0",
3334 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3335 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
3336 g_param_spec_string ("device-name", "Adaptor name",
3337 "The name of the video adaptor", NULL,
3338 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3340 * GstXvImageSink:handle-expose
3342 * When enabled, the current frame will always be drawn in response to X
3347 g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE,
3348 g_param_spec_boolean ("handle-expose", "Handle expose",
3350 "the current frame will always be drawn in response to X Expose "
3351 "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3354 * GstXvImageSink:double-buffer
3356 * Whether to double-buffer the output.
3360 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
3361 g_param_spec_boolean ("double-buffer", "Double-buffer",
3362 "Whether to double-buffer the output", TRUE,
3363 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3365 * GstXvImageSink:autopaint-colorkey
3367 * Whether to autofill overlay with colorkey
3371 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
3372 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
3373 "Whether to autofill overlay with colorkey", TRUE,
3374 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3376 * GstXvImageSink:colorkey
3378 * Color to use for the overlay mask.
3382 g_object_class_install_property (gobject_class, PROP_COLORKEY,
3383 g_param_spec_int ("colorkey", "Colorkey",
3384 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
3385 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3388 * GstXvImageSink:draw-borders
3390 * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill
3391 * unused parts of the video area.
3393 g_object_class_install_property (gobject_class, PROP_DRAW_BORDERS,
3394 g_param_spec_boolean ("draw-borders", "Draw Borders",
3395 "Draw black borders to fill unused area in force-aspect-ratio mode",
3396 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3399 * GstXvImageSink:window-width
3401 * Actual width of the video window.
3405 g_object_class_install_property (gobject_class, PROP_WINDOW_WIDTH,
3406 g_param_spec_uint64 ("window-width", "window-width",
3407 "Width of the window", 0, G_MAXUINT64, 0,
3408 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3411 * GstXvImageSink:window-height
3413 * Actual height of the video window.
3417 g_object_class_install_property (gobject_class, PROP_WINDOW_HEIGHT,
3418 g_param_spec_uint64 ("window-height", "window-height",
3419 "Height of the window", 0, G_MAXUINT64, 0,
3420 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3422 #ifdef GST_EXT_XV_ENHANCEMENT
3424 * GstXvImageSink:display-mode
3426 * select display mode
3428 g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
3429 g_param_spec_enum("display-mode", "Display Mode",
3430 "Display device setting",
3431 GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
3432 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3435 * GstXvImageSink:display-geometry-method
3437 * Display geometrical method setting
3439 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
3440 g_param_spec_enum("display-geometry-method", "Display geometry method",
3441 "Geometrical method for display",
3442 GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
3443 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3446 * GstXvImageSink:display-flip
3448 * Display flip setting
3450 g_object_class_install_property(gobject_class, PROP_FLIP,
3451 g_param_spec_enum("flip", "Display flip",
3453 GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
3454 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3457 * GstXvImageSink:rotate
3459 * Draw rotation angle setting
3461 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
3462 g_param_spec_enum("rotate", "Rotate angle",
3463 "Rotate angle of display output",
3464 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_270,
3465 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3468 * GstXvImageSink:visible
3470 * Whether reserve original src size or not
3472 g_object_class_install_property (gobject_class, PROP_VISIBLE,
3473 g_param_spec_boolean ("visible", "Visible",
3474 "Draws screen or blacks out, true means visible, false blacks out",
3475 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3478 * GstXvImageSink:zoom
3480 * Scale small area of screen to 1X~ 9
3482 g_object_class_install_property (gobject_class, PROP_ZOOM,
3483 g_param_spec_float ("zoom", "Zoom",
3484 "Zooms screen as nX", 1.0, 9.0, 1.0,
3485 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3488 * GstXvImageSink:zoom-pos-x
3490 * Standard x-position of zoom
3492 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
3493 g_param_spec_int ("zoom-pos-x", "Zoom Position X",
3494 "Standard x-position of zoom", 0, 3840, 0,
3495 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3498 * GstXvImageSink:zoom-pos-y
3500 * Standard y-position of zoom
3502 g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
3503 g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
3504 "Standard y-position of zoom", 0, 3840, 0,
3505 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3508 * GstXvImageSink:dst-roi-mode
3510 * Display geometrical method of ROI setting
3512 g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
3513 g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
3514 "Geometrical method of ROI for display",
3515 GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
3516 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3519 * GstXvImageSink:orientation
3521 * Orientation information which will be used for ROI/ZOOM
3523 g_object_class_install_property(gobject_class, PROP_ORIENTATION,
3524 g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
3525 "Orientation information for display",
3526 GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
3527 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3530 * GstXvImageSink:dst-roi-x
3532 * X value of Destination ROI
3534 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
3535 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
3536 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3537 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3540 * GstXvImageSink:dst-roi-y
3542 * Y value of Destination ROI
3544 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
3545 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
3546 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3547 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3550 * GstXvImageSink:dst-roi-w
3552 * W value of Destination ROI
3554 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
3555 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
3556 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3557 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3560 * GstXvImageSink:dst-roi-h
3562 * H value of Destination ROI
3564 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
3565 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
3566 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3567 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3568 #ifdef ENABLE_STOP_VIDEO
3569 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
3570 g_param_spec_int ("stop-video", "Stop-Video",
3571 "Stop video for releasing video source buffer", 0, 1, 0,
3572 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3574 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
3575 g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
3576 "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
3578 g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
3579 g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
3580 "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
3582 #endif /* GST_EXT_XV_ENHANCEMENT */
3584 gobject_class->finalize = gst_xvimagesink_finalize;
3586 gst_element_class_set_static_metadata (gstelement_class,
3587 "Video sink", "Sink/Video",
3588 "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
3590 gst_element_class_add_pad_template (gstelement_class,
3591 gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory));
3593 gstelement_class->change_state =
3594 GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
3596 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
3597 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
3598 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
3599 gstbasesink_class->propose_allocation =
3600 GST_DEBUG_FUNCPTR (gst_xvimagesink_propose_allocation);
3601 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
3603 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);