4 * Copyright (c) 2000 - 2011 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
25 * SECTION:element-evasimagesink
26 * Gstreamer Evas Video Sink - draw video on the given Evas Image Object
33 #include <sys/types.h>
35 #include <gst/video/video.h>
36 #include <gst/video/gstvideosink.h>
41 #include "gstevasimagesink.h"
43 #define CAP_WIDTH "width"
44 #define CAP_HEIGHT "height"
46 GST_DEBUG_CATEGORY_STATIC (gst_evas_image_sink_debug);
47 #define GST_CAT_DEFAULT gst_evas_image_sink_debug
69 #define GL_X11_ENGINE "gl_x11"
70 #define DO_RENDER_FROM_FIMC 1
71 #define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar)
73 #define EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object, x_usr_data ) \
76 if (x_evas_image_object) { \
77 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event, x_usr_data); \
78 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, x_usr_data); \
82 #define EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object ) \
85 if (x_evas_image_object) { \
86 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event); \
87 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); \
91 GMutex *instance_lock;
92 guint instance_lock_count;
94 static inline gboolean
95 is_evas_image_object (Evas_Object *obj)
101 type = evas_object_type_get (obj);
105 if (strcmp (type, "image") == 0) {
111 /* the capabilities of the inputs.
115 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
118 GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx));
120 GST_BOILERPLATE (GstEvasImageSink, gst_evas_image_sink, GstVideoSink, GST_TYPE_VIDEO_SINK);
122 static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
123 static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
124 static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps);
125 static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf);
126 static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event);
127 static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition);
128 static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
129 static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
132 gst_evas_image_sink_base_init (gpointer gclass)
134 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
136 gst_element_class_set_details_simple (element_class,
139 "Video sink element for evas image object",
140 "Samsung Electronics <www.samsung.com>");
142 gst_element_class_add_pad_template (element_class,
143 gst_static_pad_template_get (&sink_factory));
147 gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass)
149 GObjectClass *gobject_class;
150 GstBaseSinkClass *gstbasesink_class;
151 GstVideoSinkClass *gstvideosink_class;
152 GstElementClass *gstelement_class;
154 gobject_class = (GObjectClass *) klass;
155 gstbasesink_class = GST_BASE_SINK_CLASS (klass);
156 gstvideosink_class = GST_VIDEO_SINK_CLASS (klass);
157 gstelement_class = (GstElementClass *) klass;
159 gobject_class->set_property = gst_evas_image_sink_set_property;
160 gobject_class->get_property = gst_evas_image_sink_get_property;
162 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
163 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
164 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW,
165 g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
167 gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame);
168 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps);
169 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event);
170 gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state);
174 gst_evas_image_sink_fini (gpointer data, GObject *obj)
176 GST_DEBUG ("[ENTER]");
178 GstEvasImageSink *esink = GST_EVASIMAGESINK (obj);
183 gst_buffer_unref (esink->oldbuf);
187 evas_object_image_data_set(esink->eo, NULL);
190 g_mutex_lock (instance_lock);
191 instance_lock_count--;
192 g_mutex_unlock (instance_lock);
193 if (instance_lock_count == 0) {
194 g_mutex_free (instance_lock);
195 instance_lock = NULL;
198 GST_DEBUG ("[LEAVE]");
202 evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte)
205 GstEvasImageSink *esink = data;
208 GST_DEBUG ("[ENTER]");
210 if (!esink || !esink->eo) {
213 if (nbyte == SIZE_FOR_UPDATE_VISIBILITY) {
214 if(!esink->object_show) {
215 evas_object_hide(esink->eo);
216 GST_INFO ("object hide..");
218 evas_object_show(esink->eo);
219 GST_INFO ("object show..");
221 GST_DEBUG ("[LEAVE]");
224 if (!buffer || nbyte != sizeof (GstBuffer *)) {
227 if (GST_STATE(esink) < GST_STATE_PAUSED) {
228 GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink));
232 memcpy (&buf, buffer, sizeof (GstBuffer *));
234 GST_ERROR ("There is no buffer");
237 if (esink->present_data_addr == -1) {
238 /* if present_data_addr is -1, we don't use this member variable */
239 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
240 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
244 MMTA_ACUM_ITEM_BEGIN("eavsimagesink _cb_pipe total", FALSE);
246 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
247 evas_object_image_size_set (esink->eo, esink->w, esink->h);
248 GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)",esink->w,esink->h);
249 esink->is_evas_object_size_set = TRUE;
251 if (esink->gl_zerocopy) {
252 img_data = evas_object_image_data_get (esink->eo, EINA_TRUE);
253 if (!img_data || !GST_BUFFER_DATA(buf)) {
254 GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data");
255 evas_object_image_data_set(esink->eo, img_data);
257 GST_DEBUG ("img_data(%x), GST_BUFFER_DATA(buf):%x, esink->w(%d),esink->h(%d), esink->eo(%x)",img_data,GST_BUFFER_DATA(buf),esink->w,esink->h,esink->eo);
258 __ta__("evasimagesink memcpy in _cb_pipe", memcpy (img_data, GST_BUFFER_DATA (buf), esink->w * esink->h * COLOR_DEPTH););
259 evas_object_image_pixels_dirty_set (esink->eo, 1);
260 evas_object_image_data_set(esink->eo, img_data);
262 gst_buffer_unref (buf);
264 GST_DEBUG ("GST_BUFFER_DATA(buf):%x, esink->eo(%x)",GST_BUFFER_DATA(buf),esink->eo);
265 evas_object_image_data_set (esink->eo, GST_BUFFER_DATA (buf));
266 evas_object_image_pixels_dirty_set (esink->eo, 1);
268 gst_buffer_unref(esink->oldbuf);
273 MMTA_ACUM_ITEM_END("eavsimagesink _cb_pipe total", FALSE);
275 GST_DEBUG ("[LEAVE]");
279 gst_evas_image_sink_init (GstEvasImageSink *esink, GstEvasImageSinkClass *gclass)
281 GST_DEBUG ("[ENTER]");
285 esink->object_show = FALSE;
286 esink->update_visibility = UPDATE_FALSE;
287 esink->gl_zerocopy = FALSE;
288 esink->is_evas_object_size_set = FALSE;
289 esink->present_data_addr = -1;
292 instance_lock = g_mutex_new();
294 g_mutex_lock (instance_lock);
295 instance_lock_count++;
296 g_mutex_unlock (instance_lock);
298 g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL);
300 GST_DEBUG ("[LEAVE]");
304 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
306 GST_DEBUG ("[ENTER]");
308 GstEvasImageSink *esink = data;
313 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
315 gst_buffer_unref (esink->oldbuf);
316 esink->oldbuf = NULL;
320 evas_object_image_data_set(esink->eo, NULL);
324 GST_DEBUG ("[LEAVE]");
328 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
333 GST_DEBUG ("[ENTER]");
335 GstEvasImageSink *esink = data;
340 evas_object_geometry_get(esink->eo, NULL, NULL, &w, &h);
342 GST_WARNING ("evas object size (w:%d,h:%d) was not set",w,h);
344 evas_object_image_fill_set(esink->eo, 0, 0, w, h);
345 GST_DEBUG ("evas object fill set (w:%d,h:%d)",w,h);
348 GST_DEBUG ("[LEAVE]");
352 evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h)
358 if (!caps || !w || !h) {
361 s = gst_caps_get_structure (caps, 0);
366 r = gst_structure_get_int (s, CAP_WIDTH, &width);
371 r = gst_structure_get_int (s, CAP_HEIGHT, &height);
382 is_zerocopy_supported (Evas *e)
384 Eina_List *engines, *l;
393 engines = evas_render_method_list ();
398 cur_id = evas_output_method_get (e);
400 EINA_LIST_FOREACH (engines, l, name) {
401 id = evas_render_method_lookup (name);
402 if (name && id == cur_id) {
403 if (!strcmp (name, GL_X11_ENGINE)) {
413 evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event)
415 const GstStructure *st;
416 guint st_data_addr = 0;
417 gint st_data_width = 0;
418 gint st_data_height = 0;
420 g_return_val_if_fail (event != NULL, FALSE);
421 g_return_val_if_fail (esink != NULL, FALSE);
423 if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) {
424 GST_WARNING ("it's not a custom downstream oob event");
427 st = gst_event_get_structure (event);
428 if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) {
429 GST_WARNING ("structure in a given event is not proper");
432 if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) {
433 GST_WARNING ("parsing data-addr failed");
436 esink->present_data_addr = st_data_addr;
442 gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event)
444 GstEvasImageSink *esink = GST_EVASIMAGESINK (sink);
448 switch (GST_EVENT_TYPE (event)) {
449 case GST_EVENT_FLUSH_START:
450 GST_DEBUG ("GST_EVENT_FLUSH_START");
452 case GST_EVENT_FLUSH_STOP:
453 GST_DEBUG ("GST_EVENT_FLUSH_STOP");
456 GST_DEBUG ("GST_EVENT_EOS");
458 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
459 if(!evas_image_sink_event_parse_data(esink, event)) {
460 GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr);
462 GST_ERROR ("evas_image_sink_event_parse_data() failed");
468 if (GST_BASE_SINK_CLASS (parent_class)->event) {
469 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
475 static GstStateChangeReturn
476 gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition)
478 GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS;
479 GstEvasImageSink *esink = NULL;
480 esink = GST_EVASIMAGESINK(element);
484 GST_ERROR("can not get evasimagesink from element");
485 return GST_STATE_CHANGE_FAILURE;
488 switch (transition) {
489 case GST_STATE_CHANGE_NULL_TO_READY:
490 GST_INFO ("*** STATE_CHANGE_NULL_TO_READY ***");
492 case GST_STATE_CHANGE_READY_TO_PAUSED:
493 GST_INFO ("*** STATE_CHANGE_READY_TO_PAUSED ***");
495 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
496 GST_INFO ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***");
502 ret_state = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
504 switch (transition) {
505 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
506 GST_INFO ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***");
508 case GST_STATE_CHANGE_PAUSED_TO_READY:
509 GST_INFO ("*** STATE_CHANGE_PAUSED_TO_READY ***");
511 case GST_STATE_CHANGE_READY_TO_NULL:
512 GST_INFO ("*** STATE_CHANGE_READY_TO_NULL ***");
513 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
515 ecore_pipe_del (esink->epipe);
527 gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
529 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
532 g_mutex_lock (instance_lock);
535 case PROP_EVAS_OBJECT:
536 eo = g_value_get_pointer (value);
537 if (is_evas_image_object (eo)) {
538 if (eo != esink->eo) {
541 /* delete evas object callbacks registrated on a previous evas image object */
542 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
544 /* add evas object callbacks on a new evas image object */
545 EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink);
547 esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo));
548 if (esink->gl_zerocopy) {
549 evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
550 GST_DEBUG("Enable gl zerocopy");
552 GST_DEBUG("Evas Image Object(%x) is set",esink->eo);
553 esink->is_evas_object_size_set = FALSE;
554 esink->object_show = TRUE;
555 esink->update_visibility = UPDATE_TRUE;
557 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
558 if (r == EINA_FALSE) {
559 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility\n");
564 GST_ERROR ("Cannot set evas-object property: value is not an evas image object");
568 case PROP_EVAS_OBJECT_SHOW:
571 esink->object_show = g_value_get_boolean (value);
572 if( !is_evas_image_object(esink->eo) ) {
573 GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n");
576 esink->update_visibility = UPDATE_TRUE;
578 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
579 if (r == EINA_FALSE) {
580 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility)\n");
586 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
590 g_mutex_unlock (instance_lock);
594 gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
596 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
599 case PROP_EVAS_OBJECT:
600 g_value_set_pointer (value, esink->eo);
602 case PROP_EVAS_OBJECT_SHOW:
603 g_value_set_boolean (value, esink->object_show);
606 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
612 gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps)
616 GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink);
618 esink->is_evas_object_size_set = FALSE;
619 r = evas_image_sink_get_size_from_caps (caps, &w, &h);
623 GST_DEBUG ("set size w(%d), h(%d)", w, h);
629 gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf)
631 GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink);
634 g_mutex_lock (instance_lock);
635 if (esink->present_data_addr == -1) {
636 /* if present_data_addr is -1, we don't use this member variable */
637 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
638 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
639 g_mutex_unlock (instance_lock);
643 esink->epipe = ecore_pipe_add (evas_image_sink_cb_pipe, esink);
645 GST_ERROR ("ecore-pipe create failed");
646 g_mutex_unlock (instance_lock);
647 return GST_FLOW_ERROR;
650 if (esink->object_show) {
651 gst_buffer_ref (buf);
652 __ta__("evasimagesink ecore_pipe_write", r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *)););
653 if (r == EINA_FALSE) {
654 gst_buffer_unref (buf);
656 GST_DEBUG ("ecore_pipe_write() was called with GST_BUFFER_DATA(buf):%x", GST_BUFFER_DATA(buf));
658 GST_DEBUG ("skip ecore_pipe_write()");
660 g_mutex_unlock (instance_lock);
665 evas_image_sink_init (GstPlugin *evasimagesink)
667 GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink");
669 return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK);
673 #define PACKAGE "gstevasimagesink-plugin-package"
680 "Evas image object based videosink",
681 evas_image_sink_init,
684 "Samsung Electronics Co",
685 "http://www.samsung.com/"