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"
47 GST_DEBUG_CATEGORY_STATIC (gst_evas_image_sink_debug);
48 #define GST_CAT_DEFAULT gst_evas_image_sink_debug
61 PROP_EVAS_OBJECT_SHOW,
62 #ifdef USE_TBM_SURFACE
64 PROP_DISPLAY_GEOMETRY_METHOD,
65 PROP_ENABLE_FLUSH_BUFFER,
77 #define GL_X11_ENGINE "gl_x11"
78 #define DO_RENDER_FROM_FIMC 1
79 #define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar)
81 #ifdef USE_TBM_SURFACE
82 #define MAX_ECOREPIPE_BUFFER_CNT 4
83 #define DEBUGLOG_DEFAULT_COUNT 8
84 #define SIZE_FOR_NATIVE_INDEX sizeof(gint)
86 /* max channel count *********************************************************/
87 #define SCMN_IMGB_MAX_PLANE (4)
89 /* image buffer definition ***************************************************
91 +------------------------------------------+ ---
94 | +---------------------------+ --- | |
96 | |<---------- w[] ---------->| | | |
104 | +---------------------------+ --- | |
106 +------------------------------------------+ ---
108 |<----------------- s[] ------------------>|
113 /* width of each image plane */
114 int w[SCMN_IMGB_MAX_PLANE];
115 /* height of each image plane */
116 int h[SCMN_IMGB_MAX_PLANE];
117 /* stride of each image plane */
118 int s[SCMN_IMGB_MAX_PLANE];
119 /* elevation of each image plane */
120 int e[SCMN_IMGB_MAX_PLANE];
121 /* user space address of each image plane */
122 void *a[SCMN_IMGB_MAX_PLANE];
123 /* physical address of each image plane, if needs */
124 void *p[SCMN_IMGB_MAX_PLANE];
125 /* color space type of image */
127 /* left postion, if needs */
129 /* top position, if needs */
131 /* to align memory */
136 int fd[SCMN_IMGB_MAX_PLANE];
137 /* buffer share method */
138 int buf_share_method;
139 /* Y plane size in case of ST12 */
141 /* UV plane size in case of ST12 */
143 /* Tizen buffer object */
144 void *bo[SCMN_IMGB_MAX_PLANE];
149 /* TZ memory buffer */
154 #define EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object, x_usr_data ) \
157 if (x_evas_image_object) { \
158 GST_LOG("object callback add"); \
159 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event, x_usr_data); \
160 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, x_usr_data); \
164 #define EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object ) \
167 if (x_evas_image_object) { \
168 GST_LOG("object callback del"); \
169 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event); \
170 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); \
174 #ifdef USE_TBM_SURFACE
175 #define EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK( x_evas, x_usr_data ) \
179 GST_DEBUG("callback add... evas_callback_render_pre.. evas : %p esink : %p", x_evas, x_usr_data); \
180 evas_event_callback_add (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre, x_usr_data); \
184 #define EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK( x_evas ) \
188 GST_DEBUG("callback del... evas_callback_render_pre"); \
189 evas_event_callback_del (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre); \
194 GMutex *instance_lock;
195 guint instance_lock_count;
197 static inline gboolean
198 is_evas_image_object (Evas_Object *obj)
204 type = evas_object_type_get (obj);
208 if (strcmp (type, "image") == 0) {
214 #ifdef USE_TBM_SURFACE
216 gst_evas_image_sink_ref_count (GstBuffer * buf)
218 return GST_OBJECT_REFCOUNT_VALUE(GST_BUFFER_CAST(buf));
222 /* the capabilities of the inputs.
226 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
230 GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx));
232 #ifdef USE_TBM_SURFACE
233 GST_STATIC_CAPS(GST_VIDEO_CAPS_YUV ("I420") ";"
234 GST_VIDEO_CAPS_YUV ("NV12") ";"
235 GST_VIDEO_CAPS_YUV ("SN12"))
238 GST_BOILERPLATE (GstEvasImageSink, gst_evas_image_sink, GstVideoSink, GST_TYPE_VIDEO_SINK);
240 static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
241 static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
242 static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps);
243 static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf);
244 static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event);
245 static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition);
246 static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
247 static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
248 #ifdef USE_TBM_SURFACE
249 static void evas_callback_render_pre (void *data, Evas *e, void *event_info);
250 static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink);
251 static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink);
252 static void _release_flush_buffer(GstEvasImageSink *esink);
253 static void gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result);
254 static void gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink);
257 int util_write_rawdata (const char *file, const void *data, unsigned int size);
262 gst_evas_image_sink_base_init (gpointer gclass)
264 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
266 gst_element_class_set_details_simple (element_class,
269 "Video sink element for evas image object",
270 "Samsung Electronics <www.samsung.com>");
272 gst_element_class_add_pad_template (element_class,
273 gst_static_pad_template_get (&sink_factory));
277 gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass)
279 GObjectClass *gobject_class;
280 GstBaseSinkClass *gstbasesink_class;
281 GstVideoSinkClass *gstvideosink_class;
282 GstElementClass *gstelement_class;
284 gobject_class = (GObjectClass *) klass;
285 gstbasesink_class = GST_BASE_SINK_CLASS (klass);
286 gstvideosink_class = GST_VIDEO_SINK_CLASS (klass);
287 gstelement_class = (GstElementClass *) klass;
289 gobject_class->set_property = gst_evas_image_sink_set_property;
290 gobject_class->get_property = gst_evas_image_sink_get_property;
292 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
293 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW,
295 g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
296 #ifdef USE_TBM_SURFACE
297 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
298 g_param_spec_int("rotate", "Rotate angle", "Rotate angle of display output", DEGREE_0, DEGREE_NUM, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
300 g_param_spec_int("display-geometry-method", "Display geometry method",
301 "Geometrical method for display", DISP_GEO_METHOD_LETTER_BOX, DISP_GEO_METHOD_NUM, DISP_GEO_METHOD_LETTER_BOX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302 g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
303 g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
304 "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
305 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
306 g_object_class_install_property(gobject_class, PROP_FLIP,
307 g_param_spec_int("flip", "Display flip",
308 "Flip for display", FLIP_NONE, FLIP_NUM, FLIP_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310 gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame);
311 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps);
312 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event);
313 gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state);
317 gst_evas_image_sink_fini (gpointer data, GObject *obj)
319 GST_DEBUG ("[ENTER]");
321 GstEvasImageSink *esink = GST_EVASIMAGESINK (obj);
327 gst_buffer_unref (esink->oldbuf);
332 #ifdef USE_TBM_SURFACE
333 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
334 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
336 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
337 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
338 evas_object_image_data_set(esink->eo, NULL);
340 #ifdef USE_TBM_SURFACE
341 if (esink->display_buffer_lock) {
342 g_mutex_free (esink->display_buffer_lock);
343 esink->display_buffer_lock = NULL;
345 if (esink->flow_lock) {
346 g_mutex_free (esink->flow_lock);
347 esink->flow_lock = NULL;
352 g_mutex_lock (instance_lock);
353 instance_lock_count--;
354 g_mutex_unlock (instance_lock);
355 if (instance_lock_count == 0) {
356 g_mutex_free (instance_lock);
357 instance_lock = NULL;
360 GST_DEBUG ("[LEAVE]");
363 #ifdef USE_TBM_SURFACE
365 gst_evas_image_sink_reset (GstEvasImageSink *esink)
368 tbm_bo_handle bo_handle;
370 GST_DEBUG("gst_evas_image_sink_reset start");
372 g_mutex_lock(esink->display_buffer_lock);
374 for(i=0; i<NATIVE_BUFFER_NUM; i++)
376 if(esink->displaying_buffer[i].tbm_surf)
378 tbm_surface_destroy(esink->displaying_buffer[i].tbm_surf);
379 esink->displaying_buffer[i].tbm_surf = NULL;
381 if(esink->displaying_buffer[i].buffer)
383 if(esink->displaying_buffer[i].ref_count)
385 if(esink->displaying_buffer[i].bo) {
386 bo_handle = tbm_bo_map(esink->displaying_buffer[i].bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
387 if (!bo_handle.ptr) {
388 GST_WARNING("failed to map bo [%p]", esink->displaying_buffer[i].bo);
391 tbm_bo_unmap(esink->displaying_buffer[i].bo);
394 GST_WARNING("there is no bo information. so skip to map bo");
396 GST_WARNING("[reset] unreffing gst %p", esink->displaying_buffer[i].buffer);
398 while(esink->displaying_buffer[i].ref_count)
400 GST_WARNING("index[%d]'s buffer ref count=%d",i,gst_evas_image_sink_ref_count (esink->displaying_buffer[i].buffer));
401 esink->displaying_buffer[i].ref_count--;
402 gst_buffer_unref(esink->displaying_buffer[i].buffer);
405 esink->displaying_buffer[i].buffer = NULL;
407 if(esink->displaying_buffer[i].bo)
408 esink->displaying_buffer[i].bo = NULL;
410 esink->prev_buf = NULL;
411 esink->prev_index = -1;
412 esink->cur_index = -1;
414 esink->eo_size.x = esink->eo_size.y =
415 esink->eo_size.w = esink->eo_size.h = 0;
416 esink->use_ratio = FALSE;
417 esink->sent_buffer_cnt = 0;
419 g_mutex_unlock(esink->display_buffer_lock);
425 evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte)
427 #ifdef USE_TBM_SURFACE
429 evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte)
432 GstEvasImageSink *esink = data;
437 GST_DEBUG ("[ENTER]");
438 if (!esink || !esink->eo) {
439 GST_WARNING ("esink : %p, or eo is NULL returning", esink);
442 GST_LOG("esink : %p, esink->eo : %x", esink, esink->eo);
443 if (nbyte == SIZE_FOR_UPDATE_VISIBILITY) {
444 if(!esink->object_show) {
445 evas_object_hide(esink->eo);
446 GST_INFO ("object hide..");
448 evas_object_show(esink->eo);
449 GST_INFO ("object show..");
451 GST_DEBUG ("[LEAVE]");
455 if (!buffer || nbyte != sizeof (GstBuffer *)) {
456 GST_WARNING ("buffer %p, nbyte : %d, sizeof(GstBuffer *) : %d", buffer, nbyte, sizeof (GstBuffer *));
460 #ifdef USE_TBM_SURFACE
462 index = *buffer_index;
463 if ((index<0 || index>=NATIVE_BUFFER_NUM) || nbyte != SIZE_FOR_NATIVE_INDEX) {
464 GST_WARNING ("index : %d, nbyte : %d", index, nbyte);
468 if (GST_STATE(esink) < GST_STATE_PAUSED) {
469 GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink));
474 memcpy (&buf, buffer, sizeof (GstBuffer *));
476 GST_ERROR ("There is no buffer");
479 if (esink->present_data_addr == -1) {
480 /* if present_data_addr is -1, we don't use this member variable */
481 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
482 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
486 #ifdef USE_TBM_SURFACE
487 g_mutex_lock(esink->display_buffer_lock);
488 if(esink->tbm_surface_format == TBM_FORMAT_NV12) {
489 if (!esink->displaying_buffer[index].tbm_surf) {
490 GST_ERROR("the index's nbuffer was already NULL, so return");
491 g_mutex_unlock(esink->display_buffer_lock);
494 GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index);
495 } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) {
496 GST_LOG("received (bo %p) index num : %d", esink->displaying_buffer[index].bo, index);
499 Evas_Native_Surface surf;
500 surf.type = EVAS_NATIVE_SURFACE_TBM;
501 surf.version = EVAS_NATIVE_SURFACE_VERSION;
502 surf.data.tizen.buffer = esink->displaying_buffer[index].tbm_surf;
503 surf.data.tizen.rot = esink->rotate_angle;
504 surf.data.tizen.flip = esink->flip;
506 GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index);
508 GstVideoRectangle result = {0};
510 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
511 if (!esink->eo_size.w || !esink->eo_size.h) {
512 GST_ERROR ("there is no information for evas object size");
513 g_mutex_unlock(esink->display_buffer_lock);
516 gst_evas_image_sink_update_geometry(esink, &result);
517 if(!result.w || !result.h)
519 GST_ERROR("no information about geometry (%d, %d)", result.w, result.h);
520 g_mutex_unlock(esink->display_buffer_lock);
526 surf.data.tizen.ratio = (float) esink->w / esink->h;
527 GST_LOG("set ratio for letter mode");
529 evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL);
530 evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
531 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
532 evas_object_image_size_set(esink->eo, esink->w, esink->h);
533 esink->is_evas_object_size_set = TRUE;
539 guint size = esink->w*esink->h + (esink->w/2*esink->h/2)*2; //this size is for I420 format
540 tbm_bo_handle vaddr_dump;
543 GST_WARNING ("DUMP IMG_%2.2d : buffer size(%d)", g_cnt, size);
544 sprintf(file_name, "DUMP_IMG_%2.2d.dump", g_cnt++);
546 dump_data = g_malloc(size);
547 vaddr_dump = tbm_bo_map(esink->displaying_buffer[index].bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
548 if (vaddr_dump.ptr) {
549 tbm_bo_unmap(esink->displaying_buffer[index].bo);
551 memcpy (dump_data, vaddr_dump.ptr, size);
553 ret = util_write_rawdata(file_name, dump_data, size);
555 GST_ERROR_OBJECT (esink, "util_write_rawdata() failed");
560 evas_object_image_native_surface_set(esink->eo, &surf);
561 GST_DEBUG("native surface set finish");
563 if(result.x || result.y)
564 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
565 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
567 evas_object_image_pixels_dirty_set(esink->eo, EINA_TRUE);
568 GST_DEBUG_OBJECT (esink, "GEO_METHOD : src(%dx%d), dst(%dx%d), dst_x(%d), dst_y(%d), rotate(%d), flip(%d)",
569 esink->w, esink->h, esink->eo_size.w, esink->eo_size.h, esink->eo_size.x, esink->eo_size.y, esink->rotate_angle, esink->flip);
571 /* unref previous buffer */
572 if(esink->tbm_surface_format == TBM_FORMAT_NV12) {
573 if(esink->prev_buf && esink->displaying_buffer[esink->prev_index].ref_count)
575 GST_DEBUG("before index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf);
576 esink->displaying_buffer[esink->prev_index].ref_count--;
577 GST_DEBUG("after index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf);
578 /* Print debug log for 8 frame */
579 if(esink->debuglog_cnt_ecoreCbPipe > 0)
581 GST_WARNING("(%d) ecore_cb_pipe unref index[%d] .. gst_buf %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), esink->prev_index, esink->prev_buf);
582 esink->debuglog_cnt_ecoreCbPipe--;
584 if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT)
585 GST_WARNING("sent buffer cnt 4->3 so skip will be stop");
587 esink->sent_buffer_cnt--;
588 GST_DEBUG("prev gst_buffer %p's unref Start!!", esink->prev_buf);
589 gst_buffer_unref(esink->prev_buf);
590 GST_DEBUG("prev gst_buffer %p's unref End!!", esink->prev_buf);
592 GST_DEBUG("ref_count=%d unref prev gst_buffer %p", esink->displaying_buffer[esink->prev_index].ref_count,esink->prev_buf);
595 GST_DEBUG("Current gst_buf %p and index=%d is overwrited to Prev gst_buf %p & index %d",
596 esink->displaying_buffer[index].buffer, index, esink->prev_buf, esink->prev_index );
597 esink->prev_buf = esink->displaying_buffer[index].buffer;
598 esink->prev_index = index;
599 }else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) {
600 /* Print debug log for 8 frame */
601 if(esink->debuglog_cnt_ecoreCbPipe > 0)
603 GST_WARNING("(%d) ecore_cb_pipe set native surface [%d] tbm_surf[%p]",
604 DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), index, esink->displaying_buffer[index].tbm_surf);
605 esink->debuglog_cnt_ecoreCbPipe--;
607 if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT)
608 GST_WARNING("sent buffer cnt 4->3 so skip will be stop");
610 esink->sent_buffer_cnt--;
614 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
615 evas_object_image_size_set (esink->eo, esink->w, esink->h);
616 GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)", esink->w, esink->h);
617 esink->is_evas_object_size_set = TRUE;
619 if (esink->gl_zerocopy) {
620 img_data = evas_object_image_data_get (esink->eo, EINA_TRUE);
621 if (!img_data || !GST_BUFFER_DATA(buf)) {
622 GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data");
623 evas_object_image_data_set(esink->eo, img_data);
625 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);
626 memcpy (img_data, GST_BUFFER_DATA (buf), esink->w * esink->h * COLOR_DEPTH);
627 evas_object_image_pixels_dirty_set (esink->eo, 1);
628 evas_object_image_data_set(esink->eo, img_data);
630 gst_buffer_unref (buf);
632 GST_DEBUG ("GST_BUFFER_DATA(buf):%x, esink->eo(%x)",GST_BUFFER_DATA(buf),esink->eo);
633 evas_object_image_data_set (esink->eo, GST_BUFFER_DATA (buf));
634 evas_object_image_pixels_dirty_set (esink->eo, 1);
636 gst_buffer_unref(esink->oldbuf);
641 #ifdef USE_TBM_SURFACE
642 g_mutex_unlock(esink->display_buffer_lock);
644 GST_DEBUG ("[LEAVE]");
646 #ifdef USE_TBM_SURFACE
648 gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result)
650 if (!esink || !esink->eo) {
651 GST_WARNING("there is no esink");
658 switch (esink->display_geometry_method)
660 case DISP_GEO_METHOD_LETTER_BOX: // 0
661 /* set black padding for letter box mode */
662 GST_DEBUG("letter box mode");
663 esink->use_ratio = TRUE;
664 result->w = esink->eo_size.w;
665 result->h = esink->eo_size.h;
667 case DISP_GEO_METHOD_ORIGIN_SIZE: // 1
668 GST_DEBUG("origin size mode");
669 esink->use_ratio = FALSE;
670 /* set coordinate for each case */
671 result->x = (esink->eo_size.w-esink->w) / 2;
672 result->y = (esink->eo_size.h-esink->h) / 2;
673 result->w = esink->w;
674 result->h = esink->h;
676 case DISP_GEO_METHOD_FULL_SCREEN: // 2
677 GST_DEBUG("full screen mode");
678 esink->use_ratio = FALSE;
679 result->w = esink->eo_size.w;
680 result->h = esink->eo_size.h;
682 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: // 3
683 GST_DEBUG("cropped full screen mode");
684 esink->use_ratio = FALSE;
685 /* compare evas object's ratio with video's */
686 if((esink->eo_size.w/esink->eo_size.h) > (esink->w/esink->h))
688 result->w = esink->eo_size.w;
689 result->h = esink->eo_size.w * esink->h / esink->w;
690 result->y = -(result->h-esink->eo_size.h) / 2;
694 result->w = esink->eo_size.h * esink->w / esink->h;
695 result->h = esink->eo_size.h;
696 result->x = -(result->w-esink->eo_size.w) / 2;
699 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: // 4
700 GST_DEBUG("origin size or letter box mode");
701 /* if video size is smaller than evas object's, it will be set to origin size mode */
702 if((esink->eo_size.w > esink->w) && (esink->eo_size.h > esink->h))
704 GST_DEBUG("origin size mode");
705 esink->use_ratio = FALSE;
706 /* set coordinate for each case */
707 result->x = (esink->eo_size.w-esink->w) / 2;
708 result->y = (esink->eo_size.h-esink->h) / 2;
709 result->w = esink->w;
710 result->h = esink->h;
714 GST_DEBUG("letter box mode");
715 esink->use_ratio = TRUE;
716 result->w = esink->eo_size.w;
717 result->h = esink->eo_size.h;
721 GST_WARNING("unsupported mode.");
724 GST_DEBUG("geometry result [%d, %d, %d, %d]", result->x, result->y, result->w, result->h);
727 gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink)
729 if (!esink || !esink->eo) {
730 GST_WARNING("there is no esink");
734 Evas_Native_Surface *surf = evas_object_image_native_surface_get(esink->eo);
735 GstVideoRectangle result = {0};
739 GST_DEBUG("native surface exists");
740 surf->data.tizen.rot = esink->rotate_angle;
741 surf->data.tizen.flip = esink->flip;
742 evas_object_image_native_surface_set(esink->eo, surf);
744 gst_evas_image_sink_update_geometry(esink, &result);
748 surf->data.tizen.ratio = (float) esink->w / esink->h;
749 GST_LOG("set ratio for letter mode");
752 if(result.x || result.y)
753 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
755 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
758 GST_WARNING("there is no surf");
763 gst_evas_image_sink_init (GstEvasImageSink *esink, GstEvasImageSinkClass *gclass)
765 GST_DEBUG ("[ENTER]");
769 esink->object_show = FALSE;
770 esink->update_visibility = UPDATE_FALSE;
771 esink->is_evas_object_size_set = FALSE;
773 esink->gl_zerocopy = FALSE;
774 esink->present_data_addr = -1;
776 #ifdef USE_TBM_SURFACE
777 esink->display_buffer_lock = g_mutex_new ();
778 esink->flow_lock = g_mutex_new ();
780 for (i=0; i<NATIVE_BUFFER_NUM; i++)
782 esink->displaying_buffer[i].tbm_surf = NULL;
783 esink->displaying_buffer[i].buffer = NULL;
784 esink->displaying_buffer[i].bo = NULL;
785 esink->displaying_buffer[i].ref_count = 0;
787 esink->prev_buf = NULL;
788 esink->prev_index = -1;
789 esink->cur_index = -1;
790 esink->enable_flush_buffer = TRUE;
791 esink->need_flush = FALSE;
792 esink->display_geometry_method = DISP_GEO_METHOD_LETTER_BOX;
793 esink->flip = FLIP_NONE;
794 esink->eo_size.x = esink->eo_size.y =
795 esink->eo_size.w = esink->eo_size.h = 0;
796 esink->use_ratio = FALSE;
797 esink->sent_buffer_cnt = 0;
798 esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT;
799 esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT;
801 esink->src_buf_idx = 0;
802 esink->is_buffer_allocated = FALSE;
805 instance_lock = g_mutex_new();
807 g_mutex_lock (instance_lock);
808 instance_lock_count++;
809 g_mutex_unlock (instance_lock);
811 g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL);
813 GST_DEBUG ("[LEAVE]");
817 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
819 GST_DEBUG ("[ENTER]");
821 GstEvasImageSink *esink = data;
827 gst_buffer_unref (esink->oldbuf);
828 esink->oldbuf = NULL;
832 #ifdef USE_TBM_SURFACE
833 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
834 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
836 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
837 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
839 evas_object_image_data_set(esink->eo, NULL);
842 GST_DEBUG ("[LEAVE]");
846 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
851 GST_DEBUG ("[ENTER]");
853 GstEvasImageSink *esink = data;
854 if (!esink || !esink->eo) {
858 evas_object_geometry_get(esink->eo, &x, &y, &w, &h);
860 GST_WARNING ("evas object size (w:%d,h:%d) was not set", w, h);
862 #ifdef USE_TBM_SURFACE
863 esink->eo_size.x = x;
864 esink->eo_size.y = y;
865 esink->eo_size.w = w;
866 esink->eo_size.h = h;
867 GST_WARNING ("resize (x:%d, y:%d, w:%d, h:%d)", x, y, w, h);
868 gst_evas_image_sink_apply_geometry(esink);
871 evas_object_image_fill_set(esink->eo, 0, 0, w, h);
872 GST_DEBUG ("evas object fill set (w:%d,h:%d)", w, h);
875 GST_DEBUG ("[LEAVE]");
877 #ifdef USE_TBM_SURFACE
879 evas_callback_render_pre (void *data, Evas *e, void *event_info)
881 GstEvasImageSink *esink = data;
882 if (!esink || !esink->eo) {
883 GST_WARNING("there is no esink info.... esink : %p, or eo is NULL returning", esink);
886 if(esink->need_flush && esink->flush_buffer)
888 g_mutex_lock(esink->display_buffer_lock);
889 Evas_Native_Surface surf;
890 GstVideoRectangle result = {0};
892 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
893 if (!esink->eo_size.w || !esink->eo_size.h) {
894 GST_ERROR ("there is no information for evas object size");
897 gst_evas_image_sink_update_geometry(esink, &result);
898 if(!result.w || !result.h)
900 GST_ERROR("no information about geometry (%d, %d)", result.w, result.h);
906 surf.data.tizen.ratio = (float) esink->w / esink->h;
907 GST_LOG("set ratio for letter mode");
909 evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL);
910 evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
911 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
912 evas_object_image_size_set(esink->eo, esink->w, esink->h);
913 esink->is_evas_object_size_set = TRUE;
916 if(result.x || result.y)
917 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
919 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
921 surf.type = EVAS_NATIVE_SURFACE_TBM;
922 surf.version = EVAS_NATIVE_SURFACE_VERSION;
923 surf.data.tizen.buffer = esink->flush_buffer->tbm_surf;
924 surf.data.tizen.rot = esink->rotate_angle;
925 surf.data.tizen.flip = esink->flip;
926 GST_DEBUG("use esink->flush buffer->tbm_surf (%p), rotate(%d), flip(%d)",
927 esink->flush_buffer->tbm_surf, esink->rotate_angle, esink->flip);
928 evas_object_image_native_surface_set(esink->eo, &surf);
929 g_mutex_unlock(esink->display_buffer_lock);
930 esink->need_flush = FALSE;
932 evas_object_image_pixels_dirty_set (esink->eo, EINA_TRUE);
933 GST_LOG("dirty set finish");
937 gst_evas_image_sink_release_source_buffer(GstEvasImageSink *esink)
940 tbm_bo_handle bo_handle;
941 g_mutex_lock(esink->display_buffer_lock);
943 for(i = 0; i < NATIVE_BUFFER_NUM; i++) {
944 GST_WARNING("[reset] reset gst %p", esink->displaying_buffer[i].buffer);
945 esink->displaying_buffer[i].bo = NULL;
946 esink->displaying_buffer[i].tbm_surf = NULL;
947 esink->displaying_buffer[i].ref_count = 0;
950 for(i = 0; i < SOURCE_BUFFER_NUM; i++) {
951 if(esink->src_buffer_info[i].bo) {
952 tbm_bo_unmap(esink->src_buffer_info[i].bo);
953 esink->src_buffer_info[i].bo = NULL;
956 if (esink->src_buffer_info[i].tbm_surf) {
957 tbm_surface_destroy(esink->src_buffer_info[i].tbm_surf);
958 esink->src_buffer_info[i].tbm_surf = NULL;
962 esink->is_buffer_allocated = FALSE;
963 esink->src_buf_idx = 0;
964 esink->prev_buf = NULL;
965 esink->prev_index = -1;
966 esink->cur_index = -1;
968 esink->eo_size.x = esink->eo_size.y =
969 esink->eo_size.w = esink->eo_size.h = 0;
970 esink->use_ratio = FALSE;
971 esink->sent_buffer_cnt = 0;
973 g_mutex_unlock(esink->display_buffer_lock);
979 gst_evas_image_sink_allocate_source_buffer(GstEvasImageSink *esink)
985 GstFlowReturn ret=GST_FLOW_OK;
988 GST_ERROR("handle is NULL");
992 for(idx=0; idx < SOURCE_BUFFER_NUM; idx++) {
993 if(!esink->src_buffer_info[idx].tbm_surf) {
994 /* create tbm surface */
995 esink->src_buffer_info[idx].tbm_surf = tbm_surface_create(esink->w, esink->h, esink->tbm_surface_format);
997 if(!esink->src_buffer_info[idx].tbm_surf)
999 GST_ERROR("tbm_surf is NULL!!");
1003 /* get bo and size */
1004 bo = tbm_surface_internal_get_bo(esink->src_buffer_info[idx].tbm_surf, 0);
1005 size = tbm_bo_size(bo);
1008 GST_ERROR("bo(%p), size(%d)", bo, size);
1011 esink->src_buffer_info[idx].bo = bo;
1013 vaddr = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1015 GST_WARNING_OBJECT(esink, "get vaddr failed pointer = %p", vaddr.ptr);
1019 memset (vaddr.ptr, 0x0, size);
1020 GST_LOG_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr.ptr);
1023 esink->src_buffer_info[idx].usr_addr = vaddr.ptr;
1025 GST_WARNING_OBJECT(esink, "src buffer index:%d , tbm surface : %p", idx, esink->src_buffer_info[idx].tbm_surf);
1031 gst_evas_image_sink_release_source_buffer(esink);
1037 evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h)
1043 if (!caps || !w || !h) {
1046 s = gst_caps_get_structure (caps, 0);
1051 r = gst_structure_get_int (s, CAP_WIDTH, &width);
1053 GST_DEBUG("fail to get width from caps");
1057 r = gst_structure_get_int (s, CAP_HEIGHT, &height);
1059 GST_DEBUG("fail to get height from caps");
1065 GST_DEBUG ("size w(%d), h(%d)", width, height);
1071 is_zerocopy_supported (Evas *e)
1073 Eina_List *engines, *l;
1082 engines = evas_render_method_list ();
1087 cur_id = evas_output_method_get (e);
1089 EINA_LIST_FOREACH (engines, l, name) {
1090 id = evas_render_method_lookup (name);
1091 if (name && id == cur_id) {
1092 if (!strcmp (name, GL_X11_ENGINE)) {
1102 evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event)
1104 const GstStructure *st;
1105 guint st_data_addr = 0;
1106 gint st_data_width = 0;
1107 gint st_data_height = 0;
1109 g_return_val_if_fail (event != NULL, FALSE);
1110 g_return_val_if_fail (esink != NULL, FALSE);
1112 if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) {
1113 GST_WARNING ("it's not a custom downstream oob event");
1116 st = gst_event_get_structure (event);
1117 if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) {
1118 GST_WARNING ("structure in a given event is not proper");
1121 if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) {
1122 GST_WARNING ("parsing data-addr failed");
1125 esink->present_data_addr = st_data_addr;
1131 gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event)
1134 GstEvasImageSink *esink = GST_EVASIMAGESINK (sink);
1138 switch (GST_EVENT_TYPE (event)) {
1139 case GST_EVENT_FLUSH_START:
1140 GST_DEBUG ("GST_EVENT_FLUSH_START");
1142 case GST_EVENT_FLUSH_STOP:
1143 GST_DEBUG ("GST_EVENT_FLUSH_STOP");
1146 GST_DEBUG ("GST_EVENT_EOS");
1149 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
1150 if(!evas_image_sink_event_parse_data(esink, event)) {
1151 GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr);
1153 GST_ERROR ("evas_image_sink_event_parse_data() failed");
1160 if (GST_BASE_SINK_CLASS (parent_class)->event) {
1161 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
1167 static GstStateChangeReturn
1168 gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition)
1170 GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS;
1171 GstEvasImageSink *esink = NULL;
1172 GstFlowReturn ret=GST_FLOW_OK;
1173 esink = GST_EVASIMAGESINK(element);
1176 GST_ERROR("can not get evasimagesink from element");
1177 return GST_STATE_CHANGE_FAILURE;
1180 switch (transition) {
1181 case GST_STATE_CHANGE_NULL_TO_READY:
1182 GST_WARNING ("*** STATE_CHANGE_NULL_TO_READY ***");
1183 #ifdef USE_TBM_SURFACE
1184 g_mutex_lock (esink->flow_lock);
1185 if (!is_evas_image_object (esink->eo)) {
1186 GST_ERROR_OBJECT (esink, "There is no evas image object..");
1187 g_mutex_unlock (esink->flow_lock);
1188 return GST_STATE_CHANGE_FAILURE;
1190 g_mutex_unlock (esink->flow_lock);
1193 case GST_STATE_CHANGE_READY_TO_PAUSED:
1194 GST_WARNING ("*** STATE_CHANGE_READY_TO_PAUSED ***");
1196 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1197 #ifdef USE_TBM_SURFACE
1198 /* Print debug log for 8 frame */
1199 esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT;
1200 esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT;
1202 GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***");
1208 ret_state = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1210 switch (transition) {
1211 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1212 GST_WARNING ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***");
1214 case GST_STATE_CHANGE_PAUSED_TO_READY:
1215 GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_READY ***");
1216 #ifdef USE_TBM_SURFACE
1218 /* flush buffer, we will copy last buffer to keep image data and reset buffer list */
1219 GST_WARNING("esink->enable_flush_buffer : %d", esink->enable_flush_buffer);
1220 if(esink->enable_flush_buffer && esink->tbm_surface_format == TBM_FORMAT_NV12)
1222 if (gst_esink_make_flush_buffer(esink) == FALSE) {
1223 ret = gst_esink_epipe_reset(esink);
1225 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1226 return GST_STATE_CHANGE_FAILURE;
1228 gst_evas_image_sink_reset(esink);
1232 ret = gst_esink_epipe_reset(esink);
1234 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1235 return GST_STATE_CHANGE_FAILURE;
1237 if(esink->tbm_surface_format == TBM_FORMAT_NV12) {
1238 gst_evas_image_sink_reset(esink);
1239 } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) {
1240 gst_evas_image_sink_release_source_buffer(esink);
1245 case GST_STATE_CHANGE_READY_TO_NULL:
1246 GST_WARNING ("*** STATE_CHANGE_READY_TO_NULL ***");
1247 #ifdef USE_TBM_SURFACE
1248 if(esink->flush_buffer)
1249 _release_flush_buffer(esink);
1250 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
1252 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
1254 GST_DEBUG("ecore-pipe will delete");
1255 ecore_pipe_del (esink->epipe);
1256 esink->epipe = NULL;
1267 gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
1269 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
1272 g_mutex_lock (instance_lock);
1275 case PROP_EVAS_OBJECT:
1276 eo = g_value_get_pointer (value);
1277 if (is_evas_image_object (eo)) {
1278 if (eo != esink->eo) {
1280 #ifdef USE_TBM_SURFACE
1281 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
1283 /* delete evas object callbacks registrated on a previous evas image object */
1284 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
1287 /* add evas object callbacks on a new evas image object */
1288 EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink);
1289 #ifdef USE_TBM_SURFACE
1290 GST_WARNING("register render callback [esink : %p, esink->eo : %x]", esink, esink->eo);
1291 EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo), esink);
1292 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
1293 GST_WARNING ("evas object size (x:%d, y:%d, w:%d, h:%d)", esink->eo_size.x, esink->eo_size.y, esink->eo_size.w, esink->eo_size.h);
1296 esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo));
1297 if (esink->gl_zerocopy) {
1298 evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
1299 GST_DEBUG("Enable gl zerocopy");
1302 GST_DEBUG("Evas Image Object(%x) is set", esink->eo);
1303 esink->is_evas_object_size_set = FALSE;
1304 esink->object_show = TRUE;
1305 esink->update_visibility = UPDATE_TRUE;
1307 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
1308 if (r == EINA_FALSE) {
1309 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility\n");
1314 GST_ERROR ("Cannot set evas-object property: value is not an evas image object");
1318 case PROP_EVAS_OBJECT_SHOW:
1321 esink->object_show = g_value_get_boolean (value);
1322 if( !is_evas_image_object(esink->eo) ) {
1323 GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n");
1326 esink->update_visibility = UPDATE_TRUE;
1327 GST_LOG("esink->update_visibility : %d", esink->update_visibility);
1329 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
1330 if (r == EINA_FALSE) {
1331 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility)\n");
1336 #ifdef USE_TBM_SURFACE
1337 case PROP_ROTATE_ANGLE:
1340 rotate = g_value_get_int (value);
1344 esink->rotate_angle = 0;
1347 esink->rotate_angle = 90;
1350 esink->rotate_angle = 180;
1353 esink->rotate_angle = 270;
1358 GST_INFO("update rotate_angle : %d", esink->rotate_angle);
1361 case PROP_DISPLAY_GEOMETRY_METHOD:
1364 guint geometry = g_value_get_int (value);
1365 if (esink->display_geometry_method != geometry) {
1366 esink->display_geometry_method = geometry;
1367 GST_INFO_OBJECT (esink, "Overlay geometry method update, display_geometry_method(%d)", esink->display_geometry_method);
1370 g_mutex_lock(esink->display_buffer_lock);
1372 if(esink->cur_index!=-1 && esink->epipe)
1374 GST_WARNING("apply property esink->cur_index =%d",esink->cur_index);
1375 esink->displaying_buffer[esink->cur_index].ref_count++;
1376 gst_buffer_ref(esink->displaying_buffer[esink->cur_index].buffer);
1377 esink->sent_buffer_cnt++;
1378 r = ecore_pipe_write (esink->epipe, &esink->cur_index, SIZE_FOR_NATIVE_INDEX);
1380 if (r == EINA_FALSE) {
1381 GST_WARNING("ecore_pipe_write fail");
1382 esink->displaying_buffer[esink->cur_index].ref_count--;
1383 gst_buffer_unref(esink->displaying_buffer[esink->cur_index].buffer);
1384 esink->sent_buffer_cnt--;
1387 g_mutex_unlock(esink->display_buffer_lock);
1390 case PROP_ENABLE_FLUSH_BUFFER:
1391 esink->enable_flush_buffer = g_value_get_boolean(value);
1395 esink->flip = g_value_get_int(value);
1396 GST_INFO("update flip : %d", esink->flip);
1401 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1405 g_mutex_unlock (instance_lock);
1409 gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1411 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
1414 case PROP_EVAS_OBJECT:
1415 g_value_set_pointer (value, esink->eo);
1417 case PROP_EVAS_OBJECT_SHOW:
1418 g_value_set_boolean (value, esink->object_show);
1420 #ifdef USE_TBM_SURFACE
1421 case PROP_ROTATE_ANGLE:
1422 g_value_set_int (value, esink->rotate_angle);
1424 case PROP_DISPLAY_GEOMETRY_METHOD:
1425 g_value_set_int (value, esink->display_geometry_method);
1427 case PROP_ENABLE_FLUSH_BUFFER:
1428 g_value_set_boolean(value, esink->enable_flush_buffer);
1431 g_value_set_int(value, esink->flip);
1435 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1441 gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps)
1445 GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink);
1446 GstStructure *structure = NULL;
1449 esink->is_evas_object_size_set = FALSE;
1450 r = evas_image_sink_get_size_from_caps (caps, &w, &h);
1454 GST_DEBUG ("set size w(%d), h(%d)", w, h);
1457 structure = gst_caps_get_structure (caps, 0);
1462 if (!gst_structure_get_fourcc (structure, "format", &format)) {
1463 GST_DEBUG ("format(dst) is not set...it may be rgb series");
1466 GST_DEBUG_OBJECT(esink, "source color format is %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (format));
1468 #ifdef USE_TBM_SURFACE
1469 if (format == GST_MAKE_FOURCC('S','N','1','2') || format == GST_MAKE_FOURCC('N','V','1','2') ) {
1470 esink->tbm_surface_format = TBM_FORMAT_NV12;
1471 } else if (format == GST_MAKE_FOURCC('I','4','2','0')){
1472 esink->tbm_surface_format = TBM_FORMAT_YUV420;
1474 GST_ERROR("cannot parse fourcc format from caps.");
1482 static GstFlowReturn
1483 gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf)
1485 GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink);
1488 GST_LOG("[ENTER] show frame");
1489 #ifdef USE_TBM_SURFACE
1490 if (!gst_evas_image_sink_ref_count (buf))
1492 GST_WARNING("ref count is 0.. skip show frame");
1496 g_mutex_lock (instance_lock);
1498 if (esink->present_data_addr == -1) {
1499 /* if present_data_addr is -1, we don't use this member variable */
1500 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
1501 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
1502 g_mutex_unlock (instance_lock);
1506 if (!esink->epipe) {
1507 esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink);
1508 if (!esink->epipe) {
1509 GST_ERROR ("ecore-pipe create failed");
1510 g_mutex_unlock (instance_lock);
1511 return GST_FLOW_ERROR;
1513 GST_DEBUG("ecore-pipe create success");
1515 #ifdef USE_TBM_SURFACE
1518 SCMN_IMGB *scmn_imgb = NULL;
1519 gboolean exist_bo = FALSE;
1521 GST_LOG ("BUF: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p",
1522 buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), GST_BUFFER_MALLOCDATA(buf));
1524 if(esink->tbm_surface_format == TBM_FORMAT_NV12) {
1525 /* get received buffer informations */
1526 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
1528 GST_WARNING("scmn_imgb is NULL. Skip..." );
1529 g_mutex_unlock (instance_lock);
1532 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER)
1534 /* check whether bo is new or not */
1535 for(i=0; i<NATIVE_BUFFER_NUM; i++)
1537 if(esink->displaying_buffer[i].bo==scmn_imgb->bo[0])
1539 GST_DEBUG("it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i);
1550 /* find empty buffer space for indexing */
1551 for(i=0; i<NATIVE_BUFFER_NUM; i++)
1553 if(!esink->displaying_buffer[i].bo)
1561 /* keep informations */
1562 esink->displaying_buffer[index].buffer = buf;
1563 esink->displaying_buffer[index].bo = scmn_imgb->bo[0];
1564 GST_WARNING("TBM bo %p / gst_buf %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1566 /* create new tbm surface */
1567 esink->displaying_buffer[index].tbm_surf = tbm_surface_internal_create_with_bos(esink->w, esink->h,
1568 TBM_FORMAT_NV12, esink->displaying_buffer[index].bo, TBM_BO_DEFAULT);
1569 if(!esink->displaying_buffer[index].tbm_surf)
1571 GST_WARNING("there is no tbm surface.. bo : %p, gst_buf : %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1572 g_mutex_unlock (instance_lock);
1576 GST_WARNING("create tbm surface : %p", esink->displaying_buffer[index].tbm_surf);
1579 /* because it has same bo, use existing tbm surface */
1584 esink->displaying_buffer[index].buffer = buf;
1585 GST_DEBUG("existing tbm surface %p.. bo %p, gst_buf %p", esink->displaying_buffer[index].tbm_surf, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1590 /* if it couldn't find proper index */
1592 GST_WARNING("all spaces are using!!!");
1594 GST_DEBUG("selected buffer index %d", index);
1597 else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER)
1599 /* flush buffer, we will copy last buffer to keep image data and reset buffer list */
1600 GST_WARNING_OBJECT(esink, "FLUSH_BUFFER: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p",
1601 buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), GST_BUFFER_MALLOCDATA(buf));
1602 gst_buffer_ref (buf);
1603 if (gst_esink_make_flush_buffer(esink))
1604 GST_WARNING("made flush buffer");
1605 gst_buffer_unref (buf);
1609 GST_ERROR("it is not TBM buffer.. %d", scmn_imgb->buf_share_method);
1611 } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) {
1612 static int skip_count_i420=0;
1613 if(esink->sent_buffer_cnt >= MAX_ECOREPIPE_BUFFER_CNT) {
1614 if(!(skip_count_i420++%20)) {
1615 GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count_i420);
1617 g_mutex_unlock (instance_lock);
1621 if(!esink->is_buffer_allocated) {
1622 /* Allocate TBM buffer for non-zero copy case */
1623 if(!gst_evas_image_sink_allocate_source_buffer(esink)) {
1624 GST_ERROR_OBJECT(esink, "Buffer allocation failed");
1625 g_mutex_unlock (instance_lock);
1626 return GST_FLOW_ERROR;
1628 esink->is_buffer_allocated = TRUE;
1631 skip_count_i420 = 0; //for skip log in I420
1633 /* check whether bo is new or not */
1634 for(i=0; i<NATIVE_BUFFER_NUM; i++) {
1635 if(esink->displaying_buffer[i].bo == esink->src_buffer_info[esink->src_buf_idx].bo) {
1636 GST_DEBUG_OBJECT(esink, "it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i);
1647 /* find empty buffer space for indexing */
1648 for(i=0; i<NATIVE_BUFFER_NUM; i++) {
1649 if(!esink->displaying_buffer[i].bo) {
1656 /* keep informations */
1657 esink->displaying_buffer[index].bo = esink->src_buffer_info[esink->src_buf_idx].bo;
1658 esink->displaying_buffer[index].tbm_surf = esink->src_buffer_info[esink->src_buf_idx].tbm_surf;
1660 GST_DEBUG_OBJECT(esink, "gst_buf %p, TBM bo %p.. gst_buf vaddr %p .. src data size(%lu)",
1661 buf, esink->displaying_buffer[index].bo, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1663 memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1666 /* because it has same bo, use existing tbm surface */
1668 memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1670 GST_DEBUG_OBJECT(esink, "existing tbm surface %p.. gst_buf %p, bo %p, gst_buf vaddr %p",
1671 esink->displaying_buffer[index].tbm_surf, buf, esink->displaying_buffer[index].bo, GST_BUFFER_DATA(buf));
1676 /* if it couldn't find proper index */
1678 GST_WARNING_OBJECT(esink, "all spaces are being used!!!");
1680 GST_DEBUG_OBJECT(esink, "selected buffer index %d", index);
1683 GST_ERROR_OBJECT(esink, "unsupported color format");
1684 g_mutex_unlock (instance_lock);
1685 return GST_FLOW_ERROR;
1688 if (esink->object_show && index != -1) {
1690 gst_buffer_ref (buf);
1691 r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *));
1692 if (r == EINA_FALSE) {
1693 //add error handling
1694 GST_WARNING("ecore_pipe_write fail");
1695 gst_buffer_unref (buf);
1698 #ifdef USE_TBM_SURFACE
1699 int old_curidx=esink->cur_index ;
1700 static int skip_count=0;
1701 g_mutex_lock(esink->display_buffer_lock);
1703 if(esink->tbm_surface_format == TBM_FORMAT_NV12 && scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
1704 if (esink->sent_buffer_cnt < MAX_ECOREPIPE_BUFFER_CNT) {
1705 GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1706 gst_buffer_ref (buf);
1707 esink->displaying_buffer[index].ref_count++;
1708 esink->cur_index = index;
1709 GST_LOG("index %d set refcount increase as %d", index,esink->displaying_buffer[index].ref_count);
1710 GST_LOG("[show_frame] after refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1712 /* Print debug log for 8 frame */
1713 if(esink->debuglog_cnt_showFrame > 0)
1715 GST_WARNING("(%d) ecore_pipe_write index[%d] gst_buf : %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame),
1716 esink->cur_index, esink->displaying_buffer[esink->cur_index].buffer);
1717 esink->debuglog_cnt_showFrame--;
1720 esink->sent_buffer_cnt++;
1723 r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_NATIVE_INDEX);
1725 if (r == EINA_FALSE) {
1726 GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1727 esink->cur_index = old_curidx;
1728 if(esink->displaying_buffer[index].ref_count)
1730 esink->displaying_buffer[index].ref_count--;
1731 esink->sent_buffer_cnt--;
1732 gst_buffer_unref(buf);
1733 GST_ERROR("finish unreffing");
1737 /* If buffer count which is sent to ecore pipe, is upper 3, Print Error log */
1738 if(!(skip_count++%20)) {
1739 GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count);
1742 } else if (esink->tbm_surface_format == TBM_FORMAT_YUV420) {
1743 esink->cur_index = index;
1744 GST_LOG("index %d", index);
1745 GST_LOG("[show_frame] gst_buf vaddr %p", esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1747 /* Print debug log for 8 frame */
1748 if(esink->debuglog_cnt_showFrame > 0)
1750 GST_WARNING("(%d) ecore_pipe_write : index[%d], bo[%p], tbm_surf[%p], gst_buf[%p], gst_buf vaddr [%p]", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame),
1751 esink->cur_index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, buf, esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1752 esink->debuglog_cnt_showFrame--;
1755 esink->sent_buffer_cnt++;
1757 esink->src_buf_idx++;
1758 r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_NATIVE_INDEX);
1760 if (r == EINA_FALSE) {
1761 esink->cur_index = old_curidx;
1762 esink->sent_buffer_cnt--;
1763 esink->src_buf_idx--;
1764 GST_ERROR("ecore_pipe_write is failed. index[%d], bo[%p], tbm_surf[%p], gst_buf vaddr [%p]",
1765 index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1767 esink->src_buf_idx = esink->src_buf_idx % SOURCE_BUFFER_NUM;
1770 g_mutex_unlock(esink->display_buffer_lock);
1772 GST_DEBUG ("ecore_pipe_write() was called with gst_buf= %p.. gst_buf Vaddr=%p, mallocdata= %p", buf, GST_BUFFER_DATA(buf), GST_BUFFER_MALLOCDATA(buf));
1774 GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d) index(%d)", esink->object_show, index);
1776 g_mutex_unlock (instance_lock);
1777 GST_DEBUG ("Leave");
1781 #ifdef USE_TBM_SURFACE
1782 static GstFlowReturn
1783 gst_esink_epipe_reset(GstEvasImageSink *esink)
1785 if (esink == NULL) {
1786 GST_ERROR("handle is NULL");
1787 return GST_FLOW_ERROR;
1791 GST_DEBUG("ecore-pipe will delete");
1792 ecore_pipe_del (esink->epipe);
1793 esink->epipe = NULL;
1796 if (!esink->epipe) {
1797 esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink);
1798 if (!esink->epipe) {
1799 GST_ERROR ("ecore-pipe create failed");
1800 return GST_FLOW_ERROR;
1802 GST_DEBUG("ecore-pipe create success");
1809 static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink)
1811 GstEvasImageFlushBuffer *flush_buffer = NULL;
1812 GstEvasImageDisplayingBuffer *display_buffer = NULL;
1815 tbm_bo_handle vaddr_src;
1816 tbm_bo_handle vaddr_dst;
1817 GstFlowReturn ret=GST_FLOW_OK;
1820 if (esink == NULL) {
1821 GST_ERROR("handle is NULL");
1825 if (esink->cur_index == -1) {
1826 GST_WARNING_OBJECT(esink, "there is no remained buffer");
1830 if(esink->flush_buffer)
1831 _release_flush_buffer(esink);
1834 flush_buffer = (GstEvasImageFlushBuffer *)malloc(sizeof(GstEvasImageFlushBuffer));
1835 if (flush_buffer == NULL) {
1836 GST_ERROR_OBJECT(esink, "GstEvasImageFlushBuffer alloc failed");
1840 memset(flush_buffer, 0x0, sizeof(GstEvasImageFlushBuffer));
1842 display_buffer = &(esink->displaying_buffer[esink->cur_index]);
1843 GST_WARNING_OBJECT(esink, "cur_index [%d]",
1845 if(!display_buffer || !display_buffer->bo)
1847 GST_WARNING("display_buffer(%p) or bo (%p) is NULL!!", display_buffer, display_buffer->bo);
1848 goto FLUSH_BUFFER_FAILED;
1851 /* create tbm surface */
1852 flush_buffer->tbm_surf = tbm_surface_create(esink->w, esink->h, TBM_FORMAT_NV12);
1854 if(!flush_buffer->tbm_surf)
1856 GST_ERROR("tbm_surf is NULL!!");
1857 goto FLUSH_BUFFER_FAILED;
1860 /* get bo and size */
1861 bo = tbm_surface_internal_get_bo(flush_buffer->tbm_surf, 0);
1862 size = tbm_bo_size(bo);
1865 GST_ERROR("bo(%p), size(%d)", bo, size);
1866 goto FLUSH_BUFFER_FAILED;
1868 flush_buffer->bo = bo;
1870 src_size = display_buffer->buffer->size;
1872 vaddr_src = tbm_bo_map(display_buffer->bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1873 vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1874 if (!vaddr_src.ptr || !vaddr_dst.ptr) {
1875 GST_WARNING_OBJECT(esink, "get vaddr failed src %p, dst %p", vaddr_src.ptr, vaddr_dst.ptr);
1876 if (vaddr_src.ptr) {
1877 tbm_bo_unmap(display_buffer->bo);
1879 if (vaddr_dst.ptr) {
1882 goto FLUSH_BUFFER_FAILED;
1884 memset (vaddr_dst.ptr, 0x0, size);
1885 GST_WARNING_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr_dst.ptr);
1889 memcpy(vaddr_dst.ptr, vaddr_src.ptr, src_size);
1891 tbm_bo_unmap(display_buffer->bo);
1894 GST_WARNING_OBJECT(esink, "copy done.. tbm surface : %p src_size : %d", flush_buffer->tbm_surf, src_size);
1896 esink->flush_buffer = flush_buffer;
1898 /* initialize buffer list */
1899 if (esink->object_show)
1900 esink->need_flush = TRUE;
1902 ret = gst_esink_epipe_reset(esink);
1904 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1907 GST_ERROR_OBJECT(esink, "evas epipe reset success");
1910 gst_evas_image_sink_reset(esink);
1915 FLUSH_BUFFER_FAILED:
1917 if(flush_buffer->tbm_surf)
1919 tbm_surface_destroy(flush_buffer->tbm_surf);
1920 flush_buffer->tbm_surf = NULL;
1924 flush_buffer = NULL;
1929 static void _release_flush_buffer(GstEvasImageSink *esink)
1931 if (esink == NULL ||
1932 esink->flush_buffer == NULL) {
1933 GST_WARNING("handle is NULL");
1937 GST_WARNING_OBJECT(esink, "release FLUSH BUFFER start");
1938 if (esink->flush_buffer->bo) {
1939 esink->flush_buffer->bo = NULL;
1941 if(esink->flush_buffer->tbm_surf) {
1942 tbm_surface_destroy(esink->flush_buffer->tbm_surf);
1943 esink->flush_buffer->tbm_surf = NULL;
1946 GST_WARNING_OBJECT(esink, "release FLUSH BUFFER done");
1948 free(esink->flush_buffer);
1949 esink->flush_buffer = NULL;
1955 int util_write_rawdata(const char *file, const void *data, unsigned int size)
1958 fp = fopen(file, "wb");
1961 fwrite((char*)data, sizeof(char), size, fp);
1968 evas_image_sink_init (GstPlugin *evasimagesink)
1970 GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink");
1972 return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK);
1976 #define PACKAGE "gstevasimagesink-plugin-package"
1983 "Evas image object based videosink",
1984 evas_image_sink_init,
1987 "Samsung Electronics Co",
1988 "http://www.samsung.com/"