4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Sangchul Lee <sc11.lee@samsung.com>
8 * This library is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; either version 2.1 of the License, or (at your option)
13 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 * License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation, Inc., 51
20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <gst/interfaces/navigation.h>
30 #include <gst/interfaces/colorbalance.h>
31 #include <gst/interfaces/propertyprobe.h>
32 /* Helper functions */
33 #include <gst/video/video.h>
36 #include "evaspixmapsink.h"
38 /* Samsung extension headers */
39 /* For xv extension header for buffer transfer (output) */
44 #include <sys/ioctl.h>
48 #include <dri2/dri2.h>
49 #include <libdrm/drm.h>
52 BUF_SHARE_METHOD_PADDR = 0,
56 /* max channel count *********************************************************/
57 #define SCMN_IMGB_MAX_PLANE (4)
59 /* image buffer definition ***************************************************
61 +------------------------------------------+ ---
64 | +---------------------------+ --- | |
66 | |<---------- w[] ---------->| | | |
74 | +---------------------------+ --- | |
76 +------------------------------------------+ ---
78 |<----------------- s[] ------------------>|
83 /* width of each image plane */
84 int w[SCMN_IMGB_MAX_PLANE];
85 /* height of each image plane */
86 int h[SCMN_IMGB_MAX_PLANE];
87 /* stride of each image plane */
88 int s[SCMN_IMGB_MAX_PLANE];
89 /* elevation of each image plane */
90 int e[SCMN_IMGB_MAX_PLANE];
91 /* user space address of each image plane */
92 void * a[SCMN_IMGB_MAX_PLANE];
93 /* physical address of each image plane, if needs */
94 void * p[SCMN_IMGB_MAX_PLANE];
95 /* color space type of image */
97 /* left postion, if needs */
99 /* top position, if needs */
101 /* to align memory */
106 int dma_buf_fd[SCMN_IMGB_MAX_PLANE];
107 /* buffer share method */
108 int buf_share_method;
111 /* Debugging category */
112 #include <gst/gstinfo.h>
113 GST_DEBUG_CATEGORY_STATIC (gst_debug_evaspixmapsink);
114 #define GST_CAT_DEFAULT gst_debug_evaspixmapsink
115 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
126 DISP_GEO_METHOD_LETTER_BOX = 0,
127 DISP_GEO_METHOD_ORIGIN_SIZE,
128 DISP_GEO_METHOD_FULL_SCREEN,
129 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
130 DISP_GEO_METHOD_CUSTOM_ROI,
142 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
143 #define DEF_DISPLAY_FLIP FLIP_NONE
144 #define GST_TYPE_EVASPIXMAPSINK_FLIP (gst_evaspixmapsink_flip_get_type())
145 #define GST_TYPE_EVASPIXMAPSINK_ROTATE_ANGLE (gst_evaspixmapsink_rotate_angle_get_type())
146 #define GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD (gst_evaspixmapsink_display_geometry_method_get_type())
149 gst_evaspixmapsink_flip_get_type(void)
151 static GType evaspixmapsink_flip_type = 0;
152 static const GEnumValue flip_type[] = {
153 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
154 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
155 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
156 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
157 { FLIP_NUM, NULL, NULL},
160 if (!evaspixmapsink_flip_type) {
161 evaspixmapsink_flip_type = g_enum_register_static("GstEvasPixmapSinkFlipType", flip_type);
164 return evaspixmapsink_flip_type;
168 gst_evaspixmapsink_rotate_angle_get_type(void)
170 static GType evaspixmapsink_rotate_angle_type = 0;
171 static const GEnumValue rotate_angle_type[] = {
172 { 0, "No rotate", "DEGREE_0"},
173 { 1, "Rotate 90 degree", "DEGREE_90"},
174 { 2, "Rotate 180 degree", "DEGREE_180"},
175 { 3, "Rotate 270 degree", "DEGREE_270"},
179 if (!evaspixmapsink_rotate_angle_type) {
180 evaspixmapsink_rotate_angle_type = g_enum_register_static("GstEvasPixmapSinkRotateAngleType", rotate_angle_type);
183 return evaspixmapsink_rotate_angle_type;
187 gst_evaspixmapsink_display_geometry_method_get_type(void)
189 static GType evaspixmapsink_display_geometry_method_type = 0;
190 static const GEnumValue display_geometry_method_type[] = {
191 { 0, "Letter box", "LETTER_BOX"},
192 { 1, "Origin size", "ORIGIN_SIZE"},
193 { 2, "Full-screen", "FULL_SCREEN"},
194 { 3, "Cropped Full-screen", "CROPPED_FULL_SCREEN"},
195 { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
199 if (!evaspixmapsink_display_geometry_method_type) {
200 evaspixmapsink_display_geometry_method_type = g_enum_register_static("GstEvasPixmapSinkDisplayGeometryMethodType", display_geometry_method_type);
203 return evaspixmapsink_display_geometry_method_type;
209 unsigned long functions;
210 unsigned long decorations;
212 unsigned long status;
214 MotifWmHints, MwmHints;
216 #define MWM_HINTS_DECORATIONS (1L << 1)
218 static void gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink);
219 static GstBufferClass *evaspixmap_buffer_parent_class = NULL;
220 static void gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf);
221 static void gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink);
222 static void gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
223 static void gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink);
224 static gboolean gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf);
225 static gboolean gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink);
226 static void gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
227 static gint gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps);
228 static void drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle);
230 /* Default template - initiated with class struct to allow gst-register to work
232 static GstStaticPadTemplate gst_evaspixmapsink_sink_template_factory =
233 GST_STATIC_PAD_TEMPLATE ("sink",
236 GST_STATIC_CAPS ("video/x-raw-rgb, "
237 "framerate = (fraction) [ 0, MAX ], "
238 "width = (int) [ 1, MAX ], "
239 "height = (int) [ 1, MAX ]; "
241 "framerate = (fraction) [ 0, MAX ], "
242 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
254 PROP_PIXEL_ASPECT_RATIO,
258 PROP_AUTOPAINT_COLORKEY,
264 PROP_DISPLAY_GEOMETRY_METHOD,
276 static GstVideoSinkClass *parent_class = NULL;
278 /* ============================================================= */
280 /* Private Methods */
282 /* ============================================================= */
284 /* evaspixmap buffers */
286 #define GST_TYPE_EVASPIXMAP_BUFFER (gst_evaspixmap_buffer_get_type())
288 #define GST_IS_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVASPIXMAP_BUFFER))
289 #define GST_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVASPIXMAP_BUFFER, GstEvasPixmapBuffer))
292 ecore_pipe_callback_handler (void *data, void *buffer, unsigned int nbyte)
294 GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink*)data;
295 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
298 GST_WARNING_OBJECT (evaspixmapsink,"data is NULL..");
301 if (!evaspixmapsink->eo) {
302 GST_WARNING_OBJECT (evaspixmapsink,"evas object is NULL..");
306 /* mapping evas object with xpixmap */
307 if (evaspixmapsink->do_link) {
308 GST_DEBUG_OBJECT (evaspixmapsink,"do link");
309 evas_object_image_size_set(evaspixmapsink->eo, evaspixmapsink->w, evaspixmapsink->h);
310 if (evaspixmapsink->xpixmap->pixmap) {
311 Evas_Native_Surface surf;
312 surf.version = EVAS_NATIVE_SURFACE_VERSION;
313 surf.type = EVAS_NATIVE_SURFACE_X11;
314 surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get());
315 surf.data.x11.pixmap = evaspixmapsink->xpixmap->pixmap;
316 __ta__("evaspixmapsink _native_surface_set", evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); );
317 evaspixmapsink->do_link = FALSE;
319 GST_WARNING_OBJECT (evaspixmapsink,"pixmap is NULL..");
323 GST_DEBUG_OBJECT (evaspixmapsink,"update");
324 /* update evas image object size */
325 if (evaspixmapsink->use_origin_size) {
326 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evaspixmapsink->w, &evaspixmapsink->h);
328 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evas_object_image update", FALSE);
329 evas_object_image_pixels_dirty_set (evaspixmapsink->eo, 1);
330 evas_object_image_fill_set(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
331 evas_object_image_data_update_add(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
332 MMTA_ACUM_ITEM_END("evaspixmapsink evas_object_image update", FALSE);
335 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
339 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
343 float former_ratio = 0;
345 float abs_margin = 0;
347 GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink *)data;
348 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
350 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &w, &h);
351 GST_DEBUG_OBJECT (evaspixmapsink,"resized : w(%d), h(%d)", w, h);
352 if (!evaspixmapsink->use_origin_size &&
353 (evaspixmapsink->w != w || evaspixmapsink->h != h)) {
354 former_ratio = (float)evaspixmapsink->w / evaspixmapsink->h;
355 ratio = (float)w / h;
356 evaspixmapsink->w = w;
357 evaspixmapsink->h = h;
360 GST_DEBUG_OBJECT (evaspixmapsink,"resized : ratio(%.3f=>%.3f)", former_ratio, ratio);
361 if ( former_ratio >= ratio ) {
362 abs_margin = former_ratio - ratio;
364 abs_margin = ratio - former_ratio;
366 /* re-link_pixmap can only be set when ratio is changed */
367 if ( abs_margin >= MARGIN_OF_ERROR ) {
369 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
370 GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
378 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
380 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
383 static inline gboolean
384 is_evas_image_object (Evas_Object *obj)
390 type = evas_object_type_get (obj);
394 if (strcmp (type, "image") == 0) {
401 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
403 GstEvasPixmapSink *evaspixmapsink = data;
404 if (!evaspixmapsink) {
405 GST_WARNING ("evaspixmapsink is NULL..");
408 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
410 evas_object_event_callback_del(evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
411 if (evaspixmapsink->eo) {
412 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
413 evaspixmapsink->eo = NULL;
416 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
420 static gboolean error_caught = FALSE;
423 gst_evaspixmapsink_handle_xerror (Display * display, XErrorEvent * xevent)
425 char error_msg[1024];
427 XGetErrorText (display, xevent->error_code, error_msg, 1024);
428 GST_DEBUG ("evaspixmapsink triggered an XError. error: %s", error_msg);
434 /* This function checks that it is actually really possible to create an image
437 gst_evaspixmapsink_check_xshm_calls (GstXContext * xcontext)
440 XShmSegmentInfo SHMInfo;
442 int (*handler) (Display *, XErrorEvent *);
443 gboolean result = FALSE;
444 gboolean did_attach = FALSE;
446 g_return_val_if_fail (xcontext != NULL, FALSE);
448 /* Sync to ensure any older errors are already processed */
449 XSync (xcontext->disp, FALSE);
451 /* Set defaults so we don't free these later unnecessarily */
452 SHMInfo.shmaddr = ((void *) -1);
455 /* Setting an error handler to catch failure */
456 error_caught = FALSE;
457 handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
459 /* Trying to create a 1x1 picture */
460 GST_DEBUG ("XvShmCreateImage of 1x1");
461 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
462 xcontext->im_format, NULL, 1, 1, &SHMInfo);
464 /* Might cause an error, sync to ensure it is noticed */
465 XSync (xcontext->disp, FALSE);
466 if (!xvimage || error_caught) {
467 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
470 size = xvimage->data_size;
472 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
473 if (SHMInfo.shmid == -1) {
474 GST_WARNING ("could not get shared memory of %d bytes", size);
478 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
479 if (SHMInfo.shmaddr == ((void *) -1)) {
480 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
481 /* Clean up the shared memory segment */
482 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
486 xvimage->data = SHMInfo.shmaddr;
487 SHMInfo.readOnly = FALSE;
489 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
490 GST_WARNING ("Failed to XShmAttach");
491 /* Clean up the shared memory segment */
492 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
496 /* Sync to ensure we see any errors we caused */
497 XSync (xcontext->disp, FALSE);
499 /* Delete the shared memory segment as soon as everyone is attached.
500 * This way, it will be deleted as soon as we detach later, and not
501 * leaked if we crash. */
502 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
505 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
509 /* store whether we succeeded in result */
512 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
513 "Not using shared memory.");
517 /* Sync to ensure we swallow any errors we caused and reset error_caught */
518 XSync (xcontext->disp, FALSE);
520 error_caught = FALSE;
521 XSetErrorHandler (handler);
524 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
525 SHMInfo.shmid, SHMInfo.shmseg);
526 XShmDetach (xcontext->disp, &SHMInfo);
527 XSync (xcontext->disp, FALSE);
529 if (SHMInfo.shmaddr != ((void *) -1))
530 shmdt (SHMInfo.shmaddr);
535 #endif /* HAVE_XSHM */
537 /* This function destroys a GstEvasPixmap handling XShm availability */
539 gst_evaspixmap_buffer_destroy (GstEvasPixmapBuffer *evaspixmapbuf)
541 GstEvasPixmapSink *evaspixmapsink;
543 GST_DEBUG_OBJECT (evaspixmapsink,"Destroying buffer");
545 evaspixmapsink = evaspixmapbuf->evaspixmapsink;
546 if (G_UNLIKELY (evaspixmapsink == NULL)) {
550 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
552 GST_OBJECT_LOCK (evaspixmapsink);
554 /* We might have some buffers destroyed after changing state to NULL */
555 if (evaspixmapsink->xcontext == NULL) {
556 GST_DEBUG_OBJECT (evaspixmapsink,"Destroying XvImage after Xcontext");
558 /* Need to free the shared memory segment even if the x context
559 * was already cleaned up */
560 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
561 shmdt (evaspixmapbuf->SHMInfo.shmaddr);
566 g_mutex_lock (evaspixmapsink->x_lock);
569 if (evaspixmapsink->xcontext->use_xshm) {
570 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
571 GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmDetaching from 0x%x id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
572 XShmDetach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo);
573 XSync (evaspixmapsink->xcontext->disp, FALSE);
574 shmdt (evaspixmapbuf->SHMInfo.shmaddr);
576 if (evaspixmapbuf->xvimage)
577 XFree (evaspixmapbuf->xvimage);
579 #endif /* HAVE_XSHM */
581 if (evaspixmapbuf->xvimage) {
582 if (evaspixmapbuf->xvimage->data) {
583 g_free (evaspixmapbuf->xvimage->data);
585 XFree (evaspixmapbuf->xvimage);
589 XSync (evaspixmapsink->xcontext->disp, FALSE);
591 g_mutex_unlock (evaspixmapsink->x_lock);
594 GST_OBJECT_UNLOCK (evaspixmapsink);
595 evaspixmapbuf->evaspixmapsink = NULL;
596 gst_object_unref (evaspixmapsink);
598 GST_MINI_OBJECT_CLASS (evaspixmap_buffer_parent_class)->finalize (GST_MINI_OBJECT(evaspixmapbuf));
604 GST_WARNING_OBJECT (evaspixmapsink,"no sink found");
610 gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf)
612 GstEvasPixmapSink *evaspixmapsink;
614 evaspixmapsink = evaspixmapbuf->evaspixmapsink;
615 if (G_UNLIKELY (evaspixmapsink == NULL)) {
616 GST_WARNING_OBJECT (evaspixmapsink,"no sink found");
619 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
621 /* If our geometry changed we can't reuse that image. */
622 GST_LOG_OBJECT (evaspixmapsink,"destroy image as sink is shutting down");
623 gst_evaspixmap_buffer_destroy (evaspixmapbuf);
627 gst_evaspixmap_buffer_free (GstEvasPixmapBuffer *evaspixmapbuf)
629 /* make sure it is not recycled */
630 evaspixmapbuf->width = -1;
631 evaspixmapbuf->height = -1;
632 gst_buffer_unref (GST_BUFFER (evaspixmapbuf));
636 gst_evaspixmap_buffer_init (GstEvasPixmapBuffer *evaspixmapbuf, gpointer g_class)
639 evaspixmapbuf->SHMInfo.shmaddr = ((void *) -1);
640 evaspixmapbuf->SHMInfo.shmid = -1;
645 gst_evaspixmap_buffer_class_init (gpointer g_class, gpointer class_data)
647 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
649 evaspixmap_buffer_parent_class = g_type_class_peek_parent (g_class);
651 mini_object_class->finalize = (GstMiniObjectFinalizeFunction) gst_evaspixmap_buffer_finalize;
655 gst_evaspixmap_buffer_get_type (void)
657 static GType _gst_evaspixmap_buffer_type;
659 if (G_UNLIKELY (_gst_evaspixmap_buffer_type == 0)) {
660 static const GTypeInfo evaspixmap_buffer_info = {
661 sizeof (GstBufferClass),
664 gst_evaspixmap_buffer_class_init,
667 sizeof (GstEvasPixmapBuffer),
669 (GInstanceInitFunc) gst_evaspixmap_buffer_init,
672 _gst_evaspixmap_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
673 "GstEvasPixmapBuffer", &evaspixmap_buffer_info, 0);
675 return _gst_evaspixmap_buffer_type;
678 /* This function handles GstEvasPixmapBuffer creation depending on XShm availability */
679 static GstEvasPixmapBuffer*
680 gst_evaspixmap_buffer_new (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
682 GstEvasPixmapBuffer *evaspixmapbuf = NULL;
683 GstStructure *structure = NULL;
684 gboolean succeeded = FALSE;
685 int (*handler) (Display *, XErrorEvent *);
687 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
693 evaspixmapbuf = (GstEvasPixmapBuffer*) gst_mini_object_new (GST_TYPE_EVASPIXMAP_BUFFER);
694 GST_DEBUG_OBJECT (evaspixmapsink,"Creating new EvasPixmapBuffer");
696 structure = gst_caps_get_structure (caps, 0);
698 if (!gst_structure_get_int (structure, "width", &evaspixmapbuf->width) || !gst_structure_get_int (structure, "height", &evaspixmapbuf->height)) {
699 GST_WARNING_OBJECT (evaspixmapsink,"failed getting geometry from caps %" GST_PTR_FORMAT, caps);
702 GST_LOG_OBJECT (evaspixmapsink,"creating %dx%d", evaspixmapbuf->width, evaspixmapbuf->height);
704 GST_LOG_OBJECT (evaspixmapsink,"aligned size %dx%d", evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
705 if (evaspixmapsink->aligned_width == 0 || evaspixmapsink->aligned_height == 0) {
706 GST_INFO_OBJECT (evaspixmapsink,"aligned size is zero. set size of caps.");
707 evaspixmapsink->aligned_width = evaspixmapbuf->width;
708 evaspixmapsink->aligned_height = evaspixmapbuf->height;
711 evaspixmapbuf->im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
712 if (evaspixmapbuf->im_format == -1) {
713 GST_WARNING_OBJECT (evaspixmapsink,"failed to get format from caps %"GST_PTR_FORMAT, caps);
714 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",
715 evaspixmapbuf->width, evaspixmapbuf->height), ("Invalid input caps"));
718 evaspixmapbuf->evaspixmapsink = gst_object_ref (evaspixmapsink);
720 g_mutex_lock (evaspixmapsink->x_lock);
722 /* Setting an error handler to catch failure */
723 error_caught = FALSE;
724 handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
727 if (evaspixmapsink->xcontext->use_xshm) {
729 evaspixmapbuf->xvimage = XvShmCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, evaspixmapbuf->im_format, NULL,
730 evaspixmapsink->aligned_width, evaspixmapsink->aligned_height, &evaspixmapbuf->SHMInfo);
731 if(!evaspixmapbuf->xvimage) {
732 GST_ERROR_OBJECT (evaspixmapsink,"XvShmCreateImage() failed");
735 if (!evaspixmapbuf->xvimage || error_caught) {
737 GST_ERROR_OBJECT (evaspixmapsink,"error_caught!");
739 g_mutex_unlock (evaspixmapsink->x_lock);
740 /* Reset error handler */
741 error_caught = FALSE;
742 XSetErrorHandler (handler);
744 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",evaspixmapbuf->width,
745 evaspixmapbuf->height),("could not XvShmCreateImage a %dx%d image",evaspixmapbuf->width, evaspixmapbuf->height));
749 /* we have to use the returned data_size for our shm size */
750 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
751 GST_LOG_OBJECT (evaspixmapsink,"XShm image size is %" G_GSIZE_FORMAT, evaspixmapbuf->size);
753 /* calculate the expected size. This is only for sanity checking the
754 * number we get from X. */
755 switch (evaspixmapbuf->im_format) {
756 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
757 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
764 pitches[0] = GST_ROUND_UP_4 (evaspixmapbuf->width);
765 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (evaspixmapbuf->height);
766 pitches[1] = GST_ROUND_UP_8 (evaspixmapbuf->width) / 2;
768 offsets[1] + pitches[1] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
769 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
771 expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
773 for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
774 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a expected pitch of %d bytes, " "offset of %d",
775 plane, pitches[plane], offsets[plane]);
779 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
780 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
781 expected_size = evaspixmapbuf->height * GST_ROUND_UP_4 (evaspixmapbuf->width * 2);
783 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
784 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
785 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
786 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
787 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
788 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
789 expected_size = sizeof(SCMN_IMGB);
795 if (expected_size != 0 && evaspixmapbuf->size != expected_size) {
796 GST_WARNING_OBJECT (evaspixmapsink,"unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", evaspixmapbuf->size, expected_size);
799 /* Be verbose about our XvImage stride */
802 for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
803 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a pitch of %d bytes, ""offset of %d", plane,
804 evaspixmapbuf->xvimage->pitches[plane], evaspixmapbuf->xvimage->offsets[plane]);
808 evaspixmapbuf->SHMInfo.shmid = shmget (IPC_PRIVATE, evaspixmapbuf->size,IPC_CREAT | 0777);
809 if (evaspixmapbuf->SHMInfo.shmid == -1) {
810 g_mutex_unlock (evaspixmapsink->x_lock);
811 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
812 ("Failed to create output image buffer of %dx%d pixels", evaspixmapbuf->width, evaspixmapbuf->height),
813 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",evaspixmapbuf->size));
817 evaspixmapbuf->SHMInfo.shmaddr = shmat (evaspixmapbuf->SHMInfo.shmid, NULL, 0);
818 if (evaspixmapbuf->SHMInfo.shmaddr == ((void *) -1)) {
819 g_mutex_unlock (evaspixmapsink->x_lock);
820 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
821 ("Failed to create output image buffer of %dx%d pixels",
822 evaspixmapbuf->width, evaspixmapbuf->height),
823 ("Failed to shmat: %s", g_strerror (errno)));
824 /* Clean up the shared memory segment */
825 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
829 evaspixmapbuf->xvimage->data = evaspixmapbuf->SHMInfo.shmaddr;
830 evaspixmapbuf->SHMInfo.readOnly = FALSE;
832 if (XShmAttach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo) == 0) {
833 /* Clean up the shared memory segment */
834 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
836 g_mutex_unlock (evaspixmapsink->x_lock);
837 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
838 ("Failed to create output image buffer of %dx%d pixels",
839 evaspixmapbuf->width, evaspixmapbuf->height), ("Failed to XShmAttach"));
843 XSync (evaspixmapsink->xcontext->disp, FALSE);
845 /* Delete the shared memory segment as soon as we everyone is attached.
846 * This way, it will be deleted as soon as we detach later, and not
847 * leaked if we crash. */
848 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
850 GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmAttached to 0x%x, id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
852 #endif /* HAVE_XSHM */
854 evaspixmapbuf->xvimage = XvCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id,
855 evaspixmapbuf->im_format, NULL, evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
856 if (!evaspixmapbuf->xvimage || error_caught) {
857 g_mutex_unlock (evaspixmapsink->x_lock);
858 /* Reset error handler */
859 error_caught = FALSE;
860 XSetErrorHandler (handler);
862 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
863 ("Failed to create outputimage buffer of %dx%d pixels",
864 evaspixmapbuf->width, evaspixmapbuf->height),
865 ("could not XvCreateImage a %dx%d image",
866 evaspixmapbuf->width, evaspixmapbuf->height));
870 /* we have to use the returned data_size for our image size */
871 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
872 evaspixmapbuf->xvimage->data = g_malloc (evaspixmapbuf->size);
874 XSync (evaspixmapsink->xcontext->disp, FALSE);
877 /* Reset error handler */
878 error_caught = FALSE;
879 XSetErrorHandler (handler);
883 GST_BUFFER_DATA (evaspixmapbuf) = (guchar *) evaspixmapbuf->xvimage->data;
884 GST_BUFFER_SIZE (evaspixmapbuf) = evaspixmapbuf->size;
886 g_mutex_unlock (evaspixmapsink->x_lock);
890 gst_evaspixmap_buffer_free (evaspixmapbuf);
891 evaspixmapbuf = NULL;
894 return evaspixmapbuf;
897 /* This function puts a GstEvasPixmapBuffer on a GstEvasPixmapSink's pixmap. Returns FALSE
898 * if no pixmap was available */
900 gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf)
902 GstVideoRectangle result;
904 GstVideoRectangle src_origin = { 0, 0, 0, 0};
905 GstVideoRectangle src_input = { 0, 0, 0, 0};
906 GstVideoRectangle src = { 0, 0, 0, 0};
907 GstVideoRectangle dst = { 0, 0, 0, 0};
911 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evaspixmap_buffer_put", FALSE);
913 /* We take the flow_lock. If expose is in there we don't want to run
914 concurrently from the data flow thread */
915 g_mutex_lock (evaspixmapsink->flow_lock);
917 if (G_UNLIKELY (evaspixmapsink->xpixmap == NULL)) {
918 GST_WARNING_OBJECT (evaspixmapsink, "xpixmap is NULL. Skip buffer_put." );
919 g_mutex_unlock(evaspixmapsink->flow_lock);
922 if (evaspixmapsink->visible == FALSE) {
923 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. Skip buffer_put." );
924 g_mutex_unlock(evaspixmapsink->flow_lock);
927 if (!evaspixmapbuf) {
928 GST_WARNING_OBJECT (evaspixmapsink, "evaspixmapbuf is NULL. Skip buffer_put." );
929 g_mutex_unlock(evaspixmapsink->flow_lock);
933 gst_evaspixmapsink_xpixmap_update_geometry( evaspixmapsink );
936 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
937 src_input.w = src_origin.w = evaspixmapsink->video_width;
938 src_input.h = src_origin.h = evaspixmapsink->video_height;
939 if (evaspixmapsink->use_origin_size ||
940 (evaspixmapsink->rotate_angle == DEGREE_0 ||
941 evaspixmapsink->rotate_angle == DEGREE_180)) {
942 src.w = src_origin.w;
943 src.h = src_origin.h;
945 src.w = src_origin.h;
946 src.h = src_origin.w;
949 dst.w = evaspixmapsink->render_rect.w; /* pixmap width */
950 dst.h = evaspixmapsink->render_rect.h; /* pixmap heighy */
952 if (!evaspixmapsink->use_origin_size) {
953 static Atom atom_rotation = None;
954 static Atom atom_hflip = None;
955 static Atom atom_vflip = None;
956 gboolean set_hflip = FALSE;
957 gboolean set_vflip = FALSE;
959 switch (evaspixmapsink->display_geometry_method) {
960 case DISP_GEO_METHOD_LETTER_BOX:
961 gst_video_sink_center_rect (src, dst, &result, TRUE);
962 result.x += evaspixmapsink->render_rect.x;
963 result.y += evaspixmapsink->render_rect.y;
964 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : letter box");
966 case DISP_GEO_METHOD_ORIGIN_SIZE:
967 gst_video_sink_center_rect (src, dst, &result, FALSE);
968 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
969 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : origin size");
970 if (evaspixmapsink->rotate_angle == DEGREE_90 ||
971 evaspixmapsink->rotate_angle == DEGREE_270) {
972 src_input.x = src_input.x ^ src_input.y;
973 src_input.y = src_input.x ^ src_input.y;
974 src_input.x = src_input.x ^ src_input.y;
975 src_input.w = src_input.w ^ src_input.h;
976 src_input.h = src_input.w ^ src_input.h;
977 src_input.w = src_input.w ^ src_input.h;
980 case DISP_GEO_METHOD_FULL_SCREEN:
981 result.x = result.y = 0;
982 result.w = evaspixmapsink->xpixmap->width;
983 result.h = evaspixmapsink->xpixmap->height;
984 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : full screen");
986 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
987 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : cropped full screen");
988 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
989 result.x = result.y = 0;
992 if (evaspixmapsink->rotate_angle == DEGREE_90 ||
993 evaspixmapsink->rotate_angle == DEGREE_270) {
994 src_input.x = src_input.x ^ src_input.y;
995 src_input.y = src_input.x ^ src_input.y;
996 src_input.x = src_input.x ^ src_input.y;
997 src_input.w = src_input.w ^ src_input.h;
998 src_input.h = src_input.w ^ src_input.h;
999 src_input.w = src_input.w ^ src_input.h;
1002 case DISP_GEO_METHOD_CUSTOM_ROI:
1003 switch (evaspixmapsink->rotate_angle) {
1005 result.w = evaspixmapsink->dst_roi.h;
1006 result.h = evaspixmapsink->dst_roi.w;
1007 result.x = evaspixmapsink->dst_roi.y;
1008 result.y = evaspixmapsink->xpixmap->height - evaspixmapsink->dst_roi.x - evaspixmapsink->dst_roi.w;
1011 result.w = evaspixmapsink->dst_roi.w;
1012 result.h = evaspixmapsink->dst_roi.h;
1013 result.x = evaspixmapsink->xpixmap->width - result.w - evaspixmapsink->dst_roi.x;
1014 result.y = evaspixmapsink->xpixmap->height - result.h - evaspixmapsink->dst_roi.y;
1017 result.w = evaspixmapsink->dst_roi.h;
1018 result.h = evaspixmapsink->dst_roi.w;
1019 result.x = evaspixmapsink->xpixmap->width - evaspixmapsink->dst_roi.y - evaspixmapsink->dst_roi.h;
1020 result.y = evaspixmapsink->dst_roi.x;
1023 result.x = evaspixmapsink->dst_roi.x;
1024 result.y = evaspixmapsink->dst_roi.y;
1025 result.w = evaspixmapsink->dst_roi.w;
1026 result.h = evaspixmapsink->dst_roi.h;
1029 GST_LOG_OBJECT(evaspixmapsink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1030 evaspixmapsink->rotate_angle,
1031 evaspixmapsink->dst_roi.x, evaspixmapsink->dst_roi.y, evaspixmapsink->dst_roi.w, evaspixmapsink->dst_roi.h,
1032 result.x, result.y, result.w, result.h);
1037 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : src(%dx%d), dst(%dx%d), result(%dx%d), result_x(%d), result_y(%d)",
1038 src.w,src.h,dst.w,dst.h,result.w,result.h,result.x,result.y);
1040 switch( evaspixmapsink->rotate_angle ) {
1053 GST_WARNING_OBJECT( evaspixmapsink, "Unsupported rotation [%d]... set DEGREE 0.",
1054 evaspixmapsink->rotate_angle );
1058 /* set display rotation */
1059 if (atom_rotation == None) {
1060 atom_rotation = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1063 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate);
1064 if (ret != Success) {
1065 GST_ERROR_OBJECT( evaspixmapsink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1066 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate );
1070 /* set display flip */
1071 if (atom_hflip == None) {
1072 atom_hflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1074 if (atom_vflip == None) {
1075 atom_vflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1078 switch (evaspixmapsink->flip) {
1079 case FLIP_HORIZONTAL:
1097 GST_INFO_OBJECT(evaspixmapsink, "set rotate %d HFLIP %d, VFLIP %d", rotate, set_hflip, set_vflip);
1099 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1100 if (ret != Success) {
1101 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1102 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1104 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1105 if (ret != Success) {
1106 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1107 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1111 result.x = result.y = 0;
1112 result.w = evaspixmapsink->xpixmap->width;
1113 result.h = evaspixmapsink->xpixmap->height;
1114 GST_INFO_OBJECT (evaspixmapsink, "USE ORIGIN SIZE, no geometry method, no rotation/flip" );
1117 g_mutex_lock (evaspixmapsink->x_lock);
1119 /* We scale to the pixmap's geometry */
1121 if (evaspixmapsink->xcontext->use_xshm) {
1122 GST_LOG_OBJECT (evaspixmapsink,"XvShmPutImage with image %dx%d and pixmap %dx%d, from xvimage %"
1124 evaspixmapbuf->width, evaspixmapbuf->height,
1125 evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h, evaspixmapbuf);
1127 /* Trim as proper size */
1128 if (src_input.w % 2 == 1) {
1131 if (src_input.h % 2 == 1) {
1135 GST_LOG_OBJECT (evaspixmapsink, "screen[%dx%d],pixmap[%d,%d,%dx%d],method[%d],rotate[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
1136 evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1137 evaspixmapsink->xpixmap->x, evaspixmapsink->xpixmap->y, evaspixmapsink->xpixmap->width, evaspixmapsink->xpixmap->height,
1138 evaspixmapsink->display_geometry_method, rotate,
1139 src_origin.w, src_origin.h,
1140 dst.x, dst.y, dst.w, dst.h,
1141 src_input.x, src_input.y, src_input.w, src_input.h,
1142 result.x, result.y, result.w, result.h );
1144 if (evaspixmapsink->visible) {
1145 ret = XvShmPutImage (evaspixmapsink->xcontext->disp,
1146 evaspixmapsink->xcontext->xv_port_id,
1147 evaspixmapsink->xpixmap->pixmap,
1148 evaspixmapsink->xpixmap->gc, evaspixmapbuf->xvimage,
1149 src_input.x, src_input.y, src_input.w, src_input.h,
1150 result.x, result.y, result.w, result.h, FALSE);
1151 GST_LOG_OBJECT (evaspixmapsink, "XvShmPutImage return value [%d]", ret );
1154 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1157 #endif /* HAVE_XSHM */
1159 if (evaspixmapsink->visible) {
1160 XvPutImage (evaspixmapsink->xcontext->disp,
1161 evaspixmapsink->xcontext->xv_port_id,
1162 evaspixmapsink->xpixmap->pixmap,
1163 evaspixmapsink->xpixmap->gc, evaspixmapbuf->xvimage,
1164 evaspixmapsink->disp_x, evaspixmapsink->disp_y,
1165 evaspixmapsink->disp_width, evaspixmapsink->disp_height,
1166 result.x, result.y, result.w, result.h);
1168 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1171 XSync (evaspixmapsink->xcontext->disp, FALSE);
1173 g_mutex_unlock (evaspixmapsink->x_lock);
1174 g_mutex_unlock (evaspixmapsink->flow_lock);
1176 MMTA_ACUM_ITEM_END("evaspixmapsink evaspixmap_buffer_put", FALSE);
1182 drm_init(GstEvasPixmapSink *evaspixmapsink)
1190 char *driverName = NULL;
1191 char *deviceName = NULL;
1192 struct drm_auth auth_arg = {0};
1194 evaspixmapsink->drm_fd = -1;
1196 dpy = XOpenDisplay(0);
1199 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
1200 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryExtension()");
1204 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
1205 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryVersion");
1209 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
1210 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2Connect");
1214 if (!driverName || !deviceName) {
1215 GST_ERROR_OBJECT (evaspixmapsink,"driverName or deviceName is not valid");
1219 GST_INFO_OBJECT (evaspixmapsink,"Open drm device : %s", deviceName);
1221 /* get the drm_fd though opening the deviceName */
1222 evaspixmapsink->drm_fd = open(deviceName, O_RDWR);
1223 if (evaspixmapsink->drm_fd < 0) {
1224 GST_ERROR_OBJECT (evaspixmapsink,"cannot open drm device (%s)", deviceName);
1228 /* get magic from drm to authentication */
1229 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
1230 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm auth magic");
1231 close(evaspixmapsink->drm_fd);
1232 evaspixmapsink->drm_fd = -1;
1236 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
1237 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm authentication from X");
1238 close(evaspixmapsink->drm_fd);
1239 evaspixmapsink->drm_fd = -1;
1243 /* init gem handle */
1244 for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1245 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1246 evaspixmapsink->gem_info[i].gem_handle = 0;
1247 evaspixmapsink->gem_info[i].gem_name = 0;
1269 drm_fini(GstEvasPixmapSink *evaspixmapsink)
1271 if (evaspixmapsink->drm_fd >= 0) {
1273 for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1274 if (evaspixmapsink->gem_info[i].dmabuf_fd > 0) {
1275 GST_INFO_OBJECT (evaspixmapsink,"close gem_handle(%u)", evaspixmapsink->gem_info[i].gem_handle);
1276 drm_close_gem(evaspixmapsink, evaspixmapsink->gem_info[i].gem_handle);
1278 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1279 evaspixmapsink->gem_info[i].gem_handle = 0;
1280 evaspixmapsink->gem_info[i].gem_name = 0;
1285 GST_INFO_OBJECT (evaspixmapsink,"close drm_fd(%d)", evaspixmapsink->drm_fd);
1286 close(evaspixmapsink->drm_fd);
1287 evaspixmapsink->drm_fd = -1;
1292 drm_convert_dmabuf_gemname(GstEvasPixmapSink *evaspixmapsink, int dmabuf_fd)
1294 struct drm_prime_handle prime_arg = {0,};
1295 struct drm_gem_flink flink_arg = {0,};
1298 if (evaspixmapsink->drm_fd < 0) {
1299 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1303 if (dmabuf_fd <= 0) {
1304 GST_DEBUG_OBJECT (evaspixmapsink,"Ignore wrong dmabuf fd(%d)", dmabuf_fd); /* temporarily change log level to DEBUG for reducing WARNING level log */
1308 /* check duplicated dmabuf fd */
1309 for (i = 0 ; i < MAX_GEM_BUFFER_NUM ; i++) {
1310 if (evaspixmapsink->gem_info[i].dmabuf_fd == dmabuf_fd) {
1311 GST_LOG_OBJECT (evaspixmapsink,"already got fd(%u) with name(%u)", dmabuf_fd, evaspixmapsink->gem_info[i].gem_name);
1312 return evaspixmapsink->gem_info[i].gem_name;
1315 if (evaspixmapsink->gem_info[i].dmabuf_fd == 0) {
1316 GST_LOG_OBJECT (evaspixmapsink,"empty gem_info[%d] found", i);
1321 if (i == MAX_GEM_BUFFER_NUM) {
1322 GST_WARNING_OBJECT (evaspixmapsink,"too many buffers[dmabuf_fd(%d). skip it]", dmabuf_fd);
1326 evaspixmapsink->gem_info[i].dmabuf_fd = dmabuf_fd;
1327 prime_arg.fd = dmabuf_fd;
1328 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg)) {
1329 GST_ERROR_OBJECT (evaspixmapsink,"non dmabuf fd(%d)", dmabuf_fd);
1333 evaspixmapsink->gem_info[i].gem_handle = prime_arg.handle;
1334 GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_handle = %u", i, prime_arg.handle);
1336 flink_arg.handle = prime_arg.handle;
1337 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg)) {
1338 GST_ERROR_OBJECT (evaspixmapsink,"cannot convert drm handle to name");
1342 evaspixmapsink->gem_info[i].gem_name = flink_arg.name;
1343 GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_name = %u", i, flink_arg.name);
1345 return flink_arg.name;
1349 drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle)
1351 struct drm_gem_close close_arg = {0,};
1353 if (evaspixmapsink->drm_fd < 0) {
1354 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1358 if (gem_handle == 0) {
1359 GST_ERROR_OBJECT (evaspixmapsink,"invalid gem_handle(%d)",gem_handle);
1363 close_arg.handle = gem_handle;
1364 if (gem_handle > 0 && ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
1365 GST_ERROR_OBJECT (evaspixmapsink,"cannot close drm gem handle(%d)", gem_handle);
1372 /* This function destroys a GstXPixmap */
1374 gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1376 g_return_if_fail (xpixmap != NULL);
1377 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1379 g_mutex_lock (evaspixmapsink->x_lock);
1381 if(evaspixmapsink->xpixmap->pixmap) {
1382 XFreePixmap(evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap);
1383 evaspixmapsink->xpixmap->pixmap = NULL;
1384 GST_DEBUG_OBJECT (evaspixmapsink,"Free pixmap");
1388 XFreeGC (evaspixmapsink->xcontext->disp, xpixmap->gc);
1391 XSync (evaspixmapsink->xcontext->disp, FALSE);
1393 g_mutex_unlock (evaspixmapsink->x_lock);
1399 gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink)
1402 XWindowAttributes root_attr;
1404 int cur_pixmap_x = 0;
1405 int cur_pixmap_y = 0;
1406 unsigned int cur_pixmap_width = 0;
1407 unsigned int cur_pixmap_height = 0;
1408 unsigned int cur_pixmap_border_width = 0;
1409 unsigned int cur_pixmap_depth = 0;
1411 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1413 /* Update the window geometry */
1414 g_mutex_lock (evaspixmapsink->x_lock);
1415 if (G_UNLIKELY (evaspixmapsink->xpixmap == NULL)) {
1416 g_mutex_unlock (evaspixmapsink->x_lock);
1420 /* Get root window and size of current pixmap */
1421 XGetGeometry( evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap, &root_window,
1422 &cur_pixmap_x, &cur_pixmap_y, /* relative x, y, for pixmap these are alway 0 */
1423 &cur_pixmap_width, &cur_pixmap_height,
1424 &cur_pixmap_border_width, &cur_pixmap_depth ); /* cur_pixmap_border_width, cur_pixmap_depth are not used */
1426 evaspixmapsink->xpixmap->width = cur_pixmap_width;
1427 evaspixmapsink->xpixmap->height = cur_pixmap_height;
1429 evaspixmapsink->xpixmap->x = cur_pixmap_x;
1430 evaspixmapsink->xpixmap->y = cur_pixmap_y;
1432 /* Get size of root window == size of screen */
1433 XGetWindowAttributes(evaspixmapsink->xcontext->disp, root_window, &root_attr);
1435 evaspixmapsink->scr_w = root_attr.width;
1436 evaspixmapsink->scr_h = root_attr.height;
1438 if (!evaspixmapsink->have_render_rect) {
1439 evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = 0;
1440 evaspixmapsink->render_rect.w = cur_pixmap_width;
1441 evaspixmapsink->render_rect.h = cur_pixmap_height;
1444 GST_LOG_OBJECT (evaspixmapsink,"screen size %dx%d, current pixmap geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
1445 evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1446 evaspixmapsink->xpixmap->x, evaspixmapsink->xpixmap->y,
1447 evaspixmapsink->xpixmap->width, evaspixmapsink->xpixmap->height,
1448 evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y,
1449 evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1451 g_mutex_unlock (evaspixmapsink->x_lock);
1455 gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1457 g_return_if_fail (xpixmap != NULL);
1458 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1460 if (!xpixmap->pixmap) {
1461 GST_WARNING_OBJECT (evaspixmapsink,"pixmap was not created..");
1465 g_mutex_lock (evaspixmapsink->x_lock);
1467 if( evaspixmapsink->stop_video ) {
1468 XvStopVideo (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, xpixmap->pixmap);
1470 /* Preview area is not updated before other UI is updated in the screen. */
1471 XSetForeground (evaspixmapsink->xcontext->disp, xpixmap->gc, evaspixmapsink->xcontext->black);
1472 XFillRectangle (evaspixmapsink->xcontext->disp, xpixmap->pixmap, xpixmap->gc,
1473 evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y, evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1475 XSync (evaspixmapsink->xcontext->disp, FALSE);
1477 g_mutex_unlock (evaspixmapsink->x_lock);
1480 /* This function commits our internal colorbalance settings to our grabbed Xv
1481 port. If the xcontext is not initialized yet it simply returns */
1483 gst_evaspixmapsink_update_colorbalance (GstEvasPixmapSink *evaspixmapsink)
1485 GList *channels = NULL;
1487 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1489 /* If we haven't initialized the X context we can't update anything */
1490 if (evaspixmapsink->xcontext == NULL)
1493 /* Don't set the attributes if they haven't been changed, to avoid
1494 * rounding errors changing the values */
1495 if (!evaspixmapsink->cb_changed)
1498 /* For each channel of the colorbalance we calculate the correct value
1499 doing range conversion and then set the Xv port attribute to match our
1501 channels = evaspixmapsink->xcontext->channels_list;
1504 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
1505 GstColorBalanceChannel *channel = NULL;
1508 gdouble convert_coef;
1510 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
1511 g_object_ref (channel);
1513 /* Our range conversion coef */
1514 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
1516 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
1517 value = evaspixmapsink->hue;
1518 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
1519 value = evaspixmapsink->saturation;
1520 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
1521 value = evaspixmapsink->contrast;
1522 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
1523 value = evaspixmapsink->brightness;
1525 g_warning ("got an unknown channel %s", channel->label);
1526 g_object_unref (channel);
1530 /* Committing to Xv port */
1531 g_mutex_lock (evaspixmapsink->x_lock);
1533 XInternAtom (evaspixmapsink->xcontext->disp, channel->label, True);
1534 if (prop_atom != None) {
1537 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
1538 XvSetPortAttribute (evaspixmapsink->xcontext->disp,
1539 evaspixmapsink->xcontext->xv_port_id, prop_atom, xv_value);
1541 g_mutex_unlock (evaspixmapsink->x_lock);
1543 g_object_unref (channel);
1545 channels = g_list_next (channels);
1550 gst_lookup_xv_port_from_adaptor (GstXContext *xcontext, XvAdaptorInfo *adaptors, int adaptor_no)
1555 /* Do we support XvImageMask ? */
1556 if (!(adaptors[adaptor_no].type & XvImageMask)) {
1557 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", adaptors[adaptor_no].name);
1561 /* We found such an adaptor, looking for an available port */
1562 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
1563 /* We try to grab the port */
1564 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
1565 if (Success == res) {
1566 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
1567 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, adaptors[adaptor_no].num_ports);
1569 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, adaptors[adaptor_no].name, res);
1574 /* This function generates a caps with all supported format by the first
1575 Xv grabable port we find. We store each one of the supported formats in a
1576 format list and append the format to a newly created caps that we return
1577 If this function does not return NULL because of an error, it also grabs
1578 the port via XvGrabPort */
1580 gst_evaspixmapsink_get_xv_support (GstEvasPixmapSink *evaspixmapsink, GstXContext *xcontext)
1583 XvAdaptorInfo *adaptors;
1585 XvImageFormatValues *formats = NULL;
1587 XvEncodingInfo *encodings = NULL;
1588 gulong max_w = G_MAXINT, max_h = G_MAXINT;
1589 GstCaps *caps = NULL;
1590 GstCaps *rgb_caps = NULL;
1592 g_return_val_if_fail (xcontext != NULL, NULL);
1594 /* First let's check that XVideo extension is available */
1595 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
1596 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1597 ("Could not initialise Xv output"),
1598 ("XVideo extension is not available"));
1602 /* Then we get adaptors list */
1603 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
1604 &xcontext->nb_adaptors, &adaptors)) {
1605 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1606 ("Could not initialise Xv output"),
1607 ("Failed getting XV adaptors list"));
1611 xcontext->xv_port_id = 0;
1613 GST_DEBUG_OBJECT (evaspixmapsink,"Found %u XV adaptor(s)", xcontext->nb_adaptors);
1615 xcontext->adaptors =
1616 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
1618 /* Now fill up our adaptor name array */
1619 for (i = 0; i < xcontext->nb_adaptors; i++) {
1620 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
1623 if (evaspixmapsink->adaptor_no < xcontext->nb_adaptors) {
1624 /* Find xv port from user defined adaptor */
1625 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, evaspixmapsink->adaptor_no);
1628 if (!xcontext->xv_port_id) {
1629 /* Now search for an adaptor that supports XvImageMask */
1630 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
1631 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
1632 evaspixmapsink->adaptor_no = i;
1636 XvFreeAdaptorInfo (adaptors);
1638 if (!xcontext->xv_port_id) {
1639 evaspixmapsink->adaptor_no = -1;
1640 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, BUSY,
1641 ("Could not initialise Xv output"), ("No port available"));
1645 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
1647 int count, todo = 3;
1648 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
1649 xcontext->xv_port_id, &count);
1650 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
1651 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
1652 static const char colorkey[] = "XV_COLORKEY";
1654 GST_DEBUG_OBJECT (evaspixmapsink,"Checking %d Xv port attributes", count);
1656 evaspixmapsink->have_autopaint_colorkey = FALSE;
1657 evaspixmapsink->have_double_buffer = FALSE;
1658 evaspixmapsink->have_colorkey = FALSE;
1660 for (i = 0; ((i < count) && todo); i++)
1661 if (!strcmp (attr[i].name, autopaint)) {
1662 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
1664 /* turn on autopaint colorkey */
1665 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1666 (evaspixmapsink->autopaint_colorkey ? 1 : 0));
1668 evaspixmapsink->have_autopaint_colorkey = TRUE;
1669 } else if (!strcmp (attr[i].name, dbl_buffer)) {
1670 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
1672 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1673 (evaspixmapsink->double_buffer ? 1 : 0));
1675 evaspixmapsink->have_double_buffer = TRUE;
1676 } else if (!strcmp (attr[i].name, colorkey)) {
1677 /* Set the colorkey, default is something that is dark but hopefully
1678 * won't randomly appear on the screen elsewhere (ie not black or greys)
1679 * can be overridden by setting "colorkey" property
1681 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
1683 gboolean set_attr = TRUE;
1686 /* set a colorkey in the right format RGB565/RGB888
1687 * We only handle these 2 cases, because they're the only types of
1688 * devices we've encountered. If we don't recognise it, leave it alone
1690 cr = (evaspixmapsink->colorkey >> 16);
1691 cg = (evaspixmapsink->colorkey >> 8) & 0xFF;
1692 cb = (evaspixmapsink->colorkey) & 0xFF;
1693 switch (xcontext->depth) {
1694 case 16: /* RGB 565 */
1698 ckey = (cr << 11) | (cg << 5) | cb;
1701 case 32: /* RGB 888 / ARGB 8888 */
1702 ckey = (cr << 16) | (cg << 8) | cb;
1705 GST_DEBUG_OBJECT (evaspixmapsink,"Unknown bit depth %d for Xv Colorkey - not adjusting", xcontext->depth);
1711 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
1712 (guint32) attr[i].max_value);
1713 GST_LOG_OBJECT (evaspixmapsink,"Setting color key for display depth %d to 0x%x", xcontext->depth, ckey);
1715 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1719 evaspixmapsink->have_colorkey = TRUE;
1725 /* Get the list of encodings supported by the adapter and look for the
1726 * XV_IMAGE encoding so we can determine the maximum width and height
1728 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
1731 for (i = 0; i < nb_encodings; i++) {
1732 GST_LOG_OBJECT (evaspixmapsink,
1733 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
1734 i, encodings[i].name, encodings[i].width, encodings[i].height,
1735 encodings[i].rate.numerator, encodings[i].rate.denominator);
1736 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
1737 max_w = encodings[i].width;
1738 max_h = encodings[i].height;
1739 evaspixmapsink->scr_w = max_w;
1740 evaspixmapsink->scr_h = max_h;
1744 XvFreeEncodingInfo (encodings);
1746 /* We get all image formats supported by our port */
1747 formats = XvListImageFormats (xcontext->disp,
1748 xcontext->xv_port_id, &nb_formats);
1749 caps = gst_caps_new_empty ();
1750 for (i = 0; i < nb_formats; i++) {
1751 GstCaps *format_caps = NULL;
1752 gboolean is_rgb_format = FALSE;
1754 /* We set the image format of the xcontext to an existing one. This
1755 is just some valid image format for making our xshm calls check before
1756 caps negotiation really happens. */
1757 xcontext->im_format = formats[i].id;
1759 switch (formats[i].type) {
1762 XvImageFormatValues *fmt = &(formats[i]);
1763 gint endianness = G_BIG_ENDIAN;
1765 if (fmt->byte_order == LSBFirst) {
1766 /* our caps system handles 24/32bpp RGB as big-endian. */
1767 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
1768 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
1769 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
1770 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
1772 if (fmt->bits_per_pixel == 24) {
1773 fmt->red_mask >>= 8;
1774 fmt->green_mask >>= 8;
1775 fmt->blue_mask >>= 8;
1778 endianness = G_LITTLE_ENDIAN;
1781 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
1782 "endianness", G_TYPE_INT, endianness,
1783 "depth", G_TYPE_INT, fmt->depth,
1784 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
1785 "red_mask", G_TYPE_INT, fmt->red_mask,
1786 "green_mask", G_TYPE_INT, fmt->green_mask,
1787 "blue_mask", G_TYPE_INT, fmt->blue_mask,
1788 "width", GST_TYPE_INT_RANGE, 1, max_w,
1789 "height", GST_TYPE_INT_RANGE, 1, max_h,
1790 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1792 is_rgb_format = TRUE;
1796 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
1797 "format", GST_TYPE_FOURCC, formats[i].id,
1798 "width", GST_TYPE_INT_RANGE, 1, max_w,
1799 "height", GST_TYPE_INT_RANGE, 1, max_h,
1800 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1803 g_assert_not_reached ();
1808 GstEvasPixmapFormat *format = NULL;
1810 format = g_new0 (GstEvasPixmapFormat, 1);
1812 format->format = formats[i].id;
1813 format->caps = gst_caps_copy (format_caps);
1814 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
1817 if (is_rgb_format) {
1818 if (rgb_caps == NULL)
1819 rgb_caps = format_caps;
1821 gst_caps_append (rgb_caps, format_caps);
1823 gst_caps_append (caps, format_caps);
1827 /* Collected all caps into either the caps or rgb_caps structures.
1828 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
1830 gst_caps_append (caps, rgb_caps);
1835 GST_DEBUG_OBJECT (evaspixmapsink,"Generated the following caps: %" GST_PTR_FORMAT, caps);
1837 if (gst_caps_is_empty (caps)) {
1838 gst_caps_unref (caps);
1839 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
1840 GST_ELEMENT_ERROR (evaspixmapsink, STREAM, WRONG_TYPE, (NULL),
1841 ("No supported format found"));
1849 gst_evaspixmapsink_event_thread (GstEvasPixmapSink * evaspixmapsink)
1851 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
1852 int damage_base = 0;
1853 int damage_err_base = 0;
1854 int damage_case = 0;
1857 GST_OBJECT_LOCK (evaspixmapsink);
1859 if (!XDamageQueryExtension(evaspixmapsink->xcontext->disp, &damage_base, &damage_err_base)) {
1860 GST_ERROR_OBJECT (evaspixmapsink,"XDamageQueryExtension() failed");
1863 damage_case = (int)damage_base + XDamageNotify;
1865 while (evaspixmapsink->running) {
1866 GST_OBJECT_UNLOCK (evaspixmapsink);
1867 if (evaspixmapsink->xpixmap) {
1868 g_mutex_lock (evaspixmapsink->x_lock);
1869 while (XPending (evaspixmapsink->xcontext->disp)) {
1870 XNextEvent (evaspixmapsink->xcontext->disp, &e);
1871 if (e.type == damage_case ) {
1872 XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&e;
1873 if (damage_ev->drawable == evaspixmapsink->xpixmap->pixmap) {
1874 __ta__("evaspixmapsink ecore_pipe_write", ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink)););
1875 GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : after call ecore_pipe_write()");
1877 XDamageSubtract (evaspixmapsink->xcontext->disp, evaspixmapsink->damage, None, None );
1880 g_mutex_unlock (evaspixmapsink->x_lock);
1882 GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : what(%d)? skip..", e.type);
1885 g_usleep (G_USEC_PER_SEC / 40);
1886 GST_OBJECT_LOCK (evaspixmapsink);
1888 GST_OBJECT_UNLOCK (evaspixmapsink);
1893 gst_evaspixmapsink_manage_event_thread (GstEvasPixmapSink *evaspixmapsink)
1895 GThread *thread = NULL;
1897 /* don't start the thread too early */
1898 if (evaspixmapsink->xcontext == NULL) {
1899 GST_ERROR_OBJECT (evaspixmapsink,"xcontext is NULL..");
1903 GST_OBJECT_LOCK (evaspixmapsink);
1905 if (!evaspixmapsink->event_thread) {
1906 /* Setup our event listening thread */
1907 GST_DEBUG_OBJECT (evaspixmapsink,"run xevent thread");
1908 evaspixmapsink->running = TRUE;
1909 evaspixmapsink->event_thread = g_thread_create ( (GThreadFunc) gst_evaspixmapsink_event_thread, evaspixmapsink, TRUE, NULL);
1911 GST_WARNING_OBJECT (evaspixmapsink,"there already existed the event_thread.. keep going");
1912 /* Do not finalize the thread in here, Only finalize the thread by calling gst_evaspixmapsink_reset() */
1915 GST_OBJECT_UNLOCK (evaspixmapsink);
1919 /* This function calculates the pixel aspect ratio based on the properties
1920 * in the xcontext structure and stores it there. */
1922 gst_evaspixmapsink_calculate_pixel_aspect_ratio (GstXContext *xcontext)
1924 static const gint par[][2] = {
1925 {1, 1}, /* regular screen */
1926 {16, 15}, /* PAL TV */
1927 {11, 10}, /* 525 line Rec.601 video */
1928 {54, 59}, /* 625 line Rec.601 video */
1929 {64, 45}, /* 1280x1024 on 16:9 display */
1930 {5, 3}, /* 1280x1024 on 4:3 display */
1931 {4, 3} /* 800x600 on 16:9 display */
1938 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
1940 /* first calculate the "real" ratio based on the X values;
1941 * which is the "physical" w/h divided by the w/h in pixels of the display */
1942 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
1943 / (xcontext->heightmm * xcontext->width);
1945 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
1947 if (xcontext->width == 720 && xcontext->height == 576) {
1948 ratio = 4.0 * 576 / (3.0 * 720);
1950 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
1951 /* now find the one from par[][2] with the lowest delta to the real one */
1955 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
1956 gdouble this_delta = DELTA (i);
1958 if (this_delta < delta) {
1964 GST_DEBUG ("Decided on index %d (%d/%d)", index,
1965 par[index][0], par[index][1]);
1967 g_free (xcontext->par);
1968 xcontext->par = g_new0 (GValue, 1);
1969 g_value_init (xcontext->par, GST_TYPE_FRACTION);
1970 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
1971 GST_DEBUG ("set xcontext PAR to %d/%d",
1972 gst_value_get_fraction_numerator (xcontext->par),
1973 gst_value_get_fraction_denominator (xcontext->par));
1976 /* This function gets the X Display and global info about it. Everything is
1977 stored in our object and will be cleaned when the object is disposed. Note
1978 here that caps for supported format are generated without any window or
1981 gst_evaspixmapsink_xcontext_get (GstEvasPixmapSink *evaspixmapsink)
1983 GstXContext *xcontext = NULL;
1984 XPixmapFormatValues *px_formats = NULL;
1985 gint nb_formats = 0, i, j, N_attr;
1986 XvAttribute *xv_attr;
1988 const char *channels[4] = { "XV_HUE", "XV_SATURATION", "XV_BRIGHTNESS", "XV_CONTRAST"};
1990 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
1992 xcontext = g_new0 (GstXContext, 1);
1993 xcontext->im_format = 0;
1995 g_mutex_lock (evaspixmapsink->x_lock);
1997 xcontext->disp = XOpenDisplay (evaspixmapsink->display_name);
1999 if (!xcontext->disp) {
2000 g_mutex_unlock (evaspixmapsink->x_lock);
2002 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Could not initialise Xv output"), ("Could not open display"));
2006 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
2007 xcontext->screen_num = DefaultScreen (xcontext->disp);
2008 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
2009 xcontext->root = DefaultRootWindow (xcontext->disp);
2010 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
2011 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
2012 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
2014 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
2015 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
2016 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
2017 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
2019 GST_DEBUG_OBJECT (evaspixmapsink,"X reports %dx%d pixels and %d mm x %d mm", xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
2021 gst_evaspixmapsink_calculate_pixel_aspect_ratio (xcontext);
2022 /* We get supported pixmap formats at supported depth */
2023 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
2026 XCloseDisplay (xcontext->disp);
2027 g_mutex_unlock (evaspixmapsink->x_lock);
2028 g_free (xcontext->par);
2030 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
2031 ("Could not initialise Xv output"), ("Could not get pixel formats"));
2035 /* We get bpp value corresponding to our running depth */
2036 for (i = 0; i < nb_formats; i++) {
2037 if (px_formats[i].depth == xcontext->depth)
2038 xcontext->bpp = px_formats[i].bits_per_pixel;
2043 xcontext->endianness = (ImageByteOrder (xcontext->disp) == LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
2045 /* our caps system handles 24/32bpp RGB as big-endian. */
2046 if ((xcontext->bpp == 24 || xcontext->bpp == 32) && xcontext->endianness == G_LITTLE_ENDIAN) {
2047 xcontext->endianness = G_BIG_ENDIAN;
2048 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
2049 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
2050 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
2051 if (xcontext->bpp == 24) {
2052 xcontext->visual->red_mask >>= 8;
2053 xcontext->visual->green_mask >>= 8;
2054 xcontext->visual->blue_mask >>= 8;
2058 xcontext->caps = gst_evaspixmapsink_get_xv_support (evaspixmapsink, xcontext);
2060 if (!xcontext->caps) {
2061 XCloseDisplay (xcontext->disp);
2062 g_mutex_unlock (evaspixmapsink->x_lock);
2063 g_free (xcontext->par);
2065 /* GST_ELEMENT_ERROR is thrown by gst_evaspixmapsink_get_xv_support */
2069 /* Search for XShm extension support */
2070 if (XShmQueryExtension (xcontext->disp) && gst_evaspixmapsink_check_xshm_calls (xcontext)) {
2071 xcontext->use_xshm = TRUE;
2072 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is using XShm extension");
2074 #endif /* HAVE_XSHM */
2076 xcontext->use_xshm = FALSE;
2077 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is not using XShm extension");
2080 xv_attr = XvQueryPortAttributes (xcontext->disp, xcontext->xv_port_id, &N_attr);
2082 /* Generate the channels list */
2083 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
2084 XvAttribute *matching_attr = NULL;
2086 /* Retrieve the property atom if it exists. If it doesn't exist,
2087 * the attribute itself must not either, so we can skip */
2088 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
2089 if (prop_atom == None) {
2093 if (xv_attr != NULL) {
2094 for (j = 0; j < N_attr && matching_attr == NULL; ++j) {
2095 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) {
2096 matching_attr = xv_attr + j;
2101 if (matching_attr) {
2102 GstColorBalanceChannel *channel;
2103 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
2104 channel->label = g_strdup (channels[i]);
2105 channel->min_value = matching_attr->min_value;
2106 channel->max_value = matching_attr->max_value;
2108 xcontext->channels_list = g_list_append (xcontext->channels_list, channel);
2110 /* If the colorbalance settings have not been touched we get Xv values
2111 as defaults and update our internal variables */
2112 if (!evaspixmapsink->cb_changed) {
2114 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, prop_atom, &val);
2115 /* Normalize val to [-1000, 1000] */
2116 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / (double) (channel->max_value - channel->min_value));
2118 if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) {
2119 evaspixmapsink->hue = val;
2120 } else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) {
2121 evaspixmapsink->saturation = val;
2122 } else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) {
2123 evaspixmapsink->brightness = val;
2124 } else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) {
2125 evaspixmapsink->contrast = val;
2135 g_mutex_unlock (evaspixmapsink->x_lock);
2140 /* This function cleans the X context. Closing the Display, releasing the XV
2141 port and unrefing the caps for supported formats. */
2143 gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink)
2145 GList *formats_list, *channels_list;
2146 GstXContext *xcontext;
2149 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2151 GST_OBJECT_LOCK (evaspixmapsink);
2152 if (evaspixmapsink->xcontext == NULL) {
2153 GST_OBJECT_UNLOCK (evaspixmapsink);
2157 /* Take the XContext from the sink and clean it up */
2158 xcontext = evaspixmapsink->xcontext;
2159 evaspixmapsink->xcontext = NULL;
2161 GST_OBJECT_UNLOCK (evaspixmapsink);
2163 formats_list = xcontext->formats_list;
2165 while (formats_list) {
2166 GstEvasPixmapFormat *format = formats_list->data;
2168 gst_caps_unref (format->caps);
2170 formats_list = g_list_next (formats_list);
2173 if (xcontext->formats_list)
2174 g_list_free (xcontext->formats_list);
2176 channels_list = xcontext->channels_list;
2178 while (channels_list) {
2179 GstColorBalanceChannel *channel = channels_list->data;
2181 g_object_unref (channel);
2182 channels_list = g_list_next (channels_list);
2185 if (xcontext->channels_list)
2186 g_list_free (xcontext->channels_list);
2188 gst_caps_unref (xcontext->caps);
2190 for (i = 0; i < xcontext->nb_adaptors; i++) {
2191 g_free (xcontext->adaptors[i]);
2194 g_free (xcontext->adaptors);
2196 g_free (xcontext->par);
2198 g_mutex_lock (evaspixmapsink->x_lock);
2200 GST_DEBUG_OBJECT (evaspixmapsink,"Closing display and freeing X Context");
2202 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2204 XCloseDisplay (xcontext->disp);
2206 g_mutex_unlock (evaspixmapsink->x_lock);
2213 /* This function tries to get a format matching with a given caps in the
2214 supported list of formats we generated in gst_evaspixmapsink_get_xv_support */
2216 gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
2220 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2222 list = evaspixmapsink->xcontext->formats_list;
2225 GstEvasPixmapFormat *format = list->data;
2228 if (gst_caps_can_intersect (caps, format->caps)) {
2229 return format->format;
2232 list = g_list_next (list);
2239 gst_evaspixmapsink_getcaps (GstBaseSink *bsink)
2241 GstEvasPixmapSink *evaspixmapsink;
2243 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2245 if (evaspixmapsink->xcontext)
2246 return gst_caps_ref (evaspixmapsink->xcontext->caps);
2249 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
2254 gst_evaspixmapsink_setcaps (GstBaseSink *bsink, GstCaps *caps)
2256 GstEvasPixmapSink *evaspixmapsink;
2257 GstStructure *structure;
2258 guint32 im_format = 0;
2260 gint video_width, video_height;
2261 gint disp_x, disp_y;
2262 gint disp_width, disp_height;
2263 gint video_par_n, video_par_d; /* video's PAR */
2264 gint display_par_n, display_par_d; /* display's PAR */
2265 const GValue *caps_par;
2266 const GValue *caps_disp_reg;
2269 gboolean enable_last_buffer;
2271 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2273 GST_DEBUG_OBJECT (evaspixmapsink,"In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" GST_PTR_FORMAT, evaspixmapsink->xcontext->caps, caps);
2275 if (!gst_caps_can_intersect (evaspixmapsink->xcontext->caps, caps)) {
2276 goto incompatible_caps;
2279 structure = gst_caps_get_structure (caps, 0);
2280 ret = gst_structure_get_int (structure, "width", &video_width);
2281 ret &= gst_structure_get_int (structure, "height", &video_height);
2282 fps = gst_structure_get_value (structure, "framerate");
2283 ret &= (fps != NULL);
2286 goto incomplete_caps;
2289 evaspixmapsink->aligned_width = video_width;
2290 evaspixmapsink->aligned_height = video_height;
2292 /* get enable-last-buffer */
2293 g_object_get(G_OBJECT(evaspixmapsink), "enable-last-buffer", &enable_last_buffer, NULL);
2294 GST_INFO_OBJECT (evaspixmapsink,"current enable-last-buffer : %d", enable_last_buffer);
2295 /* flush if enable-last-buffer is TRUE */
2296 if (enable_last_buffer) {
2297 GST_INFO_OBJECT (evaspixmapsink,"flush last-buffer");
2298 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", FALSE, NULL);
2299 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", TRUE, NULL);
2302 evaspixmapsink->fps_n = gst_value_get_fraction_numerator (fps);
2303 evaspixmapsink->fps_d = gst_value_get_fraction_denominator (fps);
2305 evaspixmapsink->video_width = video_width;
2306 evaspixmapsink->video_height = video_height;
2308 im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
2309 if (im_format == -1) {
2310 goto invalid_format;
2313 /* get aspect ratio from caps if it's present, and
2314 * convert video width and height to a display width and height
2315 * using wd / hd = wv / hv * PARv / PARd */
2317 /* get video's PAR */
2318 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
2320 video_par_n = gst_value_get_fraction_numerator (caps_par);
2321 video_par_d = gst_value_get_fraction_denominator (caps_par);
2326 /* get display's PAR */
2327 if (evaspixmapsink->par) {
2328 display_par_n = gst_value_get_fraction_numerator (evaspixmapsink->par);
2329 display_par_d = gst_value_get_fraction_denominator (evaspixmapsink->par);
2335 /* get the display region */
2336 caps_disp_reg = gst_structure_get_value (structure, "display-region");
2337 if (caps_disp_reg) {
2338 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
2339 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
2340 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
2341 disp_height = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
2343 disp_x = disp_y = 0;
2344 disp_width = video_width;
2345 disp_height = video_height;
2348 if (!gst_video_calculate_display_ratio (&num, &den, video_width, video_height, video_par_n, video_par_d, display_par_n, display_par_d)) {
2352 evaspixmapsink->disp_x = disp_x;
2353 evaspixmapsink->disp_y = disp_y;
2354 evaspixmapsink->disp_width = disp_width;
2355 evaspixmapsink->disp_height = disp_height;
2357 GST_DEBUG_OBJECT (evaspixmapsink,"video width/height: %dx%d, calculated display ratio: %d/%d", video_width, video_height, num, den);
2359 /* now find a width x height that respects this display ratio.
2360 * prefer those that have one of w/h the same as the incoming video
2361 * using wd / hd = num / den */
2363 /* start with same height, because of interlaced video */
2364 /* check hd / den is an integer scale factor, and scale wd with the PAR */
2365 if (video_height % den == 0) {
2366 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video height");
2367 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2368 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2369 } else if (video_width % num == 0) {
2370 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video width");
2371 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = video_width;
2372 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_width, den, num);
2374 GST_DEBUG_OBJECT (evaspixmapsink,"approximating while keeping video height");
2375 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2376 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2378 GST_DEBUG_OBJECT (evaspixmapsink,"scaling to %dx%d", GST_VIDEO_SINK_WIDTH (evaspixmapsink), GST_VIDEO_SINK_HEIGHT (evaspixmapsink));
2380 /* Creating our window and our image with the display size in pixels */
2381 if (GST_VIDEO_SINK_WIDTH (evaspixmapsink) <= 0 || GST_VIDEO_SINK_HEIGHT (evaspixmapsink) <= 0) {
2382 goto no_display_size;
2385 g_mutex_lock (evaspixmapsink->flow_lock);
2387 /* We renew our evaspixmap buffer only if size or format changed;
2388 * the evaspixmap buffer is the same size as the video pixel size */
2389 if ((evaspixmapsink->evas_pixmap_buf) && ((im_format != evaspixmapsink->evas_pixmap_buf->im_format)
2390 || (video_width != evaspixmapsink->evas_pixmap_buf->width) || (video_height != evaspixmapsink->evas_pixmap_buf->height))) {
2391 GST_DEBUG_OBJECT (evaspixmapsink,"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
2392 GST_FOURCC_ARGS (evaspixmapsink->evas_pixmap_buf->im_format), GST_FOURCC_ARGS (im_format));
2393 GST_DEBUG_OBJECT (evaspixmapsink,"renewing evaspixmap buffer");
2394 gst_buffer_unref (GST_BUFFER (evaspixmapsink->evas_pixmap_buf));
2395 evaspixmapsink->evas_pixmap_buf = NULL;
2398 g_mutex_unlock (evaspixmapsink->flow_lock);
2400 if (evaspixmapsink->eo) {
2401 if (!gst_evaspixmapsink_xpixmap_link (evaspixmapsink)) {
2402 GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
2405 gst_evaspixmapsink_manage_event_thread (evaspixmapsink);
2408 GST_ERROR_OBJECT (evaspixmapsink,"setcaps success, but there is no evas image object..");
2417 GST_ERROR_OBJECT (evaspixmapsink,"caps incompatible");
2422 GST_DEBUG_OBJECT (evaspixmapsink,"Failed to retrieve either width, ""height or framerate from intersected caps");
2427 GST_DEBUG_OBJECT (evaspixmapsink,"Could not locate image format from caps %" GST_PTR_FORMAT, caps);
2432 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2437 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2442 static GstStateChangeReturn
2443 gst_evaspixmapsink_change_state (GstElement *element, GstStateChange transition)
2445 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2446 GstEvasPixmapSink *evaspixmapsink;
2448 evaspixmapsink = GST_EVASPIXMAPSINK (element);
2450 switch (transition) {
2451 case GST_STATE_CHANGE_NULL_TO_READY:
2452 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_NULL_TO_READY");
2454 /* open drm to use gem */
2455 if (drm_init(evaspixmapsink)) {
2456 GST_ERROR_OBJECT (evaspixmapsink,"drm_init() failure");
2457 return GST_STATE_CHANGE_FAILURE;
2460 /* check if there exist evas image object, need to write code related to making internal evas image object */
2461 if (!is_evas_image_object (evaspixmapsink->eo)) {
2462 GST_ERROR_OBJECT (evaspixmapsink,"There is no evas image object..");
2463 return GST_STATE_CHANGE_FAILURE;
2466 /* Set xcontext and display */
2467 if (!evaspixmapsink->xcontext) {
2468 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
2469 if (!evaspixmapsink->xcontext) {
2470 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
2471 return GST_STATE_CHANGE_FAILURE;
2475 /* update object's par with calculated one if not set yet */
2476 if (!evaspixmapsink->par) {
2477 evaspixmapsink->par = g_new0 (GValue, 1);
2478 gst_value_init_and_copy (evaspixmapsink->par, evaspixmapsink->xcontext->par);
2479 GST_DEBUG_OBJECT (evaspixmapsink,"set calculated PAR on object's PAR");
2482 /* call XSynchronize with the current value of synchronous */
2483 GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
2484 XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
2485 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2488 case GST_STATE_CHANGE_READY_TO_PAUSED:
2489 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_PAUSED");
2492 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2493 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_PLAYING");
2500 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2502 switch (transition) {
2503 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2504 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PLAYING_TO_PAUSED");
2507 case GST_STATE_CHANGE_PAUSED_TO_READY:
2508 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_READY");
2509 evaspixmapsink->fps_n = 0;
2510 evaspixmapsink->fps_d = 1;
2511 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = 0;
2512 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = 0;
2515 case GST_STATE_CHANGE_READY_TO_NULL:
2516 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_NULL");
2517 gst_evaspixmapsink_reset (evaspixmapsink);
2519 drm_fini(evaspixmapsink);
2529 gst_evaspixmapsink_get_times (GstBaseSink *bsink, GstBuffer *buf, GstClockTime *start, GstClockTime *end)
2531 GstEvasPixmapSink *evaspixmapsink;
2533 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2535 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2536 *start = GST_BUFFER_TIMESTAMP (buf);
2537 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2538 *end = *start + GST_BUFFER_DURATION (buf);
2540 if (evaspixmapsink->fps_n > 0) {
2542 gst_util_uint64_scale_int (GST_SECOND, evaspixmapsink->fps_d,
2543 evaspixmapsink->fps_n);
2549 static GstFlowReturn
2550 gst_evaspixmapsink_show_frame (GstVideoSink *vsink, GstBuffer *buf)
2552 GstEvasPixmapSink *evaspixmapsink;
2553 XV_PUTIMAGE_DATA_PTR img_data = NULL;
2554 SCMN_IMGB *scmn_imgb = NULL;
2557 evaspixmapsink = GST_EVASPIXMAPSINK (vsink);
2559 if( evaspixmapsink->stop_video ) {
2560 GST_INFO_OBJECT (evaspixmapsink, "Stop video is TRUE. so skip show frame..." );
2564 if (!evaspixmapsink->evas_pixmap_buf) {
2565 GST_DEBUG_OBJECT (evaspixmapsink,"creating our evaspixmap buffer");
2566 format = gst_evaspixmapsink_get_format_from_caps(evaspixmapsink, GST_BUFFER_CAPS(buf));
2568 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2569 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2570 case GST_MAKE_FOURCC('S', '4', '2', '0'):
2571 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2572 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2573 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2574 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2575 if(scmn_imgb == NULL) {
2576 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2579 /* skip buffer if aligned size is smaller than size of caps */
2580 if (scmn_imgb->s[0] < evaspixmapsink->video_width || scmn_imgb->e[0] < evaspixmapsink->video_height) {
2581 GST_WARNING_OBJECT (evaspixmapsink,"invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
2582 evaspixmapsink->video_width, evaspixmapsink->video_height, scmn_imgb->s[0], scmn_imgb->e[0]);
2585 evaspixmapsink->aligned_width = scmn_imgb->s[0];
2586 evaspixmapsink->aligned_height = scmn_imgb->e[0];
2587 GST_DEBUG_OBJECT (evaspixmapsink,"video width,height[%dx%d]",evaspixmapsink->video_width, evaspixmapsink->video_height);
2588 GST_INFO_OBJECT (evaspixmapsink,"Use aligned width,height[%dx%d]",evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
2591 GST_INFO_OBJECT (evaspixmapsink,"Use original width,height of caps");
2594 evaspixmapsink->evas_pixmap_buf = gst_evaspixmap_buffer_new (evaspixmapsink, GST_BUFFER_CAPS (buf));
2595 if (!evaspixmapsink->evas_pixmap_buf) {
2596 /* The create method should have posted an informative error */
2599 if (evaspixmapsink->evas_pixmap_buf->size < GST_BUFFER_SIZE (buf)) {
2600 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", evaspixmapsink->evas_pixmap_buf->width, evaspixmapsink->evas_pixmap_buf->height),("XServer allocated buffer size did not match input buffer"));
2601 gst_evaspixmap_buffer_destroy (evaspixmapsink->evas_pixmap_buf);
2602 evaspixmapsink->evas_pixmap_buf = NULL;
2607 switch (evaspixmapsink->evas_pixmap_buf->im_format) {
2608 /* Cases for specified formats of Samsung extension */
2609 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2610 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2611 case GST_MAKE_FOURCC('S', '4', '2', '0'):
2612 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2613 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2614 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2615 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
2617 GST_DEBUG_OBJECT (evaspixmapsink,"Samsung extension display format activated. fourcc:%d", evaspixmapsink->evas_pixmap_buf->im_format);
2619 if (evaspixmapsink->evas_pixmap_buf->xvimage->data) {
2620 img_data = (XV_PUTIMAGE_DATA_PTR) evaspixmapsink->evas_pixmap_buf->xvimage->data;
2621 XV_PUTIMAGE_INIT_DATA(img_data);
2622 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2623 if (scmn_imgb == NULL) {
2624 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2628 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
2629 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
2630 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
2631 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
2632 img_data->BufType = XV_BUF_TYPE_LEGACY;
2633 if (!img_data->YBuf) {
2634 GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2637 } else { /* BUF_SHARE_METHOD_FD */
2638 /* convert dma-buf fd into drm gem name */
2639 img_data->YBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[0]);
2640 img_data->CbBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[1]);
2641 img_data->CrBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[2]);
2642 img_data->BufType = XV_BUF_TYPE_DMABUF;
2643 if (!img_data->YBuf) {
2644 GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2648 GST_LOG_OBJECT(evaspixmapsink, "YBuf[%d], CbBuf[%d], CrBuf[%d]",
2649 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
2651 GST_WARNING_OBJECT (evaspixmapsink, "xvimage->data is NULL. skip buffer put..." );
2658 GST_DEBUG_OBJECT (evaspixmapsink,"Normal format activated. fourcc = %d", evaspixmapsink->evas_pixmap_buf->im_format);
2659 __ta__("evaspixmapsink memcpy in _show_frame", memcpy (evaspixmapsink->evas_pixmap_buf->xvimage->data, GST_BUFFER_DATA (buf),
2660 MIN (GST_BUFFER_SIZE (buf), evaspixmapsink->evas_pixmap_buf->size)););
2664 if (!gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf)) {
2673 /* No image available. That's very bad ! */
2674 GST_WARNING_OBJECT (evaspixmapsink,"could not create image");
2675 return GST_FLOW_ERROR;
2679 /* No Pixmap available to put our image into */
2680 GST_WARNING_OBJECT (evaspixmapsink,"could not output image - no pixmap");
2681 return GST_FLOW_ERROR;
2686 gst_evaspixmapsink_event (GstBaseSink *sink, GstEvent *event)
2688 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (sink);
2690 switch (GST_EVENT_TYPE (event)) {
2691 case GST_EVENT_FLUSH_START:
2692 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_START");
2694 case GST_EVENT_FLUSH_STOP:
2695 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_STOP");
2700 if (GST_BASE_SINK_CLASS (parent_class)->event) {
2701 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2707 /* Interfaces stuff */
2710 gst_evaspixmapsink_interface_supported (GstImplementsInterface *iface, GType type)
2712 g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE);
2717 gst_evaspixmapsink_interface_init (GstImplementsInterfaceClass *klass)
2719 klass->supported = gst_evaspixmapsink_interface_supported;
2723 gst_evaspixmapsink_navigation_send_event (GstNavigation *navigation, GstStructure *structure)
2725 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (navigation);
2728 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (evaspixmapsink)))) {
2730 GstVideoRectangle src, dst, result;
2731 gdouble x, y, xscale = 1.0, yscale = 1.0;
2733 event = gst_event_new_navigation (structure);
2735 /* We take the flow_lock while we look at the window */
2736 g_mutex_lock (evaspixmapsink->flow_lock);
2738 if (!evaspixmapsink->xpixmap) {
2739 g_mutex_unlock (evaspixmapsink->flow_lock);
2743 memcpy (&result, &evaspixmapsink->render_rect, sizeof (GstVideoRectangle));
2745 g_mutex_unlock (evaspixmapsink->flow_lock);
2747 /* We calculate scaling using the original video frames geometry to include
2748 pixel aspect ratio scaling. */
2749 xscale = (gdouble) evaspixmapsink->video_width / result.w;
2750 yscale = (gdouble) evaspixmapsink->video_height / result.h;
2752 /* Converting pointer coordinates to the non scaled geometry */
2753 if (gst_structure_get_double (structure, "pointer_x", &x)) {
2754 x = MIN (x, result.x + result.w);
2755 x = MAX (x - result.x, 0);
2756 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2757 (gdouble) x * xscale, NULL);
2759 if (gst_structure_get_double (structure, "pointer_y", &y)) {
2760 y = MIN (y, result.y + result.h);
2761 y = MAX (y - result.y, 0);
2762 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2763 (gdouble) y * yscale, NULL);
2766 gst_pad_send_event (peer, event);
2767 gst_object_unref (peer);
2772 gst_evaspixmapsink_navigation_init (GstNavigationInterface *iface)
2774 iface->send_event = gst_evaspixmapsink_navigation_send_event;
2778 gst_evaspixmapsink_colorbalance_list_channels (GstColorBalance *balance)
2780 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2782 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
2784 if (evaspixmapsink->xcontext)
2785 return evaspixmapsink->xcontext->channels_list;
2791 gst_evaspixmapsink_colorbalance_set_value (GstColorBalance *balance, GstColorBalanceChannel *channel, gint value)
2793 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2795 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2796 g_return_if_fail (channel->label != NULL);
2798 evaspixmapsink->cb_changed = TRUE;
2800 /* Normalize val to [-1000, 1000] */
2801 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
2802 (double) (channel->max_value - channel->min_value));
2804 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2805 evaspixmapsink->hue = value;
2806 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2807 evaspixmapsink->saturation = value;
2808 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2809 evaspixmapsink->contrast = value;
2810 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2811 evaspixmapsink->brightness = value;
2813 g_warning ("got an unknown channel %s", channel->label);
2817 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2821 gst_evaspixmapsink_colorbalance_get_value (GstColorBalance *balance, GstColorBalanceChannel *channel)
2823 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2826 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2827 g_return_val_if_fail (channel->label != NULL, 0);
2829 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2830 value = evaspixmapsink->hue;
2831 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2832 value = evaspixmapsink->saturation;
2833 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2834 value = evaspixmapsink->contrast;
2835 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2836 value = evaspixmapsink->brightness;
2838 g_warning ("got an unknown channel %s", channel->label);
2841 /* Normalize val to [channel->min_value, channel->max_value] */
2842 value = channel->min_value + (channel->max_value - channel->min_value) * (value + 1000) / 2000;
2848 gst_evaspixmapsink_colorbalance_init (GstColorBalanceClass *iface)
2850 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
2851 iface->list_channels = gst_evaspixmapsink_colorbalance_list_channels;
2852 iface->set_value = gst_evaspixmapsink_colorbalance_set_value;
2853 iface->get_value = gst_evaspixmapsink_colorbalance_get_value;
2856 static const GList *
2857 gst_evaspixmapsink_probe_get_properties (GstPropertyProbe *probe)
2859 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
2860 static GList *list = NULL;
2863 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
2864 list = g_list_append (list, g_object_class_find_property (klass, "autopaint-colorkey"));
2865 list = g_list_append (list, g_object_class_find_property (klass, "double-buffer"));
2866 list = g_list_append (list, g_object_class_find_property (klass, "colorkey"));
2873 gst_evaspixmapsink_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
2875 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
2879 case PROP_AUTOPAINT_COLORKEY:
2880 case PROP_DOUBLE_BUFFER:
2882 GST_DEBUG_OBJECT (evaspixmapsink,"probing device list and get capabilities");
2883 if (!evaspixmapsink->xcontext) {
2884 GST_DEBUG_OBJECT (evaspixmapsink,"generating xcontext");
2885 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
2886 if (!evaspixmapsink->xcontext) {
2887 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
2892 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2898 gst_evaspixmapsink_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
2900 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
2901 gboolean ret = FALSE;
2905 case PROP_AUTOPAINT_COLORKEY:
2906 case PROP_DOUBLE_BUFFER:
2908 if (evaspixmapsink->xcontext != NULL) {
2915 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
2922 static GValueArray *
2923 gst_evaspixmapsink_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
2925 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
2926 GValueArray *array = NULL;
2928 if (G_UNLIKELY (!evaspixmapsink->xcontext)) {
2929 GST_WARNING_OBJECT (evaspixmapsink,"we don't have any xcontext, can't "
2938 GValue value = { 0 };
2940 array = g_value_array_new (evaspixmapsink->xcontext->nb_adaptors);
2941 g_value_init (&value, G_TYPE_STRING);
2943 for (i = 0; i < evaspixmapsink->xcontext->nb_adaptors; i++) {
2944 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
2946 g_value_set_string (&value, adaptor_id_s);
2947 g_value_array_append (array, &value);
2948 g_free (adaptor_id_s);
2950 g_value_unset (&value);
2953 case PROP_AUTOPAINT_COLORKEY:
2954 if (evaspixmapsink->have_autopaint_colorkey) {
2955 GValue value = { 0 };
2957 array = g_value_array_new (2);
2958 g_value_init (&value, G_TYPE_BOOLEAN);
2959 g_value_set_boolean (&value, FALSE);
2960 g_value_array_append (array, &value);
2961 g_value_set_boolean (&value, TRUE);
2962 g_value_array_append (array, &value);
2963 g_value_unset (&value);
2966 case PROP_DOUBLE_BUFFER:
2967 if (evaspixmapsink->have_double_buffer) {
2968 GValue value = { 0 };
2970 array = g_value_array_new (2);
2971 g_value_init (&value, G_TYPE_BOOLEAN);
2972 g_value_set_boolean (&value, FALSE);
2973 g_value_array_append (array, &value);
2974 g_value_set_boolean (&value, TRUE);
2975 g_value_array_append (array, &value);
2976 g_value_unset (&value);
2980 if (evaspixmapsink->have_colorkey) {
2981 GValue value = { 0 };
2983 array = g_value_array_new (1);
2984 g_value_init (&value, GST_TYPE_INT_RANGE);
2985 gst_value_set_int_range (&value, 0, 0xffffff);
2986 g_value_array_append (array, &value);
2987 g_value_unset (&value);
2991 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3000 gst_evaspixmapsink_property_probe_interface_init (GstPropertyProbeInterface *iface)
3002 iface->get_properties = gst_evaspixmapsink_probe_get_properties;
3003 iface->probe_property = gst_evaspixmapsink_probe_probe_property;
3004 iface->needs_probe = gst_evaspixmapsink_probe_needs_probe;
3005 iface->get_values = gst_evaspixmapsink_probe_get_values;
3009 gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink)
3013 int evas_object_width = 0;
3014 int evas_object_height = 0;
3015 int pixmap_width = 0;
3016 int pixmap_height = 0;
3020 if (!evaspixmapsink) {
3021 GST_ERROR_OBJECT (evaspixmapsink,"could not get evaspixmapsink..");
3024 g_mutex_lock (evaspixmapsink->flow_lock);
3026 /* Set xcontext and display */
3027 if (!evaspixmapsink->xcontext) {
3028 GST_WARNING_OBJECT (evaspixmapsink,"there's no xcontext, try to get one..");
3029 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
3030 if (!evaspixmapsink->xcontext) {
3031 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
3036 dpy = evaspixmapsink->xcontext->disp;
3038 /* Set evas image object size */
3039 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evas_object_width, &evas_object_height);
3040 if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3041 pixmap_width = evaspixmapsink->video_width;
3042 pixmap_height = evaspixmapsink->video_height;
3043 GST_INFO_OBJECT (evaspixmapsink,"set size to media src size(%dx%d)", pixmap_width, pixmap_height);
3046 g_mutex_lock (evaspixmapsink->x_lock);
3047 if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3048 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, pixmap_width, pixmap_height, &xw, &xh);
3049 if (!evas_object_width || !evas_object_height) {
3050 evaspixmapsink->w = xw;
3051 evaspixmapsink->h = xh;
3053 evaspixmapsink->w = evas_object_width;
3054 evaspixmapsink->h = evas_object_height;
3056 GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, pixmap_width, pixmap_height, xw, xh);
3058 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, evas_object_width, evas_object_height, &xw, &xh);
3059 GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, evas_object_width, evas_object_height, xw, xh);
3060 evaspixmapsink->w = xw;
3061 evaspixmapsink->h = xh;
3064 /* create xpixmap structure */
3065 if (!evaspixmapsink->xpixmap) {
3066 /* xpixmap can be created in this function only */
3067 evaspixmapsink->xpixmap = g_new0 (GstXPixmap, 1);
3068 if(!evaspixmapsink->xpixmap) {
3069 GST_ERROR_OBJECT (evaspixmapsink,"xpixmap is not valid..");
3070 goto GO_OUT_OF_FUNC;
3076 GST_WARNING_OBJECT (evaspixmapsink,"skip creating pixmap..xw(%d),xh(%d)",xw,xh);
3077 goto GO_OUT_OF_FUNC;
3079 pixmap_id = XCreatePixmap(dpy, DefaultRootWindow(dpy), xw, xh, DefaultDepth(dpy, DefaultScreen(dpy)));
3080 if ( (int)pixmap_id == BadAlloc || (int)pixmap_id == BadDrawable || (int)pixmap_id == BadValue ) {
3081 GST_ERROR_OBJECT (evaspixmapsink,"pixmap allocation error..");
3082 goto GO_OUT_OF_FUNC;
3084 GST_DEBUG_OBJECT (evaspixmapsink,"evas_object_width(%d),evas_object_height(%d),pixmap:%d,depth:%d",
3085 evas_object_width,evas_object_height,pixmap_id,DefaultDepth(dpy, DefaultScreen(dpy)));
3088 if (evaspixmapsink->xpixmap->pixmap && pixmap_id != evaspixmapsink->xpixmap->pixmap) {
3089 /* If we reset another pixmap, do below */
3090 GST_DEBUG_OBJECT (evaspixmapsink,"destroy former pixmap(%d)",evaspixmapsink->xpixmap->pixmap);
3091 if (evaspixmapsink->eo) {
3092 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3094 g_mutex_unlock (evaspixmapsink->x_lock);
3095 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap);
3096 g_mutex_lock (evaspixmapsink->x_lock);
3097 if(evaspixmapsink->xpixmap->pixmap) {
3098 XFreePixmap(evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap);
3099 evaspixmapsink->xpixmap->pixmap = NULL;
3100 GST_DEBUG_OBJECT (evaspixmapsink,"Free pixmap");
3102 XFreeGC (evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->gc);
3103 XSync (evaspixmapsink->xcontext->disp, FALSE);
3106 /* Set pixmap id and create GC */
3107 evaspixmapsink->xpixmap->pixmap = pixmap_id;
3108 evaspixmapsink->xpixmap->gc = XCreateGC(dpy, evaspixmapsink->xpixmap->pixmap, 0,0);
3109 XSetForeground(dpy, evaspixmapsink->xpixmap->gc,evaspixmapsink->xcontext->black);
3110 XFillRectangle(dpy, evaspixmapsink->xpixmap->pixmap, evaspixmapsink->xpixmap->gc, 0, 0, xw, xh);
3113 /* Create XDamage */
3114 if (evaspixmapsink->damage) {
3115 GST_DEBUG_OBJECT (evaspixmapsink,"destroy former damage(%d)",evaspixmapsink->damage);
3116 XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage);
3117 evaspixmapsink->damage = NULL;
3119 evaspixmapsink->damage = XDamageCreate (dpy, evaspixmapsink->xpixmap->pixmap, XDamageReportRawRectangles);
3122 /* Set flag for mapping evas object with xpixmap */
3123 evaspixmapsink->do_link = TRUE;
3124 ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink));
3126 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3128 g_mutex_unlock (evaspixmapsink->x_lock);
3129 g_mutex_unlock (evaspixmapsink->flow_lock);
3134 g_mutex_unlock (evaspixmapsink->x_lock);
3135 g_mutex_unlock (evaspixmapsink->flow_lock);
3140 gst_evaspixmapsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
3142 GstEvasPixmapSink *evaspixmapsink;
3143 g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3144 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3150 evaspixmapsink->hue = g_value_get_int (value);
3151 evaspixmapsink->cb_changed = TRUE;
3152 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3155 evaspixmapsink->contrast = g_value_get_int (value);
3156 evaspixmapsink->cb_changed = TRUE;
3157 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3159 case PROP_BRIGHTNESS:
3160 evaspixmapsink->brightness = g_value_get_int (value);
3161 evaspixmapsink->cb_changed = TRUE;
3162 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3164 case PROP_SATURATION:
3165 evaspixmapsink->saturation = g_value_get_int (value);
3166 evaspixmapsink->cb_changed = TRUE;
3167 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3170 evaspixmapsink->display_name = g_strdup (g_value_get_string (value));
3172 case PROP_SYNCHRONOUS:
3173 evaspixmapsink->synchronous = g_value_get_boolean (value);
3174 if (evaspixmapsink->xcontext) {
3175 XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
3176 GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
3179 case PROP_PIXEL_ASPECT_RATIO:
3180 g_free (evaspixmapsink->par);
3181 evaspixmapsink->par = g_new0 (GValue, 1);
3182 g_value_init (evaspixmapsink->par, GST_TYPE_FRACTION);
3183 if (!g_value_transform (value, evaspixmapsink->par)) {
3184 g_warning ("Could not transform string to aspect ratio");
3185 gst_value_set_fraction (evaspixmapsink->par, 1, 1);
3187 GST_DEBUG_OBJECT (evaspixmapsink,"set PAR to %d/%d", gst_value_get_fraction_numerator (evaspixmapsink->par), gst_value_get_fraction_denominator (evaspixmapsink->par));
3190 evaspixmapsink->adaptor_no = atoi (g_value_get_string (value));
3192 case PROP_DOUBLE_BUFFER:
3193 evaspixmapsink->double_buffer = g_value_get_boolean (value);
3195 case PROP_AUTOPAINT_COLORKEY:
3196 evaspixmapsink->autopaint_colorkey = g_value_get_boolean (value);
3199 evaspixmapsink->colorkey = g_value_get_int (value);
3201 case PROP_PIXMAP_WIDTH:
3202 if (evaspixmapsink->xpixmap) {
3203 evaspixmapsink->xpixmap->width = g_value_get_uint64 (value);
3204 /* To do : code related to pixmap re-link */
3207 case PROP_PIXMAP_HEIGHT:
3208 if (evaspixmapsink->xpixmap) {
3209 evaspixmapsink->xpixmap->height = g_value_get_uint64 (value);
3210 /* To do : code related to pixmap re-link */
3213 case PROP_DISPLAY_GEOMETRY_METHOD:
3215 guint new_val = g_value_get_enum (value);
3216 if (evaspixmapsink->display_geometry_method != new_val) {
3217 evaspixmapsink->display_geometry_method = new_val;
3218 GST_INFO_OBJECT (evaspixmapsink,"Overlay geometry method update, display_geometry_method(%d)",evaspixmapsink->display_geometry_method);
3219 if( evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_FULL_SCREEN &&
3220 evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_CROPPED_FULL_SCREEN ) {
3221 if( evaspixmapsink->xcontext && evaspixmapsink->xpixmap ) {
3222 g_mutex_lock( evaspixmapsink->flow_lock );
3223 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap);
3224 g_mutex_unlock( evaspixmapsink->flow_lock );
3227 if (evaspixmapsink->xcontext) {
3228 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
3233 case PROP_DST_ROI_X:
3234 evaspixmapsink->dst_roi.x = g_value_get_int (value);
3235 GST_INFO_OBJECT (evaspixmapsink, "ROI_X(%d)",evaspixmapsink->dst_roi.x );
3237 case PROP_DST_ROI_Y:
3238 evaspixmapsink->dst_roi.y = g_value_get_int (value);
3239 GST_INFO_OBJECT (evaspixmapsink, "ROI_Y(%d)",evaspixmapsink->dst_roi.y );
3241 case PROP_DST_ROI_W:
3242 evaspixmapsink->dst_roi.w = g_value_get_int (value);
3243 GST_INFO_OBJECT (evaspixmapsink, "ROI_W(%d)",evaspixmapsink->dst_roi.w );
3245 case PROP_DST_ROI_H:
3246 evaspixmapsink->dst_roi.h = g_value_get_int (value);
3247 GST_INFO_OBJECT (evaspixmapsink, "ROI_H(%d)",evaspixmapsink->dst_roi.h );
3249 case PROP_STOP_VIDEO:
3250 evaspixmapsink->stop_video = g_value_get_int (value);
3251 g_mutex_lock( evaspixmapsink->flow_lock );
3252 if( evaspixmapsink->stop_video ) {
3253 GST_INFO_OBJECT (evaspixmapsink, "XPixmap CLEAR when set video-stop property" );
3254 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap);
3256 g_mutex_unlock( evaspixmapsink->flow_lock );
3258 case PROP_EVAS_OBJECT:
3259 eo = g_value_get_pointer (value);
3260 if ( is_evas_image_object (eo)) {
3261 if (!evaspixmapsink->epipe) {
3262 evaspixmapsink->epipe = ecore_pipe_add (ecore_pipe_callback_handler, evaspixmapsink);
3263 if (!evaspixmapsink->epipe) {
3264 GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: ecore_pipe_add() failed");
3268 if (eo != evaspixmapsink->eo) {
3269 /* delete evas object callbacks registrated on a former evas image object */
3270 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3271 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3272 if (evaspixmapsink->eo) {
3273 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3274 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3278 evaspixmapsink->eo = eo;
3279 /* add evas object callbacks on a new evas image object */
3280 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event, evaspixmapsink);
3281 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, evaspixmapsink);
3282 GST_INFO_OBJECT (evaspixmapsink,"Evas Image Object(%x) is set", evaspixmapsink->eo);
3285 GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: value is not an evas image object");
3289 evaspixmapsink->flip = g_value_get_enum(value);
3291 case PROP_ROTATE_ANGLE:
3292 evaspixmapsink->rotate_angle = g_value_get_enum (value);
3295 evaspixmapsink->visible = g_value_get_boolean (value);
3296 if (evaspixmapsink->eo) {
3297 if (!evaspixmapsink->visible) {
3298 if ( evaspixmapsink->xcontext && evaspixmapsink->xpixmap ) {
3299 g_mutex_lock( evaspixmapsink->flow_lock );
3300 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap);
3301 g_mutex_unlock( evaspixmapsink->flow_lock );
3303 evas_object_hide(evaspixmapsink->eo);
3304 GST_INFO_OBJECT (evaspixmapsink,"object hide..");
3306 evas_object_show(evaspixmapsink->eo);
3307 GST_INFO_OBJECT (evaspixmapsink,"object show..");
3310 GST_WARNING_OBJECT (evaspixmapsink,"evas image object was not set");
3313 case PROP_ORIGIN_SIZE:
3314 evaspixmapsink->use_origin_size = g_value_get_boolean (value);
3315 GST_INFO_OBJECT (evaspixmapsink,"set origin-size (%d)",evaspixmapsink->use_origin_size);
3316 if (evaspixmapsink->previous_origin_size != evaspixmapsink->use_origin_size) {
3317 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3318 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3320 evaspixmapsink->previous_origin_size = evaspixmapsink->use_origin_size;
3324 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3330 gst_evaspixmapsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
3332 GstEvasPixmapSink *evaspixmapsink;
3334 g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3336 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3340 g_value_set_int (value, evaspixmapsink->hue);
3343 g_value_set_int (value, evaspixmapsink->contrast);
3345 case PROP_BRIGHTNESS:
3346 g_value_set_int (value, evaspixmapsink->brightness);
3348 case PROP_SATURATION:
3349 g_value_set_int (value, evaspixmapsink->saturation);
3352 g_value_set_string (value, evaspixmapsink->display_name);
3354 case PROP_SYNCHRONOUS:
3355 g_value_set_boolean (value, evaspixmapsink->synchronous);
3357 case PROP_PIXEL_ASPECT_RATIO:
3358 if (evaspixmapsink->par) {
3359 if (!g_value_transform (evaspixmapsink->par, value)) {
3360 g_warning ("g_value_transform() failure");
3366 char *adaptor_no_s = g_strdup_printf ("%u", evaspixmapsink->adaptor_no);
3367 g_value_set_string (value, adaptor_no_s);
3368 g_free (adaptor_no_s);
3371 case PROP_DEVICE_NAME:
3372 if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->adaptors) {
3373 g_value_set_string (value,
3374 evaspixmapsink->xcontext->adaptors[evaspixmapsink->adaptor_no]);
3376 g_value_set_string (value, NULL);
3379 case PROP_DOUBLE_BUFFER:
3380 g_value_set_boolean (value, evaspixmapsink->double_buffer);
3382 case PROP_AUTOPAINT_COLORKEY:
3383 g_value_set_boolean (value, evaspixmapsink->autopaint_colorkey);
3386 g_value_set_int (value, evaspixmapsink->colorkey);
3388 case PROP_PIXMAP_WIDTH:
3389 if (evaspixmapsink->xpixmap) {
3390 g_value_set_uint64 (value, evaspixmapsink->xpixmap->width);
3392 g_value_set_uint64 (value, 0);
3395 case PROP_PIXMAP_HEIGHT:
3396 if (evaspixmapsink->xpixmap) {
3397 g_value_set_uint64 (value, evaspixmapsink->xpixmap->height);
3399 g_value_set_uint64 (value, 0);
3402 case PROP_DISPLAY_GEOMETRY_METHOD:
3403 g_value_set_enum (value, evaspixmapsink->display_geometry_method);
3405 case PROP_DST_ROI_X:
3406 g_value_set_int (value, evaspixmapsink->dst_roi.x);
3408 case PROP_DST_ROI_Y:
3409 g_value_set_int (value, evaspixmapsink->dst_roi.y);
3411 case PROP_DST_ROI_W:
3412 g_value_set_int (value, evaspixmapsink->dst_roi.w);
3414 case PROP_DST_ROI_H:
3415 g_value_set_int (value, evaspixmapsink->dst_roi.h);
3417 case PROP_STOP_VIDEO:
3418 g_value_set_int (value, evaspixmapsink->stop_video);
3420 case PROP_EVAS_OBJECT:
3421 g_value_set_pointer (value, evaspixmapsink->eo);
3424 g_value_set_enum(value, evaspixmapsink->flip);
3426 case PROP_ROTATE_ANGLE:
3427 g_value_set_enum (value, evaspixmapsink->rotate_angle);
3430 g_value_set_boolean (value, evaspixmapsink->visible);
3432 case PROP_ORIGIN_SIZE:
3433 g_value_set_boolean (value, evaspixmapsink->use_origin_size);
3436 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3442 gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink)
3444 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3447 GST_OBJECT_LOCK (evaspixmapsink);
3448 evaspixmapsink->running = FALSE;
3450 /* grab thread and mark it as NULL */
3451 thread = evaspixmapsink->event_thread;
3452 evaspixmapsink->event_thread = NULL;
3453 GST_OBJECT_UNLOCK (evaspixmapsink);
3455 /* Wait for our event thread to finish before we clean up our stuff. */
3457 g_thread_join (thread);
3460 if(evaspixmapsink->damage) {
3461 XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage);
3462 evaspixmapsink->damage = NULL;
3464 if(evaspixmapsink->handler) {
3465 ecore_event_handler_del (evaspixmapsink->handler);
3466 evaspixmapsink->handler = NULL;
3469 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3470 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3472 if (evaspixmapsink->evas_pixmap_buf) {
3473 gst_buffer_unref (GST_BUFFER_CAST (evaspixmapsink->evas_pixmap_buf));
3474 evaspixmapsink->evas_pixmap_buf = NULL;
3476 if (evaspixmapsink->xpixmap) {
3477 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap);
3478 gst_evaspixmapsink_xpixmap_destroy (evaspixmapsink, evaspixmapsink->xpixmap);
3479 evaspixmapsink->xpixmap = NULL;
3480 if (evaspixmapsink->eo) {
3481 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3482 evaspixmapsink->eo = NULL;
3485 evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y =
3486 evaspixmapsink->render_rect.w = evaspixmapsink->render_rect.h = 0;
3487 evaspixmapsink->have_render_rect = FALSE;
3489 gst_evaspixmapsink_xcontext_clear (evaspixmapsink);
3491 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3494 /* Finalize is called only once, dispose can be called multiple times.
3495 * We use mutexes and don't reset stuff to NULL here so let's register
3498 gst_evaspixmapsink_finalize (GObject *object)
3500 GstEvasPixmapSink *evaspixmapsink;
3501 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3502 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3504 if (evaspixmapsink->display_name) {
3505 g_free (evaspixmapsink->display_name);
3506 evaspixmapsink->display_name = NULL;
3508 if (evaspixmapsink->par) {
3509 g_free (evaspixmapsink->par);
3510 evaspixmapsink->par = NULL;
3512 if (evaspixmapsink->x_lock) {
3513 g_mutex_free (evaspixmapsink->x_lock);
3514 evaspixmapsink->x_lock = NULL;
3516 if (evaspixmapsink->flow_lock) {
3517 g_mutex_free (evaspixmapsink->flow_lock);
3518 evaspixmapsink->flow_lock = NULL;
3520 if (evaspixmapsink->epipe) {
3521 ecore_pipe_del (evaspixmapsink->epipe);
3522 evaspixmapsink->epipe = NULL;
3525 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3527 G_OBJECT_CLASS (parent_class)->finalize (object);
3529 MMTA_ACUM_ITEM_SHOW_RESULT_TO(MMTA_SHOW_FILE);
3534 gst_evaspixmapsink_init (GstEvasPixmapSink *evaspixmapsink)
3536 evaspixmapsink->display_name = NULL;
3537 evaspixmapsink->adaptor_no = 0;
3538 evaspixmapsink->xcontext = NULL;
3539 evaspixmapsink->xpixmap = NULL;
3540 evaspixmapsink->evas_pixmap_buf = NULL;
3542 evaspixmapsink->hue = evaspixmapsink->saturation = 0;
3543 evaspixmapsink->contrast = evaspixmapsink->brightness = 0;
3544 evaspixmapsink->cb_changed = FALSE;
3546 evaspixmapsink->fps_n = 0;
3547 evaspixmapsink->fps_d = 0;
3548 evaspixmapsink->video_width = 0;
3549 evaspixmapsink->video_height = 0;
3551 evaspixmapsink->x_lock = g_mutex_new ();
3552 evaspixmapsink->flow_lock = g_mutex_new ();
3554 evaspixmapsink->synchronous = FALSE;
3555 evaspixmapsink->double_buffer = TRUE;
3556 evaspixmapsink->par = NULL;
3557 evaspixmapsink->autopaint_colorkey = TRUE;
3558 evaspixmapsink->running = FALSE;
3560 /* on 16bit displays this becomes r,g,b = 1,2,3
3561 * on 24bit displays this becomes r,g,b = 8,8,16
3562 * as a port atom value
3564 evaspixmapsink->colorkey = (8 << 16) | (8 << 8) | 16;
3566 evaspixmapsink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
3567 evaspixmapsink->dst_roi.x = 0;
3568 evaspixmapsink->dst_roi.y = 0;
3569 evaspixmapsink->dst_roi.w = 0;
3570 evaspixmapsink->dst_roi.h = 0;
3571 evaspixmapsink->scr_w = 0;
3572 evaspixmapsink->scr_h = 0;
3573 evaspixmapsink->aligned_width = 0;
3574 evaspixmapsink->aligned_height = 0;
3575 evaspixmapsink->stop_video = FALSE;
3576 evaspixmapsink->eo = NULL;
3577 evaspixmapsink->epipe = NULL;
3578 evaspixmapsink->do_link = FALSE;
3579 evaspixmapsink->flip = DEF_DISPLAY_FLIP;
3580 evaspixmapsink->rotate_angle = DEGREE_0;
3581 evaspixmapsink->visible = TRUE;
3582 evaspixmapsink->use_origin_size = FALSE;
3583 evaspixmapsink->previous_origin_size = FALSE;
3589 gst_evaspixmapsink_base_init (gpointer g_class)
3591 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3593 gst_element_class_set_details_simple (element_class,
3594 "EvasPixmapSink", "Sink/Video",
3595 "evas image object videosink based on Xv extension", "Sangchul Lee <sc11.lee@samsung.com>");
3597 gst_element_class_add_pad_template (element_class,
3598 gst_static_pad_template_get (&gst_evaspixmapsink_sink_template_factory));
3602 gst_evaspixmapsink_class_init (GstEvasPixmapSinkClass *klass)
3604 GObjectClass *gobject_class;
3605 GstElementClass *gstelement_class;
3606 GstBaseSinkClass *gstbasesink_class;
3607 GstVideoSinkClass *videosink_class;
3609 gobject_class = (GObjectClass *) klass;
3610 gstelement_class = (GstElementClass *) klass;
3611 gstbasesink_class = (GstBaseSinkClass *) klass;
3612 videosink_class = (GstVideoSinkClass *) klass;
3614 parent_class = g_type_class_peek_parent (klass);
3616 gobject_class->set_property = gst_evaspixmapsink_set_property;
3617 gobject_class->get_property = gst_evaspixmapsink_get_property;
3619 g_object_class_install_property (gobject_class, PROP_CONTRAST,
3620 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
3621 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3622 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
3623 g_param_spec_int ("brightness", "Brightness",
3624 "The brightness of the video", -1000, 1000, 0,
3625 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3626 g_object_class_install_property (gobject_class, PROP_HUE,
3627 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
3628 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3629 g_object_class_install_property (gobject_class, PROP_SATURATION,
3630 g_param_spec_int ("saturation", "Saturation",
3631 "The saturation of the video", -1000, 1000, 0,
3632 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3633 g_object_class_install_property (gobject_class, PROP_DISPLAY,
3634 g_param_spec_string ("display", "Display", "X Display name", NULL,
3635 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3636 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
3637 g_param_spec_boolean ("synchronous", "Synchronous",
3638 "When enabled, runs "
3639 "the X display in synchronous mode. (used only for debugging)", FALSE,
3640 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3641 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
3642 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
3643 "The pixel aspect ratio of the device", "1/1",
3644 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3645 g_object_class_install_property (gobject_class, PROP_DEVICE,
3646 g_param_spec_string ("device", "Adaptor number",
3647 "The number of the video adaptor", "0",
3648 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3649 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
3650 g_param_spec_string ("device-name", "Adaptor name",
3651 "The name of the video adaptor", NULL,
3652 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3655 * GstEvasPixmapSink:double-buffer
3657 * Whether to double-buffer the output.
3661 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
3662 g_param_spec_boolean ("double-buffer", "Double-buffer",
3663 "Whether to double-buffer the output", TRUE,
3664 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3666 * GstEvasPixmapSink:autopaint-colorkey
3668 * Whether to autofill overlay with colorkey
3672 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
3673 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
3674 "Whether to autofill overlay with colorkey", TRUE,
3675 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3677 * GstEvasPixmapSink:colorkey
3679 * Color to use for the overlay mask.
3683 g_object_class_install_property (gobject_class, PROP_COLORKEY,
3684 g_param_spec_int ("colorkey", "Colorkey",
3685 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
3686 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3689 * GstEvasPixmapSink:pixmap-width
3691 * Actual width of the pixmap.
3693 g_object_class_install_property (gobject_class, PROP_PIXMAP_WIDTH,
3694 g_param_spec_uint64 ("pixmap-width", "pixmap-width", "Width of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3697 * GstEvasPixmapSink:pixmap-height
3699 * Actual height of the pixmap.
3701 g_object_class_install_property (gobject_class, PROP_PIXMAP_HEIGHT,
3702 g_param_spec_uint64 ("pixmap-height", "pixmap-height", "Height of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3705 * GstEvasPixmapSink:display-geometry-method
3707 * Display geometrical method setting
3709 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
3710 g_param_spec_enum("display-geometry-method", "Display geometry method",
3711 "Geometrical method for display",
3712 GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
3713 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3716 * GstEvasPixmapSink:dst-roi-x
3718 * X value of Destination ROI
3720 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
3721 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
3722 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3723 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3726 * GstEvasPixmapSink:dst-roi-y
3728 * Y value of Destination ROI
3730 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
3731 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
3732 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3733 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3736 * GstEvasPixmapSink:dst-roi-w
3738 * W value of Destination ROI
3740 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
3741 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
3742 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3743 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3746 * GstEvasPixmapSink:dst-roi-h
3748 * H value of Destination ROI
3750 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
3751 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
3752 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3753 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3756 * GstEvasPixmapSink:stop-video
3758 * Stop video for releasing video source buffer
3760 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
3761 g_param_spec_int ("stop-video", "Stop-Video", "Stop video for releasing video source buffer", 0, 1, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3764 * GstEvasPixmapSink:evas-object
3766 * Evas image object for rendering
3768 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
3769 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3772 * GstEvasPixmapSink:display-flip
3774 * Display flip setting
3776 g_object_class_install_property(gobject_class, PROP_FLIP,
3777 g_param_spec_enum("flip", "Display flip",
3779 GST_TYPE_EVASPIXMAPSINK_FLIP, DEF_DISPLAY_FLIP,
3780 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3783 * GstEvasPixmapSink:rotate
3785 * draw rotation angle setting
3787 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
3788 g_param_spec_enum("rotate", "Rotate angle", "Rotate angle of display output",GST_TYPE_EVASPIXMAPSINK_ROTATE_ANGLE, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3791 * GstEvasPixmapSink:visible
3793 * visible setting for a evas image object
3795 g_object_class_install_property (gobject_class, PROP_VISIBLE,
3796 g_param_spec_boolean ("visible", "Visible", "When setting it false, evas image object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3799 * GstEvasPixmapSink:origin-size
3801 * Set pixmap size with media source's width and height
3803 g_object_class_install_property (gobject_class, PROP_ORIGIN_SIZE,
3804 g_param_spec_boolean ("origin-size", "Origin-Size", "When setting it true, pixmap will be created with media source's width and height", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3806 gobject_class->finalize = gst_evaspixmapsink_finalize;
3808 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_change_state);
3809 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_getcaps);
3810 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_setcaps);
3811 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_get_times);
3812 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_event);
3813 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_show_frame);
3816 /* Object typing & Creation */
3818 gst_evaspixmapsink_get_type (void)
3820 static GType evaspixmapsink_type = 0;
3822 if (!evaspixmapsink_type) {
3823 static const GTypeInfo evaspixmapsink_info = {
3824 sizeof (GstEvasPixmapSinkClass),
3825 gst_evaspixmapsink_base_init,
3827 (GClassInitFunc) gst_evaspixmapsink_class_init,
3830 sizeof (GstEvasPixmapSink),
3832 (GInstanceInitFunc) gst_evaspixmapsink_init,
3834 static const GInterfaceInfo iface_info = {
3835 (GInterfaceInitFunc) gst_evaspixmapsink_interface_init,
3839 static const GInterfaceInfo navigation_info = {
3840 (GInterfaceInitFunc) gst_evaspixmapsink_navigation_init,
3844 static const GInterfaceInfo colorbalance_info = {
3845 (GInterfaceInitFunc) gst_evaspixmapsink_colorbalance_init,
3849 static const GInterfaceInfo propertyprobe_info = {
3850 (GInterfaceInitFunc) gst_evaspixmapsink_property_probe_interface_init,
3854 evaspixmapsink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, "GstEvasPixmapSink", &evaspixmapsink_info, 0);
3856 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
3857 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_NAVIGATION, &navigation_info);
3858 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_COLOR_BALANCE, &colorbalance_info);
3859 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
3861 /* register type and create class in a more safe place instead of at
3862 * runtime since the type registration and class creation is not
3864 g_type_class_ref (gst_evaspixmap_buffer_get_type ());
3867 return evaspixmapsink_type;
3871 plugin_init (GstPlugin *plugin)
3873 if (!gst_element_register (plugin, "evaspixmapsink", GST_RANK_NONE, GST_TYPE_EVASPIXMAPSINK)) {
3876 GST_DEBUG_CATEGORY_INIT (gst_debug_evaspixmapsink, "evaspixmapsink", 0, "evaspixmapsink element");
3877 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
3882 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3883 "evaspixmapsink","Evas image object render plugin using Xv extension", plugin_init,
3884 VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)