tizen 2.0 init
[framework/multimedia/gst-plugins-ext0.10.git] / evasimagesink / src / gstevasimagesink.c
1 /*
2  * evasimagesink
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
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)
11  * any later version.
12  *
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.
17  *
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
21  *
22  */
23
24 /**
25  * SECTION:element-evasimagesink
26  * Gstreamer Evas Video Sink - draw video on the given Evas Image Object
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <gst/gst.h>
35 #include <gst/video/video.h>
36 #include <gst/video/gstvideosink.h>
37 #include <Evas.h>
38 #include <Ecore.h>
39 #include <Ecore_X.h>
40
41 #include "gstevasimagesink.h"
42
43 #define CAP_WIDTH "width"
44 #define CAP_HEIGHT "height"
45
46 GST_DEBUG_CATEGORY_STATIC (gst_evas_image_sink_debug);
47 #define GST_CAT_DEFAULT gst_evas_image_sink_debug
48
49 /* Enumerations */
50 enum
51 {
52         /* FILL ME */
53         LAST_SIGNAL
54 };
55
56 enum
57 {
58         PROP_0,
59         PROP_EVAS_OBJECT,
60         PROP_EVAS_OBJECT_SHOW,
61 };
62
63 #define COLOR_DEPTH 4
64 #define GL_X11_ENGINE "gl_x11"
65
66 GMutex *instance_lock;
67 guint instance_lock_count;
68
69 static inline gboolean
70 is_evas_image_object (Evas_Object *obj)
71 {
72         const char *type;
73         if (!obj) {
74                 return FALSE;
75         }
76         type = evas_object_type_get (obj);
77         if (!type) {
78                 return FALSE;
79         }
80         if (strcmp (type, "image") == 0) {
81                 return TRUE;
82         }
83         return FALSE;
84 }
85
86 /* the capabilities of the inputs.
87  *
88  * BGRx format
89  */
90 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
91                 GST_PAD_SINK,
92                 GST_PAD_ALWAYS,
93                 GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx));
94
95 GST_BOILERPLATE (GstEvasImageSink, gst_evas_image_sink, GstVideoSink, GST_TYPE_VIDEO_SINK);
96
97 static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
98 static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
99 static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps);
100 static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf);
101 static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event);
102 static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition);
103 static void evas_image_sink_cb_del_eo (void *data, Evas *e, Evas_Object *obj, void *event_info);
104 static void evas_image_sink_cb_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
105
106 static void
107 gst_evas_image_sink_base_init (gpointer gclass)
108 {
109         GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
110
111         gst_element_class_set_details_simple (element_class,
112                 "EvasImageSink",
113                 "VideoSink",
114                 "Video sink element for evas image object",
115                 "Wonguk Jeong <wonguk.jeong@samsung.com>");
116
117         gst_element_class_add_pad_template (element_class,
118         gst_static_pad_template_get (&sink_factory));
119 }
120
121 static void
122 gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass)
123 {
124         GObjectClass *gobject_class;
125         GstBaseSinkClass *gstbasesink_class;
126         GstVideoSinkClass *gstvideosink_class;
127         GstElementClass *gstelement_class;
128
129         gobject_class = (GObjectClass *) klass;
130         gstbasesink_class = GST_BASE_SINK_CLASS (klass);
131         gstvideosink_class = GST_VIDEO_SINK_CLASS (klass);
132         gstelement_class = (GstElementClass *) klass;
133
134         gobject_class->set_property = gst_evas_image_sink_set_property;
135         gobject_class->get_property = gst_evas_image_sink_get_property;
136
137         g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
138                 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139         g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW,
140                 g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
141
142         gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame);
143         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps);
144         gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event);
145         gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state);
146 }
147
148 static void
149 gst_evas_image_sink_fini (gpointer data, GObject *obj)
150 {
151         GST_INFO ("enter");
152
153         GstEvasImageSink *esink = GST_EVASIMAGESINK (obj);
154         if (!esink) {
155                 return;
156         }
157         if (esink->oldbuf) {
158                 gst_buffer_unref (esink->oldbuf);
159         }
160
161         g_mutex_lock (instance_lock);
162         instance_lock_count--;
163         g_mutex_unlock (instance_lock);
164         if (instance_lock_count == 0) {
165                 g_mutex_free (instance_lock);
166                 instance_lock = NULL;
167         }
168 }
169
170 static void
171 evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte)
172 {
173         GstBuffer *buf;
174         GstEvasImageSink *esink = data;
175         void *img_data;
176
177         if (!data || !buffer) {
178                 return;
179         }
180         if (nbyte != sizeof (GstBuffer *)) {
181                 return;
182         }
183         if (!esink->eo) {
184                 return;
185         }
186         if (GST_STATE(esink) < GST_STATE_PAUSED) {
187                 GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink));
188                 return;
189         }
190
191         memcpy (&buf, buffer, sizeof (GstBuffer *));
192         if (!buf) {
193                 GST_ERROR ("There is no buffer");
194                 return;
195         }
196         if (esink->present_data_addr == -1) {
197                 /* if present_data_addr is -1, we don't use this member variable */
198         } else if (esink->present_data_addr != GST_BUFFER_DATA (buf)) {
199                 GST_WARNING ("skip rendering this buffer, present_data_addr:%x, GST_BUFFER_DATA(buf):%x", esink->present_data_addr,GST_BUFFER_DATA(buf));
200                 return;
201         }
202
203         MMTA_ACUM_ITEM_BEGIN("eavsimagesink _cb_pipe total", FALSE);
204
205         if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
206                         evas_object_image_size_set (esink->eo, esink->w, esink->h);
207                         GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)",esink->w,esink->h);
208                         esink->is_evas_object_size_set = TRUE;
209         }
210         if (esink->gl_zerocopy) {
211                 img_data = evas_object_image_data_get (esink->eo, EINA_TRUE);
212                 if (!img_data || !GST_BUFFER_DATA(buf)) {
213                         GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data");
214                         evas_object_image_data_set(esink->eo, img_data);
215                 } else {
216                         GST_DEBUG ("img_data(%x), GST_BUFFER_DATA(buf):%x, esink->w(%d),esink->h(%d)",img_data,GST_BUFFER_DATA(buf),esink->w,esink->h);
217                         __ta__("evasimagesink memcpy in _cb_pipe", memcpy (img_data, GST_BUFFER_DATA (buf), esink->w * esink->h * COLOR_DEPTH););
218                         evas_object_image_pixels_dirty_set (esink->eo, 1);
219                         evas_object_image_data_set(esink->eo, img_data);
220                 }
221                 gst_buffer_unref (buf);
222         } else {
223                 GST_DEBUG ("GST_BUFFER_DATA(buf):%x",GST_BUFFER_DATA(buf));
224                 evas_object_image_data_set (esink->eo, GST_BUFFER_DATA (buf));
225                 evas_object_image_pixels_dirty_set (esink->eo, 1);
226                 if (esink->oldbuf) {
227                         gst_buffer_unref(esink->oldbuf);
228                 }
229                 esink->oldbuf = buf;
230         }
231
232         MMTA_ACUM_ITEM_END("eavsimagesink _cb_pipe total", FALSE);
233 }
234
235 static void
236 gst_evas_image_sink_init (GstEvasImageSink *esink, GstEvasImageSinkClass *gclass)
237 {
238         GST_INFO ("enter");
239
240         esink->eo = NULL;
241         esink->epipe = NULL;
242         esink->object_show = FALSE;
243         esink->gl_zerocopy = FALSE;
244         esink->is_evas_object_size_set = FALSE;
245         esink->present_data_addr = -1;
246
247         if(!instance_lock) {
248                 instance_lock = g_mutex_new();
249         }
250         g_mutex_lock (instance_lock);
251         instance_lock_count++;
252         g_mutex_unlock (instance_lock);
253
254         g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL);
255 }
256
257 static void
258 evas_image_sink_cb_del_eo (void *data, Evas *e, Evas_Object *obj, void *event_info)
259 {
260         GstEvasImageSink *esink = data;
261         if (!esink) {
262                 return;
263         }
264
265         evas_object_event_callback_del (esink->eo, EVAS_CALLBACK_RESIZE, evas_image_sink_cb_resize_event);
266         if (esink->oldbuf) {
267                 gst_buffer_unref (esink->oldbuf);
268                 esink->oldbuf = NULL;
269                 esink->eo = NULL;
270         }
271 }
272
273 static void
274 evas_image_sink_cb_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
275 {
276         int w = 0;
277         int h = 0;
278         GstEvasImageSink *esink = data;
279         if (!esink) {
280                 return;
281         }
282
283         evas_object_geometry_get(esink->eo, NULL, NULL, &w, &h);
284         if (!w || !h) {
285                 GST_WARNING ("evas object size (w:%d,h:%d) was not set",w,h);
286         } else {
287                 evas_object_image_fill_set(esink->eo, 0, 0, w, h);
288                 GST_DEBUG ("evas object fill set (w:%d,h:%d)",w,h);
289         }
290 }
291
292 static int
293 evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h)
294 {
295         gboolean r;
296         int width, height;
297         GstStructure *s;
298
299         if (!caps || !w || !h) {
300                 return -1;
301         }
302         s = gst_caps_get_structure (caps, 0);
303         if (!s) {
304                 return -1;
305         }
306
307         r = gst_structure_get_int (s, CAP_WIDTH, &width);
308         if (r == FALSE) {
309                 return -1;
310         }
311
312         r = gst_structure_get_int (s, CAP_HEIGHT, &height);
313         if (r == FALSE) {
314                 return -1;
315         }
316
317         *w = width;
318         *h = height;
319         return 0;
320 }
321
322 static gboolean
323 is_zerocopy_supported (Evas *e)
324 {
325         Eina_List *engines, *l;
326         int cur_id;
327         int id;
328         char *name;
329
330         if (!e) {
331                 return FALSE;
332         }
333
334         engines = evas_render_method_list ();
335         if (!engines) {
336                 return FALSE;
337         }
338
339         cur_id = evas_output_method_get (e);
340
341         EINA_LIST_FOREACH (engines, l, name) {
342                 id = evas_render_method_lookup (name);
343                 if (name && id == cur_id) {
344                         if (!strcmp (name, GL_X11_ENGINE)) {
345                                 return TRUE;
346                         }
347                         break;
348                 }
349         }
350         return FALSE;
351 }
352
353 static int
354 evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event)
355 {
356         const GstStructure *st;
357         guint st_data_addr = 0;
358         gint st_data_width = 0;
359         gint st_data_height = 0;
360
361         g_return_val_if_fail (event != NULL, FALSE);
362         g_return_val_if_fail (esink != NULL, FALSE);
363
364         if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) {
365                 GST_WARNING ("it's not a custom downstream oob event");
366                 return -1;
367         }
368         st = gst_event_get_structure (event);
369         if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) {
370                 GST_WARNING ("structure in a given event is not proper");
371                 return -1;
372         }
373         if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) {
374                 GST_WARNING ("parsing data-addr failed");
375                 return -1;
376         }
377         esink->present_data_addr = st_data_addr;
378
379         return 0;
380 }
381
382 static gboolean
383 gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event)
384 {
385         GstEvasImageSink *esink = GST_EVASIMAGESINK (sink);
386         GstMessage *msg;
387         gchar *str;
388
389         switch (GST_EVENT_TYPE (event)) {
390                 case GST_EVENT_FLUSH_START:
391                         GST_DEBUG ("GST_EVENT_FLUSH_START");
392                         break;
393                 case GST_EVENT_FLUSH_STOP:
394                         GST_DEBUG ("GST_EVENT_FLUSH_STOP");
395                         break;
396                 case GST_EVENT_EOS:
397                         GST_DEBUG ("GST_EVENT_EOS");
398                         break;
399                 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
400                         if(!evas_image_sink_event_parse_data(esink, event)) {
401                                 GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr);
402                         } else {
403                                 GST_ERROR ("evas_image_sink_event_parse_data() failed");
404                         }
405                         break;
406                 default:
407                         break;
408         }
409         if (GST_BASE_SINK_CLASS (parent_class)->event) {
410                 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
411         } else {
412                 return TRUE;
413         }
414 }
415
416 static GstStateChangeReturn
417 gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition)
418 {
419         GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS;
420         GstEvasImageSink *esink = NULL;
421         esink = GST_EVASIMAGESINK(element);
422         int ret = 0;
423
424         if(!esink) {
425                 GST_ERROR("can not get evasimagesink from element");
426         }
427         switch (transition) {
428                 case GST_STATE_CHANGE_NULL_TO_READY:
429                         GST_INFO ("*** STATE_CHANGE_NULL_TO_READY ***");
430                         break;
431                 case GST_STATE_CHANGE_READY_TO_PAUSED:
432                         GST_INFO ("*** STATE_CHANGE_READY_TO_PAUSED ***");
433                         break;
434                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
435                         GST_INFO ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***");
436                         break;
437                 default:
438                         break;
439         }
440
441         ret_state = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
442
443         switch (transition) {
444                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
445                         GST_INFO ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***");
446                         break;
447                 case GST_STATE_CHANGE_PAUSED_TO_READY:
448                         GST_INFO ("*** STATE_CHANGE_PAUSED_TO_READY ***");
449                         break;
450                 case GST_STATE_CHANGE_READY_TO_NULL:
451                         GST_INFO ("*** STATE_CHANGE_READY_TO_NULL ***");
452                         evas_object_event_callback_del(esink->eo, EVAS_CALLBACK_DEL, evas_image_sink_cb_del_eo);
453                         evas_object_event_callback_del(esink->eo, EVAS_CALLBACK_RESIZE, evas_image_sink_cb_resize_event);
454                         if (esink->epipe) {
455                                 ecore_pipe_del (esink->epipe);
456                                 esink->epipe = NULL;
457                         }
458                         break;
459                 default:
460                         break;
461         }
462
463         return ret_state;
464 }
465
466 static void
467 gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
468 {
469         GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
470         Evas_Object *eo;
471
472         g_mutex_lock (instance_lock);
473
474         switch (prop_id) {
475         case PROP_EVAS_OBJECT:
476                 eo = g_value_get_pointer (value);
477                 if (is_evas_image_object (eo)) {
478                         if (eo != esink->eo) {
479                                 /* delete evas object callbacks registrated on a former evas image object */
480                                 evas_object_event_callback_del (esink->eo, EVAS_CALLBACK_DEL, evas_image_sink_cb_del_eo);
481                                 evas_object_event_callback_del (esink->eo, EVAS_CALLBACK_RESIZE, evas_image_sink_cb_resize_event);
482
483                                 esink->eo = eo;
484
485                                 /* add evas object callbacks on a new evas image object */
486                                 evas_object_event_callback_add (esink->eo, EVAS_CALLBACK_DEL, evas_image_sink_cb_del_eo, esink);
487                                 evas_object_event_callback_add (esink->eo, EVAS_CALLBACK_RESIZE, evas_image_sink_cb_resize_event, esink);
488
489                                 esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo));
490                                 if (esink->gl_zerocopy) {
491                                         evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
492                                         GST_DEBUG("Enable gl zerocopy");
493                                 }
494                                 GST_DEBUG("Evas Image Object(%x) is set",esink->eo);
495                                 evas_object_show(esink->eo);
496                                 esink->object_show = TRUE;
497                         }
498                 } else {
499                         GST_ERROR ("Cannot set evas-object property: value is not an evas image object");
500                 }
501                 break;
502
503         case PROP_EVAS_OBJECT_SHOW:
504                 esink->object_show = g_value_get_boolean (value);
505                 if( !is_evas_image_object(esink->eo) ) {
506                         GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n");
507                         break;
508                 }
509                 if(!esink->object_show) {
510                         evas_object_hide(esink->eo);
511                         GST_INFO ("object hide..");
512                 } else {
513                         evas_object_show(esink->eo);
514                         GST_INFO ("object show..");
515                 }
516                 break;
517
518         default:
519                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
520                 break;
521         }
522
523         g_mutex_unlock (instance_lock);
524 }
525
526 static void
527 gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
528 {
529         GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
530
531         switch (prop_id) {
532         case PROP_EVAS_OBJECT:
533                 g_value_set_pointer (value, esink->eo);
534                 break;
535         case PROP_EVAS_OBJECT_SHOW:
536                 g_value_set_boolean (value, esink->object_show);
537                 break;
538         default:
539                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
540                 break;
541         }
542 }
543
544 static gboolean
545 gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps)
546 {
547         int r;
548         int w, h;
549         GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink);
550
551         esink->is_evas_object_size_set = FALSE;
552         r = evas_image_sink_get_size_from_caps (caps, &w, &h);
553         if (!r) {
554                 esink->w = w;
555                 esink->h = h;
556                 GST_DEBUG ("set size w(%d), h(%d)", w, h);
557         }
558         return TRUE;
559 }
560
561 static GstFlowReturn
562 gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf)
563 {
564         GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink);
565         Eina_Bool r;
566
567         g_mutex_lock (instance_lock);
568         if (esink->present_data_addr == -1) {
569                 /* if present_data_addr is -1, we don't use this member variable */
570         } else if (esink->present_data_addr != GST_BUFFER_DATA (buf)) {
571                 GST_WARNING ("skip rendering this buffer, present_data_addr:%x, GST_BUFFER_DATA(buf):%x", esink->present_data_addr,GST_BUFFER_DATA(buf));
572                 g_mutex_unlock (instance_lock);
573                 return;
574         }
575         if (!esink->epipe) {
576                 esink->epipe = ecore_pipe_add (evas_image_sink_cb_pipe, esink);
577                 if (!esink->epipe) {
578                         GST_ERROR ("ecore-pipe create failed");
579                         return GST_FLOW_ERROR;
580                 }
581         }
582         if (esink->object_show) {
583                 gst_buffer_ref (buf);
584                 __ta__("evasimagesink ecore_pipe_write", r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *)););
585                 if (r == EINA_FALSE)  {
586                         gst_buffer_unref (buf);
587                 }
588                 GST_DEBUG ("after ecore_pipe_write()");
589         } else {
590                 GST_DEBUG ("skip ecore_pipe_write()");
591         }
592         g_mutex_unlock (instance_lock);
593         return GST_FLOW_OK;
594 }
595
596 static gboolean
597 evas_image_sink_init (GstPlugin *evasimagesink)
598 {
599         GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink");
600
601         return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK);
602 }
603
604 #ifndef PACKAGE
605 #define PACKAGE "gstevasimagesink-plugin-package"
606 #endif
607
608 GST_PLUGIN_DEFINE (
609         GST_VERSION_MAJOR,
610         GST_VERSION_MINOR,
611         "evasimagesink",
612         "Evas image object based videosink",
613         evas_image_sink_init,
614         VERSION,
615         "LGPL",
616         "Samsung Electronics Co",
617         "http://www.samsung.com/"
618 )