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"
40 /* Samsung extension headers */
41 /* For xv extension header for buffer transfer (output) */
46 #include <sys/ioctl.h>
50 #include <dri2/dri2.h>
51 #include <libdrm/drm.h>
54 BUF_SHARE_METHOD_PADDR = 0,
58 /* max channel count *********************************************************/
59 #define SCMN_IMGB_MAX_PLANE (4)
61 /* image buffer definition ***************************************************
63 +------------------------------------------+ ---
66 | +---------------------------+ --- | |
68 | |<---------- w[] ---------->| | | |
76 | +---------------------------+ --- | |
78 +------------------------------------------+ ---
80 |<----------------- s[] ------------------>|
85 /* width of each image plane */
86 int w[SCMN_IMGB_MAX_PLANE];
87 /* height of each image plane */
88 int h[SCMN_IMGB_MAX_PLANE];
89 /* stride of each image plane */
90 int s[SCMN_IMGB_MAX_PLANE];
91 /* elevation of each image plane */
92 int e[SCMN_IMGB_MAX_PLANE];
93 /* user space address of each image plane */
94 void * a[SCMN_IMGB_MAX_PLANE];
95 /* physical address of each image plane, if needs */
96 void * p[SCMN_IMGB_MAX_PLANE];
97 /* color space type of image */
99 /* left postion, if needs */
101 /* top position, if needs */
103 /* to align memory */
108 int dma_buf_fd[SCMN_IMGB_MAX_PLANE];
109 /* buffer share method */
110 int buf_share_method;
113 /* Debugging category */
114 #include <gst/gstinfo.h>
115 GST_DEBUG_CATEGORY_STATIC (gst_debug_evaspixmapsink);
116 #define GST_CAT_DEFAULT gst_debug_evaspixmapsink
117 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
128 DISP_GEO_METHOD_LETTER_BOX = 0,
129 DISP_GEO_METHOD_ORIGIN_SIZE,
130 DISP_GEO_METHOD_FULL_SCREEN,
131 DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
132 DISP_GEO_METHOD_CUSTOM_ROI,
144 #define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
145 #define DEF_DISPLAY_FLIP FLIP_NONE
146 #define GST_TYPE_EVASPIXMAPSINK_FLIP (gst_evaspixmapsink_flip_get_type())
147 #define GST_TYPE_EVASPIXMAPSINK_ROTATE_ANGLE (gst_evaspixmapsink_rotate_angle_get_type())
148 #define GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD (gst_evaspixmapsink_display_geometry_method_get_type())
151 gst_evaspixmapsink_flip_get_type(void)
153 static GType evaspixmapsink_flip_type = 0;
154 static const GEnumValue flip_type[] = {
155 { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
156 { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
157 { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
158 { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
159 { FLIP_NUM, NULL, NULL},
162 if (!evaspixmapsink_flip_type) {
163 evaspixmapsink_flip_type = g_enum_register_static("GstEvasPixmapSinkFlipType", flip_type);
166 return evaspixmapsink_flip_type;
170 gst_evaspixmapsink_rotate_angle_get_type(void)
172 static GType evaspixmapsink_rotate_angle_type = 0;
173 static const GEnumValue rotate_angle_type[] = {
174 { 0, "No rotate", "DEGREE_0"},
175 { 1, "Rotate 90 degree", "DEGREE_90"},
176 { 2, "Rotate 180 degree", "DEGREE_180"},
177 { 3, "Rotate 270 degree", "DEGREE_270"},
181 if (!evaspixmapsink_rotate_angle_type) {
182 evaspixmapsink_rotate_angle_type = g_enum_register_static("GstEvasPixmapSinkRotateAngleType", rotate_angle_type);
185 return evaspixmapsink_rotate_angle_type;
189 gst_evaspixmapsink_display_geometry_method_get_type(void)
191 static GType evaspixmapsink_display_geometry_method_type = 0;
192 static const GEnumValue display_geometry_method_type[] = {
193 { 0, "Letter box", "LETTER_BOX"},
194 { 1, "Origin size", "ORIGIN_SIZE"},
195 { 2, "Full-screen", "FULL_SCREEN"},
196 { 3, "Cropped Full-screen", "CROPPED_FULL_SCREEN"},
197 { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
201 if (!evaspixmapsink_display_geometry_method_type) {
202 evaspixmapsink_display_geometry_method_type = g_enum_register_static("GstEvasPixmapSinkDisplayGeometryMethodType", display_geometry_method_type);
205 return evaspixmapsink_display_geometry_method_type;
211 unsigned long functions;
212 unsigned long decorations;
214 unsigned long status;
216 MotifWmHints, MwmHints;
218 #define MWM_HINTS_DECORATIONS (1L << 1)
220 static void gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink);
221 static GstBufferClass *evaspixmap_buffer_parent_class = NULL;
222 static void gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf);
223 static void gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink);
224 static void gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
225 static void gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink, int idx);
226 static gboolean gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf);
227 static gboolean gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink);
228 static void gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap);
229 static gint gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps);
230 static void drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle);
232 /* Default template - initiated with class struct to allow gst-register to work
234 static GstStaticPadTemplate gst_evaspixmapsink_sink_template_factory =
235 GST_STATIC_PAD_TEMPLATE ("sink",
238 GST_STATIC_CAPS ("video/x-raw-rgb, "
239 "framerate = (fraction) [ 0, MAX ], "
240 "width = (int) [ 1, MAX ], "
241 "height = (int) [ 1, MAX ]; "
243 "framerate = (fraction) [ 0, MAX ], "
244 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
256 PROP_PIXEL_ASPECT_RATIO,
260 PROP_AUTOPAINT_COLORKEY,
266 PROP_DISPLAY_GEOMETRY_METHOD,
278 static GstVideoSinkClass *parent_class = NULL;
280 /* ============================================================= */
282 /* Private Methods */
284 /* ============================================================= */
286 /* evaspixmap buffers */
288 #define GST_TYPE_EVASPIXMAP_BUFFER (gst_evaspixmap_buffer_get_type())
290 #define GST_IS_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVASPIXMAP_BUFFER))
291 #define GST_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVASPIXMAP_BUFFER, GstEvasPixmapBuffer))
293 static int get_millis_time()
296 clock_gettime(CLOCK_MONOTONIC, &tp);
297 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
301 ecore_pipe_callback_handler (void *data, void *buffer, unsigned int nbyte)
303 GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink*)data;
304 GST_DEBUG_OBJECT (evaspixmapsink,"[START] Evas_Object(0x%x)", evaspixmapsink->eo);
305 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink - ecore thread cb : TOTAL", FALSE);
308 GstXPixmap *xpixmap = NULL;
311 GST_WARNING_OBJECT (evaspixmapsink,"data is NULL..");
314 if (!evaspixmapsink->eo) {
315 GST_WARNING_OBJECT (evaspixmapsink,"evas object is NULL..");
319 g_mutex_lock (evaspixmapsink->pixmap_ref_lock);
321 /* mapping evas object with xpixmap */
322 if (evaspixmapsink->do_link) {
323 GST_DEBUG_OBJECT (evaspixmapsink,"do link");
324 evas_object_image_size_set(evaspixmapsink->eo, evaspixmapsink->w, evaspixmapsink->h);
325 if (evaspixmapsink->xpixmap[idx]->pixmap) {
326 Evas_Native_Surface surf;
327 surf.version = EVAS_NATIVE_SURFACE_VERSION;
328 surf.type = EVAS_NATIVE_SURFACE_X11;
329 surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get());
330 surf.data.x11.pixmap = evaspixmapsink->xpixmap[idx]->pixmap;
331 __ta__("evaspixmapsink - ecore thread cb : _native_surface_set(LINK)", evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); );
332 evaspixmapsink->do_link = FALSE;
333 evaspixmapsink->last_updated_idx = -1;
335 GST_WARNING_OBJECT (evaspixmapsink,"pixmap is NULL..");
336 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
340 GST_DEBUG_OBJECT (evaspixmapsink,"update");
341 /* update evas image object size */
342 if (evaspixmapsink->use_origin_size) {
343 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evaspixmapsink->w, &evaspixmapsink->h);
346 /* find a oldest damaged pixmap */
348 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
349 if (evaspixmapsink->last_updated_idx == i) {
352 xpixmap = evaspixmapsink->xpixmap[i];
353 if (xpixmap->ref > 0 && xpixmap->damaged_time) {
354 if (temp_time == 0) {
355 temp_time = xpixmap->damaged_time;
358 if (temp_time > xpixmap->damaged_time) {
359 temp_time = xpixmap->damaged_time;
367 xpixmap = evaspixmapsink->xpixmap[idx];
368 if (xpixmap->pixmap) {
369 if (evaspixmapsink->last_updated_idx != idx) {
370 Evas_Native_Surface surf;
371 surf.version = EVAS_NATIVE_SURFACE_VERSION;
372 surf.type = EVAS_NATIVE_SURFACE_X11;
373 surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get());
374 surf.data.x11.pixmap = xpixmap->pixmap;
375 if (evaspixmapsink->eo) {
376 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
378 __ta__("evaspixmapsink - ecore thread cb : _native_surface_set", evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); );
379 GST_LOG_OBJECT (evaspixmapsink,"update, native_surface_set of xpixmap[%d]",idx);
380 if (evaspixmapsink->last_updated_idx == -1) {
381 xpixmap->damaged_time = 0;
382 GST_INFO_OBJECT (evaspixmapsink,"this is the first time to request to update : pixmap(%d), refcount(%d), damaged_time(%d), idx(%d)",
383 xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time, idx);
385 xpixmap = evaspixmapsink->xpixmap[evaspixmapsink->last_updated_idx];
387 xpixmap->damaged_time = 0;
388 GST_INFO_OBJECT (evaspixmapsink,"pixmap ref-count DECREASED : pixmap(%d), refcount(%d), damaged_time(%d), idx(%d)",
389 xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time, evaspixmapsink->last_updated_idx);
391 evaspixmapsink->last_updated_idx = idx;
394 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evas_object_image update", FALSE);
395 evas_object_image_pixels_dirty_set (evaspixmapsink->eo, 1);
396 evas_object_image_fill_set(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
397 evas_object_image_data_update_add(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h);
398 MMTA_ACUM_ITEM_END("evaspixmapsink evas_object_image update", FALSE);
400 //GST_LOG_OBJECT (evaspixmapsink,"request to update : pixmap idx(%d), ref(%d)", idx, xpixmap->ref);
402 GST_ERROR_OBJECT (evaspixmapsink,"pixmap is NULL..");
403 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
407 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
409 MMTA_ACUM_ITEM_END("evaspixmapsink - ecore thread cb : TOTAL", FALSE);
411 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
415 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
419 float former_ratio = 0;
421 float abs_margin = 0;
424 GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink *)data;
425 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
427 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &w, &h);
428 GST_DEBUG_OBJECT (evaspixmapsink,"resized : w(%d), h(%d)", w, h);
429 if (!evaspixmapsink->use_origin_size &&
430 (evaspixmapsink->w != w || evaspixmapsink->h != h)) {
431 former_ratio = (float)evaspixmapsink->w / evaspixmapsink->h;
432 ratio = (float)w / h;
433 evaspixmapsink->w = w;
434 evaspixmapsink->h = h;
437 GST_DEBUG_OBJECT (evaspixmapsink,"resized : ratio(%.3f=>%.3f)", former_ratio, ratio);
438 if ( former_ratio >= ratio ) {
439 abs_margin = former_ratio - ratio;
441 abs_margin = ratio - former_ratio;
443 /* re-link_pixmap can only be set when ratio is changed */
444 if ( abs_margin >= MARGIN_OF_ERROR ) {
446 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
447 GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
455 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
456 if (evaspixmapsink->xpixmap[i]->ref == 0) {
460 if (GST_STATE(evaspixmapsink) == GST_STATE_PAUSED && i < evaspixmapsink->num_of_pixmaps) {
461 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
464 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
467 static inline gboolean
468 is_evas_image_object (Evas_Object *obj)
474 type = evas_object_type_get (obj);
478 if (strcmp (type, "image") == 0) {
485 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
487 GstEvasPixmapSink *evaspixmapsink = data;
488 if (!evaspixmapsink) {
489 GST_WARNING ("evaspixmapsink is NULL..");
492 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
494 evas_object_event_callback_del(evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
495 if (evaspixmapsink->eo) {
496 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
497 evaspixmapsink->eo = NULL;
500 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
504 static gboolean error_caught = FALSE;
507 gst_evaspixmapsink_handle_xerror (Display * display, XErrorEvent * xevent)
509 char error_msg[1024];
511 XGetErrorText (display, xevent->error_code, error_msg, 1024);
512 GST_DEBUG ("evaspixmapsink triggered an XError. error: %s", error_msg);
518 /* This function checks that it is actually really possible to create an image
521 gst_evaspixmapsink_check_xshm_calls (GstXContext * xcontext)
524 XShmSegmentInfo SHMInfo;
526 int (*handler) (Display *, XErrorEvent *);
527 gboolean result = FALSE;
528 gboolean did_attach = FALSE;
530 g_return_val_if_fail (xcontext != NULL, FALSE);
532 /* Sync to ensure any older errors are already processed */
533 XSync (xcontext->disp, FALSE);
535 /* Set defaults so we don't free these later unnecessarily */
536 SHMInfo.shmaddr = ((void *) -1);
539 /* Setting an error handler to catch failure */
540 error_caught = FALSE;
541 handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
543 /* Trying to create a 1x1 picture */
544 GST_DEBUG ("XvShmCreateImage of 1x1");
545 xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
546 xcontext->im_format, NULL, 1, 1, &SHMInfo);
548 /* Might cause an error, sync to ensure it is noticed */
549 XSync (xcontext->disp, FALSE);
550 if (!xvimage || error_caught) {
551 GST_WARNING ("could not XvShmCreateImage a 1x1 image");
554 size = xvimage->data_size;
556 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
557 if (SHMInfo.shmid == -1) {
558 GST_WARNING ("could not get shared memory of %d bytes", size);
562 SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
563 if (SHMInfo.shmaddr == ((void *) -1)) {
564 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
565 /* Clean up the shared memory segment */
566 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
570 xvimage->data = SHMInfo.shmaddr;
571 SHMInfo.readOnly = FALSE;
573 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
574 GST_WARNING ("Failed to XShmAttach");
575 /* Clean up the shared memory segment */
576 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
580 /* Sync to ensure we see any errors we caused */
581 XSync (xcontext->disp, FALSE);
583 /* Delete the shared memory segment as soon as everyone is attached.
584 * This way, it will be deleted as soon as we detach later, and not
585 * leaked if we crash. */
586 shmctl (SHMInfo.shmid, IPC_RMID, NULL);
589 GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
593 /* store whether we succeeded in result */
596 GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
597 "Not using shared memory.");
601 /* Sync to ensure we swallow any errors we caused and reset error_caught */
602 XSync (xcontext->disp, FALSE);
604 error_caught = FALSE;
605 XSetErrorHandler (handler);
608 GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
609 SHMInfo.shmid, SHMInfo.shmseg);
610 XShmDetach (xcontext->disp, &SHMInfo);
611 XSync (xcontext->disp, FALSE);
613 if (SHMInfo.shmaddr != ((void *) -1))
614 shmdt (SHMInfo.shmaddr);
619 #endif /* HAVE_XSHM */
621 /* This function destroys a GstEvasPixmap handling XShm availability */
623 gst_evaspixmap_buffer_destroy (GstEvasPixmapBuffer *evaspixmapbuf)
625 GstEvasPixmapSink *evaspixmapsink;
627 evaspixmapsink = evaspixmapbuf->evaspixmapsink;
628 if (G_UNLIKELY (evaspixmapsink == NULL)) {
631 GST_DEBUG_OBJECT (evaspixmapsink, "Destroying buffer");
633 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
635 GST_OBJECT_LOCK (evaspixmapsink);
637 /* We might have some buffers destroyed after changing state to NULL */
638 if (evaspixmapsink->xcontext == NULL) {
639 GST_DEBUG_OBJECT (evaspixmapsink,"Destroying XvImage after Xcontext");
641 /* Need to free the shared memory segment even if the x context
642 * was already cleaned up */
643 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
644 shmdt (evaspixmapbuf->SHMInfo.shmaddr);
649 g_mutex_lock (evaspixmapsink->x_lock);
652 if (evaspixmapsink->xcontext->use_xshm) {
653 if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) {
654 GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmDetaching from 0x%x id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
655 XShmDetach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo);
656 XSync (evaspixmapsink->xcontext->disp, FALSE);
657 shmdt (evaspixmapbuf->SHMInfo.shmaddr);
659 if (evaspixmapbuf->xvimage)
660 XFree (evaspixmapbuf->xvimage);
662 #endif /* HAVE_XSHM */
664 if (evaspixmapbuf->xvimage) {
665 if (evaspixmapbuf->xvimage->data) {
666 g_free (evaspixmapbuf->xvimage->data);
668 XFree (evaspixmapbuf->xvimage);
672 XSync (evaspixmapsink->xcontext->disp, FALSE);
674 g_mutex_unlock (evaspixmapsink->x_lock);
677 GST_OBJECT_UNLOCK (evaspixmapsink);
678 evaspixmapbuf->evaspixmapsink = NULL;
679 gst_object_unref (evaspixmapsink);
681 GST_MINI_OBJECT_CLASS (evaspixmap_buffer_parent_class)->finalize (GST_MINI_OBJECT(evaspixmapbuf));
687 GST_WARNING ("no sink found");
693 gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf)
695 GstEvasPixmapSink *evaspixmapsink;
697 evaspixmapsink = evaspixmapbuf->evaspixmapsink;
698 if (G_UNLIKELY (evaspixmapsink == NULL)) {
699 GST_WARNING_OBJECT (evaspixmapsink,"no sink found");
702 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
704 /* If our geometry changed we can't reuse that image. */
705 GST_LOG_OBJECT (evaspixmapsink,"destroy image as sink is shutting down");
706 gst_evaspixmap_buffer_destroy (evaspixmapbuf);
710 gst_evaspixmap_buffer_free (GstEvasPixmapBuffer *evaspixmapbuf)
712 /* make sure it is not recycled */
713 evaspixmapbuf->width = -1;
714 evaspixmapbuf->height = -1;
715 gst_buffer_unref (GST_BUFFER (evaspixmapbuf));
719 gst_evaspixmap_buffer_init (GstEvasPixmapBuffer *evaspixmapbuf, gpointer g_class)
722 evaspixmapbuf->SHMInfo.shmaddr = ((void *) -1);
723 evaspixmapbuf->SHMInfo.shmid = -1;
728 gst_evaspixmap_buffer_class_init (gpointer g_class, gpointer class_data)
730 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
732 evaspixmap_buffer_parent_class = g_type_class_peek_parent (g_class);
734 mini_object_class->finalize = (GstMiniObjectFinalizeFunction) gst_evaspixmap_buffer_finalize;
738 gst_evaspixmap_buffer_get_type (void)
740 static GType _gst_evaspixmap_buffer_type;
742 if (G_UNLIKELY (_gst_evaspixmap_buffer_type == 0)) {
743 static const GTypeInfo evaspixmap_buffer_info = {
744 sizeof (GstBufferClass),
747 gst_evaspixmap_buffer_class_init,
750 sizeof (GstEvasPixmapBuffer),
752 (GInstanceInitFunc) gst_evaspixmap_buffer_init,
755 _gst_evaspixmap_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
756 "GstEvasPixmapBuffer", &evaspixmap_buffer_info, 0);
758 return _gst_evaspixmap_buffer_type;
761 /* This function handles GstEvasPixmapBuffer creation depending on XShm availability */
762 static GstEvasPixmapBuffer*
763 gst_evaspixmap_buffer_new (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
765 GstEvasPixmapBuffer *evaspixmapbuf = NULL;
766 GstStructure *structure = NULL;
767 gboolean succeeded = FALSE;
768 int (*handler) (Display *, XErrorEvent *);
770 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
776 evaspixmapbuf = (GstEvasPixmapBuffer*) gst_mini_object_new (GST_TYPE_EVASPIXMAP_BUFFER);
777 GST_DEBUG_OBJECT (evaspixmapsink,"Creating new EvasPixmapBuffer");
779 structure = gst_caps_get_structure (caps, 0);
781 if (!gst_structure_get_int (structure, "width", &evaspixmapbuf->width) || !gst_structure_get_int (structure, "height", &evaspixmapbuf->height)) {
782 GST_WARNING_OBJECT (evaspixmapsink,"failed getting geometry from caps %" GST_PTR_FORMAT, caps);
785 GST_LOG_OBJECT (evaspixmapsink,"creating %dx%d", evaspixmapbuf->width, evaspixmapbuf->height);
787 GST_LOG_OBJECT (evaspixmapsink,"aligned size %dx%d", evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
788 if (evaspixmapsink->aligned_width == 0 || evaspixmapsink->aligned_height == 0) {
789 GST_INFO_OBJECT (evaspixmapsink,"aligned size is zero. set size of caps.");
790 evaspixmapsink->aligned_width = evaspixmapbuf->width;
791 evaspixmapsink->aligned_height = evaspixmapbuf->height;
794 evaspixmapbuf->im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
795 if (evaspixmapbuf->im_format == -1) {
796 GST_WARNING_OBJECT (evaspixmapsink,"failed to get format from caps %"GST_PTR_FORMAT, caps);
797 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",
798 evaspixmapbuf->width, evaspixmapbuf->height), ("Invalid input caps"));
801 evaspixmapbuf->evaspixmapsink = gst_object_ref (evaspixmapsink);
803 g_mutex_lock (evaspixmapsink->x_lock);
805 /* Setting an error handler to catch failure */
806 error_caught = FALSE;
807 handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror);
810 if (evaspixmapsink->xcontext->use_xshm) {
812 evaspixmapbuf->xvimage = XvShmCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, evaspixmapbuf->im_format, NULL,
813 evaspixmapsink->aligned_width, evaspixmapsink->aligned_height, &evaspixmapbuf->SHMInfo);
814 if(!evaspixmapbuf->xvimage) {
815 GST_ERROR_OBJECT (evaspixmapsink,"XvShmCreateImage() failed");
818 if (!evaspixmapbuf->xvimage || error_caught) {
820 GST_ERROR_OBJECT (evaspixmapsink,"error_caught!");
822 g_mutex_unlock (evaspixmapsink->x_lock);
823 /* Reset error handler */
824 error_caught = FALSE;
825 XSetErrorHandler (handler);
827 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",evaspixmapbuf->width,
828 evaspixmapbuf->height),("could not XvShmCreateImage a %dx%d image",evaspixmapbuf->width, evaspixmapbuf->height));
832 /* we have to use the returned data_size for our shm size */
833 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
834 GST_LOG_OBJECT (evaspixmapsink,"XShm image size is %" G_GSIZE_FORMAT, evaspixmapbuf->size);
836 /* calculate the expected size. This is only for sanity checking the
837 * number we get from X. */
838 switch (evaspixmapbuf->im_format) {
839 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
840 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
847 pitches[0] = GST_ROUND_UP_4 (evaspixmapbuf->width);
848 offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (evaspixmapbuf->height);
849 pitches[1] = GST_ROUND_UP_8 (evaspixmapbuf->width) / 2;
851 offsets[1] + pitches[1] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
852 pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
854 expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2;
856 for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
857 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a expected pitch of %d bytes, " "offset of %d",
858 plane, pitches[plane], offsets[plane]);
862 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
863 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
864 expected_size = evaspixmapbuf->height * GST_ROUND_UP_4 (evaspixmapbuf->width * 2);
866 case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
867 case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
868 case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
869 case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
870 case GST_MAKE_FOURCC ('S', '4', '2', '0'):
871 case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
872 expected_size = sizeof(SCMN_IMGB);
878 if (expected_size != 0 && evaspixmapbuf->size != expected_size) {
879 GST_WARNING_OBJECT (evaspixmapsink,"unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", evaspixmapbuf->size, expected_size);
882 /* Be verbose about our XvImage stride */
885 for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) {
886 GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a pitch of %d bytes, ""offset of %d", plane,
887 evaspixmapbuf->xvimage->pitches[plane], evaspixmapbuf->xvimage->offsets[plane]);
891 evaspixmapbuf->SHMInfo.shmid = shmget (IPC_PRIVATE, evaspixmapbuf->size,IPC_CREAT | 0777);
892 if (evaspixmapbuf->SHMInfo.shmid == -1) {
893 g_mutex_unlock (evaspixmapsink->x_lock);
894 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
895 ("Failed to create output image buffer of %dx%d pixels", evaspixmapbuf->width, evaspixmapbuf->height),
896 ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",evaspixmapbuf->size));
900 evaspixmapbuf->SHMInfo.shmaddr = shmat (evaspixmapbuf->SHMInfo.shmid, NULL, 0);
901 if (evaspixmapbuf->SHMInfo.shmaddr == ((void *) -1)) {
902 g_mutex_unlock (evaspixmapsink->x_lock);
903 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
904 ("Failed to create output image buffer of %dx%d pixels",
905 evaspixmapbuf->width, evaspixmapbuf->height),
906 ("Failed to shmat: %s", g_strerror (errno)));
907 /* Clean up the shared memory segment */
908 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
912 evaspixmapbuf->xvimage->data = evaspixmapbuf->SHMInfo.shmaddr;
913 evaspixmapbuf->SHMInfo.readOnly = FALSE;
915 if (XShmAttach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo) == 0) {
916 /* Clean up the shared memory segment */
917 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
919 g_mutex_unlock (evaspixmapsink->x_lock);
920 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
921 ("Failed to create output image buffer of %dx%d pixels",
922 evaspixmapbuf->width, evaspixmapbuf->height), ("Failed to XShmAttach"));
926 XSync (evaspixmapsink->xcontext->disp, FALSE);
928 /* Delete the shared memory segment as soon as we everyone is attached.
929 * This way, it will be deleted as soon as we detach later, and not
930 * leaked if we crash. */
931 shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL);
933 GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmAttached to 0x%x, id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg);
935 #endif /* HAVE_XSHM */
937 evaspixmapbuf->xvimage = XvCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id,
938 evaspixmapbuf->im_format, NULL, evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
939 if (!evaspixmapbuf->xvimage || error_caught) {
940 g_mutex_unlock (evaspixmapsink->x_lock);
941 /* Reset error handler */
942 error_caught = FALSE;
943 XSetErrorHandler (handler);
945 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,
946 ("Failed to create outputimage buffer of %dx%d pixels",
947 evaspixmapbuf->width, evaspixmapbuf->height),
948 ("could not XvCreateImage a %dx%d image",
949 evaspixmapbuf->width, evaspixmapbuf->height));
953 /* we have to use the returned data_size for our image size */
954 evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size;
955 evaspixmapbuf->xvimage->data = g_malloc (evaspixmapbuf->size);
957 XSync (evaspixmapsink->xcontext->disp, FALSE);
960 /* Reset error handler */
961 error_caught = FALSE;
962 XSetErrorHandler (handler);
966 GST_BUFFER_DATA (evaspixmapbuf) = (guchar *) evaspixmapbuf->xvimage->data;
967 GST_BUFFER_SIZE (evaspixmapbuf) = evaspixmapbuf->size;
969 g_mutex_unlock (evaspixmapsink->x_lock);
973 gst_evaspixmap_buffer_free (evaspixmapbuf);
974 evaspixmapbuf = NULL;
977 return evaspixmapbuf;
980 /* This function puts a GstEvasPixmapBuffer on a GstEvasPixmapSink's pixmap. Returns FALSE
981 * if no pixmap was available */
983 gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf)
985 GstVideoRectangle result;
987 GstVideoRectangle src_origin = { 0, 0, 0, 0};
988 GstVideoRectangle src_input = { 0, 0, 0, 0};
989 GstVideoRectangle src = { 0, 0, 0, 0};
990 GstVideoRectangle dst = { 0, 0, 0, 0};
994 GstXPixmap *xpixmap = NULL;
996 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink evaspixmap_buffer_put()", FALSE);
998 /* We take the flow_lock. If expose is in there we don't want to run
999 concurrently from the data flow thread */
1000 g_mutex_lock (evaspixmapsink->flow_lock);
1002 if (G_UNLIKELY (evaspixmapsink->xpixmap[idx] == NULL)) {
1003 GST_WARNING_OBJECT (evaspixmapsink, "xpixmap is NULL. Skip buffer_put." );
1004 g_mutex_unlock(evaspixmapsink->flow_lock);
1007 if (evaspixmapsink->visible == FALSE) {
1008 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. Skip buffer_put." );
1009 g_mutex_unlock(evaspixmapsink->flow_lock);
1012 if (!evaspixmapbuf) {
1013 GST_WARNING_OBJECT (evaspixmapsink, "evaspixmapbuf is NULL. Skip buffer_put." );
1014 g_mutex_unlock(evaspixmapsink->flow_lock);
1018 for (idx = 0; idx < evaspixmapsink->num_of_pixmaps; idx++) {
1019 g_mutex_lock (evaspixmapsink->pixmap_ref_lock);
1020 if (idx == evaspixmapsink->last_updated_idx) {
1021 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1024 xpixmap = evaspixmapsink->xpixmap[idx];
1025 if (xpixmap->ref == 0 && xpixmap->damaged_time == 0) {
1027 GST_LOG_OBJECT (evaspixmapsink, "found an available pixmap(%d) : xpixmap[%d]", xpixmap->pixmap, idx);
1028 GST_INFO_OBJECT (evaspixmapsink,"pixmap ref-count INCREASED : pixmap(%d), refcount(%d)", xpixmap->pixmap, xpixmap->ref);
1029 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1032 g_mutex_unlock (evaspixmapsink->pixmap_ref_lock);
1035 if (idx == evaspixmapsink->num_of_pixmaps) {
1036 GST_LOG_OBJECT (evaspixmapsink, "Could not find a pixmap with idle state, skip buffer_put." );
1037 g_mutex_unlock(evaspixmapsink->flow_lock);
1041 gst_evaspixmapsink_xpixmap_update_geometry(evaspixmapsink, idx);
1044 src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
1045 src_input.w = src_origin.w = evaspixmapsink->video_width;
1046 src_input.h = src_origin.h = evaspixmapsink->video_height;
1047 if (evaspixmapsink->use_origin_size ||
1048 (evaspixmapsink->rotate_angle == DEGREE_0 ||
1049 evaspixmapsink->rotate_angle == DEGREE_180)) {
1050 src.w = src_origin.w;
1051 src.h = src_origin.h;
1053 src.w = src_origin.h;
1054 src.h = src_origin.w;
1057 dst.w = evaspixmapsink->render_rect.w; /* pixmap width */
1058 dst.h = evaspixmapsink->render_rect.h; /* pixmap height */
1060 if (!evaspixmapsink->use_origin_size) {
1061 static Atom atom_rotation = None;
1062 static Atom atom_hflip = None;
1063 static Atom atom_vflip = None;
1064 gboolean set_hflip = FALSE;
1065 gboolean set_vflip = FALSE;
1067 /* compensation of size information (between evas image object's and pixmap's) */
1068 if (evaspixmapsink->sizediff_width > 1) {
1069 if (evaspixmapsink->sizediff_height > 1) {
1070 dst.w -= (evaspixmapsink->sizediff_width >> 1) << 1;
1071 dst.h -= (evaspixmapsink->sizediff_height >> 1) << 1;
1073 dst.w -= (evaspixmapsink->sizediff_width >> 1) << 1;
1075 } else if (evaspixmapsink->sizediff_height > 1) {
1076 dst.h -= (evaspixmapsink->sizediff_height >> 1) << 1;
1079 switch (evaspixmapsink->display_geometry_method) {
1080 case DISP_GEO_METHOD_LETTER_BOX:
1081 gst_video_sink_center_rect (src, dst, &result, TRUE);
1082 result.x += evaspixmapsink->render_rect.x;
1083 result.y += evaspixmapsink->render_rect.y;
1084 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : letter box");
1086 case DISP_GEO_METHOD_ORIGIN_SIZE:
1087 gst_video_sink_center_rect (src, dst, &result, FALSE);
1088 gst_video_sink_center_rect (dst, src, &src_input, FALSE);
1089 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : origin size");
1090 if (evaspixmapsink->rotate_angle == DEGREE_90 ||
1091 evaspixmapsink->rotate_angle == DEGREE_270) {
1092 src_input.x = src_input.x ^ src_input.y;
1093 src_input.y = src_input.x ^ src_input.y;
1094 src_input.x = src_input.x ^ src_input.y;
1095 src_input.w = src_input.w ^ src_input.h;
1096 src_input.h = src_input.w ^ src_input.h;
1097 src_input.w = src_input.w ^ src_input.h;
1100 case DISP_GEO_METHOD_FULL_SCREEN:
1101 result.x = result.y = 0;
1102 result.w = evaspixmapsink->xpixmap[idx]->width;
1103 result.h = evaspixmapsink->xpixmap[idx]->height;
1104 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : full screen");
1106 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
1107 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : cropped full screen");
1108 gst_video_sink_center_rect(dst, src, &src_input, TRUE);
1109 result.x = result.y = 0;
1112 if (evaspixmapsink->rotate_angle == DEGREE_90 ||
1113 evaspixmapsink->rotate_angle == DEGREE_270) {
1114 src_input.x = src_input.x ^ src_input.y;
1115 src_input.y = src_input.x ^ src_input.y;
1116 src_input.x = src_input.x ^ src_input.y;
1117 src_input.w = src_input.w ^ src_input.h;
1118 src_input.h = src_input.w ^ src_input.h;
1119 src_input.w = src_input.w ^ src_input.h;
1122 case DISP_GEO_METHOD_CUSTOM_ROI:
1123 switch (evaspixmapsink->rotate_angle) {
1125 result.w = evaspixmapsink->dst_roi.h;
1126 result.h = evaspixmapsink->dst_roi.w;
1127 result.x = evaspixmapsink->dst_roi.y;
1128 result.y = evaspixmapsink->xpixmap[idx]->height - evaspixmapsink->dst_roi.x - evaspixmapsink->dst_roi.w;
1131 result.w = evaspixmapsink->dst_roi.w;
1132 result.h = evaspixmapsink->dst_roi.h;
1133 result.x = evaspixmapsink->xpixmap[idx]->width - result.w - evaspixmapsink->dst_roi.x;
1134 result.y = evaspixmapsink->xpixmap[idx]->height - result.h - evaspixmapsink->dst_roi.y;
1137 result.w = evaspixmapsink->dst_roi.h;
1138 result.h = evaspixmapsink->dst_roi.w;
1139 result.x = evaspixmapsink->xpixmap[idx]->width - evaspixmapsink->dst_roi.y - evaspixmapsink->dst_roi.h;
1140 result.y = evaspixmapsink->dst_roi.x;
1143 result.x = evaspixmapsink->dst_roi.x;
1144 result.y = evaspixmapsink->dst_roi.y;
1145 result.w = evaspixmapsink->dst_roi.w;
1146 result.h = evaspixmapsink->dst_roi.h;
1149 GST_LOG_OBJECT(evaspixmapsink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
1150 evaspixmapsink->rotate_angle,
1151 evaspixmapsink->dst_roi.x, evaspixmapsink->dst_roi.y, evaspixmapsink->dst_roi.w, evaspixmapsink->dst_roi.h,
1152 result.x, result.y, result.w, result.h);
1157 GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : src(%dx%d), dst(%dx%d), result(%dx%d), result_x(%d), result_y(%d)",
1158 src.w,src.h,dst.w,dst.h,result.w,result.h,result.x,result.y);
1160 switch( evaspixmapsink->rotate_angle ) {
1173 GST_WARNING_OBJECT( evaspixmapsink, "Unsupported rotation [%d]... set DEGREE 0.",
1174 evaspixmapsink->rotate_angle );
1178 /* set display rotation */
1179 if (atom_rotation == None) {
1180 atom_rotation = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
1183 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate);
1184 if (ret != Success) {
1185 GST_ERROR_OBJECT( evaspixmapsink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
1186 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_rotation, rotate );
1190 /* set display flip */
1191 if (atom_hflip == None) {
1192 atom_hflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
1194 if (atom_vflip == None) {
1195 atom_vflip = XInternAtom(evaspixmapsink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
1198 switch (evaspixmapsink->flip) {
1199 case FLIP_HORIZONTAL:
1217 GST_INFO_OBJECT(evaspixmapsink, "set rotate %d HFLIP %d, VFLIP %d", rotate, set_hflip, set_vflip);
1219 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1220 if (ret != Success) {
1221 GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
1222 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_hflip, set_hflip);
1224 ret = XvSetPortAttribute(evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1225 if (ret != Success) {
1226 GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
1227 ret, evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, atom_vflip, set_vflip);
1231 result.x = result.y = 0;
1232 result.w = evaspixmapsink->xpixmap[idx]->width;
1233 result.h = evaspixmapsink->xpixmap[idx]->height;
1234 GST_INFO_OBJECT (evaspixmapsink, "USE ORIGIN SIZE, no geometry method, no rotation/flip" );
1237 g_mutex_lock (evaspixmapsink->x_lock);
1239 /* We scale to the pixmap's geometry */
1241 if (evaspixmapsink->xcontext->use_xshm) {
1242 GST_LOG_OBJECT (evaspixmapsink,"XvShmPutImage with image %dx%d and pixmap %dx%d, from xvimage %"
1244 evaspixmapbuf->width, evaspixmapbuf->height,
1245 evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h, evaspixmapbuf);
1247 /* Trim as proper size */
1248 if (src_input.w % 2 == 1) {
1251 if (src_input.h % 2 == 1) {
1255 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]",
1256 evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1257 evaspixmapsink->xpixmap[idx]->x, evaspixmapsink->xpixmap[idx]->y, evaspixmapsink->xpixmap[idx]->width, evaspixmapsink->xpixmap[idx]->height,
1258 evaspixmapsink->display_geometry_method, rotate,
1259 src_origin.w, src_origin.h,
1260 dst.x, dst.y, dst.w, dst.h,
1261 src_input.x, src_input.y, src_input.w, src_input.h,
1262 result.x, result.y, result.w, result.h );
1264 if (evaspixmapsink->visible) {
1265 ret = XvShmPutImage (evaspixmapsink->xcontext->disp,
1266 evaspixmapsink->xcontext->xv_port_id,
1267 evaspixmapsink->xpixmap[idx]->pixmap,
1268 evaspixmapsink->xpixmap[idx]->gc, evaspixmapbuf->xvimage,
1269 src_input.x, src_input.y, src_input.w, src_input.h,
1270 result.x, result.y, result.w, result.h, FALSE);
1271 GST_LOG_OBJECT (evaspixmapsink, "XvShmPutImage return value [%d]", ret );
1274 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1277 #endif /* HAVE_XSHM */
1279 if (evaspixmapsink->visible) {
1280 XvPutImage (evaspixmapsink->xcontext->disp,
1281 evaspixmapsink->xcontext->xv_port_id,
1282 evaspixmapsink->xpixmap[idx]->pixmap,
1283 evaspixmapsink->xpixmap[idx]->gc, evaspixmapbuf->xvimage,
1284 evaspixmapsink->disp_x, evaspixmapsink->disp_y,
1285 evaspixmapsink->disp_width, evaspixmapsink->disp_height,
1286 result.x, result.y, result.w, result.h);
1288 GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." );
1291 XSync (evaspixmapsink->xcontext->disp, FALSE);
1293 g_mutex_unlock (evaspixmapsink->x_lock);
1294 g_mutex_unlock (evaspixmapsink->flow_lock);
1296 MMTA_ACUM_ITEM_END("evaspixmapsink evaspixmap_buffer_put()", FALSE);
1302 drm_init(GstEvasPixmapSink *evaspixmapsink)
1310 char *driverName = NULL;
1311 char *deviceName = NULL;
1312 struct drm_auth auth_arg = {0};
1314 evaspixmapsink->drm_fd = -1;
1316 dpy = XOpenDisplay(0);
1319 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
1320 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryExtension()");
1324 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
1325 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryVersion");
1329 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
1330 GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2Connect");
1334 if (!driverName || !deviceName) {
1335 GST_ERROR_OBJECT (evaspixmapsink,"driverName or deviceName is not valid");
1339 GST_INFO_OBJECT (evaspixmapsink,"Open drm device : %s", deviceName);
1341 /* get the drm_fd though opening the deviceName */
1342 evaspixmapsink->drm_fd = open(deviceName, O_RDWR);
1343 if (evaspixmapsink->drm_fd < 0) {
1344 GST_ERROR_OBJECT (evaspixmapsink,"cannot open drm device (%s)", deviceName);
1348 /* get magic from drm to authentication */
1349 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
1350 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm auth magic");
1351 close(evaspixmapsink->drm_fd);
1352 evaspixmapsink->drm_fd = -1;
1356 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
1357 GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm authentication from X");
1358 close(evaspixmapsink->drm_fd);
1359 evaspixmapsink->drm_fd = -1;
1363 /* init gem handle */
1364 for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1365 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1366 evaspixmapsink->gem_info[i].gem_handle = 0;
1367 evaspixmapsink->gem_info[i].gem_name = 0;
1389 drm_fini(GstEvasPixmapSink *evaspixmapsink)
1391 if (evaspixmapsink->drm_fd >= 0) {
1392 GST_INFO_OBJECT (evaspixmapsink,"close drm_fd(%d)", evaspixmapsink->drm_fd);
1393 close(evaspixmapsink->drm_fd);
1394 evaspixmapsink->drm_fd = -1;
1399 drm_init_convert_dmabuf_gemname(GstEvasPixmapSink *evaspixmapsink, int dmabuf_fd)
1401 struct drm_prime_handle prime_arg = {0,};
1402 struct drm_gem_flink flink_arg = {0,};
1405 if (evaspixmapsink->drm_fd < 0) {
1406 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1410 if (dmabuf_fd <= 0) {
1411 GST_DEBUG_OBJECT (evaspixmapsink,"Ignore wrong dmabuf fd(%d)", dmabuf_fd); /* temporarily change log level to DEBUG for reducing WARNING level log */
1415 /* check duplicated dmabuf fd */
1416 for (i = 0 ; i < MAX_GEM_BUFFER_NUM ; i++) {
1417 if (evaspixmapsink->gem_info[i].dmabuf_fd == dmabuf_fd) {
1418 GST_LOG_OBJECT (evaspixmapsink,"already got fd(%u) with name(%u)", dmabuf_fd, evaspixmapsink->gem_info[i].gem_name);
1419 return evaspixmapsink->gem_info[i].gem_name;
1422 if (evaspixmapsink->gem_info[i].dmabuf_fd == 0) {
1423 GST_LOG_OBJECT (evaspixmapsink,"empty gem_info[%d] found", i);
1428 if (i == MAX_GEM_BUFFER_NUM) {
1429 GST_WARNING_OBJECT (evaspixmapsink,"too many buffers[dmabuf_fd(%d). skip it]", dmabuf_fd);
1433 evaspixmapsink->gem_info[i].dmabuf_fd = dmabuf_fd;
1434 prime_arg.fd = dmabuf_fd;
1435 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg)) {
1436 GST_ERROR_OBJECT (evaspixmapsink,"non dmabuf fd(%d)", dmabuf_fd);
1440 evaspixmapsink->gem_info[i].gem_handle = prime_arg.handle;
1441 GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_handle = %u", i, prime_arg.handle);
1443 flink_arg.handle = prime_arg.handle;
1444 if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg)) {
1445 GST_ERROR_OBJECT (evaspixmapsink,"cannot convert drm handle to name");
1449 evaspixmapsink->gem_info[i].gem_name = flink_arg.name;
1450 GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_name = %u", i, flink_arg.name);
1452 return flink_arg.name;
1456 drm_fini_close_gem_handle(GstEvasPixmapSink *evaspixmapsink)
1459 if (evaspixmapsink->drm_fd >= 0) {
1460 for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) {
1461 if (evaspixmapsink->gem_info[i].dmabuf_fd > 0) {
1462 GST_INFO_OBJECT (evaspixmapsink,"close gem_handle(%u)", evaspixmapsink->gem_info[i].gem_handle);
1463 drm_close_gem(evaspixmapsink, evaspixmapsink->gem_info[i].gem_handle);
1464 evaspixmapsink->gem_info[i].dmabuf_fd = 0;
1465 evaspixmapsink->gem_info[i].gem_handle = 0;
1466 evaspixmapsink->gem_info[i].gem_name = 0;
1475 drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle)
1477 struct drm_gem_close close_arg = {0,};
1479 if (evaspixmapsink->drm_fd < 0) {
1480 GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened");
1484 if (gem_handle == 0) {
1485 GST_ERROR_OBJECT (evaspixmapsink,"invalid gem_handle(%d)",gem_handle);
1489 close_arg.handle = gem_handle;
1490 if (gem_handle > 0 && ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
1491 GST_ERROR_OBJECT (evaspixmapsink,"cannot close drm gem handle(%d)", gem_handle);
1498 /* This function destroys a GstXPixmap */
1500 gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1502 g_return_if_fail (xpixmap != NULL);
1503 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1505 g_mutex_lock (evaspixmapsink->x_lock);
1507 if(xpixmap->pixmap) {
1508 GST_LOG_OBJECT (evaspixmapsink,"Free pixmap(%d)", xpixmap->pixmap);
1509 XFreePixmap(evaspixmapsink->xcontext->disp, xpixmap->pixmap);
1510 xpixmap->pixmap = 0;
1514 XFreeGC (evaspixmapsink->xcontext->disp, xpixmap->gc);
1517 XSync (evaspixmapsink->xcontext->disp, FALSE);
1519 g_mutex_unlock (evaspixmapsink->x_lock);
1525 gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink, int idx)
1528 XWindowAttributes root_attr;
1530 int cur_pixmap_x = 0;
1531 int cur_pixmap_y = 0;
1532 unsigned int cur_pixmap_width = 0;
1533 unsigned int cur_pixmap_height = 0;
1534 unsigned int cur_pixmap_border_width = 0;
1535 unsigned int cur_pixmap_depth = 0;
1537 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1539 /* Update the window geometry */
1540 g_mutex_lock (evaspixmapsink->x_lock);
1541 if (G_UNLIKELY (evaspixmapsink->xpixmap[idx] == NULL)) {
1542 g_mutex_unlock (evaspixmapsink->x_lock);
1546 /* Get root window and size of current pixmap */
1547 XGetGeometry( evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap[idx]->pixmap, &root_window,
1548 &cur_pixmap_x, &cur_pixmap_y, /* relative x, y, for pixmap these are alway 0 */
1549 &cur_pixmap_width, &cur_pixmap_height,
1550 &cur_pixmap_border_width, &cur_pixmap_depth ); /* cur_pixmap_border_width, cur_pixmap_depth are not used */
1552 evaspixmapsink->xpixmap[idx]->width = cur_pixmap_width;
1553 evaspixmapsink->xpixmap[idx]->height = cur_pixmap_height;
1555 evaspixmapsink->xpixmap[idx]->x = cur_pixmap_x;
1556 evaspixmapsink->xpixmap[idx]->y = cur_pixmap_y;
1558 /* Get size of root window == size of screen */
1559 XGetWindowAttributes(evaspixmapsink->xcontext->disp, root_window, &root_attr);
1561 evaspixmapsink->scr_w = root_attr.width;
1562 evaspixmapsink->scr_h = root_attr.height;
1564 if (!evaspixmapsink->have_render_rect) {
1565 evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = 0;
1566 evaspixmapsink->render_rect.w = cur_pixmap_width;
1567 evaspixmapsink->render_rect.h = cur_pixmap_height;
1570 GST_LOG_OBJECT (evaspixmapsink,"screen size %dx%d, current pixmap geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
1571 evaspixmapsink->scr_w, evaspixmapsink->scr_h,
1572 evaspixmapsink->xpixmap[idx]->x, evaspixmapsink->xpixmap[idx]->y,
1573 evaspixmapsink->xpixmap[idx]->width, evaspixmapsink->xpixmap[idx]->height,
1574 evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y,
1575 evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1577 g_mutex_unlock (evaspixmapsink->x_lock);
1581 gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap)
1583 g_return_if_fail (xpixmap != NULL);
1584 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1586 if (!xpixmap->pixmap) {
1587 GST_WARNING_OBJECT (evaspixmapsink,"pixmap was not created..");
1591 g_mutex_lock (evaspixmapsink->x_lock);
1593 if (!evaspixmapsink->xcontext) {
1594 GST_WARNING_OBJECT (evaspixmapsink,"xcontext is null..");
1595 g_mutex_unlock (evaspixmapsink->x_lock);
1599 if (evaspixmapsink->stop_video) {
1600 XvStopVideo (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, xpixmap->pixmap);
1602 XSetForeground (evaspixmapsink->xcontext->disp, xpixmap->gc, evaspixmapsink->xcontext->black);
1603 XFillRectangle (evaspixmapsink->xcontext->disp, xpixmap->pixmap, xpixmap->gc,
1604 evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y, evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h);
1606 XSync (evaspixmapsink->xcontext->disp, FALSE);
1608 g_mutex_unlock (evaspixmapsink->x_lock);
1611 /* This function commits our internal colorbalance settings to our grabbed Xv
1612 port. If the xcontext is not initialized yet it simply returns */
1614 gst_evaspixmapsink_update_colorbalance (GstEvasPixmapSink *evaspixmapsink)
1616 GList *channels = NULL;
1618 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
1620 /* If we haven't initialized the X context we can't update anything */
1621 if (evaspixmapsink->xcontext == NULL)
1624 /* Don't set the attributes if they haven't been changed, to avoid
1625 * rounding errors changing the values */
1626 if (!evaspixmapsink->cb_changed)
1629 /* For each channel of the colorbalance we calculate the correct value
1630 doing range conversion and then set the Xv port attribute to match our
1632 channels = evaspixmapsink->xcontext->channels_list;
1635 if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
1636 GstColorBalanceChannel *channel = NULL;
1639 gdouble convert_coef;
1641 channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
1642 g_object_ref (channel);
1644 /* Our range conversion coef */
1645 convert_coef = (channel->max_value - channel->min_value) / 2000.0;
1647 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
1648 value = evaspixmapsink->hue;
1649 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
1650 value = evaspixmapsink->saturation;
1651 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
1652 value = evaspixmapsink->contrast;
1653 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
1654 value = evaspixmapsink->brightness;
1656 g_warning ("got an unknown channel %s", channel->label);
1657 g_object_unref (channel);
1661 /* Committing to Xv port */
1662 g_mutex_lock (evaspixmapsink->x_lock);
1664 XInternAtom (evaspixmapsink->xcontext->disp, channel->label, True);
1665 if (prop_atom != None) {
1668 floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
1669 XvSetPortAttribute (evaspixmapsink->xcontext->disp,
1670 evaspixmapsink->xcontext->xv_port_id, prop_atom, xv_value);
1672 g_mutex_unlock (evaspixmapsink->x_lock);
1674 g_object_unref (channel);
1676 channels = g_list_next (channels);
1681 gst_lookup_xv_port_from_adaptor (GstXContext *xcontext, XvAdaptorInfo *adaptors, int adaptor_no)
1686 /* Do we support XvImageMask ? */
1687 if (!(adaptors[adaptor_no].type & XvImageMask)) {
1688 GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", adaptors[adaptor_no].name);
1692 /* We found such an adaptor, looking for an available port */
1693 for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) {
1694 /* We try to grab the port */
1695 res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0);
1696 if (Success == res) {
1697 xcontext->xv_port_id = adaptors[adaptor_no].base_id + j;
1698 GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, adaptors[adaptor_no].num_ports);
1700 GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, adaptors[adaptor_no].name, res);
1705 /* This function generates a caps with all supported format by the first
1706 Xv grabable port we find. We store each one of the supported formats in a
1707 format list and append the format to a newly created caps that we return
1708 If this function does not return NULL because of an error, it also grabs
1709 the port via XvGrabPort */
1711 gst_evaspixmapsink_get_xv_support (GstEvasPixmapSink *evaspixmapsink, GstXContext *xcontext)
1714 XvAdaptorInfo *adaptors;
1716 XvImageFormatValues *formats = NULL;
1718 XvEncodingInfo *encodings = NULL;
1719 gulong max_w = G_MAXINT, max_h = G_MAXINT;
1720 GstCaps *caps = NULL;
1721 GstCaps *rgb_caps = NULL;
1723 g_return_val_if_fail (xcontext != NULL, NULL);
1725 /* First let's check that XVideo extension is available */
1726 if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
1727 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1728 ("Could not initialise Xv output"),
1729 ("XVideo extension is not available"));
1733 /* Then we get adaptors list */
1734 if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
1735 &xcontext->nb_adaptors, &adaptors)) {
1736 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
1737 ("Could not initialise Xv output"),
1738 ("Failed getting XV adaptors list"));
1742 xcontext->xv_port_id = 0;
1744 GST_DEBUG_OBJECT (evaspixmapsink,"Found %u XV adaptor(s)", xcontext->nb_adaptors);
1746 xcontext->adaptors =
1747 (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
1749 /* Now fill up our adaptor name array */
1750 for (i = 0; i < xcontext->nb_adaptors; i++) {
1751 xcontext->adaptors[i] = g_strdup (adaptors[i].name);
1754 if (evaspixmapsink->adaptor_no < xcontext->nb_adaptors) {
1755 /* Find xv port from user defined adaptor */
1756 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, evaspixmapsink->adaptor_no);
1759 if (!xcontext->xv_port_id) {
1760 /* Now search for an adaptor that supports XvImageMask */
1761 for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
1762 gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
1763 evaspixmapsink->adaptor_no = i;
1767 XvFreeAdaptorInfo (adaptors);
1769 if (!xcontext->xv_port_id) {
1770 evaspixmapsink->adaptor_no = -1;
1771 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, BUSY,
1772 ("Could not initialise Xv output"), ("No port available"));
1776 /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
1778 int count, todo = 3;
1779 XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp,
1780 xcontext->xv_port_id, &count);
1781 static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
1782 static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
1783 static const char colorkey[] = "XV_COLORKEY";
1785 GST_DEBUG_OBJECT (evaspixmapsink,"Checking %d Xv port attributes", count);
1787 evaspixmapsink->have_autopaint_colorkey = FALSE;
1788 evaspixmapsink->have_double_buffer = FALSE;
1789 evaspixmapsink->have_colorkey = FALSE;
1791 for (i = 0; ((i < count) && todo); i++)
1792 if (!strcmp (attr[i].name, autopaint)) {
1793 const Atom atom = XInternAtom (xcontext->disp, autopaint, False);
1795 /* turn on autopaint colorkey */
1796 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1797 (evaspixmapsink->autopaint_colorkey ? 1 : 0));
1799 evaspixmapsink->have_autopaint_colorkey = TRUE;
1800 } else if (!strcmp (attr[i].name, dbl_buffer)) {
1801 const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False);
1803 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1804 (evaspixmapsink->double_buffer ? 1 : 0));
1806 evaspixmapsink->have_double_buffer = TRUE;
1807 } else if (!strcmp (attr[i].name, colorkey)) {
1808 /* Set the colorkey, default is something that is dark but hopefully
1809 * won't randomly appear on the screen elsewhere (ie not black or greys)
1810 * can be overridden by setting "colorkey" property
1812 const Atom atom = XInternAtom (xcontext->disp, colorkey, False);
1814 gboolean set_attr = TRUE;
1817 /* set a colorkey in the right format RGB565/RGB888
1818 * We only handle these 2 cases, because they're the only types of
1819 * devices we've encountered. If we don't recognise it, leave it alone
1821 cr = (evaspixmapsink->colorkey >> 16);
1822 cg = (evaspixmapsink->colorkey >> 8) & 0xFF;
1823 cb = (evaspixmapsink->colorkey) & 0xFF;
1824 switch (xcontext->depth) {
1825 case 16: /* RGB 565 */
1829 ckey = (cr << 11) | (cg << 5) | cb;
1832 case 32: /* RGB 888 / ARGB 8888 */
1833 ckey = (cr << 16) | (cg << 8) | cb;
1836 GST_DEBUG_OBJECT (evaspixmapsink,"Unknown bit depth %d for Xv Colorkey - not adjusting", xcontext->depth);
1842 ckey = CLAMP (ckey, (guint32) attr[i].min_value,
1843 (guint32) attr[i].max_value);
1844 GST_LOG_OBJECT (evaspixmapsink,"Setting color key for display depth %d to 0x%x", xcontext->depth, ckey);
1846 XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom,
1850 evaspixmapsink->have_colorkey = TRUE;
1856 /* Get the list of encodings supported by the adapter and look for the
1857 * XV_IMAGE encoding so we can determine the maximum width and height
1859 XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
1862 for (i = 0; i < nb_encodings; i++) {
1863 GST_LOG_OBJECT (evaspixmapsink,
1864 "Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
1865 i, encodings[i].name, encodings[i].width, encodings[i].height,
1866 encodings[i].rate.numerator, encodings[i].rate.denominator);
1867 if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
1868 max_w = encodings[i].width;
1869 max_h = encodings[i].height;
1870 evaspixmapsink->scr_w = max_w;
1871 evaspixmapsink->scr_h = max_h;
1875 XvFreeEncodingInfo (encodings);
1877 /* We get all image formats supported by our port */
1878 formats = XvListImageFormats (xcontext->disp,
1879 xcontext->xv_port_id, &nb_formats);
1880 caps = gst_caps_new_empty ();
1881 for (i = 0; i < nb_formats; i++) {
1882 GstCaps *format_caps = NULL;
1883 gboolean is_rgb_format = FALSE;
1885 /* We set the image format of the xcontext to an existing one. This
1886 is just some valid image format for making our xshm calls check before
1887 caps negotiation really happens. */
1888 xcontext->im_format = formats[i].id;
1890 switch (formats[i].type) {
1893 XvImageFormatValues *fmt = &(formats[i]);
1894 gint endianness = G_BIG_ENDIAN;
1896 if (fmt->byte_order == LSBFirst) {
1897 /* our caps system handles 24/32bpp RGB as big-endian. */
1898 if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
1899 fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
1900 fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
1901 fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
1903 if (fmt->bits_per_pixel == 24) {
1904 fmt->red_mask >>= 8;
1905 fmt->green_mask >>= 8;
1906 fmt->blue_mask >>= 8;
1909 endianness = G_LITTLE_ENDIAN;
1912 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
1913 "endianness", G_TYPE_INT, endianness,
1914 "depth", G_TYPE_INT, fmt->depth,
1915 "bpp", G_TYPE_INT, fmt->bits_per_pixel,
1916 "red_mask", G_TYPE_INT, fmt->red_mask,
1917 "green_mask", G_TYPE_INT, fmt->green_mask,
1918 "blue_mask", G_TYPE_INT, fmt->blue_mask,
1919 "width", GST_TYPE_INT_RANGE, 1, max_w,
1920 "height", GST_TYPE_INT_RANGE, 1, max_h,
1921 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1923 is_rgb_format = TRUE;
1927 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
1928 "format", GST_TYPE_FOURCC, formats[i].id,
1929 "width", GST_TYPE_INT_RANGE, 1, max_w,
1930 "height", GST_TYPE_INT_RANGE, 1, max_h,
1931 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1934 g_assert_not_reached ();
1939 GstEvasPixmapFormat *format = NULL;
1941 format = g_new0 (GstEvasPixmapFormat, 1);
1943 format->format = formats[i].id;
1944 format->caps = gst_caps_copy (format_caps);
1945 xcontext->formats_list = g_list_append (xcontext->formats_list, format);
1948 if (is_rgb_format) {
1949 if (rgb_caps == NULL)
1950 rgb_caps = format_caps;
1952 gst_caps_append (rgb_caps, format_caps);
1954 gst_caps_append (caps, format_caps);
1958 /* Collected all caps into either the caps or rgb_caps structures.
1959 * Append rgb_caps on the end of YUV, so that YUV is always preferred */
1961 gst_caps_append (caps, rgb_caps);
1966 GST_DEBUG_OBJECT (evaspixmapsink,"Generated the following caps: %" GST_PTR_FORMAT, caps);
1968 if (gst_caps_is_empty (caps)) {
1969 gst_caps_unref (caps);
1970 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
1971 GST_ELEMENT_ERROR (evaspixmapsink, STREAM, WRONG_TYPE, (NULL),
1972 ("No supported format found"));
1980 gst_evaspixmapsink_event_thread (GstEvasPixmapSink * evaspixmapsink)
1982 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
1983 int damage_base = 0;
1984 int damage_err_base = 0;
1985 int damage_case = 0;
1988 Display *disp = NULL;
1990 GST_OBJECT_LOCK (evaspixmapsink);
1992 if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->disp) {
1993 disp = evaspixmapsink->xcontext->disp;
1995 GST_ERROR_OBJECT (evaspixmapsink,"evaspixmapsink->xcontext(->disp) is not ready");
1999 if (!XDamageQueryExtension(evaspixmapsink->xcontext->disp, &damage_base, &damage_err_base)) {
2000 GST_ERROR_OBJECT (evaspixmapsink,"XDamageQueryExtension() failed");
2003 damage_case = (int)damage_base + XDamageNotify;
2005 while (evaspixmapsink->running) {
2006 GST_OBJECT_UNLOCK (evaspixmapsink);
2008 g_mutex_lock (evaspixmapsink->x_lock);
2009 while (XPending (disp)) {
2010 XNextEvent (disp, &e);
2011 if (e.type == damage_case ) {
2012 XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&e;
2013 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
2014 GstXPixmap *xpixmap = evaspixmapsink->xpixmap[i];
2015 if (xpixmap && damage_ev->drawable == xpixmap->pixmap) {
2016 g_mutex_lock(evaspixmapsink->pixmap_ref_lock);
2018 /* set it only if damage event comes from _buffer_put() */
2019 xpixmap->damaged_time = (gint)get_millis_time();
2021 GST_LOG_OBJECT (evaspixmapsink,"event_handler : got a damage event for pixmap(%d), refcount(%d), damaged_time(%d)",
2022 xpixmap->pixmap, xpixmap->ref, xpixmap->damaged_time);
2023 g_mutex_unlock(evaspixmapsink->pixmap_ref_lock);
2025 __ta__("evaspixmapsink ecore_pipe_write", ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink)););
2026 GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : after call ecore_pipe_write() for pixmap(%d)", xpixmap->pixmap);
2027 XDamageSubtract (evaspixmapsink->xcontext->disp, evaspixmapsink->damage[i], None, None );
2032 if (i == evaspixmapsink->num_of_pixmaps) {
2033 GST_WARNING_OBJECT (evaspixmapsink,"event_handler : could not find corresponding pixmap with this damage event(%d)", damage_ev->drawable);
2036 GST_LOG_OBJECT (evaspixmapsink,"event_handler : unidentified event(%d)", e.type);
2040 //XSync (disp, FALSE);
2041 g_mutex_unlock (evaspixmapsink->x_lock);
2043 g_usleep (G_USEC_PER_SEC / 40);
2044 GST_OBJECT_LOCK (evaspixmapsink);
2046 GST_OBJECT_UNLOCK (evaspixmapsink);
2051 gst_evaspixmapsink_manage_event_thread (GstEvasPixmapSink *evaspixmapsink)
2053 /* don't start the thread too early */
2054 if (evaspixmapsink->xcontext == NULL) {
2055 GST_ERROR_OBJECT (evaspixmapsink,"xcontext is NULL..");
2059 GST_OBJECT_LOCK (evaspixmapsink);
2061 if (!evaspixmapsink->event_thread) {
2062 /* Setup our event listening thread */
2063 GST_DEBUG_OBJECT (evaspixmapsink,"run xevent thread");
2064 evaspixmapsink->running = TRUE;
2065 evaspixmapsink->event_thread = g_thread_create ( (GThreadFunc) gst_evaspixmapsink_event_thread, evaspixmapsink, TRUE, NULL);
2067 GST_WARNING_OBJECT (evaspixmapsink,"there already existed the event_thread.. keep going");
2068 /* Do not finalize the thread in here, Only finalize the thread by calling gst_evaspixmapsink_reset() */
2071 GST_OBJECT_UNLOCK (evaspixmapsink);
2075 /* This function calculates the pixel aspect ratio based on the properties
2076 * in the xcontext structure and stores it there. */
2078 gst_evaspixmapsink_calculate_pixel_aspect_ratio (GstXContext *xcontext)
2080 static const gint par[][2] = {
2081 {1, 1}, /* regular screen */
2082 {16, 15}, /* PAL TV */
2083 {11, 10}, /* 525 line Rec.601 video */
2084 {54, 59}, /* 625 line Rec.601 video */
2085 {64, 45}, /* 1280x1024 on 16:9 display */
2086 {5, 3}, /* 1280x1024 on 4:3 display */
2087 {4, 3} /* 800x600 on 16:9 display */
2094 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
2096 /* first calculate the "real" ratio based on the X values;
2097 * which is the "physical" w/h divided by the w/h in pixels of the display */
2098 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
2099 / (xcontext->heightmm * xcontext->width);
2101 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
2103 if (xcontext->width == 720 && xcontext->height == 576) {
2104 ratio = 4.0 * 576 / (3.0 * 720);
2106 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
2107 /* now find the one from par[][2] with the lowest delta to the real one */
2111 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
2112 gdouble this_delta = DELTA (i);
2114 if (this_delta < delta) {
2120 GST_DEBUG ("Decided on index %d (%d/%d)", index,
2121 par[index][0], par[index][1]);
2123 g_free (xcontext->par);
2124 xcontext->par = g_new0 (GValue, 1);
2125 g_value_init (xcontext->par, GST_TYPE_FRACTION);
2126 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
2127 GST_DEBUG ("set xcontext PAR to %d/%d",
2128 gst_value_get_fraction_numerator (xcontext->par),
2129 gst_value_get_fraction_denominator (xcontext->par));
2132 /* This function gets the X Display and global info about it. Everything is
2133 stored in our object and will be cleaned when the object is disposed. Note
2134 here that caps for supported format are generated without any window or
2137 gst_evaspixmapsink_xcontext_get (GstEvasPixmapSink *evaspixmapsink)
2139 GstXContext *xcontext = NULL;
2140 XPixmapFormatValues *px_formats = NULL;
2141 gint nb_formats = 0, i, j, N_attr;
2142 XvAttribute *xv_attr;
2144 const char *channels[4] = { "XV_HUE", "XV_SATURATION", "XV_BRIGHTNESS", "XV_CONTRAST"};
2146 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
2148 xcontext = g_new0 (GstXContext, 1);
2149 xcontext->im_format = 0;
2151 g_mutex_lock (evaspixmapsink->x_lock);
2153 xcontext->disp = XOpenDisplay (evaspixmapsink->display_name);
2155 if (!xcontext->disp) {
2156 g_mutex_unlock (evaspixmapsink->x_lock);
2158 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Could not initialise Xv output"), ("Could not open display"));
2162 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
2163 xcontext->screen_num = DefaultScreen (xcontext->disp);
2164 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
2165 xcontext->root = DefaultRootWindow (xcontext->disp);
2166 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
2167 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
2168 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
2170 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
2171 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
2172 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
2173 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
2175 GST_DEBUG_OBJECT (evaspixmapsink,"X reports %dx%d pixels and %d mm x %d mm", xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
2177 gst_evaspixmapsink_calculate_pixel_aspect_ratio (xcontext);
2178 /* We get supported pixmap formats at supported depth */
2179 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
2182 XCloseDisplay (xcontext->disp);
2183 g_mutex_unlock (evaspixmapsink->x_lock);
2184 g_free (xcontext->par);
2186 GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS,
2187 ("Could not initialise Xv output"), ("Could not get pixel formats"));
2191 /* We get bpp value corresponding to our running depth */
2192 for (i = 0; i < nb_formats; i++) {
2193 if (px_formats[i].depth == xcontext->depth)
2194 xcontext->bpp = px_formats[i].bits_per_pixel;
2199 xcontext->endianness = (ImageByteOrder (xcontext->disp) == LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
2201 /* our caps system handles 24/32bpp RGB as big-endian. */
2202 if ((xcontext->bpp == 24 || xcontext->bpp == 32) && xcontext->endianness == G_LITTLE_ENDIAN) {
2203 xcontext->endianness = G_BIG_ENDIAN;
2204 xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask);
2205 xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask);
2206 xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask);
2207 if (xcontext->bpp == 24) {
2208 xcontext->visual->red_mask >>= 8;
2209 xcontext->visual->green_mask >>= 8;
2210 xcontext->visual->blue_mask >>= 8;
2214 xcontext->caps = gst_evaspixmapsink_get_xv_support (evaspixmapsink, xcontext);
2216 if (!xcontext->caps) {
2217 XCloseDisplay (xcontext->disp);
2218 g_mutex_unlock (evaspixmapsink->x_lock);
2219 g_free (xcontext->par);
2221 /* GST_ELEMENT_ERROR is thrown by gst_evaspixmapsink_get_xv_support */
2225 /* Search for XShm extension support */
2226 if (XShmQueryExtension (xcontext->disp) && gst_evaspixmapsink_check_xshm_calls (xcontext)) {
2227 xcontext->use_xshm = TRUE;
2228 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is using XShm extension");
2230 #endif /* HAVE_XSHM */
2232 xcontext->use_xshm = FALSE;
2233 GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is not using XShm extension");
2236 xv_attr = XvQueryPortAttributes (xcontext->disp, xcontext->xv_port_id, &N_attr);
2238 /* Generate the channels list */
2239 for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
2240 XvAttribute *matching_attr = NULL;
2242 /* Retrieve the property atom if it exists. If it doesn't exist,
2243 * the attribute itself must not either, so we can skip */
2244 prop_atom = XInternAtom (xcontext->disp, channels[i], True);
2245 if (prop_atom == None) {
2249 if (xv_attr != NULL) {
2250 for (j = 0; j < N_attr && matching_attr == NULL; ++j) {
2251 if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) {
2252 matching_attr = xv_attr + j;
2257 if (matching_attr) {
2258 GstColorBalanceChannel *channel;
2259 channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
2260 channel->label = g_strdup (channels[i]);
2261 channel->min_value = matching_attr->min_value;
2262 channel->max_value = matching_attr->max_value;
2264 xcontext->channels_list = g_list_append (xcontext->channels_list, channel);
2266 /* If the colorbalance settings have not been touched we get Xv values
2267 as defaults and update our internal variables */
2268 if (!evaspixmapsink->cb_changed) {
2270 XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, prop_atom, &val);
2271 /* Normalize val to [-1000, 1000] */
2272 val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / (double) (channel->max_value - channel->min_value));
2274 if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) {
2275 evaspixmapsink->hue = val;
2276 } else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) {
2277 evaspixmapsink->saturation = val;
2278 } else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) {
2279 evaspixmapsink->brightness = val;
2280 } else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) {
2281 evaspixmapsink->contrast = val;
2291 g_mutex_unlock (evaspixmapsink->x_lock);
2296 /* This function cleans the X context. Closing the Display, releasing the XV
2297 port and unrefing the caps for supported formats. */
2299 gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink)
2301 GList *formats_list, *channels_list;
2302 GstXContext *xcontext;
2305 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2307 GST_OBJECT_LOCK (evaspixmapsink);
2308 if (evaspixmapsink->xcontext == NULL) {
2309 GST_OBJECT_UNLOCK (evaspixmapsink);
2313 /* Take the XContext from the sink and clean it up */
2314 xcontext = evaspixmapsink->xcontext;
2315 evaspixmapsink->xcontext = NULL;
2317 GST_OBJECT_UNLOCK (evaspixmapsink);
2319 formats_list = xcontext->formats_list;
2321 while (formats_list) {
2322 GstEvasPixmapFormat *format = formats_list->data;
2324 gst_caps_unref (format->caps);
2326 formats_list = g_list_next (formats_list);
2329 if (xcontext->formats_list)
2330 g_list_free (xcontext->formats_list);
2332 channels_list = xcontext->channels_list;
2334 while (channels_list) {
2335 GstColorBalanceChannel *channel = channels_list->data;
2337 g_object_unref (channel);
2338 channels_list = g_list_next (channels_list);
2341 if (xcontext->channels_list)
2342 g_list_free (xcontext->channels_list);
2344 gst_caps_unref (xcontext->caps);
2346 for (i = 0; i < xcontext->nb_adaptors; i++) {
2347 g_free (xcontext->adaptors[i]);
2350 g_free (xcontext->adaptors);
2352 g_free (xcontext->par);
2354 g_mutex_lock (evaspixmapsink->x_lock);
2356 GST_DEBUG_OBJECT (evaspixmapsink,"Closing display and freeing X Context");
2358 XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
2360 XCloseDisplay (xcontext->disp);
2362 g_mutex_unlock (evaspixmapsink->x_lock);
2369 /* This function tries to get a format matching with a given caps in the
2370 supported list of formats we generated in gst_evaspixmapsink_get_xv_support */
2372 gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps)
2376 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2378 list = evaspixmapsink->xcontext->formats_list;
2381 GstEvasPixmapFormat *format = list->data;
2384 if (gst_caps_can_intersect (caps, format->caps)) {
2385 return format->format;
2388 list = g_list_next (list);
2395 gst_evaspixmapsink_getcaps (GstBaseSink *bsink)
2397 GstEvasPixmapSink *evaspixmapsink;
2399 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2401 if (evaspixmapsink->xcontext)
2402 return gst_caps_ref (evaspixmapsink->xcontext->caps);
2405 gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
2410 gst_evaspixmapsink_setcaps (GstBaseSink *bsink, GstCaps *caps)
2412 GstEvasPixmapSink *evaspixmapsink;
2413 GstStructure *structure;
2414 guint32 im_format = 0;
2416 gint video_width, video_height;
2417 gint disp_x, disp_y;
2418 gint disp_width, disp_height;
2419 gint video_par_n, video_par_d; /* video's PAR */
2420 gint display_par_n, display_par_d; /* display's PAR */
2421 const GValue *caps_par;
2422 const GValue *caps_disp_reg;
2425 gboolean enable_last_buffer;
2427 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2429 GST_DEBUG_OBJECT (evaspixmapsink,"In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" GST_PTR_FORMAT, evaspixmapsink->xcontext->caps, caps);
2431 if (!gst_caps_can_intersect (evaspixmapsink->xcontext->caps, caps)) {
2432 goto incompatible_caps;
2435 structure = gst_caps_get_structure (caps, 0);
2436 ret = gst_structure_get_int (structure, "width", &video_width);
2437 ret &= gst_structure_get_int (structure, "height", &video_height);
2438 fps = gst_structure_get_value (structure, "framerate");
2439 ret &= (fps != NULL);
2442 goto incomplete_caps;
2445 evaspixmapsink->aligned_width = video_width;
2446 evaspixmapsink->aligned_height = video_height;
2448 /* get enable-last-buffer */
2449 g_object_get(G_OBJECT(evaspixmapsink), "enable-last-buffer", &enable_last_buffer, NULL);
2450 GST_INFO_OBJECT (evaspixmapsink,"current enable-last-buffer : %d", enable_last_buffer);
2451 /* flush if enable-last-buffer is TRUE */
2452 if (enable_last_buffer) {
2453 GST_INFO_OBJECT (evaspixmapsink,"flush last-buffer");
2454 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", FALSE, NULL);
2455 g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", TRUE, NULL);
2458 evaspixmapsink->fps_n = gst_value_get_fraction_numerator (fps);
2459 evaspixmapsink->fps_d = gst_value_get_fraction_denominator (fps);
2461 evaspixmapsink->video_width = video_width;
2462 evaspixmapsink->video_height = video_height;
2464 im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps);
2465 if (im_format == -1) {
2466 goto invalid_format;
2469 /* get aspect ratio from caps if it's present, and
2470 * convert video width and height to a display width and height
2471 * using wd / hd = wv / hv * PARv / PARd */
2473 /* get video's PAR */
2474 caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
2476 video_par_n = gst_value_get_fraction_numerator (caps_par);
2477 video_par_d = gst_value_get_fraction_denominator (caps_par);
2482 /* get display's PAR */
2483 if (evaspixmapsink->par) {
2484 display_par_n = gst_value_get_fraction_numerator (evaspixmapsink->par);
2485 display_par_d = gst_value_get_fraction_denominator (evaspixmapsink->par);
2491 /* get the display region */
2492 caps_disp_reg = gst_structure_get_value (structure, "display-region");
2493 if (caps_disp_reg) {
2494 disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0));
2495 disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1));
2496 disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2));
2497 disp_height = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3));
2499 disp_x = disp_y = 0;
2500 disp_width = video_width;
2501 disp_height = video_height;
2504 if (!gst_video_calculate_display_ratio (&num, &den, video_width, video_height, video_par_n, video_par_d, display_par_n, display_par_d)) {
2508 evaspixmapsink->disp_x = disp_x;
2509 evaspixmapsink->disp_y = disp_y;
2510 evaspixmapsink->disp_width = disp_width;
2511 evaspixmapsink->disp_height = disp_height;
2513 GST_DEBUG_OBJECT (evaspixmapsink,"video width/height: %dx%d, calculated display ratio: %d/%d", video_width, video_height, num, den);
2515 /* now find a width x height that respects this display ratio.
2516 * prefer those that have one of w/h the same as the incoming video
2517 * using wd / hd = num / den */
2519 /* start with same height, because of interlaced video */
2520 /* check hd / den is an integer scale factor, and scale wd with the PAR */
2521 if (video_height % den == 0) {
2522 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video height");
2523 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2524 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2525 } else if (video_width % num == 0) {
2526 GST_DEBUG_OBJECT (evaspixmapsink,"keeping video width");
2527 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = video_width;
2528 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_width, den, num);
2530 GST_DEBUG_OBJECT (evaspixmapsink,"approximating while keeping video height");
2531 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den);
2532 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height;
2534 GST_DEBUG_OBJECT (evaspixmapsink,"scaling to %dx%d", GST_VIDEO_SINK_WIDTH (evaspixmapsink), GST_VIDEO_SINK_HEIGHT (evaspixmapsink));
2536 /* Creating our window and our image with the display size in pixels */
2537 if (GST_VIDEO_SINK_WIDTH (evaspixmapsink) <= 0 || GST_VIDEO_SINK_HEIGHT (evaspixmapsink) <= 0) {
2538 goto no_display_size;
2541 g_mutex_lock (evaspixmapsink->flow_lock);
2543 /* We renew our evaspixmap buffer only if size or format changed;
2544 * the evaspixmap buffer is the same size as the video pixel size */
2545 if ((evaspixmapsink->evas_pixmap_buf) && ((im_format != evaspixmapsink->evas_pixmap_buf->im_format)
2546 || (video_width != evaspixmapsink->evas_pixmap_buf->width) || (video_height != evaspixmapsink->evas_pixmap_buf->height))) {
2547 GST_DEBUG_OBJECT (evaspixmapsink,"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
2548 GST_FOURCC_ARGS (evaspixmapsink->evas_pixmap_buf->im_format), GST_FOURCC_ARGS (im_format));
2549 GST_DEBUG_OBJECT (evaspixmapsink,"renewing evaspixmap buffer");
2550 gst_buffer_unref (GST_BUFFER (evaspixmapsink->evas_pixmap_buf));
2551 evaspixmapsink->evas_pixmap_buf = NULL;
2554 g_mutex_unlock (evaspixmapsink->flow_lock);
2556 if (evaspixmapsink->eo) {
2557 if (!gst_evaspixmapsink_xpixmap_link (evaspixmapsink)) {
2558 GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
2561 gst_evaspixmapsink_manage_event_thread (evaspixmapsink);
2564 GST_ERROR_OBJECT (evaspixmapsink,"setcaps success, but there is no evas image object..");
2573 GST_ERROR_OBJECT (evaspixmapsink,"caps incompatible");
2578 GST_DEBUG_OBJECT (evaspixmapsink,"Failed to retrieve either width, ""height or framerate from intersected caps");
2583 GST_DEBUG_OBJECT (evaspixmapsink,"Could not locate image format from caps %" GST_PTR_FORMAT, caps);
2588 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2593 GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video."));
2598 static GstStateChangeReturn
2599 gst_evaspixmapsink_change_state (GstElement *element, GstStateChange transition)
2601 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2602 GstEvasPixmapSink *evaspixmapsink;
2604 evaspixmapsink = GST_EVASPIXMAPSINK (element);
2606 switch (transition) {
2607 case GST_STATE_CHANGE_NULL_TO_READY:
2608 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_NULL_TO_READY");
2610 /* open drm to use gem */
2611 if (drm_init(evaspixmapsink)) {
2612 GST_ERROR_OBJECT (evaspixmapsink,"drm_init() failure");
2613 return GST_STATE_CHANGE_FAILURE;
2616 /* check if there exist evas image object, need to write code related to making internal evas image object */
2617 if (!is_evas_image_object (evaspixmapsink->eo)) {
2618 GST_ERROR_OBJECT (evaspixmapsink,"There is no evas image object..");
2619 return GST_STATE_CHANGE_FAILURE;
2622 /* Set xcontext and display */
2623 if (!evaspixmapsink->xcontext) {
2624 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
2625 if (!evaspixmapsink->xcontext) {
2626 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
2627 return GST_STATE_CHANGE_FAILURE;
2631 /* update object's par with calculated one if not set yet */
2632 if (!evaspixmapsink->par) {
2633 evaspixmapsink->par = g_new0 (GValue, 1);
2634 gst_value_init_and_copy (evaspixmapsink->par, evaspixmapsink->xcontext->par);
2635 GST_DEBUG_OBJECT (evaspixmapsink,"set calculated PAR on object's PAR");
2638 /* call XSynchronize with the current value of synchronous */
2639 GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
2640 XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
2641 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2644 case GST_STATE_CHANGE_READY_TO_PAUSED:
2645 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_PAUSED");
2648 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2649 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_PLAYING");
2656 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2658 switch (transition) {
2659 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2660 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PLAYING_TO_PAUSED");
2663 case GST_STATE_CHANGE_PAUSED_TO_READY:
2664 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_READY");
2665 evaspixmapsink->fps_n = 0;
2666 evaspixmapsink->fps_d = 1;
2667 GST_VIDEO_SINK_WIDTH (evaspixmapsink) = 0;
2668 GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = 0;
2669 drm_fini_close_gem_handle(evaspixmapsink);
2672 case GST_STATE_CHANGE_READY_TO_NULL:
2673 GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_NULL");
2674 gst_evaspixmapsink_reset(evaspixmapsink);
2676 drm_fini(evaspixmapsink);
2686 gst_evaspixmapsink_get_times (GstBaseSink *bsink, GstBuffer *buf, GstClockTime *start, GstClockTime *end)
2688 GstEvasPixmapSink *evaspixmapsink;
2690 evaspixmapsink = GST_EVASPIXMAPSINK (bsink);
2692 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
2693 *start = GST_BUFFER_TIMESTAMP (buf);
2694 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
2695 *end = *start + GST_BUFFER_DURATION (buf);
2697 if (evaspixmapsink->fps_n > 0) {
2699 gst_util_uint64_scale_int (GST_SECOND, evaspixmapsink->fps_d,
2700 evaspixmapsink->fps_n);
2706 static GstFlowReturn
2707 gst_evaspixmapsink_show_frame (GstVideoSink *vsink, GstBuffer *buf)
2709 GstEvasPixmapSink *evaspixmapsink;
2710 XV_PUTIMAGE_DATA_PTR img_data = NULL;
2711 SCMN_IMGB *scmn_imgb = NULL;
2714 MMTA_ACUM_ITEM_BEGIN("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2716 evaspixmapsink = GST_EVASPIXMAPSINK (vsink);
2718 if( evaspixmapsink->stop_video ) {
2719 GST_INFO_OBJECT (evaspixmapsink, "Stop video is TRUE. so skip show frame..." );
2723 if (!evaspixmapsink->evas_pixmap_buf) {
2724 GST_DEBUG_OBJECT (evaspixmapsink,"creating our evaspixmap buffer");
2725 format = gst_evaspixmapsink_get_format_from_caps(evaspixmapsink, GST_BUFFER_CAPS(buf));
2727 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2728 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2729 case GST_MAKE_FOURCC('S', '4', '2', '0'):
2730 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2731 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2732 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2733 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2734 if(scmn_imgb == NULL) {
2735 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2738 /* skip buffer if aligned size is smaller than size of caps */
2739 if (scmn_imgb->s[0] < evaspixmapsink->video_width || scmn_imgb->e[0] < evaspixmapsink->video_height) {
2740 GST_WARNING_OBJECT (evaspixmapsink,"invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
2741 evaspixmapsink->video_width, evaspixmapsink->video_height, scmn_imgb->s[0], scmn_imgb->e[0]);
2744 evaspixmapsink->aligned_width = scmn_imgb->s[0];
2745 evaspixmapsink->aligned_height = scmn_imgb->e[0];
2746 GST_DEBUG_OBJECT (evaspixmapsink,"video width,height[%dx%d]",evaspixmapsink->video_width, evaspixmapsink->video_height);
2747 GST_INFO_OBJECT (evaspixmapsink,"Use aligned width,height[%dx%d]",evaspixmapsink->aligned_width, evaspixmapsink->aligned_height);
2750 GST_INFO_OBJECT (evaspixmapsink,"Use original width,height of caps");
2753 evaspixmapsink->evas_pixmap_buf = gst_evaspixmap_buffer_new (evaspixmapsink, GST_BUFFER_CAPS (buf));
2754 if (!evaspixmapsink->evas_pixmap_buf) {
2755 /* The create method should have posted an informative error */
2758 if (evaspixmapsink->evas_pixmap_buf->size < GST_BUFFER_SIZE (buf)) {
2759 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"));
2760 gst_evaspixmap_buffer_destroy (evaspixmapsink->evas_pixmap_buf);
2761 evaspixmapsink->evas_pixmap_buf = NULL;
2766 switch (evaspixmapsink->evas_pixmap_buf->im_format) {
2767 /* Cases for specified formats of Samsung extension */
2768 case GST_MAKE_FOURCC('S', 'T', '1', '2'):
2769 case GST_MAKE_FOURCC('S', 'N', '1', '2'):
2770 case GST_MAKE_FOURCC('S', '4', '2', '0'):
2771 case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
2772 case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
2773 case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
2774 case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
2776 GST_DEBUG_OBJECT (evaspixmapsink,"Samsung extension display format activated. fourcc:%d", evaspixmapsink->evas_pixmap_buf->im_format);
2778 if (evaspixmapsink->evas_pixmap_buf->xvimage->data) {
2779 img_data = (XV_PUTIMAGE_DATA_PTR) evaspixmapsink->evas_pixmap_buf->xvimage->data;
2780 XV_PUTIMAGE_INIT_DATA(img_data);
2781 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
2782 if (scmn_imgb == NULL) {
2783 GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." );
2787 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
2788 img_data->YBuf = (unsigned int)scmn_imgb->p[0];
2789 img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
2790 img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
2791 img_data->BufType = XV_BUF_TYPE_LEGACY;
2792 if (!img_data->YBuf) {
2793 GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2796 } else { /* BUF_SHARE_METHOD_FD */
2797 /* set gem information to gem_info structure of handle and convert dma-buf fd into drm gem name */
2798 img_data->YBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[0]);
2799 img_data->CbBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[1]);
2800 img_data->CrBuf = drm_init_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[2]);
2801 img_data->BufType = XV_BUF_TYPE_DMABUF;
2802 if (!img_data->YBuf) {
2803 GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." );
2807 GST_LOG_OBJECT(evaspixmapsink, "YBuf[%d], CbBuf[%d], CrBuf[%d]",
2808 img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
2810 GST_WARNING_OBJECT (evaspixmapsink, "xvimage->data is NULL. skip buffer put..." );
2817 GST_DEBUG_OBJECT (evaspixmapsink,"Normal format activated. fourcc = %d", evaspixmapsink->evas_pixmap_buf->im_format);
2818 __ta__("evaspixmapsink memcpy in _show_frame", memcpy (evaspixmapsink->evas_pixmap_buf->xvimage->data, GST_BUFFER_DATA (buf),
2819 MIN (GST_BUFFER_SIZE (buf), evaspixmapsink->evas_pixmap_buf->size)););
2823 if (!gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf)) {
2824 MMTA_ACUM_ITEM_END("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2828 MMTA_ACUM_ITEM_END("evaspixmapsink gst_evaspixmapsink_show_frame()", FALSE);
2835 /* No image available. That's very bad ! */
2836 GST_WARNING_OBJECT (evaspixmapsink,"could not create image");
2837 return GST_FLOW_ERROR;
2842 gst_evaspixmapsink_event (GstBaseSink *sink, GstEvent *event)
2844 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (sink);
2846 switch (GST_EVENT_TYPE (event)) {
2847 case GST_EVENT_FLUSH_START:
2848 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_START");
2850 case GST_EVENT_FLUSH_STOP:
2851 GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_STOP");
2856 if (GST_BASE_SINK_CLASS (parent_class)->event) {
2857 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
2863 /* Interfaces stuff */
2866 gst_evaspixmapsink_interface_supported (GstImplementsInterface *iface, GType type)
2868 g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE);
2873 gst_evaspixmapsink_interface_init (GstImplementsInterfaceClass *klass)
2875 klass->supported = gst_evaspixmapsink_interface_supported;
2879 gst_evaspixmapsink_navigation_send_event (GstNavigation *navigation, GstStructure *structure)
2881 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (navigation);
2885 if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (evaspixmapsink)))) {
2887 GstVideoRectangle result;
2888 gdouble x, y, xscale = 1.0, yscale = 1.0;
2890 event = gst_event_new_navigation (structure);
2892 /* We take the flow_lock while we look at the window */
2893 g_mutex_lock (evaspixmapsink->flow_lock);
2895 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i ++) {
2896 if (!evaspixmapsink->xpixmap[i]) {
2897 g_mutex_unlock (evaspixmapsink->flow_lock);
2902 memcpy (&result, &evaspixmapsink->render_rect, sizeof (GstVideoRectangle));
2904 g_mutex_unlock (evaspixmapsink->flow_lock);
2906 /* We calculate scaling using the original video frames geometry to include
2907 pixel aspect ratio scaling. */
2908 xscale = (gdouble) evaspixmapsink->video_width / result.w;
2909 yscale = (gdouble) evaspixmapsink->video_height / result.h;
2911 /* Converting pointer coordinates to the non scaled geometry */
2912 if (gst_structure_get_double (structure, "pointer_x", &x)) {
2913 x = MIN (x, result.x + result.w);
2914 x = MAX (x - result.x, 0);
2915 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
2916 (gdouble) x * xscale, NULL);
2918 if (gst_structure_get_double (structure, "pointer_y", &y)) {
2919 y = MIN (y, result.y + result.h);
2920 y = MAX (y - result.y, 0);
2921 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
2922 (gdouble) y * yscale, NULL);
2925 gst_pad_send_event (peer, event);
2926 gst_object_unref (peer);
2931 gst_evaspixmapsink_navigation_init (GstNavigationInterface *iface)
2933 iface->send_event = gst_evaspixmapsink_navigation_send_event;
2937 gst_evaspixmapsink_colorbalance_list_channels (GstColorBalance *balance)
2939 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2941 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL);
2943 if (evaspixmapsink->xcontext)
2944 return evaspixmapsink->xcontext->channels_list;
2950 gst_evaspixmapsink_colorbalance_set_value (GstColorBalance *balance, GstColorBalanceChannel *channel, gint value)
2952 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2954 g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink));
2955 g_return_if_fail (channel->label != NULL);
2957 evaspixmapsink->cb_changed = TRUE;
2959 /* Normalize val to [-1000, 1000] */
2960 value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) /
2961 (double) (channel->max_value - channel->min_value));
2963 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2964 evaspixmapsink->hue = value;
2965 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2966 evaspixmapsink->saturation = value;
2967 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2968 evaspixmapsink->contrast = value;
2969 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2970 evaspixmapsink->brightness = value;
2972 g_warning ("got an unknown channel %s", channel->label);
2976 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
2980 gst_evaspixmapsink_colorbalance_get_value (GstColorBalance *balance, GstColorBalanceChannel *channel)
2982 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance);
2985 g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0);
2986 g_return_val_if_fail (channel->label != NULL, 0);
2988 if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
2989 value = evaspixmapsink->hue;
2990 } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
2991 value = evaspixmapsink->saturation;
2992 } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
2993 value = evaspixmapsink->contrast;
2994 } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
2995 value = evaspixmapsink->brightness;
2997 g_warning ("got an unknown channel %s", channel->label);
3000 /* Normalize val to [channel->min_value, channel->max_value] */
3001 value = channel->min_value + (channel->max_value - channel->min_value) * (value + 1000) / 2000;
3007 gst_evaspixmapsink_colorbalance_init (GstColorBalanceClass *iface)
3009 GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
3010 iface->list_channels = gst_evaspixmapsink_colorbalance_list_channels;
3011 iface->set_value = gst_evaspixmapsink_colorbalance_set_value;
3012 iface->get_value = gst_evaspixmapsink_colorbalance_get_value;
3015 static const GList *
3016 gst_evaspixmapsink_probe_get_properties (GstPropertyProbe *probe)
3018 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
3019 static GList *list = NULL;
3022 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
3023 list = g_list_append (list, g_object_class_find_property (klass, "autopaint-colorkey"));
3024 list = g_list_append (list, g_object_class_find_property (klass, "double-buffer"));
3025 list = g_list_append (list, g_object_class_find_property (klass, "colorkey"));
3032 gst_evaspixmapsink_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3034 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3038 case PROP_AUTOPAINT_COLORKEY:
3039 case PROP_DOUBLE_BUFFER:
3041 GST_DEBUG_OBJECT (evaspixmapsink,"probing device list and get capabilities");
3042 if (!evaspixmapsink->xcontext) {
3043 GST_DEBUG_OBJECT (evaspixmapsink,"generating xcontext");
3044 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
3045 if (!evaspixmapsink->xcontext) {
3046 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
3051 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3057 gst_evaspixmapsink_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3059 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3060 gboolean ret = FALSE;
3064 case PROP_AUTOPAINT_COLORKEY:
3065 case PROP_DOUBLE_BUFFER:
3067 if (evaspixmapsink->xcontext != NULL) {
3074 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3081 static GValueArray *
3082 gst_evaspixmapsink_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec)
3084 GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe);
3085 GValueArray *array = NULL;
3087 if (G_UNLIKELY (!evaspixmapsink->xcontext)) {
3088 GST_WARNING_OBJECT (evaspixmapsink,"we don't have any xcontext, can't "
3097 GValue value = { 0 };
3099 array = g_value_array_new (evaspixmapsink->xcontext->nb_adaptors);
3100 g_value_init (&value, G_TYPE_STRING);
3102 for (i = 0; i < evaspixmapsink->xcontext->nb_adaptors; i++) {
3103 gchar *adaptor_id_s = g_strdup_printf ("%u", i);
3105 g_value_set_string (&value, adaptor_id_s);
3106 g_value_array_append (array, &value);
3107 g_free (adaptor_id_s);
3109 g_value_unset (&value);
3112 case PROP_AUTOPAINT_COLORKEY:
3113 if (evaspixmapsink->have_autopaint_colorkey) {
3114 GValue value = { 0 };
3116 array = g_value_array_new (2);
3117 g_value_init (&value, G_TYPE_BOOLEAN);
3118 g_value_set_boolean (&value, FALSE);
3119 g_value_array_append (array, &value);
3120 g_value_set_boolean (&value, TRUE);
3121 g_value_array_append (array, &value);
3122 g_value_unset (&value);
3125 case PROP_DOUBLE_BUFFER:
3126 if (evaspixmapsink->have_double_buffer) {
3127 GValue value = { 0 };
3129 array = g_value_array_new (2);
3130 g_value_init (&value, G_TYPE_BOOLEAN);
3131 g_value_set_boolean (&value, FALSE);
3132 g_value_array_append (array, &value);
3133 g_value_set_boolean (&value, TRUE);
3134 g_value_array_append (array, &value);
3135 g_value_unset (&value);
3139 if (evaspixmapsink->have_colorkey) {
3140 GValue value = { 0 };
3142 array = g_value_array_new (1);
3143 g_value_init (&value, GST_TYPE_INT_RANGE);
3144 gst_value_set_int_range (&value, 0, 0xffffff);
3145 g_value_array_append (array, &value);
3146 g_value_unset (&value);
3150 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
3159 gst_evaspixmapsink_property_probe_interface_init (GstPropertyProbeInterface *iface)
3161 iface->get_properties = gst_evaspixmapsink_probe_get_properties;
3162 iface->probe_property = gst_evaspixmapsink_probe_probe_property;
3163 iface->needs_probe = gst_evaspixmapsink_probe_needs_probe;
3164 iface->get_values = gst_evaspixmapsink_probe_get_values;
3168 gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink)
3171 Pixmap *pixmap_id[NUM_OF_PIXMAP];
3172 int evas_object_width = 0;
3173 int evas_object_height = 0;
3174 int pixmap_width = 0;
3175 int pixmap_height = 0;
3176 unsigned int xw = 0;
3177 unsigned int xh = 0;
3180 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3182 if (!evaspixmapsink) {
3183 GST_ERROR_OBJECT (evaspixmapsink,"could not get evaspixmapsink..");
3186 g_mutex_lock (evaspixmapsink->flow_lock);
3188 /* Set xcontext and display */
3189 if (!evaspixmapsink->xcontext) {
3190 GST_WARNING_OBJECT (evaspixmapsink,"there's no xcontext, try to get one..");
3191 evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink);
3192 if (!evaspixmapsink->xcontext) {
3193 GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext..");
3198 dpy = evaspixmapsink->xcontext->disp;
3200 /* Set evas image object size */
3201 evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evas_object_width, &evas_object_height);
3202 if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3203 pixmap_width = evaspixmapsink->video_width;
3204 pixmap_height = evaspixmapsink->video_height;
3205 GST_INFO_OBJECT (evaspixmapsink,"set size to media src size(%dx%d)", pixmap_width, pixmap_height);
3208 g_mutex_lock (evaspixmapsink->x_lock);
3209 evaspixmapsink->sizediff_width = 0;
3210 evaspixmapsink->sizediff_height = 0;
3211 if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) {
3212 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, pixmap_width, pixmap_height, &xw, &xh);
3213 if (!evas_object_width || !evas_object_height) {
3214 evaspixmapsink->w = xw;
3215 evaspixmapsink->h = xh;
3217 evaspixmapsink->w = evas_object_width;
3218 evaspixmapsink->h = evas_object_height;
3220 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);
3222 XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, evas_object_width, evas_object_height, &xw, &xh);
3223 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);
3224 evaspixmapsink->w = xw;
3225 evaspixmapsink->h = xh;
3226 /* update difference of size information (between evas image object's and pixmap's) */
3227 evaspixmapsink->sizediff_width = xw - evas_object_width;
3228 evaspixmapsink->sizediff_height = xh - evas_object_height;
3231 /* create xpixmap structure */
3232 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3233 if (!evaspixmapsink->xpixmap[i]) {
3234 /* xpixmap can be created in this function only */
3235 evaspixmapsink->xpixmap[i] = g_new0 (GstXPixmap, 1);
3236 if(!evaspixmapsink->xpixmap[i]) {
3237 GST_ERROR_OBJECT (evaspixmapsink,"xpixmap is not valid..");
3239 for (j = 0; j < i; j++) {
3240 g_free(evaspixmapsink->xpixmap[j]);
3242 goto GO_OUT_OF_FUNC;
3249 GST_WARNING_OBJECT (evaspixmapsink,"skip creating pixmap..xw(%d),xh(%d)",xw,xh);
3250 goto GO_OUT_OF_FUNC;
3252 /* multiple pixmaps creation */
3253 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3254 pixmap_id[i] = XCreatePixmap(dpy, DefaultRootWindow(dpy), xw, xh, DefaultDepth(dpy, DefaultScreen(dpy)));
3255 if ( (int)pixmap_id[i] == BadAlloc || (int)pixmap_id[i] == BadDrawable || (int)pixmap_id[i] == BadValue ) {
3256 GST_ERROR_OBJECT (evaspixmapsink,"pixmap[%d] allocation error..", i);
3258 for (j = 0; j < i; j++) {
3259 XFreePixmap(dpy, pixmap_id[j]);
3261 goto GO_OUT_OF_FUNC;
3263 GST_INFO_OBJECT (evaspixmapsink,"creation pixmap_id[%d]:%d success", i, pixmap_id[i]);
3264 GST_DEBUG_OBJECT (evaspixmapsink,"evas_object_width(%d),evas_object_height(%d),pixmap:%d,depth:%d",
3265 evas_object_width,evas_object_height,pixmap_id[i],DefaultDepth(dpy, DefaultScreen(dpy)));
3269 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3270 if (evaspixmapsink->xpixmap[i]->pixmap && pixmap_id[i] != evaspixmapsink->xpixmap[i]->pixmap) {
3271 /* If we reset another pixmap, do below */
3272 GST_DEBUG_OBJECT (evaspixmapsink,"destroy previous pixmap(%d)",evaspixmapsink->xpixmap[i]->pixmap);
3273 if (evaspixmapsink->eo) {
3274 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3277 GST_LOG_OBJECT (evaspixmapsink,"Free pixmap(%d)", evaspixmapsink->xpixmap[i]->pixmap);
3278 XFreePixmap(dpy, evaspixmapsink->xpixmap[i]->pixmap);
3279 evaspixmapsink->xpixmap[i]->pixmap = 0;
3280 evaspixmapsink->xpixmap[i]->ref = 0;
3281 evaspixmapsink->xpixmap[i]->damaged_time = 0;
3283 XFreeGC (evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap[i]->gc);
3284 XSync (evaspixmapsink->xcontext->disp, FALSE);
3288 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3289 /* Set pixmap id and create GC */
3290 evaspixmapsink->xpixmap[i]->pixmap = pixmap_id[i];
3291 evaspixmapsink->xpixmap[i]->gc = XCreateGC(dpy, evaspixmapsink->xpixmap[i]->pixmap, 0,0);
3292 XSetForeground(dpy, evaspixmapsink->xpixmap[i]->gc,evaspixmapsink->xcontext->black);
3293 XFillRectangle(dpy, evaspixmapsink->xpixmap[i]->pixmap, evaspixmapsink->xpixmap[i]->gc, 0, 0, xw, xh);
3296 /* Create XDamage */
3297 if (evaspixmapsink->damage[i]) {
3298 GST_DEBUG_OBJECT (evaspixmapsink,"destroy previous damage(%d)",evaspixmapsink->damage[i]);
3299 XDamageDestroy(dpy, evaspixmapsink->damage[i]);
3300 evaspixmapsink->damage[i] = NULL;
3302 evaspixmapsink->damage[i] = XDamageCreate (dpy, evaspixmapsink->xpixmap[i]->pixmap, XDamageReportRawRectangles);
3304 GST_WARNING_OBJECT (evaspixmapsink,"xpixmap[%d]->(pixmap:%d,gc:%p), damage[%d]:%d",
3305 i, evaspixmapsink->xpixmap[i]->pixmap, evaspixmapsink->xpixmap[i]->gc, i, evaspixmapsink->damage[i]);
3310 /* Set flag for mapping evas object with xpixmap */
3311 evaspixmapsink->do_link = TRUE;
3312 ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink));
3314 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3316 g_mutex_unlock (evaspixmapsink->x_lock);
3317 g_mutex_unlock (evaspixmapsink->flow_lock);
3319 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3324 g_mutex_unlock (evaspixmapsink->x_lock);
3325 g_mutex_unlock (evaspixmapsink->flow_lock);
3330 gst_evaspixmapsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
3332 GstEvasPixmapSink *evaspixmapsink;
3333 g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3334 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3338 evaspixmapsink->hue = g_value_get_int (value);
3339 evaspixmapsink->cb_changed = TRUE;
3340 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3343 evaspixmapsink->contrast = g_value_get_int (value);
3344 evaspixmapsink->cb_changed = TRUE;
3345 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3347 case PROP_BRIGHTNESS:
3348 evaspixmapsink->brightness = g_value_get_int (value);
3349 evaspixmapsink->cb_changed = TRUE;
3350 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3352 case PROP_SATURATION:
3353 evaspixmapsink->saturation = g_value_get_int (value);
3354 evaspixmapsink->cb_changed = TRUE;
3355 gst_evaspixmapsink_update_colorbalance (evaspixmapsink);
3358 evaspixmapsink->display_name = g_strdup (g_value_get_string (value));
3360 case PROP_SYNCHRONOUS:
3361 evaspixmapsink->synchronous = g_value_get_boolean (value);
3362 if (evaspixmapsink->xcontext) {
3363 XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous);
3364 GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE");
3367 case PROP_PIXEL_ASPECT_RATIO:
3368 g_free (evaspixmapsink->par);
3369 evaspixmapsink->par = g_new0 (GValue, 1);
3370 g_value_init (evaspixmapsink->par, GST_TYPE_FRACTION);
3371 if (!g_value_transform (value, evaspixmapsink->par)) {
3372 g_warning ("Could not transform string to aspect ratio");
3373 gst_value_set_fraction (evaspixmapsink->par, 1, 1);
3375 GST_DEBUG_OBJECT (evaspixmapsink,"set PAR to %d/%d", gst_value_get_fraction_numerator (evaspixmapsink->par), gst_value_get_fraction_denominator (evaspixmapsink->par));
3378 evaspixmapsink->adaptor_no = atoi (g_value_get_string (value));
3380 case PROP_DOUBLE_BUFFER:
3381 evaspixmapsink->double_buffer = g_value_get_boolean (value);
3383 case PROP_AUTOPAINT_COLORKEY:
3384 evaspixmapsink->autopaint_colorkey = g_value_get_boolean (value);
3387 evaspixmapsink->colorkey = g_value_get_int (value);
3389 case PROP_PIXMAP_WIDTH:
3391 /* To do : code related to pixmap re-link */
3392 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3395 case PROP_PIXMAP_HEIGHT:
3397 /* To do : code related to pixmap re-link */
3398 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3401 case PROP_DISPLAY_GEOMETRY_METHOD:
3403 guint new_val = g_value_get_enum (value);
3404 if (evaspixmapsink->display_geometry_method != new_val) {
3405 evaspixmapsink->display_geometry_method = new_val;
3406 GST_INFO_OBJECT (evaspixmapsink,"Overlay geometry method update, display_geometry_method(%d)",evaspixmapsink->display_geometry_method);
3407 if( evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_FULL_SCREEN &&
3408 evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_CROPPED_FULL_SCREEN ) {
3409 if( evaspixmapsink->xcontext ) {
3410 g_mutex_lock( evaspixmapsink->flow_lock );
3412 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3413 if (evaspixmapsink->xpixmap[i]) {
3414 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3417 g_mutex_unlock( evaspixmapsink->flow_lock );
3420 if (evaspixmapsink->xcontext) {
3421 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
3426 case PROP_DST_ROI_X:
3427 evaspixmapsink->dst_roi.x = g_value_get_int (value);
3428 GST_INFO_OBJECT (evaspixmapsink, "ROI_X(%d)",evaspixmapsink->dst_roi.x );
3430 case PROP_DST_ROI_Y:
3431 evaspixmapsink->dst_roi.y = g_value_get_int (value);
3432 GST_INFO_OBJECT (evaspixmapsink, "ROI_Y(%d)",evaspixmapsink->dst_roi.y );
3434 case PROP_DST_ROI_W:
3435 evaspixmapsink->dst_roi.w = g_value_get_int (value);
3436 GST_INFO_OBJECT (evaspixmapsink, "ROI_W(%d)",evaspixmapsink->dst_roi.w );
3438 case PROP_DST_ROI_H:
3439 evaspixmapsink->dst_roi.h = g_value_get_int (value);
3440 GST_INFO_OBJECT (evaspixmapsink, "ROI_H(%d)",evaspixmapsink->dst_roi.h );
3442 case PROP_STOP_VIDEO:
3443 evaspixmapsink->stop_video = g_value_get_int (value);
3444 g_mutex_lock( evaspixmapsink->flow_lock );
3445 if( evaspixmapsink->stop_video ) {
3446 GST_INFO_OBJECT (evaspixmapsink, "XPixmap CLEAR when set video-stop property" );
3448 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3449 if (evaspixmapsink->xpixmap[i]) {
3450 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3454 g_mutex_unlock( evaspixmapsink->flow_lock );
3456 case PROP_EVAS_OBJECT:
3458 Evas_Object *eo = g_value_get_pointer (value);
3459 if ( is_evas_image_object (eo)) {
3460 if (!evaspixmapsink->epipe) {
3461 evaspixmapsink->epipe = ecore_pipe_add (ecore_pipe_callback_handler, evaspixmapsink);
3462 if (!evaspixmapsink->epipe) {
3463 GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: ecore_pipe_add() failed");
3467 if (eo != evaspixmapsink->eo) {
3468 /* delete evas object callbacks registrated on a former evas image object */
3469 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3470 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3471 if (evaspixmapsink->eo) {
3472 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3473 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3477 evaspixmapsink->eo = eo;
3478 /* add evas object callbacks on a new evas image object */
3479 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event, evaspixmapsink);
3480 evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, evaspixmapsink);
3481 GST_INFO_OBJECT (evaspixmapsink,"Evas Image Object(%x) is set", evaspixmapsink->eo);
3484 GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: value is not an evas image object");
3489 evaspixmapsink->flip = g_value_get_enum(value);
3491 case PROP_ROTATE_ANGLE:
3492 evaspixmapsink->rotate_angle = g_value_get_enum (value);
3496 gboolean visible = g_value_get_boolean (value);
3497 if (evaspixmapsink->visible != visible) {
3498 evaspixmapsink->visible = visible;
3499 if (evaspixmapsink->eo) {
3502 g_mutex_lock( evaspixmapsink->flow_lock );
3503 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3504 if (evaspixmapsink->xpixmap[i]) {
3505 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3508 g_mutex_unlock( evaspixmapsink->flow_lock );
3509 evas_object_hide(evaspixmapsink->eo);
3510 GST_INFO_OBJECT (evaspixmapsink,"object hide..");
3512 evas_object_show(evaspixmapsink->eo);
3513 GST_INFO_OBJECT (evaspixmapsink,"object show..");
3514 gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf);
3517 GST_WARNING_OBJECT (evaspixmapsink,"evas image object was not set");
3522 case PROP_ORIGIN_SIZE:
3523 evaspixmapsink->use_origin_size = g_value_get_boolean (value);
3524 GST_INFO_OBJECT (evaspixmapsink,"set origin-size (%d)",evaspixmapsink->use_origin_size);
3525 if (evaspixmapsink->previous_origin_size != evaspixmapsink->use_origin_size) {
3526 if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) {
3527 GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed...");
3529 evaspixmapsink->previous_origin_size = evaspixmapsink->use_origin_size;
3533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3539 gst_evaspixmapsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
3541 GstEvasPixmapSink *evaspixmapsink;
3543 g_return_if_fail (GST_IS_EVASPIXMAPSINK (object));
3545 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3549 g_value_set_int (value, evaspixmapsink->hue);
3552 g_value_set_int (value, evaspixmapsink->contrast);
3554 case PROP_BRIGHTNESS:
3555 g_value_set_int (value, evaspixmapsink->brightness);
3557 case PROP_SATURATION:
3558 g_value_set_int (value, evaspixmapsink->saturation);
3561 g_value_set_string (value, evaspixmapsink->display_name);
3563 case PROP_SYNCHRONOUS:
3564 g_value_set_boolean (value, evaspixmapsink->synchronous);
3566 case PROP_PIXEL_ASPECT_RATIO:
3567 if (evaspixmapsink->par) {
3568 if (!g_value_transform (evaspixmapsink->par, value)) {
3569 g_warning ("g_value_transform() failure");
3575 char *adaptor_no_s = g_strdup_printf ("%u", evaspixmapsink->adaptor_no);
3576 g_value_set_string (value, adaptor_no_s);
3577 g_free (adaptor_no_s);
3580 case PROP_DEVICE_NAME:
3581 if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->adaptors) {
3582 g_value_set_string (value,
3583 evaspixmapsink->xcontext->adaptors[evaspixmapsink->adaptor_no]);
3585 g_value_set_string (value, NULL);
3588 case PROP_DOUBLE_BUFFER:
3589 g_value_set_boolean (value, evaspixmapsink->double_buffer);
3591 case PROP_AUTOPAINT_COLORKEY:
3592 g_value_set_boolean (value, evaspixmapsink->autopaint_colorkey);
3595 g_value_set_int (value, evaspixmapsink->colorkey);
3597 case PROP_PIXMAP_WIDTH:
3599 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3602 case PROP_PIXMAP_HEIGHT:
3604 GST_LOG_OBJECT (evaspixmapsink, "Not supported");
3607 case PROP_DISPLAY_GEOMETRY_METHOD:
3608 g_value_set_enum (value, evaspixmapsink->display_geometry_method);
3610 case PROP_DST_ROI_X:
3611 g_value_set_int (value, evaspixmapsink->dst_roi.x);
3613 case PROP_DST_ROI_Y:
3614 g_value_set_int (value, evaspixmapsink->dst_roi.y);
3616 case PROP_DST_ROI_W:
3617 g_value_set_int (value, evaspixmapsink->dst_roi.w);
3619 case PROP_DST_ROI_H:
3620 g_value_set_int (value, evaspixmapsink->dst_roi.h);
3622 case PROP_STOP_VIDEO:
3623 g_value_set_int (value, evaspixmapsink->stop_video);
3625 case PROP_EVAS_OBJECT:
3626 g_value_set_pointer (value, evaspixmapsink->eo);
3629 g_value_set_enum(value, evaspixmapsink->flip);
3631 case PROP_ROTATE_ANGLE:
3632 g_value_set_enum (value, evaspixmapsink->rotate_angle);
3635 g_value_set_boolean (value, evaspixmapsink->visible);
3637 case PROP_ORIGIN_SIZE:
3638 g_value_set_boolean (value, evaspixmapsink->use_origin_size);
3641 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3647 gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink)
3649 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3652 GST_OBJECT_LOCK (evaspixmapsink);
3653 evaspixmapsink->running = FALSE;
3656 /* grab thread and mark it as NULL */
3657 thread = evaspixmapsink->event_thread;
3658 evaspixmapsink->event_thread = NULL;
3659 GST_OBJECT_UNLOCK (evaspixmapsink);
3661 /* Wait for our event thread to finish before we clean up our stuff. */
3663 g_thread_join (thread);
3666 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3667 if(evaspixmapsink->damage[i]) {
3668 XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage[i]);
3669 evaspixmapsink->damage[i] = NULL;
3672 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event);
3673 evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event);
3675 if (evaspixmapsink->evas_pixmap_buf) {
3676 gst_buffer_unref (GST_BUFFER_CAST (evaspixmapsink->evas_pixmap_buf));
3677 evaspixmapsink->evas_pixmap_buf = NULL;
3680 for (i = 0; i < evaspixmapsink->num_of_pixmaps; i++) {
3681 gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3682 gst_evaspixmapsink_xpixmap_destroy (evaspixmapsink, evaspixmapsink->xpixmap[i]);
3683 evaspixmapsink->xpixmap[i] = NULL;
3685 if (evaspixmapsink->eo) {
3686 evas_object_image_native_surface_set(evaspixmapsink->eo, NULL);
3687 evaspixmapsink->eo = NULL;
3690 evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y =
3691 evaspixmapsink->render_rect.w = evaspixmapsink->render_rect.h = 0;
3692 evaspixmapsink->have_render_rect = FALSE;
3694 gst_evaspixmapsink_xcontext_clear (evaspixmapsink);
3696 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3699 /* Finalize is called only once, dispose can be called multiple times.
3700 * We use mutexes and don't reset stuff to NULL here so let's register
3703 gst_evaspixmapsink_finalize (GObject *object)
3705 GstEvasPixmapSink *evaspixmapsink;
3706 evaspixmapsink = GST_EVASPIXMAPSINK (object);
3707 GST_DEBUG_OBJECT (evaspixmapsink,"[START]");
3709 if (evaspixmapsink->display_name) {
3710 g_free (evaspixmapsink->display_name);
3711 evaspixmapsink->display_name = NULL;
3713 if (evaspixmapsink->par) {
3714 g_free (evaspixmapsink->par);
3715 evaspixmapsink->par = NULL;
3717 if (evaspixmapsink->x_lock) {
3718 g_mutex_free (evaspixmapsink->x_lock);
3719 evaspixmapsink->x_lock = NULL;
3721 if (evaspixmapsink->flow_lock) {
3722 g_mutex_free (evaspixmapsink->flow_lock);
3723 evaspixmapsink->flow_lock = NULL;
3725 if (evaspixmapsink->pixmap_ref_lock) {
3726 g_mutex_free (evaspixmapsink->pixmap_ref_lock);
3727 evaspixmapsink->pixmap_ref_lock = NULL;
3729 if (evaspixmapsink->epipe) {
3730 ecore_pipe_del (evaspixmapsink->epipe);
3731 evaspixmapsink->epipe = NULL;
3734 GST_DEBUG_OBJECT (evaspixmapsink,"[END]");
3736 G_OBJECT_CLASS (parent_class)->finalize (object);
3738 MMTA_ACUM_ITEM_SHOW_RESULT_TO(MMTA_SHOW_FILE);
3743 gst_evaspixmapsink_init (GstEvasPixmapSink *evaspixmapsink)
3746 evaspixmapsink->display_name = NULL;
3747 evaspixmapsink->adaptor_no = 0;
3748 evaspixmapsink->xcontext = NULL;
3750 for (i = 0; i < NUM_OF_PIXMAP; i++) {
3751 evaspixmapsink->xpixmap[i] = NULL;
3752 evaspixmapsink->damage[i] = 0;
3755 evaspixmapsink->evas_pixmap_buf = NULL;
3757 evaspixmapsink->hue = evaspixmapsink->saturation = 0;
3758 evaspixmapsink->contrast = evaspixmapsink->brightness = 0;
3759 evaspixmapsink->cb_changed = FALSE;
3761 evaspixmapsink->fps_n = 0;
3762 evaspixmapsink->fps_d = 0;
3763 evaspixmapsink->video_width = 0;
3764 evaspixmapsink->video_height = 0;
3766 evaspixmapsink->x_lock = g_mutex_new ();
3767 evaspixmapsink->flow_lock = g_mutex_new ();
3768 evaspixmapsink->pixmap_ref_lock = g_mutex_new();
3770 evaspixmapsink->synchronous = FALSE;
3771 evaspixmapsink->double_buffer = TRUE;
3772 evaspixmapsink->par = NULL;
3773 evaspixmapsink->autopaint_colorkey = TRUE;
3774 evaspixmapsink->running = FALSE;
3776 /* on 16bit displays this becomes r,g,b = 1,2,3
3777 * on 24bit displays this becomes r,g,b = 8,8,16
3778 * as a port atom value
3780 evaspixmapsink->colorkey = (8 << 16) | (8 << 8) | 16;
3782 evaspixmapsink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
3783 evaspixmapsink->dst_roi.x = 0;
3784 evaspixmapsink->dst_roi.y = 0;
3785 evaspixmapsink->dst_roi.w = 0;
3786 evaspixmapsink->dst_roi.h = 0;
3787 evaspixmapsink->scr_w = 0;
3788 evaspixmapsink->scr_h = 0;
3789 evaspixmapsink->aligned_width = 0;
3790 evaspixmapsink->aligned_height = 0;
3791 evaspixmapsink->stop_video = FALSE;
3792 evaspixmapsink->eo = NULL;
3793 evaspixmapsink->epipe = NULL;
3794 evaspixmapsink->do_link = FALSE;
3795 evaspixmapsink->flip = DEF_DISPLAY_FLIP;
3796 evaspixmapsink->rotate_angle = DEGREE_0;
3797 evaspixmapsink->visible = TRUE;
3798 evaspixmapsink->use_origin_size = FALSE;
3799 evaspixmapsink->previous_origin_size = FALSE;
3801 evaspixmapsink->num_of_pixmaps = NUM_OF_PIXMAP;
3807 gst_evaspixmapsink_base_init (gpointer g_class)
3809 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3811 gst_element_class_set_details_simple (element_class,
3812 "EvasPixmapSink", "Sink/Video",
3813 "evas image object videosink based on Xv extension", "Sangchul Lee <sc11.lee@samsung.com>");
3815 gst_element_class_add_pad_template (element_class,
3816 gst_static_pad_template_get (&gst_evaspixmapsink_sink_template_factory));
3820 gst_evaspixmapsink_class_init (GstEvasPixmapSinkClass *klass)
3822 GObjectClass *gobject_class;
3823 GstElementClass *gstelement_class;
3824 GstBaseSinkClass *gstbasesink_class;
3825 GstVideoSinkClass *videosink_class;
3827 gobject_class = (GObjectClass *) klass;
3828 gstelement_class = (GstElementClass *) klass;
3829 gstbasesink_class = (GstBaseSinkClass *) klass;
3830 videosink_class = (GstVideoSinkClass *) klass;
3832 parent_class = g_type_class_peek_parent (klass);
3834 gobject_class->set_property = gst_evaspixmapsink_set_property;
3835 gobject_class->get_property = gst_evaspixmapsink_get_property;
3837 g_object_class_install_property (gobject_class, PROP_CONTRAST,
3838 g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
3839 -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3840 g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
3841 g_param_spec_int ("brightness", "Brightness",
3842 "The brightness of the video", -1000, 1000, 0,
3843 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3844 g_object_class_install_property (gobject_class, PROP_HUE,
3845 g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0,
3846 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3847 g_object_class_install_property (gobject_class, PROP_SATURATION,
3848 g_param_spec_int ("saturation", "Saturation",
3849 "The saturation of the video", -1000, 1000, 0,
3850 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3851 g_object_class_install_property (gobject_class, PROP_DISPLAY,
3852 g_param_spec_string ("display", "Display", "X Display name", NULL,
3853 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3854 g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
3855 g_param_spec_boolean ("synchronous", "Synchronous",
3856 "When enabled, runs "
3857 "the X display in synchronous mode. (used only for debugging)", FALSE,
3858 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3859 g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
3860 g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
3861 "The pixel aspect ratio of the device", "1/1",
3862 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3863 g_object_class_install_property (gobject_class, PROP_DEVICE,
3864 g_param_spec_string ("device", "Adaptor number",
3865 "The number of the video adaptor", "0",
3866 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3867 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
3868 g_param_spec_string ("device-name", "Adaptor name",
3869 "The name of the video adaptor", NULL,
3870 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3873 * GstEvasPixmapSink:double-buffer
3875 * Whether to double-buffer the output.
3879 g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER,
3880 g_param_spec_boolean ("double-buffer", "Double-buffer",
3881 "Whether to double-buffer the output", TRUE,
3882 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3884 * GstEvasPixmapSink:autopaint-colorkey
3886 * Whether to autofill overlay with colorkey
3890 g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY,
3891 g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey",
3892 "Whether to autofill overlay with colorkey", TRUE,
3893 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3895 * GstEvasPixmapSink:colorkey
3897 * Color to use for the overlay mask.
3901 g_object_class_install_property (gobject_class, PROP_COLORKEY,
3902 g_param_spec_int ("colorkey", "Colorkey",
3903 "Color to use for the overlay mask", G_MININT, G_MAXINT, 0,
3904 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3907 * GstEvasPixmapSink:pixmap-width
3909 * Actual width of the pixmap.
3911 g_object_class_install_property (gobject_class, PROP_PIXMAP_WIDTH,
3912 g_param_spec_uint64 ("pixmap-width", "pixmap-width", "Width of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3915 * GstEvasPixmapSink:pixmap-height
3917 * Actual height of the pixmap.
3919 g_object_class_install_property (gobject_class, PROP_PIXMAP_HEIGHT,
3920 g_param_spec_uint64 ("pixmap-height", "pixmap-height", "Height of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
3923 * GstEvasPixmapSink:display-geometry-method
3925 * Display geometrical method setting
3927 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
3928 g_param_spec_enum("display-geometry-method", "Display geometry method",
3929 "Geometrical method for display",
3930 GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD,
3931 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3934 * GstEvasPixmapSink:dst-roi-x
3936 * X value of Destination ROI
3938 g_object_class_install_property (gobject_class, PROP_DST_ROI_X,
3939 g_param_spec_int ("dst-roi-x", "Dst-ROI-X",
3940 "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3941 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3944 * GstEvasPixmapSink:dst-roi-y
3946 * Y value of Destination ROI
3948 g_object_class_install_property (gobject_class, PROP_DST_ROI_Y,
3949 g_param_spec_int ("dst-roi-y", "Dst-ROI-Y",
3950 "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3951 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3954 * GstEvasPixmapSink:dst-roi-w
3956 * W value of Destination ROI
3958 g_object_class_install_property (gobject_class, PROP_DST_ROI_W,
3959 g_param_spec_int ("dst-roi-w", "Dst-ROI-W",
3960 "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0,
3961 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3964 * GstEvasPixmapSink:dst-roi-h
3966 * H value of Destination ROI
3968 g_object_class_install_property (gobject_class, PROP_DST_ROI_H,
3969 g_param_spec_int ("dst-roi-h", "Dst-ROI-H",
3970 "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0,
3971 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3974 * GstEvasPixmapSink:stop-video
3976 * Stop video for releasing video source buffer
3978 g_object_class_install_property (gobject_class, PROP_STOP_VIDEO,
3979 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));
3982 * GstEvasPixmapSink:evas-object
3984 * Evas image object for rendering
3986 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
3987 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3990 * GstEvasPixmapSink:display-flip
3992 * Display flip setting
3994 g_object_class_install_property(gobject_class, PROP_FLIP,
3995 g_param_spec_enum("flip", "Display flip",
3997 GST_TYPE_EVASPIXMAPSINK_FLIP, DEF_DISPLAY_FLIP,
3998 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4001 * GstEvasPixmapSink:rotate
4003 * draw rotation angle setting
4005 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
4006 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));
4009 * GstEvasPixmapSink:visible
4011 * visible setting for a evas image object
4013 g_object_class_install_property (gobject_class, PROP_VISIBLE,
4014 g_param_spec_boolean ("visible", "Visible", "When setting it false, evas image object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4017 * GstEvasPixmapSink:origin-size
4019 * Set pixmap size with media source's width and height
4021 g_object_class_install_property (gobject_class, PROP_ORIGIN_SIZE,
4022 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));
4024 gobject_class->finalize = gst_evaspixmapsink_finalize;
4026 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_change_state);
4027 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_getcaps);
4028 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_setcaps);
4029 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_get_times);
4030 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_event);
4031 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_show_frame);
4034 /* Object typing & Creation */
4036 gst_evaspixmapsink_get_type (void)
4038 static GType evaspixmapsink_type = 0;
4040 if (!evaspixmapsink_type) {
4041 static const GTypeInfo evaspixmapsink_info = {
4042 sizeof (GstEvasPixmapSinkClass),
4043 gst_evaspixmapsink_base_init,
4045 (GClassInitFunc) gst_evaspixmapsink_class_init,
4048 sizeof (GstEvasPixmapSink),
4050 (GInstanceInitFunc) gst_evaspixmapsink_init,
4052 static const GInterfaceInfo iface_info = {
4053 (GInterfaceInitFunc) gst_evaspixmapsink_interface_init,
4057 static const GInterfaceInfo navigation_info = {
4058 (GInterfaceInitFunc) gst_evaspixmapsink_navigation_init,
4062 static const GInterfaceInfo colorbalance_info = {
4063 (GInterfaceInitFunc) gst_evaspixmapsink_colorbalance_init,
4067 static const GInterfaceInfo propertyprobe_info = {
4068 (GInterfaceInitFunc) gst_evaspixmapsink_property_probe_interface_init,
4072 evaspixmapsink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, "GstEvasPixmapSink", &evaspixmapsink_info, 0);
4074 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
4075 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_NAVIGATION, &navigation_info);
4076 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_COLOR_BALANCE, &colorbalance_info);
4077 g_type_add_interface_static (evaspixmapsink_type, GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
4079 /* register type and create class in a more safe place instead of at
4080 * runtime since the type registration and class creation is not
4082 g_type_class_ref (gst_evaspixmap_buffer_get_type ());
4085 return evaspixmapsink_type;
4089 plugin_init (GstPlugin *plugin)
4091 if (!gst_element_register (plugin, "evaspixmapsink", GST_RANK_NONE, GST_TYPE_EVASPIXMAPSINK)) {
4094 GST_DEBUG_CATEGORY_INIT (gst_debug_evaspixmapsink, "evaspixmapsink", 0, "evaspixmapsink element");
4095 GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
4100 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
4101 "evaspixmapsink","Evas image object render plugin using Xv extension", plugin_init,
4102 VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)